[BACK]Return to cmdline.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/cmdline.c, Revision 1.1

1.1     ! downsj      1: /* $OpenBSD$   */
        !             2: /* vi:set ts=4 sw=4:
        !             3:  *
        !             4:  * VIM - Vi IMproved       by Bram Moolenaar
        !             5:  *
        !             6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
        !             7:  * Do ":help credits" in Vim to see a list of people who contributed.
        !             8:  */
        !             9:
        !            10: /*
        !            11:  * cmdline.c: functions for reading in the command line and executing it
        !            12:  */
        !            13:
        !            14: #include "vim.h"
        !            15: #include "globals.h"
        !            16: #include "proto.h"
        !            17: #include "option.h"
        !            18: #include "cmdtab.h"
        !            19: #include "ops.h"           /* included because we call functions in ops.c */
        !            20: #ifdef HAVE_FCNTL_H
        !            21: # include <fcntl.h>            /* for chdir() */
        !            22: #endif
        !            23:
        !            24: /*
        !            25:  * variables shared between getcmdline() and redrawcmdline()
        !            26:  */
        !            27: static char_u  *cmdbuff;       /* pointer to command line buffer */
        !            28: static int      cmdbufflen;    /* length of cmdbuff */
        !            29: static int      cmdlen;        /* number of chars on command line */
        !            30: static int      cmdpos;        /* current cursor position */
        !            31: static int      cmdspos;       /* cursor column on screen */
        !            32: static int      cmdfirstc;     /* ':', '/' or '?' */
        !            33:
        !            34: /*
        !            35:  * Typing mode on the command line.  Shared by getcmdline() and
        !            36:  * put_on_cmdline().
        !            37:  */
        !            38: static int     overstrike = FALSE; /* typing mode */
        !            39:
        !            40: /*
        !            41:  * The next two variables contain the bounds of any range given in a command.
        !            42:  * They are set by do_cmdline().
        !            43:  */
        !            44: static linenr_t    line1, line2;
        !            45:
        !            46: static int         forceit;
        !            47: static int         regname;
        !            48: static int         quitmore = 0;
        !            49: static int         cmd_numfiles = -1;    /* number of files found by
        !            50:                                                    filename completion */
        !            51: /*
        !            52:  * There are two history tables:
        !            53:  * 0: colon commands
        !            54:  * 1: search commands
        !            55:  */
        !            56: static char_u      **(history[2]) = {NULL, NULL};  /* history tables */
        !            57: static int         hisidx[2] = {-1, -1};           /* last entered entry */
        !            58: static int         hislen = 0;         /* actual lengt of history tables */
        !            59:
        !            60: #ifdef RIGHTLEFT
        !            61: static int         cmd_hkmap = 0;      /* Hebrew mapping during command line */
        !            62: #endif
        !            63:
        !            64: static void        init_history __ARGS((void));
        !            65:
        !            66: static int     is_in_history __ARGS((int, char_u *, int));
        !            67: static void        putcmdline __ARGS((int));
        !            68: static void        redrawcmd __ARGS((void));
        !            69: static void        cursorcmd __ARGS((void));
        !            70: static int     ccheck_abbr __ARGS((int));
        !            71: static char_u  *do_one_cmd __ARGS((char_u **, int *, int));
        !            72: static int     buf_write_all __ARGS((BUF *));
        !            73: static int     do_write __ARGS((char_u *, int));
        !            74: static char_u  *getargcmd __ARGS((char_u **));
        !            75: static void        backslash_halve __ARGS((char_u *p, int expand_wildcards));
        !            76: static void        do_make __ARGS((char_u *));
        !            77: static int     do_arglist __ARGS((char_u *));
        !            78: static int     is_backslash __ARGS((char_u *str));
        !            79: static int     check_readonly __ARGS((void));
        !            80: static int     check_changed __ARGS((BUF *, int, int));
        !            81: static int     check_changed_any __ARGS((void));
        !            82: static int     check_more __ARGS((int));
        !            83: static void        vim_strncpy __ARGS((char_u *, char_u *, int));
        !            84: static int     nextwild __ARGS((int));
        !            85: static int     showmatches __ARGS((char_u *));
        !            86: static linenr_t get_address __ARGS((char_u **));
        !            87: static void        set_expand_context __ARGS((int, char_u *));
        !            88: static char_u  *set_one_cmd_context __ARGS((int, char_u *));
        !            89: static int     ExpandFromContext __ARGS((char_u *, int *, char_u ***, int, int));
        !            90: static int     ExpandCommands __ARGS((regexp *, int *, char_u ***));
        !            91:
        !            92: /*
        !            93:  * init_history() - initialize the command line history
        !            94:  */
        !            95:    static void
        !            96: init_history()
        !            97: {
        !            98:    int     newlen;         /* new length of history table */
        !            99:    char_u  **temp;
        !           100:    register int i;
        !           101:    int     j;
        !           102:    int     type;
        !           103:
        !           104:    /*
        !           105:     * If size of history table changed, reallocate it
        !           106:     */
        !           107:    newlen = (int)p_hi;
        !           108:    if (newlen != hislen)                       /* history length changed */
        !           109:    {
        !           110:        for (type = 0; type <= 1; ++type)       /* adjust both history tables */
        !           111:        {
        !           112:            if (newlen)
        !           113:                temp = (char_u **)lalloc((long_u)(newlen * sizeof(char_u *)),
        !           114:                                    TRUE);
        !           115:            else
        !           116:                temp = NULL;
        !           117:            if (newlen == 0 || temp != NULL)
        !           118:            {
        !           119:                if (hisidx[type] < 0)           /* there are no entries yet */
        !           120:                {
        !           121:                    for (i = 0; i < newlen; ++i)
        !           122:                        temp[i] = NULL;
        !           123:                }
        !           124:                else if (newlen > hislen)       /* array becomes bigger */
        !           125:                {
        !           126:                    for (i = 0; i <= hisidx[type]; ++i)
        !           127:                        temp[i] = history[type][i];
        !           128:                    j = i;
        !           129:                    for ( ; i <= newlen - (hislen - hisidx[type]); ++i)
        !           130:                        temp[i] = NULL;
        !           131:                    for ( ; j < hislen; ++i, ++j)
        !           132:                        temp[i] = history[type][j];
        !           133:                }
        !           134:                else                            /* array becomes smaller or 0 */
        !           135:                {
        !           136:                    j = hisidx[type];
        !           137:                    for (i = newlen - 1; ; --i)
        !           138:                    {
        !           139:                        if (i >= 0)             /* copy newest entries */
        !           140:                            temp[i] = history[type][j];
        !           141:                        else                    /* remove older entries */
        !           142:                            vim_free(history[type][j]);
        !           143:                        if (--j < 0)
        !           144:                            j = hislen - 1;
        !           145:                        if (j == hisidx[type])
        !           146:                            break;
        !           147:                    }
        !           148:                    hisidx[type] = newlen - 1;
        !           149:                }
        !           150:                vim_free(history[type]);
        !           151:                history[type] = temp;
        !           152:            }
        !           153:        }
        !           154:        hislen = newlen;
        !           155:    }
        !           156: }
        !           157:
        !           158: /*
        !           159:  * check if command line 'str' is already in history
        !           160:  * 'type' is 0 for ':' commands, '1' for search commands
        !           161:  * if 'move_to_front' is TRUE, matching entry is moved to end of history
        !           162:  */
        !           163:    static int
        !           164: is_in_history(type, str, move_to_front)
        !           165:    int     type;
        !           166:    char_u  *str;
        !           167:    int     move_to_front;      /* Move the entry to the front if it exists */
        !           168: {
        !           169:    int     i;
        !           170:    int     last_i = -1;
        !           171:
        !           172:    if (hisidx[type] < 0)
        !           173:        return FALSE;
        !           174:    i = hisidx[type];
        !           175:    do
        !           176:    {
        !           177:        if (history[type][i] == NULL)
        !           178:            return FALSE;
        !           179:        if (STRCMP(str, history[type][i]) == 0)
        !           180:        {
        !           181:            if (!move_to_front)
        !           182:                return TRUE;
        !           183:            last_i = i;
        !           184:            break;
        !           185:        }
        !           186:        if (--i < 0)
        !           187:            i = hislen - 1;
        !           188:    } while (i != hisidx[type]);
        !           189:
        !           190:    if (last_i >= 0)
        !           191:    {
        !           192:        str = history[type][i];
        !           193:        while (i != hisidx[type])
        !           194:        {
        !           195:            if (++i >= hislen)
        !           196:                i = 0;
        !           197:            history[type][last_i] = history[type][i];
        !           198:            last_i = i;
        !           199:        }
        !           200:        history[type][i] = str;
        !           201:        return TRUE;
        !           202:    }
        !           203:    return FALSE;
        !           204: }
        !           205:
        !           206: /*
        !           207:  * Add the given string to the given history.  If the string is already in the
        !           208:  * history then it is moved to the front.  histype may be 0 for the ':'
        !           209:  * history, or 1 for the '/' history.
        !           210:  */
        !           211:    void
        !           212: add_to_history(histype, new_entry)
        !           213:    int     histype;
        !           214:    char_u  *new_entry;
        !           215: {
        !           216:    if (hislen != 0 && !is_in_history(histype, new_entry, TRUE))
        !           217:    {
        !           218:        if (++hisidx[histype] == hislen)
        !           219:            hisidx[histype] = 0;
        !           220:        vim_free(history[histype][hisidx[histype]]);
        !           221:        history[histype][hisidx[histype]] = strsave(new_entry);
        !           222:    }
        !           223: }
        !           224:
        !           225:
        !           226: /*
        !           227:  * getcmdline() - accept a command line starting with ':', '/', or '?'
        !           228:  *
        !           229:  * The line is collected in cmdbuff, which is reallocated to fit the command
        !           230:  * line.
        !           231:  *
        !           232:  * Return pointer to allocated string if there is a commandline, NULL
        !           233:  * otherwise.
        !           234:  */
        !           235:
        !           236:    char_u *
        !           237: getcmdline(firstc, count)
        !           238:    int         firstc;     /* either ':', '/', or '?' */
        !           239:    long        count;      /* only used for incremental search */
        !           240: {
        !           241:    register int        c;
        !           242: #ifdef DIGRAPHS
        !           243:             int        cc;
        !           244: #endif
        !           245:    register int        i;
        !           246:             int        j;
        !           247:             char_u     *p;
        !           248:             int        hiscnt;             /* current history line in use */
        !           249:             char_u     *lookfor = NULL;    /* string to match */
        !           250:             int        gotesc = FALSE;     /* TRUE when <ESC> just typed */
        !           251:             int        do_abbr;            /* when TRUE check for abbr. */
        !           252:             int        histype;            /* history type to be used */
        !           253:             FPOS       old_cursor;
        !           254:             colnr_t    old_curswant;
        !           255:             int        did_incsearch = FALSE;
        !           256:             int        incsearch_postponed = FALSE;
        !           257:             int        save_msg_scroll = msg_scroll;
        !           258:             int        some_key_typed = FALSE; /* one of the keys was typed */
        !           259: #ifdef USE_MOUSE
        !           260:             /* mouse drag and release events are ignored, unless they are
        !           261:              * preceded with a mouse down event */
        !           262:             int        ignore_drag_release = TRUE;
        !           263: #endif
        !           264:
        !           265:    overstrike = FALSE;                     /* always start in insert mode */
        !           266:    old_cursor = curwin->w_cursor;          /* needs to be restored later */
        !           267:    old_curswant = curwin->w_curswant;
        !           268: /*
        !           269:  * set some variables for redrawcmd()
        !           270:  */
        !           271:    cmdfirstc = firstc;
        !           272:    alloc_cmdbuff(0);                   /* allocate initial cmdbuff */
        !           273:    if (cmdbuff == NULL)
        !           274:        return NULL;                    /* out of memory */
        !           275:    cmdlen = cmdpos = 0;
        !           276:    cmdspos = 1;
        !           277:    State = CMDLINE;
        !           278: #ifdef USE_MOUSE
        !           279:    setmouse();
        !           280: #endif
        !           281:    gotocmdline(TRUE);
        !           282:    msg_outchar(firstc);
        !           283:    /*
        !           284:     * Avoid scrolling when called by a recursive do_cmdline(), e.g. when doing
        !           285:     * ":@0" when register 0 doesn't contain a CR.
        !           286:     */
        !           287:    msg_scroll = FALSE;
        !           288:
        !           289:    init_history();
        !           290:    hiscnt = hislen;            /* set hiscnt to impossible history value */
        !           291:    histype = (firstc == ':' ? 0 : 1);
        !           292:
        !           293: #ifdef DIGRAPHS
        !           294:    do_digraph(-1);             /* init digraph typahead */
        !           295: #endif
        !           296:
        !           297:    /* collect the command string, handling editing keys */
        !           298:    for (;;)
        !           299:    {
        !           300:        cursorcmd();            /* set the cursor on the right spot */
        !           301:        c = vgetc();
        !           302:        if (KeyTyped)
        !           303:        {
        !           304:            some_key_typed = TRUE;
        !           305: #ifdef RIGHTLEFT
        !           306:            if (cmd_hkmap)
        !           307:                c = hkmap(c);
        !           308: #endif
        !           309:        }
        !           310:        if (c == Ctrl('C'))
        !           311:            got_int = FALSE;    /* ignore got_int when CTRL-C was typed here */
        !           312:
        !           313:            /* free old command line when finished moving around in the
        !           314:             * history list */
        !           315:        if (lookfor && c != K_S_DOWN && c != K_S_UP &&
        !           316:                c != K_DOWN && c != K_UP &&
        !           317:                c != K_PAGEDOWN && c != K_PAGEUP &&
        !           318:                (cmd_numfiles > 0 || (c != Ctrl('P') && c != Ctrl('N'))))
        !           319:        {
        !           320:            vim_free(lookfor);
        !           321:            lookfor = NULL;
        !           322:        }
        !           323:
        !           324:        /*
        !           325:         * <S-Tab> works like CTRL-P (unless 'wc' is <S-Tab>).
        !           326:         */
        !           327:        if (c != p_wc && c == K_S_TAB)
        !           328:            c = Ctrl('P');
        !           329:
        !           330:            /* free expanded names when finished walking through matches */
        !           331:        if (cmd_numfiles != -1 && !(c == p_wc && KeyTyped) && c != Ctrl('N') &&
        !           332:                        c != Ctrl('P') && c != Ctrl('A') && c != Ctrl('L'))
        !           333:            (void)ExpandOne(NULL, NULL, 0, WILD_FREE);
        !           334:
        !           335: #ifdef DIGRAPHS
        !           336:        c = do_digraph(c);
        !           337: #endif
        !           338:
        !           339:        if (c == '\n' || c == '\r' || (c == ESC && (!KeyTyped ||
        !           340:                                         vim_strchr(p_cpo, CPO_ESC) != NULL)))
        !           341:        {
        !           342:            if (ccheck_abbr(c + ABBR_OFF))
        !           343:                goto cmdline_changed;
        !           344:            outchar('\r');      /* show that we got the return */
        !           345:            screen_cur_col = 0;
        !           346:            flushbuf();
        !           347:            break;
        !           348:        }
        !           349:
        !           350:            /* hitting <ESC> twice means: abandon command line */
        !           351:            /* wildcard expansion is only done when the key is really typed,
        !           352:             * not when it comes from a macro */
        !           353:        if (c == p_wc && !gotesc && KeyTyped)
        !           354:        {
        !           355:            if (cmd_numfiles > 0)   /* typed p_wc twice */
        !           356:                i = nextwild(WILD_NEXT);
        !           357:            else                    /* typed p_wc first time */
        !           358:                i = nextwild(WILD_EXPAND_KEEP);
        !           359:            if (c == ESC)
        !           360:                gotesc = TRUE;
        !           361:            if (i)
        !           362:                goto cmdline_changed;
        !           363:        }
        !           364:        gotesc = FALSE;
        !           365:
        !           366:        if (c == NUL || c == K_ZERO)        /* NUL is stored as NL */
        !           367:            c = NL;
        !           368:
        !           369:        do_abbr = TRUE;         /* default: check for abbreviation */
        !           370:        switch (c)
        !           371:        {
        !           372:        case K_BS:
        !           373:        case Ctrl('H'):
        !           374:        case K_DEL:
        !           375:        case Ctrl('W'):
        !           376:                /*
        !           377:                 * delete current character is the same as backspace on next
        !           378:                 * character, except at end of line
        !           379:                 */
        !           380:                if (c == K_DEL && cmdpos != cmdlen)
        !           381:                    ++cmdpos;
        !           382:                if (cmdpos > 0)
        !           383:                {
        !           384:                    j = cmdpos;
        !           385:                    if (c == Ctrl('W'))
        !           386:                    {
        !           387:                        while (cmdpos && vim_isspace(cmdbuff[cmdpos - 1]))
        !           388:                            --cmdpos;
        !           389:                        i = iswordchar(cmdbuff[cmdpos - 1]);
        !           390:                        while (cmdpos && !vim_isspace(cmdbuff[cmdpos - 1]) &&
        !           391:                                         iswordchar(cmdbuff[cmdpos - 1]) == i)
        !           392:                            --cmdpos;
        !           393:                    }
        !           394:                    else
        !           395:                        --cmdpos;
        !           396:                    cmdlen -= j - cmdpos;
        !           397:                    i = cmdpos;
        !           398:                    while (i < cmdlen)
        !           399:                        cmdbuff[i++] = cmdbuff[j++];
        !           400:                    redrawcmd();
        !           401:                }
        !           402:                else if (cmdlen == 0 && c != Ctrl('W'))
        !           403:                {
        !           404:                    vim_free(cmdbuff);      /* no commandline to return */
        !           405:                    cmdbuff = NULL;
        !           406:                    msg_pos(-1, 0);
        !           407:                    msg_outchar(' ');   /* delete ':' */
        !           408:                    redraw_cmdline = TRUE;
        !           409:                    goto returncmd;     /* back to cmd mode */
        !           410:                }
        !           411:                goto cmdline_changed;
        !           412:
        !           413:        case K_INS:
        !           414:                overstrike = !overstrike;
        !           415:                /* should change shape of cursor */
        !           416:                goto cmdline_not_changed;
        !           417:
        !           418: /*     case '@':   only in very old vi */
        !           419:        case Ctrl('U'):
        !           420:                cmdpos = 0;
        !           421:                cmdlen = 0;
        !           422:                cmdspos = 1;
        !           423:                redrawcmd();
        !           424:                goto cmdline_changed;
        !           425:
        !           426:        case ESC:       /* get here if p_wc != ESC or when ESC typed twice */
        !           427:        case Ctrl('C'):
        !           428:                gotesc = TRUE;      /* will free cmdbuff after putting it in
        !           429:                                        history */
        !           430:                goto returncmd;     /* back to cmd mode */
        !           431:
        !           432:        case Ctrl('R'):             /* insert register */
        !           433:                putcmdline('"');
        !           434:                ++no_mapping;
        !           435:                c = vgetc();
        !           436:                --no_mapping;
        !           437:                if (c != ESC)       /* use ESC to cancel inserting register */
        !           438:                    cmdline_paste(c);
        !           439:                redrawcmd();
        !           440:                goto cmdline_changed;
        !           441:
        !           442:        case Ctrl('D'):
        !           443:            {
        !           444:                if (showmatches(cmdbuff) == FAIL)
        !           445:                    break;      /* Use ^D as normal char instead */
        !           446:
        !           447:                redrawcmd();
        !           448:                continue;       /* don't do incremental search now */
        !           449:            }
        !           450:
        !           451:        case K_RIGHT:
        !           452:        case K_S_RIGHT:
        !           453:                do
        !           454:                {
        !           455:                        if (cmdpos >= cmdlen)
        !           456:                                break;
        !           457:                        cmdspos += charsize(cmdbuff[cmdpos]);
        !           458:                        ++cmdpos;
        !           459:                }
        !           460:                while (c == K_S_RIGHT && cmdbuff[cmdpos] != ' ');
        !           461:                goto cmdline_not_changed;
        !           462:
        !           463:        case K_LEFT:
        !           464:        case K_S_LEFT:
        !           465:                do
        !           466:                {
        !           467:                        if (cmdpos <= 0)
        !           468:                                break;
        !           469:                        --cmdpos;
        !           470:                        cmdspos -= charsize(cmdbuff[cmdpos]);
        !           471:                }
        !           472:                while (c == K_S_LEFT && cmdbuff[cmdpos - 1] != ' ');
        !           473:                goto cmdline_not_changed;
        !           474:
        !           475: #ifdef USE_MOUSE
        !           476:        case K_MIDDLEDRAG:
        !           477:        case K_MIDDLERELEASE:
        !           478:        case K_IGNORE:
        !           479:                goto cmdline_not_changed;   /* Ignore mouse */
        !           480:
        !           481:        case K_MIDDLEMOUSE:
        !           482: # ifdef USE_GUI
        !           483:                /* When GUI is active, also paste when 'mouse' is empty */
        !           484:                if (!gui.in_use)
        !           485: # endif
        !           486:                    if (!mouse_has(MOUSE_COMMAND))
        !           487:                        goto cmdline_not_changed;   /* Ignore mouse */
        !           488: # ifdef USE_GUI
        !           489:                if (gui.in_use && yankbuffer == 0)
        !           490:                    cmdline_paste('*');
        !           491:                else
        !           492: # endif
        !           493:                    cmdline_paste(yankbuffer);
        !           494:                redrawcmd();
        !           495:                goto cmdline_changed;
        !           496:
        !           497:        case K_LEFTDRAG:
        !           498:        case K_LEFTRELEASE:
        !           499:        case K_RIGHTDRAG:
        !           500:        case K_RIGHTRELEASE:
        !           501:                if (ignore_drag_release)
        !           502:                    goto cmdline_not_changed;
        !           503:                /* FALLTHROUGH */
        !           504:        case K_LEFTMOUSE:
        !           505:        case K_RIGHTMOUSE:
        !           506:                if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE)
        !           507:                    ignore_drag_release = TRUE;
        !           508:                else
        !           509:                    ignore_drag_release = FALSE;
        !           510: # ifdef USE_GUI
        !           511:                /* When GUI is active, also move when 'mouse' is empty */
        !           512:                if (!gui.in_use)
        !           513: # endif
        !           514:                    if (!mouse_has(MOUSE_COMMAND))
        !           515:                        goto cmdline_not_changed;   /* Ignore mouse */
        !           516:                cmdspos = 1;
        !           517:                for (cmdpos = 0; cmdpos < cmdlen; ++cmdpos)
        !           518:                {
        !           519:                    i = charsize(cmdbuff[cmdpos]);
        !           520:                    if (mouse_row <= cmdline_row + cmdspos / Columns &&
        !           521:                                        mouse_col < cmdspos % Columns + i)
        !           522:                        break;
        !           523:                    cmdspos += i;
        !           524:                }
        !           525:                goto cmdline_not_changed;
        !           526: #endif /* USE_MOUSE */
        !           527:
        !           528: #ifdef USE_GUI
        !           529:        case K_SCROLLBAR:
        !           530:                if (!msg_scrolled)
        !           531:                {
        !           532:                    gui_do_scroll();
        !           533:                    redrawcmd();
        !           534:                }
        !           535:                goto cmdline_not_changed;
        !           536:
        !           537:        case K_HORIZ_SCROLLBAR:
        !           538:                if (!msg_scrolled)
        !           539:                {
        !           540:                    gui_do_horiz_scroll();
        !           541:                    redrawcmd();
        !           542:                }
        !           543:                goto cmdline_not_changed;
        !           544: #endif
        !           545:
        !           546:        case Ctrl('B'):     /* begin of command line */
        !           547:        case K_HOME:
        !           548:                cmdpos = 0;
        !           549:                cmdspos = 1;
        !           550:                goto cmdline_not_changed;
        !           551:
        !           552:        case Ctrl('E'):     /* end of command line */
        !           553:        case K_END:
        !           554:                cmdpos = cmdlen;
        !           555:                cmdbuff[cmdlen] = NUL;
        !           556:                cmdspos = strsize(cmdbuff) + 1;
        !           557:                goto cmdline_not_changed;
        !           558:
        !           559:        case Ctrl('A'):     /* all matches */
        !           560:                if (!nextwild(WILD_ALL))
        !           561:                    break;
        !           562:                goto cmdline_changed;
        !           563:
        !           564:        case Ctrl('L'):     /* longest common part */
        !           565:                if (!nextwild(WILD_LONGEST))
        !           566:                    break;
        !           567:                goto cmdline_changed;
        !           568:
        !           569:        case Ctrl('N'):     /* next match */
        !           570:        case Ctrl('P'):     /* previous match */
        !           571:                if (cmd_numfiles > 0)
        !           572:                {
        !           573:                    if (!nextwild((c == Ctrl('P')) ? WILD_PREV : WILD_NEXT))
        !           574:                        break;
        !           575:                    goto cmdline_changed;
        !           576:                }
        !           577:
        !           578:        case K_UP:
        !           579:        case K_DOWN:
        !           580:        case K_S_UP:
        !           581:        case K_S_DOWN:
        !           582:        case K_PAGEUP:
        !           583:        case K_PAGEDOWN:
        !           584:                if (hislen == 0)        /* no history */
        !           585:                    goto cmdline_not_changed;
        !           586:
        !           587:                i = hiscnt;
        !           588:
        !           589:                /* save current command string so it can be restored later */
        !           590:                cmdbuff[cmdpos] = NUL;
        !           591:                if (lookfor == NULL && (lookfor = strsave(cmdbuff)) == NULL)
        !           592:                    goto cmdline_not_changed;
        !           593:
        !           594:                j = STRLEN(lookfor);
        !           595:                for (;;)
        !           596:                {
        !           597:                        /* one step backwards */
        !           598:                    if (c == K_UP || c == K_S_UP || c == Ctrl('P') ||
        !           599:                            c == K_PAGEUP)
        !           600:                    {
        !           601:                        if (hiscnt == hislen)   /* first time */
        !           602:                            hiscnt = hisidx[histype];
        !           603:                        else if (hiscnt == 0 && hisidx[histype] != hislen - 1)
        !           604:                            hiscnt = hislen - 1;
        !           605:                        else if (hiscnt != hisidx[histype] + 1)
        !           606:                            --hiscnt;
        !           607:                        else                    /* at top of list */
        !           608:                        {
        !           609:                            hiscnt = i;
        !           610:                            break;
        !           611:                        }
        !           612:                    }
        !           613:                    else    /* one step forwards */
        !           614:                    {
        !           615:                                    /* on last entry, clear the line */
        !           616:                        if (hiscnt == hisidx[histype])
        !           617:                        {
        !           618:                            hiscnt = hislen;
        !           619:                            break;
        !           620:                        }
        !           621:                                    /* not on a history line, nothing to do */
        !           622:                        if (hiscnt == hislen)
        !           623:                            break;
        !           624:                        if (hiscnt == hislen - 1)   /* wrap around */
        !           625:                            hiscnt = 0;
        !           626:                        else
        !           627:                            ++hiscnt;
        !           628:                    }
        !           629:                    if (hiscnt < 0 || history[histype][hiscnt] == NULL)
        !           630:                    {
        !           631:                        hiscnt = i;
        !           632:                        break;
        !           633:                    }
        !           634:                    if ((c != K_UP && c != K_DOWN) || hiscnt == i ||
        !           635:                            STRNCMP(history[histype][hiscnt],
        !           636:                                                    lookfor, (size_t)j) == 0)
        !           637:                        break;
        !           638:                }
        !           639:
        !           640:                if (hiscnt != i)        /* jumped to other entry */
        !           641:                {
        !           642:                    vim_free(cmdbuff);
        !           643:                    if (hiscnt == hislen)
        !           644:                        p = lookfor;    /* back to the old one */
        !           645:                    else
        !           646:                        p = history[histype][hiscnt];
        !           647:
        !           648:                    alloc_cmdbuff((int)STRLEN(p));
        !           649:                    if (cmdbuff == NULL)
        !           650:                        goto returncmd;
        !           651:                    STRCPY(cmdbuff, p);
        !           652:
        !           653:                    cmdpos = cmdlen = STRLEN(cmdbuff);
        !           654:                    redrawcmd();
        !           655:                    goto cmdline_changed;
        !           656:                }
        !           657:                beep_flush();
        !           658:                goto cmdline_not_changed;
        !           659:
        !           660:        case Ctrl('V'):
        !           661:        case Ctrl('Q'):
        !           662: #ifdef USE_MOUSE
        !           663:                ignore_drag_release = TRUE;
        !           664: #endif
        !           665:                putcmdline('^');
        !           666:                c = get_literal();          /* get next (two) character(s) */
        !           667:                do_abbr = FALSE;            /* don't do abbreviation now */
        !           668:                break;
        !           669:
        !           670: #ifdef DIGRAPHS
        !           671:        case Ctrl('K'):
        !           672: #ifdef USE_MOUSE
        !           673:                ignore_drag_release = TRUE;
        !           674: #endif
        !           675:                putcmdline('?');
        !           676:                ++no_mapping;
        !           677:                ++allow_keys;
        !           678:                c = vgetc();
        !           679:                --no_mapping;
        !           680:                --allow_keys;
        !           681:                if (c != ESC)               /* ESC cancels CTRL-K */
        !           682:                {
        !           683:                    if (IS_SPECIAL(c))          /* insert special key code */
        !           684:                        break;
        !           685:                    if (charsize(c) == 1)
        !           686:                        putcmdline(c);
        !           687:                    ++no_mapping;
        !           688:                    ++allow_keys;
        !           689:                    cc = vgetc();
        !           690:                    --no_mapping;
        !           691:                    --allow_keys;
        !           692:                    if (cc != ESC)          /* ESC cancels CTRL-K */
        !           693:                    {
        !           694:                        c = getdigraph(c, cc, TRUE);
        !           695:                        break;
        !           696:                    }
        !           697:                }
        !           698:                redrawcmd();
        !           699:                goto cmdline_not_changed;
        !           700: #endif /* DIGRAPHS */
        !           701:
        !           702: #ifdef RIGHTLEFT
        !           703:        case Ctrl('_'):     /* CTRL-_: switch language mode */
        !           704:                cmd_hkmap = !cmd_hkmap;
        !           705:                goto cmdline_not_changed;
        !           706: #endif
        !           707:
        !           708:        default:
        !           709:                /*
        !           710:                 * Normal character with no special meaning.  Just set mod_mask
        !           711:                 * to 0x0 so that typing Shift-Space in the GUI doesn't enter
        !           712:                 * the string <S-Space>.  This should only happen after ^V.
        !           713:                 */
        !           714:                if (!IS_SPECIAL(c))
        !           715:                    mod_mask = 0x0;
        !           716:                break;
        !           717:        }
        !           718:
        !           719:        /* we come here if we have a normal character */
        !           720:
        !           721:        if (do_abbr && (IS_SPECIAL(c) || !iswordchar(c)) && ccheck_abbr(c))
        !           722:            goto cmdline_changed;
        !           723:
        !           724:        /*
        !           725:         * put the character in the command line
        !           726:         */
        !           727:        if (IS_SPECIAL(c) || mod_mask != 0x0)
        !           728:            put_on_cmdline(get_special_key_name(c, mod_mask), -1, TRUE);
        !           729:        else
        !           730:        {
        !           731:            IObuff[0] = c;
        !           732:            put_on_cmdline(IObuff, 1, TRUE);
        !           733:        }
        !           734:        goto cmdline_changed;
        !           735:
        !           736: /*
        !           737:  * This part implements incremental searches for "/" and "?"
        !           738:  * Jump to cmdline_not_changed when a character has been read but the command
        !           739:  * line did not change. Then we only search and redraw if something changed in
        !           740:  * the past.
        !           741:  * Jump to cmdline_changed when the command line did change.
        !           742:  * (Sorry for the goto's, I know it is ugly).
        !           743:  */
        !           744: cmdline_not_changed:
        !           745:        if (!incsearch_postponed)
        !           746:            continue;
        !           747:
        !           748: cmdline_changed:
        !           749:        if (p_is && (firstc == '/' || firstc == '?'))
        !           750:        {
        !           751:                /* if there is a character waiting, search and redraw later */
        !           752:            if (char_avail())
        !           753:            {
        !           754:                incsearch_postponed = TRUE;
        !           755:                continue;
        !           756:            }
        !           757:            incsearch_postponed = FALSE;
        !           758:            curwin->w_cursor = old_cursor;  /* start at old position */
        !           759:
        !           760:                /* If there is no command line, don't do anything */
        !           761:            if (cmdlen == 0)
        !           762:                i = 0;
        !           763:            else
        !           764:            {
        !           765:                cmdbuff[cmdlen] = NUL;
        !           766:                emsg_off = TRUE;    /* So it doesn't beep if bad expr */
        !           767:                i = do_search(firstc, cmdbuff, count,
        !           768:                                      SEARCH_KEEP + SEARCH_OPT + SEARCH_NOOF);
        !           769:                emsg_off = FALSE;
        !           770:            }
        !           771:            if (i)
        !           772:            {
        !           773:                highlight_match = TRUE;         /* highlight position */
        !           774:                cursupdate();
        !           775:            }
        !           776:            else
        !           777:            {
        !           778:                highlight_match = FALSE;            /* don't highlight */
        !           779:                /* vim_beep(); */ /* even beeps when invalid expr, e.g. "[" */
        !           780:            }
        !           781:            updateScreen(NOT_VALID);
        !           782:            redrawcmdline();
        !           783:            did_incsearch = TRUE;
        !           784:        }
        !           785:    }
        !           786:
        !           787: returncmd:
        !           788:    if (did_incsearch)
        !           789:    {
        !           790:        curwin->w_cursor = old_cursor;
        !           791:        curwin->w_curswant = old_curswant;
        !           792:        highlight_match = FALSE;
        !           793:        redraw_later(NOT_VALID);
        !           794:    }
        !           795:    if (cmdbuff != NULL)
        !           796:    {
        !           797:        /*
        !           798:         * Put line in history buffer (":" only when it was typed).
        !           799:         */
        !           800:        cmdbuff[cmdlen] = NUL;
        !           801:        if (cmdlen != 0 && (some_key_typed || firstc != ':'))
        !           802:        {
        !           803:            add_to_history(histype, cmdbuff);
        !           804:            if (firstc == ':')
        !           805:            {
        !           806:                vim_free(new_last_cmdline);
        !           807:                new_last_cmdline = strsave(cmdbuff);
        !           808:            }
        !           809:        }
        !           810:
        !           811:        if (gotesc)         /* abandon command line */
        !           812:        {
        !           813:            vim_free(cmdbuff);
        !           814:            cmdbuff = NULL;
        !           815:            MSG("");
        !           816:            redraw_cmdline = TRUE;
        !           817:        }
        !           818:    }
        !           819:
        !           820:    /*
        !           821:     * If the screen was shifted up, redraw the whole screen (later).
        !           822:     * If the line is too long, clear it, so ruler and shown command do
        !           823:     * not get printed in the middle of it.
        !           824:     */
        !           825:    msg_check();
        !           826:    msg_scroll = save_msg_scroll;
        !           827:    State = NORMAL;
        !           828: #ifdef USE_MOUSE
        !           829:    setmouse();
        !           830: #endif
        !           831:    return cmdbuff;
        !           832: }
        !           833:
        !           834: /*
        !           835:  * Put the given string, of the given length, onto the command line.
        !           836:  * If len is -1, then STRLEN() is used to calculate the length.
        !           837:  * If 'redraw' is TRUE then the new part of the command line, and the remaining
        !           838:  * part will be redrawn, otherwise it will not.  If this function is called
        !           839:  * twice in a row, then 'redraw' should be FALSE and redrawcmd() should be
        !           840:  * called afterwards.
        !           841:  */
        !           842:    int
        !           843: put_on_cmdline(str, len, redraw)
        !           844:    char_u  *str;
        !           845:    int     len;
        !           846:    int     redraw;
        !           847: {
        !           848:    int     i;
        !           849:
        !           850:    if (len < 0)
        !           851:        len = STRLEN(str);
        !           852:
        !           853:    /* Check if cmdbuff needs to be longer */
        !           854:    if (cmdlen + len + 1 >= cmdbufflen)
        !           855:        i = realloc_cmdbuff(cmdlen + len);
        !           856:    else
        !           857:        i = OK;
        !           858:    if (i == OK)
        !           859:    {
        !           860:        if (!overstrike)
        !           861:        {
        !           862:            vim_memmove(cmdbuff + cmdpos + len, cmdbuff + cmdpos,
        !           863:                                                   (size_t)(cmdlen - cmdpos));
        !           864:            cmdlen += len;
        !           865:        }
        !           866:        else if (cmdpos + len > cmdlen)
        !           867:            cmdlen = cmdpos + len;
        !           868:        vim_memmove(cmdbuff + cmdpos, str, (size_t)len);
        !           869:        if (redraw)
        !           870:            msg_outtrans_len(cmdbuff + cmdpos, cmdlen - cmdpos);
        !           871:        cmdpos += len;
        !           872:        while (len--)
        !           873:            cmdspos += charsize(str[len]);
        !           874:    }
        !           875:    if (redraw)
        !           876:        msg_check();
        !           877:    return i;
        !           878: }
        !           879:
        !           880:    void
        !           881: alloc_cmdbuff(len)
        !           882:    int     len;
        !           883: {
        !           884:    /*
        !           885:     * give some extra space to avoid having to allocate all the time
        !           886:     */
        !           887:    if (len < 80)
        !           888:        len = 100;
        !           889:    else
        !           890:        len += 20;
        !           891:
        !           892:    cmdbuff = alloc(len);       /* caller should check for out of memory */
        !           893:    cmdbufflen = len;
        !           894: }
        !           895:
        !           896: /*
        !           897:  * Re-allocate the command line to length len + something extra.
        !           898:  * return FAIL for failure, OK otherwise
        !           899:  */
        !           900:    int
        !           901: realloc_cmdbuff(len)
        !           902:    int     len;
        !           903: {
        !           904:    char_u      *p;
        !           905:
        !           906:    p = cmdbuff;
        !           907:    alloc_cmdbuff(len);             /* will get some more */
        !           908:    if (cmdbuff == NULL)            /* out of memory */
        !           909:    {
        !           910:        cmdbuff = p;                /* keep the old one */
        !           911:        return FAIL;
        !           912:    }
        !           913:    vim_memmove(cmdbuff, p, (size_t)cmdlen);
        !           914:    vim_free(p);
        !           915:    return OK;
        !           916: }
        !           917:
        !           918: /*
        !           919:  * put a character on the command line.
        !           920:  * Used for CTRL-V and CTRL-K
        !           921:  */
        !           922:    static void
        !           923: putcmdline(c)
        !           924:    int     c;
        !           925: {
        !           926:    char_u  buf[1];
        !           927:
        !           928:    buf[0] = c;
        !           929:    msg_outtrans_len(buf, 1);
        !           930:    msg_outtrans_len(cmdbuff + cmdpos, cmdlen - cmdpos);
        !           931:    cursorcmd();
        !           932: }
        !           933:
        !           934: /*
        !           935:  * this fuction is called when the screen size changes and with incremental
        !           936:  * search
        !           937:  */
        !           938:    void
        !           939: redrawcmdline()
        !           940: {
        !           941:    msg_scrolled = 0;
        !           942:    need_wait_return = FALSE;
        !           943:    compute_cmdrow();
        !           944:    redrawcmd();
        !           945:    cursorcmd();
        !           946: }
        !           947:
        !           948:    void
        !           949: compute_cmdrow()
        !           950: {
        !           951:    cmdline_row = lastwin->w_winpos + lastwin->w_height +
        !           952:                                        lastwin->w_status_height;
        !           953: }
        !           954:
        !           955: /*
        !           956:  * Redraw what is currently on the command line.
        !           957:  */
        !           958:    static void
        !           959: redrawcmd()
        !           960: {
        !           961:    register int    i;
        !           962:
        !           963:    msg_start();
        !           964:    msg_outchar(cmdfirstc);
        !           965:    msg_outtrans_len(cmdbuff, cmdlen);
        !           966:    msg_clr_eos();
        !           967:
        !           968:    cmdspos = 1;
        !           969:    for (i = 0; i < cmdlen && i < cmdpos; ++i)
        !           970:        cmdspos += charsize(cmdbuff[i]);
        !           971:    /*
        !           972:     * An emsg() before may have set msg_scroll and need_sleep. These are used
        !           973:     * in normal mode, in cmdline mode we can reset them now.
        !           974:     */
        !           975:    msg_scroll = FALSE;         /* next message overwrites cmdline */
        !           976: #ifdef SLEEP_IN_EMSG
        !           977:    need_sleep = FALSE;         /* don't sleep */
        !           978: #endif
        !           979: }
        !           980:
        !           981:    static void
        !           982: cursorcmd()
        !           983: {
        !           984:    msg_pos(cmdline_row + (cmdspos / (int)Columns), cmdspos % (int)Columns);
        !           985:    windgoto(msg_row, msg_col);
        !           986: }
        !           987:
        !           988: /*
        !           989:  * Check the word in front of the cursor for an abbreviation.
        !           990:  * Called when the non-id character "c" has been entered.
        !           991:  * When an abbreviation is recognized it is removed from the text with
        !           992:  * backspaces and the replacement string is inserted, followed by "c".
        !           993:  */
        !           994:    static int
        !           995: ccheck_abbr(c)
        !           996:    int c;
        !           997: {
        !           998:    if (p_paste || no_abbr)         /* no abbreviations or in paste mode */
        !           999:        return FALSE;
        !          1000:
        !          1001:    return check_abbr(c, cmdbuff, cmdpos, 0);
        !          1002: }
        !          1003:
        !          1004: /*
        !          1005:  * do_cmdline(): execute an Ex command line
        !          1006:  *
        !          1007:  * 1. If no line given, get one.
        !          1008:  * 2. Split up in parts separated with '|'.
        !          1009:  *
        !          1010:  * This function may be called recursively!
        !          1011:  *
        !          1012:  * If 'sourcing' is TRUE, the command will be included in the error message.
        !          1013:  * If 'repeating' is TRUE, there is no wait_return() and friends.
        !          1014:  *
        !          1015:  * return FAIL if commandline could not be executed, OK otherwise
        !          1016:  */
        !          1017:    int
        !          1018: do_cmdline(cmdline, sourcing, repeating)
        !          1019:    char_u      *cmdline;
        !          1020:    int         sourcing;
        !          1021:    int         repeating;
        !          1022: {
        !          1023:    int         cmdlinelen;
        !          1024:    char_u      *nextcomm;
        !          1025:    static int  recursive = 0;          /* recursive depth */
        !          1026:    int         got_cmdline = FALSE;    /* TRUE when cmdline was typed */
        !          1027:    int         msg_didout_before_start;
        !          1028:
        !          1029: /*
        !          1030:  * 1. If no line given: Get a line in cmdbuff.
        !          1031:  *    If a line is given: Copy it into cmdbuff.
        !          1032:  *    After this we don't use cmdbuff but cmdline, because of recursiveness
        !          1033:  */
        !          1034:    if (cmdline == NULL)
        !          1035:    {
        !          1036:        if ((cmdline = getcmdline(':', 1L)) == NULL)
        !          1037:        {
        !          1038:                /* don't call wait_return for aborted command line */
        !          1039:            need_wait_return = FALSE;
        !          1040:            return FAIL;
        !          1041:        }
        !          1042:        got_cmdline = TRUE;
        !          1043:    }
        !          1044:    else
        !          1045:    {
        !          1046:        /* Make a copy of the command so we can mess with it. */
        !          1047:        alloc_cmdbuff((int)STRLEN(cmdline));
        !          1048:        if (cmdbuff == NULL)
        !          1049:            return FAIL;
        !          1050:        STRCPY(cmdbuff, cmdline);
        !          1051:        cmdline = cmdbuff;
        !          1052:    }
        !          1053:    cmdlinelen = cmdbufflen;        /* we need to copy it for recursiveness */
        !          1054:
        !          1055: /*
        !          1056:  * All output from the commands is put below each other, without waiting for a
        !          1057:  * return. Don't do this when executing commands from a script or when being
        !          1058:  * called recursive (e.g. for ":e +command file").
        !          1059:  */
        !          1060:    msg_didout_before_start = msg_didout;
        !          1061:    if (!repeating && !recursive)
        !          1062:    {
        !          1063:        msg_didany = FALSE;     /* no output yet */
        !          1064:        msg_start();
        !          1065:        msg_scroll = TRUE;      /* put messages below each other */
        !          1066: #ifdef SLEEP_IN_EMSG
        !          1067:        ++dont_sleep;           /* don't sleep in emsg() */
        !          1068: #endif
        !          1069:        ++no_wait_return;       /* dont wait for return until finished */
        !          1070:        ++RedrawingDisabled;
        !          1071:    }
        !          1072:
        !          1073: /*
        !          1074:  * 2. Loop for each '|' separated command.
        !          1075:  *    do_one_cmd will set nextcomm to NULL if there is no trailing '|'.
        !          1076:  *    cmdline and cmdlinelen may change, e.g. for '%' and '#' expansion.
        !          1077:  */
        !          1078:    ++recursive;
        !          1079:    for (;;)
        !          1080:    {
        !          1081:        nextcomm = do_one_cmd(&cmdline, &cmdlinelen, sourcing);
        !          1082:        if (nextcomm == NULL)
        !          1083:            break;
        !          1084:        STRCPY(cmdline, nextcomm);
        !          1085:    }
        !          1086:    --recursive;
        !          1087:    vim_free(cmdline);
        !          1088:
        !          1089: /*
        !          1090:  * If there was too much output to fit on the command line, ask the user to
        !          1091:  * hit return before redrawing the screen. With the ":global" command we do
        !          1092:  * this only once after the command is finished.
        !          1093:  */
        !          1094:    if (!repeating && !recursive)
        !          1095:    {
        !          1096:        --RedrawingDisabled;
        !          1097: #ifdef SLEEP_IN_EMSG
        !          1098:        --dont_sleep;
        !          1099: #endif
        !          1100:        --no_wait_return;
        !          1101:        msg_scroll = FALSE;
        !          1102:        if (need_wait_return || (msg_check() && !dont_wait_return))
        !          1103:        {
        !          1104:            /*
        !          1105:             * The msg_start() above clears msg_didout. The wait_return we do
        !          1106:             * here should not overwrite the command that may be shown before
        !          1107:             * doing that.
        !          1108:             */
        !          1109:            msg_didout = msg_didout_before_start;
        !          1110:            wait_return(FALSE);
        !          1111:        }
        !          1112:    }
        !          1113:
        !          1114: /*
        !          1115:  * If the command was typed, remember it for register :
        !          1116:  * Do this AFTER executing the command to make :@: work.
        !          1117:  */
        !          1118:    if (got_cmdline && new_last_cmdline != NULL)
        !          1119:    {
        !          1120:        vim_free(last_cmdline);
        !          1121:        last_cmdline = new_last_cmdline;
        !          1122:        new_last_cmdline = NULL;
        !          1123:    }
        !          1124:    return OK;
        !          1125: }
        !          1126:
        !          1127: static char *(make_cmd_chars[6]) =
        !          1128: {  " \164\145a",
        !          1129:    "\207\171\204\170\060\175\171\174\173\117\032",
        !          1130:    " c\157\146\146e\145",
        !          1131:    "\200\174\165\161\203\165\060\171\176\203\165\202\204\060\163\177\171\176\060\204\177\060\202\205\176\060\175\161\173\165\032",
        !          1132:    " \164o\141\163t",
        !          1133:    "\136\137\122\137\124\151\060\165\210\200\165\163\204\203\060\204\170\165\060\143\200\161\176\171\203\170\060\171\176\201\205\171\203\171\204\171\177\176\061\032"
        !          1134: };
        !          1135:
        !          1136: /*
        !          1137:  * Execute one Ex command.
        !          1138:  *
        !          1139:  * If 'sourcing' is TRUE, the command will be included in the error message.
        !          1140:  *
        !          1141:  * 2. skip comment lines and leading space
        !          1142:  * 3. parse range
        !          1143:  * 4. parse command
        !          1144:  * 5. parse arguments
        !          1145:  * 6. switch on command name
        !          1146:  *
        !          1147:  * This function may be called recursively!
        !          1148:  */
        !          1149:    static char_u *
        !          1150: do_one_cmd(cmdlinep, cmdlinelenp, sourcing)
        !          1151:    char_u      **cmdlinep;
        !          1152:    int         *cmdlinelenp;
        !          1153:    int         sourcing;
        !          1154: {
        !          1155:    char_u              *p;
        !          1156:    char_u              *q;
        !          1157:    char_u              *s;
        !          1158:    char_u              *cmd, *arg;
        !          1159:    char_u              *do_ecmd_cmd = NULL;    /* +command for do_ecmd() */
        !          1160:    linenr_t            do_ecmd_lnum = 0;       /* lnum file for do_ecmd() */
        !          1161:    int                 i = 0;                  /* init to shut up gcc */
        !          1162:    int                 len;
        !          1163:    int                 cmdidx;
        !          1164:    long                argt;
        !          1165:    register linenr_t   lnum;
        !          1166:    long                n = 0;                  /* init to shut up gcc */
        !          1167:    int                 addr_count;             /* number of address specs */
        !          1168:    FPOS                pos;
        !          1169:    int                 append = FALSE;         /* write with append */
        !          1170:    int                 usefilter = FALSE;      /* no read/write but filter */
        !          1171:    char_u              *nextcomm = NULL;       /* no next command yet */
        !          1172:    int                 amount = 0;             /* for ":>"; init for gcc */
        !          1173:    char_u              *errormsg = NULL;       /* error message */
        !          1174:    WIN                 *old_curwin = NULL;     /* init for GCC */
        !          1175:
        !          1176:        /* when not editing the last file :q has to be typed twice */
        !          1177:    if (quitmore)
        !          1178:        --quitmore;
        !          1179:    did_emsg = FALSE;       /* will be set to TRUE when emsg() used, in which
        !          1180:                             * case we set nextcomm to NULL to cancel the
        !          1181:                             * whole command line */
        !          1182: /*
        !          1183:  * 2. skip comment lines and leading space and colons
        !          1184:  */
        !          1185:    for (cmd = *cmdlinep; vim_strchr((char_u *)" \t:", *cmd) != NULL; cmd++)
        !          1186:        ;
        !          1187:
        !          1188:    if (*cmd == '"' || *cmd == NUL) /* ignore comment and empty lines */
        !          1189:        goto doend;
        !          1190:
        !          1191: /*
        !          1192:  * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
        !          1193:  *
        !          1194:  * where 'addr' is:
        !          1195:  *
        !          1196:  * %         (entire file)
        !          1197:  * $  [+-NUM]
        !          1198:  * 'x [+-NUM] (where x denotes a currently defined mark)
        !          1199:  * .  [+-NUM]
        !          1200:  * [+-NUM]..
        !          1201:  * NUM
        !          1202:  *
        !          1203:  * The cmd pointer is updated to point to the first character following the
        !          1204:  * range spec. If an initial address is found, but no second, the upper bound
        !          1205:  * is equal to the lower.
        !          1206:  */
        !          1207:
        !          1208:    addr_count = 0;
        !          1209:    --cmd;
        !          1210:    do
        !          1211:    {
        !          1212:        line1 = line2;
        !          1213:        line2 = curwin->w_cursor.lnum;  /* default is current line number */
        !          1214:        cmd = skipwhite(cmd + 1);       /* skip ',' or ';' and following ' ' */
        !          1215:        lnum = get_address(&cmd);
        !          1216:        if (cmd == NULL)                /* error detected */
        !          1217:            goto doend;
        !          1218:        if (lnum == MAXLNUM)
        !          1219:        {
        !          1220:            if (*cmd == '%')            /* '%' - all lines */
        !          1221:            {
        !          1222:                ++cmd;
        !          1223:                line1 = 1;
        !          1224:                line2 = curbuf->b_ml.ml_line_count;
        !          1225:                ++addr_count;
        !          1226:            }
        !          1227:            else if (*cmd == '*')       /* '*' - visual area */
        !          1228:            {
        !          1229:                FPOS        *fp;
        !          1230:
        !          1231:                ++cmd;
        !          1232:                fp = getmark('<', FALSE);
        !          1233:                if (check_mark(fp) == FAIL)
        !          1234:                    goto doend;
        !          1235:                line1 = fp->lnum;
        !          1236:                fp = getmark('>', FALSE);
        !          1237:                if (check_mark(fp) == FAIL)
        !          1238:                    goto doend;
        !          1239:                line2 = fp->lnum;
        !          1240:                ++addr_count;
        !          1241:            }
        !          1242:        }
        !          1243:        else
        !          1244:            line2 = lnum;
        !          1245:        addr_count++;
        !          1246:
        !          1247:        if (*cmd == ';')
        !          1248:        {
        !          1249:            if (line2 == 0)
        !          1250:                curwin->w_cursor.lnum = 1;
        !          1251:            else
        !          1252:                curwin->w_cursor.lnum = line2;
        !          1253:        }
        !          1254:    } while (*cmd == ',' || *cmd == ';');
        !          1255:
        !          1256:    /* One address given: set start and end lines */
        !          1257:    if (addr_count == 1)
        !          1258:    {
        !          1259:        line1 = line2;
        !          1260:            /* ... but only implicit: really no address given */
        !          1261:        if (lnum == MAXLNUM)
        !          1262:            addr_count = 0;
        !          1263:    }
        !          1264:
        !          1265: /*
        !          1266:  * 4. parse command
        !          1267:  */
        !          1268:
        !          1269:    /*
        !          1270:     * Skip ':' and any white space
        !          1271:     */
        !          1272:    cmd = skipwhite(cmd);
        !          1273:    if (*cmd == ':')
        !          1274:        cmd = skipwhite(cmd + 1);
        !          1275:
        !          1276:    /*
        !          1277:     * If we got a line, but no command, then go to the line.
        !          1278:     * If we find a '|' or '\n' we set nextcomm.
        !          1279:     */
        !          1280:    if (*cmd == NUL || *cmd == '"' ||
        !          1281:            ((*cmd == '|' || *cmd == '\n') &&
        !          1282:                    (nextcomm = cmd + 1) != NULL))      /* just an assignment */
        !          1283:    {
        !          1284:        /*
        !          1285:         * strange vi behaviour:
        !          1286:         * ":3"         jumps to line 3
        !          1287:         * ":3|..."     prints line 3
        !          1288:         * ":|"         prints current line
        !          1289:         */
        !          1290:        if (*cmd == '|')
        !          1291:        {
        !          1292:            cmdidx = CMD_print;
        !          1293:            goto cmdswitch;         /* UGLY goto */
        !          1294:        }
        !          1295:        if (addr_count != 0)
        !          1296:        {
        !          1297:            if (line2 == 0)
        !          1298:                curwin->w_cursor.lnum = 1;
        !          1299:            else if (line2 > curbuf->b_ml.ml_line_count)
        !          1300:                curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
        !          1301:            else
        !          1302:                curwin->w_cursor.lnum = line2;
        !          1303:            beginline(MAYBE);
        !          1304:            /* This causes problems for ":234", since displaying is disabled
        !          1305:             * here */
        !          1306:            /* cursupdate(); */
        !          1307:        }
        !          1308:        goto doend;
        !          1309:    }
        !          1310:
        !          1311:    /*
        !          1312:     * Isolate the command and search for it in the command table.
        !          1313:     * Exeptions:
        !          1314:     * - the 'k' command can directly be followed by any character.
        !          1315:     * - the 's' command can be followed directly by 'c', 'g' or 'r'
        !          1316:     *      but :sre[wind] is another command.
        !          1317:     */
        !          1318:    if (*cmd == 'k')
        !          1319:    {
        !          1320:        cmdidx = CMD_k;
        !          1321:        p = cmd + 1;
        !          1322:    }
        !          1323:    else if (*cmd == 's' && vim_strchr((char_u *)"cgr", cmd[1]) != NULL &&
        !          1324:                                          STRNCMP("sre", cmd, (size_t)3) != 0)
        !          1325:    {
        !          1326:        cmdidx = CMD_substitute;
        !          1327:        p = cmd + 1;
        !          1328:    }
        !          1329:    else
        !          1330:    {
        !          1331:        p = cmd;
        !          1332:        while (isalpha(*p))
        !          1333:            ++p;
        !          1334:            /* check for non-alpha command */
        !          1335:        if (p == cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL)
        !          1336:            ++p;
        !          1337:        i = (int)(p - cmd);
        !          1338:
        !          1339:        for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
        !          1340:            if (STRNCMP(cmdnames[cmdidx].cmd_name, (char *)cmd, (size_t)i) == 0)
        !          1341:                break;
        !          1342:        if (i == 0 || cmdidx == CMD_SIZE)
        !          1343:        {
        !          1344:            STRCPY(IObuff, "Not an editor command");
        !          1345:            if (!sourcing)
        !          1346:            {
        !          1347:                STRCAT(IObuff, ": ");
        !          1348:                STRNCAT(IObuff, *cmdlinep, 40);
        !          1349:            }
        !          1350:            errormsg = IObuff;
        !          1351:            goto doend;
        !          1352:        }
        !          1353:    }
        !          1354:
        !          1355:    if (*p == '!')                  /* forced commands */
        !          1356:    {
        !          1357:        ++p;
        !          1358:        forceit = TRUE;
        !          1359:    }
        !          1360:    else
        !          1361:        forceit = FALSE;
        !          1362:
        !          1363: /*
        !          1364:  * 5. parse arguments
        !          1365:  */
        !          1366:    argt = cmdnames[cmdidx].cmd_argt;
        !          1367:
        !          1368:    if (!(argt & RANGE) && addr_count)      /* no range allowed */
        !          1369:    {
        !          1370:        errormsg = e_norange;
        !          1371:        goto doend;
        !          1372:    }
        !          1373:
        !          1374:    if (!(argt & BANG) && forceit)          /* no <!> allowed */
        !          1375:    {
        !          1376:        errormsg = e_nobang;
        !          1377:        goto doend;
        !          1378:    }
        !          1379:
        !          1380: /*
        !          1381:  * If the range is backwards, ask for confirmation and, if given, swap
        !          1382:  * line1 & line2 so it's forwards again.
        !          1383:  * When global command is busy, don't ask, will fail below.
        !          1384:  */
        !          1385:    if (!global_busy && line1 > line2)
        !          1386:    {
        !          1387:        if (sourcing)
        !          1388:        {
        !          1389:            errormsg = (char_u *)"Backwards range given";
        !          1390:            goto doend;
        !          1391:        }
        !          1392:        else if (ask_yesno((char_u *)"Backwards range given, OK to swap", FALSE) != 'y')
        !          1393:            goto doend;
        !          1394:        lnum = line1;
        !          1395:        line1 = line2;
        !          1396:        line2 = lnum;
        !          1397:    }
        !          1398:    /*
        !          1399:     * don't complain about the range if it is not used
        !          1400:     * (could happen if line_count is accidently set to 0)
        !          1401:     */
        !          1402:    if (line1 < 0 || line2 < 0  || line1 > line2 || ((argt & RANGE) &&
        !          1403:                    !(argt & NOTADR) && line2 > curbuf->b_ml.ml_line_count))
        !          1404:    {
        !          1405:        errormsg = e_invrange;
        !          1406:        goto doend;
        !          1407:    }
        !          1408:
        !          1409:    if ((argt & NOTADR) && addr_count == 0)     /* default is 1, not cursor */
        !          1410:        line2 = 1;
        !          1411:
        !          1412:    if (!(argt & ZEROR))            /* zero in range not allowed */
        !          1413:    {
        !          1414:        if (line1 == 0)
        !          1415:            line1 = 1;
        !          1416:        if (line2 == 0)
        !          1417:            line2 = 1;
        !          1418:    }
        !          1419:
        !          1420:    /*
        !          1421:     * for the :make command we insert the 'makeprg' option here,
        !          1422:     * so things like % get expanded
        !          1423:     */
        !          1424:    if (cmdidx == CMD_make)
        !          1425:    {
        !          1426:        alloc_cmdbuff((int)(STRLEN(p_mp) + STRLEN(p) + 2));
        !          1427:        if (cmdbuff == NULL)        /* out of memory */
        !          1428:            goto doend;
        !          1429:        /*
        !          1430:         * Check for special command characters and echo them.
        !          1431:         */
        !          1432:        for (i = 0; i < 6; i += 2)
        !          1433:            if (!STRCMP(make_cmd_chars[i], p))
        !          1434:                for (s = (char_u *)(make_cmd_chars[i + 1]); *s; ++s)
        !          1435:                    msg_outchar(*s - 16);
        !          1436:        STRCPY(cmdbuff, p_mp);
        !          1437:        STRCAT(cmdbuff, " ");
        !          1438:        STRCAT(cmdbuff, p);
        !          1439:            /* 'cmd' is not set here, because it is not used at CMD_make */
        !          1440:        vim_free(*cmdlinep);
        !          1441:        *cmdlinep = cmdbuff;
        !          1442:        *cmdlinelenp = cmdbufflen;
        !          1443:        p = cmdbuff;
        !          1444:    }
        !          1445:
        !          1446:    /*
        !          1447:     * Skip to start of argument.
        !          1448:     * Don't do this for the ":!" command, because ":!! -l" needs the space.
        !          1449:     */
        !          1450:    if (cmdidx == CMD_bang)
        !          1451:        arg = p;
        !          1452:    else
        !          1453:        arg = skipwhite(p);
        !          1454:
        !          1455:    if (cmdidx == CMD_write)
        !          1456:    {
        !          1457:        if (*arg == '>')                        /* append */
        !          1458:        {
        !          1459:            if (*++arg != '>')              /* typed wrong */
        !          1460:            {
        !          1461:                errormsg = (char_u *)"Use w or w>>";
        !          1462:                goto doend;
        !          1463:            }
        !          1464:            arg = skipwhite(arg + 1);
        !          1465:            append = TRUE;
        !          1466:        }
        !          1467:        else if (*arg == '!')                   /* :w !filter */
        !          1468:        {
        !          1469:            ++arg;
        !          1470:            usefilter = TRUE;
        !          1471:        }
        !          1472:    }
        !          1473:
        !          1474:    if (cmdidx == CMD_read)
        !          1475:    {
        !          1476:        if (forceit)
        !          1477:        {
        !          1478:            usefilter = TRUE;                   /* :r! filter if forceit */
        !          1479:            forceit = FALSE;
        !          1480:        }
        !          1481:        else if (*arg == '!')                   /* :r !filter */
        !          1482:        {
        !          1483:            ++arg;
        !          1484:            usefilter = TRUE;
        !          1485:        }
        !          1486:    }
        !          1487:
        !          1488:    if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
        !          1489:    {
        !          1490:        amount = 1;
        !          1491:        while (*arg == *cmd)        /* count number of '>' or '<' */
        !          1492:        {
        !          1493:            ++arg;
        !          1494:            ++amount;
        !          1495:        }
        !          1496:        arg = skipwhite(arg);
        !          1497:    }
        !          1498:
        !          1499:    /*
        !          1500:     * Check for "+command" argument, before checking for next command.
        !          1501:     * Don't do this for ":read !cmd" and ":write !cmd".
        !          1502:     */
        !          1503:    if ((argt & EDITCMD) && !usefilter)
        !          1504:        do_ecmd_cmd = getargcmd(&arg);
        !          1505:
        !          1506:    /*
        !          1507:     * Check for '|' to separate commands and '"' to start comments.
        !          1508:     * Don't do this for ":read !cmd" and ":write !cmd".
        !          1509:     */
        !          1510:    if ((argt & TRLBAR) && !usefilter)
        !          1511:    {
        !          1512:        for (p = arg; *p; ++p)
        !          1513:        {
        !          1514:            if (*p == Ctrl('V'))
        !          1515:            {
        !          1516:                if (argt & (USECTRLV | XFILE))
        !          1517:                    ++p;                /* skip CTRL-V and next char */
        !          1518:                else
        !          1519:                    STRCPY(p, p + 1);   /* remove CTRL-V and skip next char */
        !          1520:                if (*p == NUL)          /* stop at NUL after CTRL-V */
        !          1521:                    break;
        !          1522:            }
        !          1523:            else if ((*p == '"' && !(argt & NOTRLCOM)) ||
        !          1524:                                                      *p == '|' || *p == '\n')
        !          1525:            {
        !          1526:                /*
        !          1527:                 * We remove the '\' before the '|', unless USECTRLV is used
        !          1528:                 * AND 'b' is present in 'cpoptions'.
        !          1529:                 */
        !          1530:                if ((vim_strchr(p_cpo, CPO_BAR) == NULL ||
        !          1531:                                       !(argt & USECTRLV)) && *(p - 1) == '\\')
        !          1532:                {
        !          1533:                    STRCPY(p - 1, p);   /* remove the backslash */
        !          1534:                    --p;
        !          1535:                }
        !          1536:                else
        !          1537:                {
        !          1538:                    if (*p == '|' || *p == '\n')
        !          1539:                        nextcomm = p + 1;
        !          1540:                    *p = NUL;
        !          1541:                    break;
        !          1542:                }
        !          1543:            }
        !          1544:        }
        !          1545:        if (!(argt & NOTRLCOM))         /* remove trailing spaces */
        !          1546:            del_trailing_spaces(arg);
        !          1547:    }
        !          1548:
        !          1549:    /*
        !          1550:     * Check for <newline> to end a shell command.
        !          1551:     * Also do this for ":read !cmd" and ":write !cmd".
        !          1552:     */
        !          1553:    else if (cmdidx == CMD_bang || usefilter)
        !          1554:    {
        !          1555:        for (p = arg; *p; ++p)
        !          1556:        {
        !          1557:            if (*p == '\\' && p[1])
        !          1558:                ++p;
        !          1559:            else if (*p == '\n')
        !          1560:            {
        !          1561:                nextcomm = p + 1;
        !          1562:                *p = NUL;
        !          1563:                break;
        !          1564:            }
        !          1565:        }
        !          1566:    }
        !          1567:
        !          1568:    if ((argt & DFLALL) && addr_count == 0)
        !          1569:    {
        !          1570:        line1 = 1;
        !          1571:        line2 = curbuf->b_ml.ml_line_count;
        !          1572:    }
        !          1573:
        !          1574:    regname = 0;
        !          1575:        /* accept numbered register only when no count allowed (:put) */
        !          1576:    if ((argt & REGSTR) && *arg != NUL && is_yank_buffer(*arg, FALSE) &&
        !          1577:                                           !((argt & COUNT) && isdigit(*arg)))
        !          1578:    {
        !          1579:        regname = *arg;
        !          1580:        arg = skipwhite(arg + 1);
        !          1581:    }
        !          1582:
        !          1583:    if ((argt & COUNT) && isdigit(*arg))
        !          1584:    {
        !          1585:        n = getdigits(&arg);
        !          1586:        arg = skipwhite(arg);
        !          1587:        if (n <= 0)
        !          1588:        {
        !          1589:            errormsg = e_zerocount;
        !          1590:            goto doend;
        !          1591:        }
        !          1592:        if (argt & NOTADR)      /* e.g. :buffer 2, :sleep 3 */
        !          1593:        {
        !          1594:            line2 = n;
        !          1595:            if (addr_count == 0)
        !          1596:                addr_count = 1;
        !          1597:        }
        !          1598:        else
        !          1599:        {
        !          1600:            line1 = line2;
        !          1601:            line2 += n - 1;
        !          1602:            ++addr_count;
        !          1603:            /*
        !          1604:             * Be vi compatible: no error message for out of range.
        !          1605:             */
        !          1606:            if (line2 > curbuf->b_ml.ml_line_count)
        !          1607:                line2 = curbuf->b_ml.ml_line_count;
        !          1608:        }
        !          1609:    }
        !          1610:                                                /* no arguments allowed */
        !          1611:    if (!(argt & EXTRA) && *arg != NUL &&
        !          1612:                                    vim_strchr((char_u *)"|\"", *arg) == NULL)
        !          1613:    {
        !          1614:        errormsg = e_trailing;
        !          1615:        goto doend;
        !          1616:    }
        !          1617:
        !          1618:    if ((argt & NEEDARG) && *arg == NUL)
        !          1619:    {
        !          1620:        errormsg = e_argreq;
        !          1621:        goto doend;
        !          1622:    }
        !          1623:
        !          1624:    /*
        !          1625:     * change '%'       to curbuf->b_filename
        !          1626:     *        '#'       to curwin->w_altfile
        !          1627:     *        '<cword>' to word under the cursor
        !          1628:     *        '<cWORD>' to WORD under the cursor
        !          1629:     *        '<cfile>' to path name under the cursor
        !          1630:     *        '<afile>' to file name for autocommand
        !          1631:     */
        !          1632:    if (argt & XFILE)
        !          1633:    {
        !          1634:        char_u      *buf = NULL;
        !          1635:        int         expand_wildcards;       /* need to expand wildcards */
        !          1636:        int         spec_idx;
        !          1637:        static char *(spec_str[]) =
        !          1638:                    {
        !          1639:                        "%",
        !          1640: #define SPEC_PERC  0
        !          1641:                        "#",
        !          1642: #define SPEC_HASH  1
        !          1643:                        "<cword>",          /* cursor word */
        !          1644: #define SPEC_CWORD 2
        !          1645:                        "<cWORD>",          /* cursor WORD */
        !          1646: #define SPEC_CCWORD    3
        !          1647:                        "<cfile>",          /* cursor path name */
        !          1648: #define SPEC_CFILE 4
        !          1649:                        "<afile>"           /* autocommand file name */
        !          1650: #define SPEC_AFILE 5
        !          1651:                    };
        !          1652: #define SPEC_COUNT 6
        !          1653:
        !          1654:        /*
        !          1655:         * Decide to expand wildcards *before* replacing '%', '#', etc.  If
        !          1656:         * the file name contains a wildcard it should not cause expanding.
        !          1657:         * (it will be expanded anyway if there is a wildcard before replacing).
        !          1658:         */
        !          1659:        expand_wildcards = mch_has_wildcard(arg);
        !          1660:        for (p = arg; *p; ++p)
        !          1661:        {
        !          1662:            /*
        !          1663:             * Check if there is something to do.
        !          1664:             */
        !          1665:            for (spec_idx = 0; spec_idx < SPEC_COUNT; ++spec_idx)
        !          1666:            {
        !          1667:                n = strlen(spec_str[spec_idx]);
        !          1668:                if (STRNCMP(p, spec_str[spec_idx], n) == 0)
        !          1669:                    break;
        !          1670:            }
        !          1671:            if (spec_idx == SPEC_COUNT)     /* no match */
        !          1672:                continue;
        !          1673:
        !          1674:            /*
        !          1675:             * Skip when preceded with a backslash "\%" and "\#".
        !          1676:             * Note: In "\\%" the % is also not recognized!
        !          1677:             */
        !          1678:            if (*(p - 1) == '\\')
        !          1679:            {
        !          1680:                --p;
        !          1681:                STRCPY(p, p + 1);           /* remove escaped char */
        !          1682:                continue;
        !          1683:            }
        !          1684:
        !          1685:            /*
        !          1686:             * word or WORD under cursor
        !          1687:             */
        !          1688:            if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD)
        !          1689:            {
        !          1690:                len = find_ident_under_cursor(&q, spec_idx == SPEC_CWORD ?
        !          1691:                                      (FIND_IDENT|FIND_STRING) : FIND_STRING);
        !          1692:                if (len == 0)
        !          1693:                    goto doend;
        !          1694:            }
        !          1695:
        !          1696:            /*
        !          1697:             * '#': Alternate file name
        !          1698:             * '%': Current file name
        !          1699:             *      File name under the cursor
        !          1700:             *      File name for autocommand
        !          1701:             *  and following modifiers
        !          1702:             */
        !          1703:            else
        !          1704:            {
        !          1705:                switch (spec_idx)
        !          1706:                {
        !          1707:                    case SPEC_PERC:             /* '%': current file */
        !          1708:                                if (curbuf->b_filename == NULL)
        !          1709:                                {
        !          1710:                                    errormsg = (char_u *)"No file name to substitute for '%'";
        !          1711:                                    goto doend;
        !          1712:                                }
        !          1713:                                q = curbuf->b_xfilename;
        !          1714:                                break;
        !          1715:
        !          1716:                    case SPEC_HASH:         /* '#' or "#99": alternate file */
        !          1717:                                q = p + 1;
        !          1718:                                i = (int)getdigits(&q);
        !          1719:                                n = q - p;      /* length of what we expand */
        !          1720:
        !          1721:                                if (buflist_name_nr(i, &q, &do_ecmd_lnum) ==
        !          1722:                                                                         FAIL)
        !          1723:                                {
        !          1724:                                    errormsg = (char_u *)"no alternate filename to substitute for '#'";
        !          1725:                                    goto doend;
        !          1726:                                }
        !          1727:                                break;
        !          1728:
        !          1729:                    case SPEC_CFILE:            /* file name under cursor */
        !          1730:                                q = file_name_at_cursor(FNAME_MESS|FNAME_HYP);
        !          1731:                                if (q == NULL)
        !          1732:                                    goto doend;
        !          1733:                                buf = q;
        !          1734:                                break;
        !          1735:
        !          1736:                    case SPEC_AFILE:            /* file name for autocommand */
        !          1737:                                q = autocmd_fname;
        !          1738:                                if (q == NULL)
        !          1739:                                {
        !          1740:                                    errormsg = (char_u *)"no autocommand filename to substitute for \"<afile>\"";
        !          1741:                                    goto doend;
        !          1742:                                }
        !          1743:                                break;
        !          1744:                }
        !          1745:
        !          1746:                len = STRLEN(q);        /* length of new string */
        !          1747:                if (p[n] == '<')        /* remove the file name extension */
        !          1748:                {
        !          1749:                    ++n;
        !          1750:                    if ((s = vim_strrchr(q, '.')) != NULL && s >= gettail(q))
        !          1751:                        len = s - q;
        !          1752:                }
        !          1753:                else
        !          1754:                {
        !          1755:                    char_u      *tail;
        !          1756:
        !          1757:                    /* ":p" - full path/filename */
        !          1758:                    if (p[n] == ':' && p[n + 1] == 'p')
        !          1759:                    {
        !          1760:                        n += 2;
        !          1761:                        s = FullName_save(q);
        !          1762:                        vim_free(buf);      /* free any allocated file name */
        !          1763:                        if (s == NULL)
        !          1764:                            goto doend;
        !          1765:                        q = s;
        !          1766:                        len = STRLEN(q);
        !          1767:                        buf = q;
        !          1768:                    }
        !          1769:
        !          1770:                    tail = gettail(q);
        !          1771:
        !          1772:                    /* ":h" - head, remove "/filename"  */
        !          1773:                    /* ":h" can be repeated */
        !          1774:                    while (p[n] == ':' && p[n + 1] == 'h')
        !          1775:                    {
        !          1776:                        n += 2;
        !          1777:                        while (tail > q && ispathsep(tail[-1]))
        !          1778:                            --tail;
        !          1779:                        len = tail - q;
        !          1780:                        while (tail > q && !ispathsep(tail[-1]))
        !          1781:                            --tail;
        !          1782:                    }
        !          1783:
        !          1784:                    /* ":t" - tail, just the basename */
        !          1785:                    if (p[n] == ':' && p[n + 1] == 't')
        !          1786:                    {
        !          1787:                        n += 2;
        !          1788:                        len -= tail - q;
        !          1789:                        q = tail;
        !          1790:                    }
        !          1791:
        !          1792:                    /* ":e" - extension */
        !          1793:                    /* ":e" can be repeated */
        !          1794:                    /* ":r" - root, without extension */
        !          1795:                    /* ":r" can be repeated */
        !          1796:                    while (p[n] == ':' &&
        !          1797:                                     (p[n + 1] == 'e' || p[n + 1] == 'r'))
        !          1798:                    {
        !          1799:                        /* find a '.' in the tail:
        !          1800:                         * - for second :e: before the current fname
        !          1801:                         * - otherwise: The last '.'
        !          1802:                         */
        !          1803:                        if (p[n + 1] == 'e' && q > tail)
        !          1804:                            s = q - 2;
        !          1805:                        else
        !          1806:                            s = q + len - 1;
        !          1807:                        for ( ; s > tail; --s)
        !          1808:                            if (s[0] == '.')
        !          1809:                                break;
        !          1810:                        if (p[n + 1] == 'e')            /* :e */
        !          1811:                        {
        !          1812:                            if (s > tail)
        !          1813:                            {
        !          1814:                                len += q - (s + 1);
        !          1815:                                q = s + 1;
        !          1816:                            }
        !          1817:                            else if (q <= tail)
        !          1818:                                len = 0;
        !          1819:                        }
        !          1820:                        else                            /* :r */
        !          1821:                        {
        !          1822:                            if (s > tail)       /* remove one extension */
        !          1823:                                len = s - q;
        !          1824:                        }
        !          1825:                        n += 2;
        !          1826:                    }
        !          1827:                }
        !          1828:
        !          1829:                /* TODO - ":s/pat/foo/" - substitute */
        !          1830:                /* if (p[n] == ':' && p[n + 1] == 's') */
        !          1831:            }
        !          1832:
        !          1833:            /*
        !          1834:             * The new command line is build in cmdbuff[].
        !          1835:             * First allocate it.
        !          1836:             */
        !          1837:            i = STRLEN(*cmdlinep) + len + 3;
        !          1838:            if (nextcomm)
        !          1839:                i += STRLEN(nextcomm);          /* add space for next command */
        !          1840:            alloc_cmdbuff(i);
        !          1841:            if (cmdbuff == NULL)                /* out of memory! */
        !          1842:                goto doend;
        !          1843:
        !          1844:            i = p - *cmdlinep;          /* length of part before c */
        !          1845:            vim_memmove(cmdbuff, *cmdlinep, (size_t)i);
        !          1846:            vim_memmove(cmdbuff + i, q, (size_t)len);   /* append the string */
        !          1847:            i += len;                   /* remember the end of the string */
        !          1848:            STRCPY(cmdbuff + i, p + n); /* append what is after '#' or '%' */
        !          1849:            p = cmdbuff + i - 1;        /* remember where to continue */
        !          1850:            vim_free(buf);              /* free any allocated string */
        !          1851:
        !          1852:            if (nextcomm)               /* append next command */
        !          1853:            {
        !          1854:                i = STRLEN(cmdbuff) + 1;
        !          1855:                STRCPY(cmdbuff + i, nextcomm);
        !          1856:                nextcomm = cmdbuff + i;
        !          1857:            }
        !          1858:            cmd = cmdbuff + (cmd - *cmdlinep);
        !          1859:            arg = cmdbuff + (arg - *cmdlinep);
        !          1860:            vim_free(*cmdlinep);
        !          1861:            *cmdlinep = cmdbuff;
        !          1862:            *cmdlinelenp = cmdbufflen;
        !          1863:        }
        !          1864:
        !          1865:        /*
        !          1866:         * One file argument: expand wildcards.
        !          1867:         * Don't do this with ":r !command" or ":w !command".
        !          1868:         */
        !          1869:        if ((argt & NOSPC) && !usefilter)
        !          1870:        {
        !          1871: #if defined(UNIX)
        !          1872:            /*
        !          1873:             * Only for Unix we check for more than one file name.
        !          1874:             * For other systems spaces are considered to be part
        !          1875:             * of the file name.
        !          1876:             * Only check here if there is no wildcard, otherwise ExpandOne
        !          1877:             * will check for errors. This allows ":e `ls ve*.c`" on Unix.
        !          1878:             */
        !          1879:            if (!expand_wildcards)
        !          1880:                for (p = arg; *p; ++p)
        !          1881:                {
        !          1882:                                /* skip escaped characters */
        !          1883:                    if (p[1] && (*p == '\\' || *p == Ctrl('V')))
        !          1884:                        ++p;
        !          1885:                    else if (vim_iswhite(*p))
        !          1886:                    {
        !          1887:                        errormsg = (char_u *)"Only one file name allowed";
        !          1888:                        goto doend;
        !          1889:                    }
        !          1890:                }
        !          1891: #endif
        !          1892:            /*
        !          1893:             * halve the number of backslashes (this is vi compatible)
        !          1894:             */
        !          1895:            backslash_halve(arg, expand_wildcards);
        !          1896:
        !          1897:            if (expand_wildcards)
        !          1898:            {
        !          1899:                if ((p = ExpandOne(arg, NULL, WILD_LIST_NOTFOUND,
        !          1900:                                                   WILD_EXPAND_FREE)) == NULL)
        !          1901:                    goto doend;
        !          1902:                n = arg - *cmdlinep;
        !          1903:                i = STRLEN(p) + n;
        !          1904:                if (nextcomm)
        !          1905:                    i += STRLEN(nextcomm);
        !          1906:                alloc_cmdbuff(i);
        !          1907:                if (cmdbuff != NULL)
        !          1908:                {
        !          1909:                    STRNCPY(cmdbuff, *cmdlinep, n);
        !          1910:                    STRCPY(cmdbuff + n, p);
        !          1911:                    if (nextcomm)               /* append next command */
        !          1912:                    {
        !          1913:                        i = STRLEN(cmdbuff) + 1;
        !          1914:                        STRCPY(cmdbuff + i, nextcomm);
        !          1915:                        nextcomm = cmdbuff + i;
        !          1916:                    }
        !          1917:                    cmd = cmdbuff + (cmd - *cmdlinep);
        !          1918:                    arg = cmdbuff + n;
        !          1919:                    vim_free(*cmdlinep);
        !          1920:                    *cmdlinep = cmdbuff;
        !          1921:                    *cmdlinelenp = cmdbufflen;
        !          1922:                }
        !          1923:                vim_free(p);
        !          1924:            }
        !          1925:        }
        !          1926:    }
        !          1927:
        !          1928:    /*
        !          1929:     * Accept buffer name.  Cannot be used at the same time with a buffer
        !          1930:     * number.
        !          1931:     */
        !          1932:    if ((argt & BUFNAME) && *arg && addr_count == 0)
        !          1933:    {
        !          1934:        /*
        !          1935:         * :bdelete and :bunload take several arguments, separated by spaces:
        !          1936:         * find next space (skipping over escaped characters).
        !          1937:         * The others take one argument: ignore trailing spaces.
        !          1938:         */
        !          1939:        if (cmdidx == CMD_bdelete || cmdidx == CMD_bunload)
        !          1940:            p = skiptowhite_esc(arg);
        !          1941:        else
        !          1942:        {
        !          1943:            p = arg + STRLEN(arg);
        !          1944:            while (p > arg && vim_iswhite(p[-1]))
        !          1945:                --p;
        !          1946:        }
        !          1947:        line2 = buflist_findpat(arg, p);
        !          1948:        if (line2 < 0)          /* failed */
        !          1949:            goto doend;
        !          1950:        addr_count = 1;
        !          1951:        arg = skipwhite(p);
        !          1952:    }
        !          1953:
        !          1954: /*
        !          1955:  * 6. switch on command name
        !          1956:  *    arg      points to the argument of the command
        !          1957:  *    nextcomm points to the next command (if any)
        !          1958:  *   cmd       points to the name of the command (except for :make)
        !          1959:  *   cmdidx    is the index for the command
        !          1960:  *   forceit   is TRUE if ! present
        !          1961:  *   addr_count is the number of addresses given
        !          1962:  *   line1     is the first line number
        !          1963:  *   line2     is the second line number or count
        !          1964:  *   do_ecmd_cmd   is +command argument to be used in edited file
        !          1965:  *   do_ecmd_lnum  is the line number in edited file
        !          1966:  *   append    is TRUE with ":w >>file" command
        !          1967:  *   usefilter is TRUE with ":w !command" and ":r!command"
        !          1968:  *   amount    is number of '>' or '<' for shift command
        !          1969:  */
        !          1970: cmdswitch:
        !          1971:    switch (cmdidx)
        !          1972:    {
        !          1973:        /*
        !          1974:         * quit current window, quit Vim if closed the last window
        !          1975:         */
        !          1976:        case CMD_quit:
        !          1977:                        /* if more files or windows we won't exit */
        !          1978:                if (check_more(FALSE) == OK && only_one_window())
        !          1979:                    exiting = TRUE;
        !          1980:                if (check_changed(curbuf, FALSE, FALSE) ||
        !          1981:                            check_more(TRUE) == FAIL ||
        !          1982:                            (only_one_window() && check_changed_any()))
        !          1983:                {
        !          1984:                    exiting = FALSE;
        !          1985:                    settmode(1);
        !          1986:                    break;
        !          1987:                }
        !          1988:                if (only_one_window())  /* quit last window */
        !          1989:                    getout(0);
        !          1990:                close_window(curwin, TRUE); /* may free buffer */
        !          1991:                break;
        !          1992:
        !          1993:        /*
        !          1994:         * try to quit all windows
        !          1995:         */
        !          1996:        case CMD_qall:
        !          1997:                exiting = TRUE;
        !          1998:                if (!check_changed_any())
        !          1999:                    getout(0);
        !          2000:                exiting = FALSE;
        !          2001:                settmode(1);
        !          2002:                break;
        !          2003:
        !          2004:        /*
        !          2005:         * close current window, unless it is the last one
        !          2006:         */
        !          2007:        case CMD_close:
        !          2008:                close_window(curwin, FALSE);    /* don't free buffer */
        !          2009:                break;
        !          2010:
        !          2011:        /*
        !          2012:         * close all but current window, unless it is the last one
        !          2013:         */
        !          2014:        case CMD_only:
        !          2015:                close_others(TRUE);
        !          2016:                break;
        !          2017:
        !          2018:        case CMD_stop:
        !          2019:        case CMD_suspend:
        !          2020: #ifdef WIN32
        !          2021:                /*
        !          2022:                 * Check if external commands are allowed now.
        !          2023:                 */
        !          2024:                if (can_end_termcap_mode(TRUE) == FALSE)
        !          2025:                    break;
        !          2026: #endif
        !          2027:                if (!forceit)
        !          2028:                    autowrite_all();
        !          2029:                windgoto((int)Rows - 1, 0);
        !          2030:                outchar('\n');
        !          2031:                flushbuf();
        !          2032:                stoptermcap();
        !          2033:                mch_restore_title(3);   /* restore window titles */
        !          2034:                mch_suspend();          /* call machine specific function */
        !          2035:                maketitle();
        !          2036:                starttermcap();
        !          2037:                scroll_start();         /* scroll screen before redrawing */
        !          2038:                must_redraw = CLEAR;
        !          2039:                set_winsize(0, 0, FALSE); /* May have resized window -- webb */
        !          2040:                break;
        !          2041:
        !          2042:        case CMD_exit:
        !          2043:        case CMD_xit:
        !          2044:        case CMD_wq:
        !          2045:                            /* if more files or windows we won't exit */
        !          2046:                if (check_more(FALSE) == OK && only_one_window())
        !          2047:                    exiting = TRUE;
        !          2048:                if (((cmdidx == CMD_wq || curbuf->b_changed) &&
        !          2049:                                              do_write(arg, FALSE) == FAIL) ||
        !          2050:                                                   check_more(TRUE) == FAIL ||
        !          2051:                            (only_one_window() && check_changed_any()))
        !          2052:                {
        !          2053:                    exiting = FALSE;
        !          2054:                    settmode(1);
        !          2055:                    break;
        !          2056:                }
        !          2057:                if (only_one_window())  /* quit last window, exit Vim */
        !          2058:                    getout(0);
        !          2059:                close_window(curwin, TRUE); /* quit current window, may free buffer */
        !          2060:                break;
        !          2061:
        !          2062:        case CMD_xall:      /* write all changed files and exit */
        !          2063:        case CMD_wqall:     /* write all changed files and quit */
        !          2064:                exiting = TRUE;
        !          2065:                /* FALLTHROUGH */
        !          2066:
        !          2067:        case CMD_wall:      /* write all changed files */
        !          2068:                {
        !          2069:                    BUF     *buf;
        !          2070:                    int     error = 0;
        !          2071:
        !          2072:                    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
        !          2073:                    {
        !          2074:                        if (buf->b_changed)
        !          2075:                        {
        !          2076:                            if (buf->b_filename == NULL)
        !          2077:                            {
        !          2078:                                emsg(e_noname);
        !          2079:                                ++error;
        !          2080:                            }
        !          2081:                            else if (!forceit && buf->b_p_ro)
        !          2082:                            {
        !          2083:                                EMSG2("\"%s\" is readonly, use ! to write anyway", buf->b_xfilename);
        !          2084:                                ++error;
        !          2085:                            }
        !          2086:                            else if (buf_write_all(buf) == FAIL)
        !          2087:                                ++error;
        !          2088:                        }
        !          2089:                    }
        !          2090:                    if (exiting)
        !          2091:                    {
        !          2092:                        if (!error)
        !          2093:                            getout(0);          /* exit Vim */
        !          2094:                        exiting = FALSE;
        !          2095:                        settmode(1);
        !          2096:                    }
        !          2097:                }
        !          2098:                break;
        !          2099:
        !          2100:        case CMD_preserve:                  /* put everything in .swp file */
        !          2101:                ml_preserve(curbuf, TRUE);
        !          2102:                break;
        !          2103:
        !          2104:        case CMD_recover:                   /* recover file */
        !          2105:                recoverymode = TRUE;
        !          2106:                if (!check_changed(curbuf, FALSE, TRUE) &&
        !          2107:                            (*arg == NUL || setfname(arg, NULL, TRUE) == OK))
        !          2108:                    ml_recover();
        !          2109:                recoverymode = FALSE;
        !          2110:                break;
        !          2111:
        !          2112:        case CMD_args:
        !          2113:                    /*
        !          2114:                     * ":args file": handle like :next
        !          2115:                     */
        !          2116:                if (*arg != NUL && *arg != '|' && *arg != '\n')
        !          2117:                    goto do_next;
        !          2118:
        !          2119:                if (arg_count == 0)             /* no file name list */
        !          2120:                {
        !          2121:                    if (check_fname() == OK)    /* check for no file name */
        !          2122:                        smsg((char_u *)"[%s]", curbuf->b_filename);
        !          2123:                    break;
        !          2124:                }
        !          2125:                /*
        !          2126:                 * Overwrite the command, in most cases there is no scrolling
        !          2127:                 * required and no wait_return().
        !          2128:                 */
        !          2129:                gotocmdline(TRUE);
        !          2130:                for (i = 0; i < arg_count; ++i)
        !          2131:                {
        !          2132:                    if (i == curwin->w_arg_idx)
        !          2133:                        msg_outchar('[');
        !          2134:                    msg_outtrans(arg_files[i]);
        !          2135:                    if (i == curwin->w_arg_idx)
        !          2136:                        msg_outchar(']');
        !          2137:                    msg_outchar(' ');
        !          2138:                }
        !          2139:                break;
        !          2140:
        !          2141:        case CMD_wnext:
        !          2142:        case CMD_wNext:
        !          2143:        case CMD_wprevious:
        !          2144:                if (cmd[1] == 'n')
        !          2145:                    i = curwin->w_arg_idx + (int)line2;
        !          2146:                else
        !          2147:                    i = curwin->w_arg_idx - (int)line2;
        !          2148:                line1 = 1;
        !          2149:                line2 = curbuf->b_ml.ml_line_count;
        !          2150:                if (do_write(arg, FALSE) == FAIL)
        !          2151:                    break;
        !          2152:                goto donextfile;
        !          2153:
        !          2154:        case CMD_next:
        !          2155:        case CMD_snext:
        !          2156: do_next:
        !          2157:                    /*
        !          2158:                     * check for changed buffer now, if this fails the
        !          2159:                     * argument list is not redefined.
        !          2160:                     */
        !          2161:                if (!(p_hid || cmdidx == CMD_snext) &&
        !          2162:                                check_changed(curbuf, TRUE, FALSE))
        !          2163:                    break;
        !          2164:
        !          2165:                if (*arg != NUL)                /* redefine file list */
        !          2166:                {
        !          2167:                    if (do_arglist(arg) == FAIL)
        !          2168:                        break;
        !          2169:                    i = 0;
        !          2170:                }
        !          2171:                else
        !          2172:                    i = curwin->w_arg_idx + (int)line2;
        !          2173:
        !          2174: donextfile:        if (i < 0 || i >= arg_count)
        !          2175:                {
        !          2176:                    if (arg_count <= 1)
        !          2177:                        EMSG("There is only one file to edit");
        !          2178:                    else if (i < 0)
        !          2179:                        EMSG("Cannot go before first file");
        !          2180:                    else
        !          2181:                        EMSG("Cannot go beyond last file");
        !          2182:                    break;
        !          2183:                }
        !          2184:                setpcmark();
        !          2185:                if (*cmd == 's')        /* split window first */
        !          2186:                {
        !          2187:                    if (win_split(0, FALSE) == FAIL)
        !          2188:                        break;
        !          2189:                }
        !          2190:                else
        !          2191:                {
        !          2192:                    register int other;
        !          2193:
        !          2194:                    /*
        !          2195:                     * if 'hidden' set, only check for changed file when
        !          2196:                     * re-editing the same buffer
        !          2197:                     */
        !          2198:                    other = TRUE;
        !          2199:                    if (p_hid)
        !          2200:                        other = otherfile(fix_fname(arg_files[i]));
        !          2201:                    if ((!p_hid || !other) &&
        !          2202:                                        check_changed(curbuf, TRUE, !other))
        !          2203:                    break;
        !          2204:                }
        !          2205:                curwin->w_arg_idx = i;
        !          2206:                if (i == arg_count - 1)
        !          2207:                    arg_had_last = TRUE;
        !          2208:                (void)do_ecmd(0, arg_files[curwin->w_arg_idx],
        !          2209:                               NULL, do_ecmd_cmd, p_hid, do_ecmd_lnum, FALSE);
        !          2210:                break;
        !          2211:
        !          2212:        case CMD_previous:
        !          2213:        case CMD_sprevious:
        !          2214:        case CMD_Next:
        !          2215:        case CMD_sNext:
        !          2216:                i = curwin->w_arg_idx - (int)line2;
        !          2217:                goto donextfile;
        !          2218:
        !          2219:        case CMD_rewind:
        !          2220:        case CMD_srewind:
        !          2221:                i = 0;
        !          2222:                goto donextfile;
        !          2223:
        !          2224:        case CMD_last:
        !          2225:        case CMD_slast:
        !          2226:                i = arg_count - 1;
        !          2227:                goto donextfile;
        !          2228:
        !          2229:        case CMD_argument:
        !          2230:        case CMD_sargument:
        !          2231:                if (addr_count)
        !          2232:                    i = line2 - 1;
        !          2233:                else
        !          2234:                    i = curwin->w_arg_idx;
        !          2235:                goto donextfile;
        !          2236:
        !          2237:        case CMD_all:
        !          2238:        case CMD_sall:
        !          2239:                if (addr_count == 0)
        !          2240:                    line2 = 9999;
        !          2241:                do_arg_all((int)line2); /* open a window for each argument */
        !          2242:                break;
        !          2243:
        !          2244:        case CMD_buffer:            /* :[N]buffer [N]    to buffer N */
        !          2245:        case CMD_sbuffer:           /* :[N]sbuffer [N]   to buffer N */
        !          2246:                if (*arg)
        !          2247:                {
        !          2248:                    errormsg = e_trailing;
        !          2249:                    break;
        !          2250:                }
        !          2251:                if (addr_count == 0)        /* default is current buffer */
        !          2252:                    (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
        !          2253:                                                DOBUF_CURRENT, FORWARD, 0, 0);
        !          2254:                else
        !          2255:                    (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
        !          2256:                                         DOBUF_FIRST, FORWARD, (int)line2, 0);
        !          2257:                break;
        !          2258:
        !          2259:        case CMD_bmodified:         /* :[N]bmod [N]   to next modified buffer */
        !          2260:        case CMD_sbmodified:        /* :[N]sbmod [N]  to next modified buffer */
        !          2261:                (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
        !          2262:                                           DOBUF_MOD, FORWARD, (int)line2, 0);
        !          2263:                break;
        !          2264:
        !          2265:        case CMD_bnext:             /* :[N]bnext [N]     to next buffer */
        !          2266:        case CMD_sbnext:            /* :[N]sbnext [N]    to next buffer */
        !          2267:                (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
        !          2268:                                       DOBUF_CURRENT, FORWARD, (int)line2, 0);
        !          2269:                break;
        !          2270:
        !          2271:        case CMD_bNext:             /* :[N]bNext [N]     to previous buffer */
        !          2272:        case CMD_bprevious:         /* :[N]bprevious [N] to previous buffer */
        !          2273:        case CMD_sbNext:            /* :[N]sbNext [N]     to previous buffer */
        !          2274:        case CMD_sbprevious:        /* :[N]sbprevious [N] to previous buffer */
        !          2275:                (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
        !          2276:                                      DOBUF_CURRENT, BACKWARD, (int)line2, 0);
        !          2277:                break;
        !          2278:
        !          2279:        case CMD_brewind:           /* :brewind          to first buffer */
        !          2280:        case CMD_sbrewind:          /* :sbrewind         to first buffer */
        !          2281:                (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
        !          2282:                                                  DOBUF_FIRST, FORWARD, 0, 0);
        !          2283:                break;
        !          2284:
        !          2285:        case CMD_blast:             /* :blast            to last buffer */
        !          2286:        case CMD_sblast:            /* :sblast           to last buffer */
        !          2287:                (void)do_buffer(*cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
        !          2288:                                                   DOBUF_LAST, FORWARD, 0, 0);
        !          2289:                break;
        !          2290:
        !          2291:        case CMD_bunload:       /* :[N]bunload[!] [N] [bufname] unload buffer */
        !          2292:        case CMD_bdelete:       /* :[N]bdelete[!] [N] [bufname] delete buffer */
        !          2293:                errormsg = do_bufdel(
        !          2294:                            cmdidx == CMD_bdelete ? DOBUF_DEL : DOBUF_UNLOAD,
        !          2295:                            arg, addr_count, (int)line1, (int)line2, forceit);
        !          2296:                break;
        !          2297:
        !          2298:        case CMD_unhide:
        !          2299:        case CMD_sunhide:   /* open a window for loaded buffers */
        !          2300:                if (addr_count == 0)
        !          2301:                    line2 = 9999;
        !          2302:                (void)do_buffer_all((int)line2, FALSE);
        !          2303:                break;
        !          2304:
        !          2305:        case CMD_ball:
        !          2306:        case CMD_sball:     /* open a window for every buffer */
        !          2307:                if (addr_count == 0)
        !          2308:                    line2 = 9999;
        !          2309:                (void)do_buffer_all((int)line2, TRUE);
        !          2310:                break;
        !          2311:
        !          2312:        case CMD_buffers:
        !          2313:        case CMD_files:
        !          2314:        case CMD_ls:
        !          2315:                buflist_list();
        !          2316:                break;
        !          2317:
        !          2318:        case CMD_write:
        !          2319:                if (usefilter)      /* input lines to shell command */
        !          2320:                    do_bang(1, line1, line2, FALSE, arg, TRUE, FALSE);
        !          2321:                else
        !          2322:                    (void)do_write(arg, append);
        !          2323:                break;
        !          2324:
        !          2325:            /*
        !          2326:             * set screen mode
        !          2327:             * if no argument given, just get the screen size and redraw
        !          2328:             */
        !          2329:        case CMD_mode:
        !          2330:                if (*arg == NUL || mch_screenmode(arg) != FAIL)
        !          2331:                    set_winsize(0, 0, FALSE);
        !          2332:                break;
        !          2333:
        !          2334:                /*
        !          2335:                 * set, increment or decrement current window height
        !          2336:                 */
        !          2337:        case CMD_resize:
        !          2338:                n = atol((char *)arg);
        !          2339:                if (*arg == '-' || *arg == '+')
        !          2340:                    win_setheight(curwin->w_height + (int)n);
        !          2341:                else
        !          2342:                {
        !          2343:                    if (n == 0)     /* default is very high */
        !          2344:                        n = 9999;
        !          2345:                    win_setheight((int)n);
        !          2346:                }
        !          2347:                break;
        !          2348:
        !          2349:                /*
        !          2350:                 * :sview [+command] file    split window with new file, ro
        !          2351:                 * :split [[+command] file]  split window with current or new file
        !          2352:                 * :new [[+command] file]    split window with no or new file
        !          2353:                 */
        !          2354:        case CMD_sview:
        !          2355:        case CMD_split:
        !          2356:        case CMD_new:
        !          2357:                old_curwin = curwin;
        !          2358:                if (win_split(addr_count ? (int)line2 : 0, FALSE) == FAIL)
        !          2359:                    break;
        !          2360:                /*FALLTHROUGH*/
        !          2361:
        !          2362:        case CMD_edit:
        !          2363:        case CMD_ex:
        !          2364:        case CMD_visual:
        !          2365:        case CMD_view:
        !          2366:                if ((cmdidx == CMD_new) && *arg == NUL)
        !          2367:                {
        !          2368:                    setpcmark();
        !          2369:                    (void)do_ecmd(0, NULL, NULL, do_ecmd_cmd, TRUE,
        !          2370:                                                          (linenr_t)1, FALSE);
        !          2371:                }
        !          2372:                else if (cmdidx != CMD_split || *arg != NUL)
        !          2373:                {
        !          2374:                    n = readonlymode;
        !          2375:                    if (cmdidx == CMD_view || cmdidx == CMD_sview)
        !          2376:                        readonlymode = TRUE;
        !          2377:                    setpcmark();
        !          2378:                    (void)do_ecmd(0, arg, NULL, do_ecmd_cmd, p_hid,
        !          2379:                                                           do_ecmd_lnum, FALSE);
        !          2380:                    readonlymode = n;
        !          2381:                }
        !          2382:                else
        !          2383:                    updateScreen(NOT_VALID);
        !          2384:                    /* if ":split file" worked, set alternate filename in
        !          2385:                     * old window to new file */
        !          2386:                if ((cmdidx == CMD_new || cmdidx == CMD_split) &&
        !          2387:                                *arg != NUL && curwin != old_curwin &&
        !          2388:                                old_curwin->w_buffer != curbuf)
        !          2389:                    old_curwin->w_alt_fnum = curbuf->b_fnum;
        !          2390:                break;
        !          2391:
        !          2392: #ifdef USE_GUI
        !          2393:        /*
        !          2394:         * Change from the terminal version to the GUI version.  File names may
        !          2395:         * be given to redefine the args list -- webb
        !          2396:         */
        !          2397:        case CMD_gvim:
        !          2398:        case CMD_gui:
        !          2399:                if (arg[0] == '-' && arg[1] == 'f' &&
        !          2400:                                       (arg[2] == NUL || vim_iswhite(arg[2])))
        !          2401:                {
        !          2402:                    gui.dofork = FALSE;
        !          2403:                    arg = skipwhite(arg + 2);
        !          2404:                }
        !          2405:                else
        !          2406:                    gui.dofork = TRUE;
        !          2407:                if (!gui.in_use)
        !          2408:                    gui_start();
        !          2409:                if (*arg != NUL && *arg != '|' && *arg != '\n')
        !          2410:                    goto do_next;
        !          2411:                break;
        !          2412: #endif
        !          2413:
        !          2414:        case CMD_file:
        !          2415:                do_file(arg, forceit);
        !          2416:                break;
        !          2417:
        !          2418:        case CMD_swapname:
        !          2419:                if (curbuf->b_ml.ml_mfp == NULL ||
        !          2420:                                (p = curbuf->b_ml.ml_mfp->mf_fname) == NULL)
        !          2421:                    MSG("No swap file");
        !          2422:                else
        !          2423:                    msg(p);
        !          2424:                break;
        !          2425:
        !          2426:        case CMD_mfstat:        /* print memfile statistics, for debugging */
        !          2427:                mf_statistics();
        !          2428:                break;
        !          2429:
        !          2430:        case CMD_read:
        !          2431:                if (usefilter)                  /* :r!cmd */
        !          2432:                {
        !          2433:                    do_bang(1, line1, line2, FALSE, arg, FALSE, TRUE);
        !          2434:                    break;
        !          2435:                }
        !          2436:                if (u_save(line2, (linenr_t)(line2 + 1)) == FAIL)
        !          2437:                    break;
        !          2438:                if (*arg == NUL)
        !          2439:                {
        !          2440:                    if (check_fname() == FAIL)  /* check for no file name */
        !          2441:                        break;
        !          2442:                    i = readfile(curbuf->b_filename, curbuf->b_sfilename,
        !          2443:                                    line2, FALSE, (linenr_t)0, MAXLNUM, FALSE);
        !          2444:                }
        !          2445:                else
        !          2446:                {
        !          2447:                    i = readfile(arg, NULL,
        !          2448:                                    line2, FALSE, (linenr_t)0, MAXLNUM, FALSE);
        !          2449:                }
        !          2450:                if (i == FAIL)
        !          2451:                {
        !          2452:                    emsg2(e_notopen, arg);
        !          2453:                    break;
        !          2454:                }
        !          2455:
        !          2456:                updateScreen(NOT_VALID);
        !          2457:                break;
        !          2458:
        !          2459:        case CMD_cd:
        !          2460:        case CMD_chdir:
        !          2461: #ifdef UNIX
        !          2462:                /*
        !          2463:                 * for UNIX ":cd" means: go to home directory
        !          2464:                 */
        !          2465:                if (*arg == NUL)     /* use NameBuff for home directory name */
        !          2466:                {
        !          2467:                    expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
        !          2468:                    arg = NameBuff;
        !          2469:                }
        !          2470: #endif
        !          2471:                if (*arg != NUL)
        !          2472:                {
        !          2473:                    if (!did_cd)
        !          2474:                    {
        !          2475:                        BUF     *buf;
        !          2476:
        !          2477:                            /* use full path from now on for names of files
        !          2478:                             * being edited and swap files */
        !          2479:                        for (buf = firstbuf; buf != NULL; buf = buf->b_next)
        !          2480:                        {
        !          2481:                            buf->b_xfilename = buf->b_filename;
        !          2482:                            mf_fullname(buf->b_ml.ml_mfp);
        !          2483:                        }
        !          2484:                        status_redraw_all();
        !          2485:                    }
        !          2486:                    did_cd = TRUE;
        !          2487:                    if (vim_chdir((char *)arg))
        !          2488:                        emsg(e_failed);
        !          2489:                    break;
        !          2490:                }
        !          2491:                /*FALLTHROUGH*/
        !          2492:
        !          2493:        case CMD_pwd:
        !          2494:                if (mch_dirname(NameBuff, MAXPATHL) == OK)
        !          2495:                    msg(NameBuff);
        !          2496:                else
        !          2497:                    emsg(e_unknown);
        !          2498:                break;
        !          2499:
        !          2500:        case CMD_equal:
        !          2501:                smsg((char_u *)"line %ld", (long)line2);
        !          2502:                break;
        !          2503:
        !          2504:        case CMD_list:
        !          2505:                i = curwin->w_p_list;
        !          2506:                curwin->w_p_list = 1;
        !          2507:        case CMD_number:                /* :nu */
        !          2508:        case CMD_pound:                 /* :# */
        !          2509:        case CMD_print:                 /* :p */
        !          2510:                for ( ;!got_int; mch_breakcheck())
        !          2511:                {
        !          2512:                    print_line(line1,
        !          2513:                               (cmdidx == CMD_number || cmdidx == CMD_pound));
        !          2514:                    if (++line1 > line2)
        !          2515:                        break;
        !          2516:                    flushbuf();         /* show one line at a time */
        !          2517:                }
        !          2518:                setpcmark();
        !          2519:                curwin->w_cursor.lnum = line2;  /* put cursor at last line */
        !          2520:
        !          2521:                if (cmdidx == CMD_list)
        !          2522:                    curwin->w_p_list = i;
        !          2523:
        !          2524:                break;
        !          2525:
        !          2526:        case CMD_shell:
        !          2527:                do_shell(NULL);
        !          2528:                break;
        !          2529:
        !          2530:        case CMD_sleep:
        !          2531:                n = curwin->w_winpos + curwin->w_row - msg_scrolled;
        !          2532:                if (n >= 0)
        !          2533:                {
        !          2534:                    windgoto((int)n, curwin->w_col);
        !          2535:                    flushbuf();
        !          2536:                }
        !          2537:                mch_delay(line2 * 1000L, TRUE);
        !          2538:                break;
        !          2539:
        !          2540:        case CMD_stag:
        !          2541:                postponed_split = TRUE;
        !          2542:                /*FALLTHROUGH*/
        !          2543:        case CMD_tag:
        !          2544:                do_tag(arg, 0, addr_count ? (int)line2 : 1);
        !          2545:                break;
        !          2546:
        !          2547:        case CMD_pop:
        !          2548:                do_tag((char_u *)"", 1, addr_count ? (int)line2 : 1);
        !          2549:                break;
        !          2550:
        !          2551:        case CMD_tags:
        !          2552:                do_tags();
        !          2553:                break;
        !          2554:
        !          2555:        case CMD_marks:
        !          2556:                do_marks(arg);
        !          2557:                break;
        !          2558:
        !          2559:        case CMD_jumps:
        !          2560:                do_jumps();
        !          2561:                break;
        !          2562:
        !          2563:        case CMD_ascii:
        !          2564:                do_ascii();
        !          2565:                break;
        !          2566:
        !          2567:        case CMD_checkpath:
        !          2568:                find_pattern_in_path(NULL, 0, FALSE, FALSE, CHECK_PATH, 1L,
        !          2569:                                      forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
        !          2570:                                            (linenr_t)1, (linenr_t)MAXLNUM);
        !          2571:                break;
        !          2572:
        !          2573:        case CMD_digraphs:
        !          2574: #ifdef DIGRAPHS
        !          2575:                if (*arg)
        !          2576:                    putdigraph(arg);
        !          2577:                else
        !          2578:                    listdigraphs();
        !          2579: #else
        !          2580:                EMSG("No digraphs in this version");
        !          2581: #endif /* DIGRAPHS */
        !          2582:                break;
        !          2583:
        !          2584:        case CMD_set:
        !          2585:                (void)do_set(arg);
        !          2586:                break;
        !          2587:
        !          2588:        case CMD_fixdel:
        !          2589:                do_fixdel();
        !          2590:                break;
        !          2591:
        !          2592: #ifdef AUTOCMD
        !          2593:        case CMD_autocmd:
        !          2594:                /*
        !          2595:                 * Disallow auto commands from .exrc and .vimrc in current
        !          2596:                 * directory for security reasons.
        !          2597:                 */
        !          2598:                if (secure)
        !          2599:                {
        !          2600:                    secure = 2;
        !          2601:                    errormsg = e_curdir;
        !          2602:                }
        !          2603:                else
        !          2604:                    do_autocmd(arg, forceit);   /* handle the auto commands */
        !          2605:                break;
        !          2606:
        !          2607:        case CMD_doautocmd:
        !          2608:                do_doautocmd(arg);      /* apply the automatic commands */
        !          2609:                do_modelines();
        !          2610:                break;
        !          2611: #endif
        !          2612:
        !          2613:        case CMD_abbreviate:
        !          2614:        case CMD_cabbrev:
        !          2615:        case CMD_iabbrev:
        !          2616:        case CMD_cnoreabbrev:
        !          2617:        case CMD_inoreabbrev:
        !          2618:        case CMD_noreabbrev:
        !          2619:        case CMD_unabbreviate:
        !          2620:        case CMD_cunabbrev:
        !          2621:        case CMD_iunabbrev:
        !          2622:                i = ABBREV;
        !          2623:                goto doabbr;        /* almost the same as mapping */
        !          2624:
        !          2625:        case CMD_nmap:
        !          2626:        case CMD_vmap:
        !          2627:        case CMD_cmap:
        !          2628:        case CMD_imap:
        !          2629:        case CMD_map:
        !          2630:        case CMD_nnoremap:
        !          2631:        case CMD_vnoremap:
        !          2632:        case CMD_cnoremap:
        !          2633:        case CMD_inoremap:
        !          2634:        case CMD_noremap:
        !          2635:                /*
        !          2636:                 * If we are sourcing .exrc or .vimrc in current directory we
        !          2637:                 * print the mappings for security reasons.
        !          2638:                 */
        !          2639:                if (secure)
        !          2640:                {
        !          2641:                    secure = 2;
        !          2642:                    msg_outtrans(cmd);
        !          2643:                    msg_outchar('\n');
        !          2644:                }
        !          2645:        case CMD_nunmap:
        !          2646:        case CMD_vunmap:
        !          2647:        case CMD_cunmap:
        !          2648:        case CMD_iunmap:
        !          2649:        case CMD_unmap:
        !          2650:                i = 0;
        !          2651: doabbr:
        !          2652:                if (*cmd == 'c')            /* cmap, cunmap, cnoremap, etc. */
        !          2653:                {
        !          2654:                    i += CMDLINE;
        !          2655:                    ++cmd;
        !          2656:                }
        !          2657:                else if (*cmd == 'i')       /* imap, iunmap, inoremap, etc. */
        !          2658:                {
        !          2659:                    i += INSERT;
        !          2660:                    ++cmd;
        !          2661:                }
        !          2662:                                            /* nmap, nunmap, nnoremap */
        !          2663:                else if (*cmd == 'n' && *(cmd + 1) != 'o')
        !          2664:                {
        !          2665:                    i += NORMAL;
        !          2666:                    ++cmd;
        !          2667:                }
        !          2668:                else if (*cmd == 'v')       /* vmap, vunmap, vnoremap */
        !          2669:                {
        !          2670:                    i += VISUAL;
        !          2671:                    ++cmd;
        !          2672:                }
        !          2673:                else if (forceit || i)      /* map!, unmap!, noremap!, abbrev */
        !          2674:                    i += INSERT + CMDLINE;
        !          2675:                else                        /* map, unmap, noremap */
        !          2676:                    i += NORMAL + VISUAL;
        !          2677:                switch (do_map((*cmd == 'n') ? 2 : (*cmd == 'u'), arg, i))
        !          2678:                {
        !          2679:                    case 1: emsg(e_invarg);
        !          2680:                            break;
        !          2681:                    case 2: emsg(e_nomap);
        !          2682:                            break;
        !          2683:                    case 3: emsg(e_ambmap);
        !          2684:                            break;
        !          2685:                }
        !          2686:                break;
        !          2687:
        !          2688:        case CMD_mapclear:
        !          2689:        case CMD_imapclear:
        !          2690:        case CMD_nmapclear:
        !          2691:        case CMD_vmapclear:
        !          2692:        case CMD_cmapclear:
        !          2693:                map_clear(*cmd, forceit, FALSE);
        !          2694:                break;
        !          2695:
        !          2696:        case CMD_abclear:
        !          2697:        case CMD_iabclear:
        !          2698:        case CMD_cabclear:
        !          2699:                map_clear(*cmd, FALSE, TRUE);
        !          2700:                break;
        !          2701:
        !          2702: #ifdef USE_GUI
        !          2703:        case CMD_menu:      case CMD_noremenu:      case CMD_unmenu:
        !          2704:        case CMD_nmenu:     case CMD_nnoremenu:     case CMD_nunmenu:
        !          2705:        case CMD_vmenu:     case CMD_vnoremenu:     case CMD_vunmenu:
        !          2706:        case CMD_imenu:     case CMD_inoremenu:     case CMD_iunmenu:
        !          2707:        case CMD_cmenu:     case CMD_cnoremenu:     case CMD_cunmenu:
        !          2708:                gui_do_menu(cmd, arg, forceit);
        !          2709:                break;
        !          2710: #endif /* USE_GUI */
        !          2711:
        !          2712:        case CMD_display:
        !          2713:        case CMD_registers:
        !          2714:                do_dis(arg);        /* display buffer contents */
        !          2715:                break;
        !          2716:
        !          2717:        case CMD_help:
        !          2718:                do_help(arg);
        !          2719:                break;
        !          2720:
        !          2721:        case CMD_version:
        !          2722:                do_version(arg);
        !          2723:                break;
        !          2724:
        !          2725:        case CMD_winsize:                   /* obsolete command */
        !          2726:                line1 = getdigits(&arg);
        !          2727:                arg = skipwhite(arg);
        !          2728:                line2 = getdigits(&arg);
        !          2729:                set_winsize((int)line1, (int)line2, TRUE);
        !          2730:                break;
        !          2731:
        !          2732:        case CMD_delete:
        !          2733:        case CMD_yank:
        !          2734:        case CMD_rshift:
        !          2735:        case CMD_lshift:
        !          2736:                yankbuffer = regname;
        !          2737:                curbuf->b_op_start.lnum = line1;
        !          2738:                curbuf->b_op_end.lnum = line2;
        !          2739:                op_line_count = line2 - line1 + 1;
        !          2740:                op_motion_type = MLINE;
        !          2741:                if (cmdidx != CMD_yank)     /* set cursor position for undo */
        !          2742:                {
        !          2743:                    setpcmark();
        !          2744:                    curwin->w_cursor.lnum = line1;
        !          2745:                    beginline(MAYBE);
        !          2746:                }
        !          2747:                switch (cmdidx)
        !          2748:                {
        !          2749:                case CMD_delete:
        !          2750:                    do_delete();
        !          2751:                    break;
        !          2752:                case CMD_yank:
        !          2753:                    (void)do_yank(FALSE, TRUE);
        !          2754:                    break;
        !          2755: #ifdef RIGHTLEFT
        !          2756:                case CMD_rshift:
        !          2757:                    do_shift(curwin->w_p_rl ? LSHIFT : RSHIFT, FALSE, amount);
        !          2758:                    break;
        !          2759:                case CMD_lshift:
        !          2760:                    do_shift(curwin->w_p_rl ? RSHIFT : LSHIFT, FALSE, amount);
        !          2761:                    break;
        !          2762: #else
        !          2763:                case CMD_rshift:
        !          2764:                    do_shift(RSHIFT, FALSE, amount);
        !          2765:                    break;
        !          2766:                case CMD_lshift:
        !          2767:                    do_shift(LSHIFT, FALSE, amount);
        !          2768:                    break;
        !          2769: #endif
        !          2770:                }
        !          2771:                break;
        !          2772:
        !          2773:        case CMD_put:
        !          2774:                yankbuffer = regname;
        !          2775:                curwin->w_cursor.lnum = line2;
        !          2776:                do_put(forceit ? BACKWARD : FORWARD, -1L, FALSE);
        !          2777:                break;
        !          2778:
        !          2779:        case CMD_t:
        !          2780:        case CMD_copy:
        !          2781:        case CMD_move:
        !          2782:                n = get_address(&arg);
        !          2783:                if (arg == NULL)            /* error detected */
        !          2784:                {
        !          2785:                    nextcomm = NULL;
        !          2786:                    break;
        !          2787:                }
        !          2788:                /*
        !          2789:                 * move or copy lines from 'line1'-'line2' to below line 'n'
        !          2790:                 */
        !          2791:                if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count)
        !          2792:                {
        !          2793:                    emsg(e_invaddr);
        !          2794:                    break;
        !          2795:                }
        !          2796:
        !          2797:                if (cmdidx == CMD_move)
        !          2798:                {
        !          2799:                    if (do_move(line1, line2, n) == FAIL)
        !          2800:                        break;
        !          2801:                }
        !          2802:                else
        !          2803:                    do_copy(line1, line2, n);
        !          2804:                u_clearline();
        !          2805:                beginline(MAYBE);
        !          2806:                updateScreen(NOT_VALID);
        !          2807:                break;
        !          2808:
        !          2809:        case CMD_and:           /* :& */
        !          2810:        case CMD_tilde:         /* :~ */
        !          2811:        case CMD_substitute:    /* :s */
        !          2812:                do_sub(line1, line2, arg, &nextcomm,
        !          2813:                            cmdidx == CMD_substitute ? 0 :
        !          2814:                            cmdidx == CMD_and ? 1 : 2);
        !          2815:                break;
        !          2816:
        !          2817:        case CMD_join:
        !          2818:                curwin->w_cursor.lnum = line1;
        !          2819:                if (line1 == line2)
        !          2820:                {
        !          2821:                    if (addr_count >= 2)    /* :2,2join does nothing */
        !          2822:                        break;
        !          2823:                    if (line2 == curbuf->b_ml.ml_line_count)
        !          2824:                    {
        !          2825:                        beep_flush();
        !          2826:                        break;
        !          2827:                    }
        !          2828:                    ++line2;
        !          2829:                }
        !          2830:                do_do_join(line2 - line1 + 1, !forceit, FALSE);
        !          2831:                beginline(TRUE);
        !          2832:                break;
        !          2833:
        !          2834:        case CMD_global:
        !          2835:                if (forceit)
        !          2836:                    *cmd = 'v';
        !          2837:        case CMD_vglobal:
        !          2838:                do_glob(*cmd, line1, line2, arg);
        !          2839:                break;
        !          2840:
        !          2841:        case CMD_at:                /* :[addr]@r */
        !          2842:                curwin->w_cursor.lnum = line2;
        !          2843:                                    /* put the register in mapbuf */
        !          2844:                if (do_execbuf(*arg, TRUE,
        !          2845:                              vim_strchr(p_cpo, CPO_EXECBUF) != NULL) == FAIL)
        !          2846:                    beep_flush();
        !          2847:                else
        !          2848:                                    /* execute from the mapbuf */
        !          2849:                    while (vpeekc() == ':')
        !          2850:                    {
        !          2851:                        (void)vgetc();
        !          2852:                        (void)do_cmdline((char_u *)NULL, TRUE, TRUE);
        !          2853:                    }
        !          2854:                break;
        !          2855:
        !          2856:        case CMD_bang:
        !          2857:                do_bang(addr_count, line1, line2, forceit, arg, TRUE, TRUE);
        !          2858:                break;
        !          2859:
        !          2860:        case CMD_undo:
        !          2861:                u_undo(1);
        !          2862:                break;
        !          2863:
        !          2864:        case CMD_redo:
        !          2865:                u_redo(1);
        !          2866:                break;
        !          2867:
        !          2868:        case CMD_source:
        !          2869:                if (forceit)                    /* :so! read vi commands */
        !          2870:                    (void)openscript(arg);
        !          2871:                                                /* :so read ex commands */
        !          2872:                else if (do_source(arg, FALSE) == FAIL)
        !          2873:                    emsg2(e_notopen, arg);
        !          2874:                break;
        !          2875:
        !          2876: #ifdef VIMINFO
        !          2877:        case CMD_rviminfo:
        !          2878:                p = p_viminfo;
        !          2879:                if (*p_viminfo == NUL)
        !          2880:                    p_viminfo = (char_u *)"'100";
        !          2881:                if (read_viminfo(arg, TRUE, TRUE, forceit) == FAIL)
        !          2882:                    EMSG("Cannot open viminfo file for reading");
        !          2883:                p_viminfo = p;
        !          2884:                break;
        !          2885:
        !          2886:        case CMD_wviminfo:
        !          2887:                p = p_viminfo;
        !          2888:                if (*p_viminfo == NUL)
        !          2889:                    p_viminfo = (char_u *)"'100";
        !          2890:                write_viminfo(arg, forceit);
        !          2891:                p_viminfo = p;
        !          2892:                break;
        !          2893: #endif /* VIMINFO */
        !          2894:
        !          2895:        case CMD_mkvimrc:
        !          2896:                if (*arg == NUL)
        !          2897:                    arg = (char_u *)VIMRC_FILE;
        !          2898:                /*FALLTHROUGH*/
        !          2899:
        !          2900:        case CMD_mkexrc:
        !          2901:                {
        !          2902:                    FILE    *fd;
        !          2903:
        !          2904:                    if (*arg == NUL)
        !          2905:                        arg = (char_u *)EXRC_FILE;
        !          2906: #ifdef UNIX
        !          2907:                    /* with Unix it is possible to open a directory */
        !          2908:                    if (mch_isdir(arg))
        !          2909:                    {
        !          2910:                        EMSG2("\"%s\" is a directory", arg);
        !          2911:                        break;
        !          2912:                    }
        !          2913: #endif
        !          2914:                    if (!forceit && vim_fexists(arg))
        !          2915:                    {
        !          2916:                        EMSG2("\"%s\" exists (use ! to override)", arg);
        !          2917:                        break;
        !          2918:                    }
        !          2919:
        !          2920:                    if ((fd = fopen((char *)arg, WRITEBIN)) == NULL)
        !          2921:                    {
        !          2922:                        EMSG2("Cannot open \"%s\" for writing", arg);
        !          2923:                        break;
        !          2924:                    }
        !          2925:
        !          2926:                    /* Write the version command for :mkvimrc */
        !          2927:                    if (cmdidx == CMD_mkvimrc)
        !          2928:                    {
        !          2929: #ifdef USE_CRNL
        !          2930:                        fprintf(fd, "version 4.0\r\n");
        !          2931: #else
        !          2932:                        fprintf(fd, "version 4.0\n");
        !          2933: #endif
        !          2934:                    }
        !          2935:
        !          2936:                    if (makemap(fd) == FAIL || makeset(fd) == FAIL ||
        !          2937:                                                                   fclose(fd))
        !          2938:                        emsg(e_write);
        !          2939:                    break;
        !          2940:                }
        !          2941:
        !          2942:        case CMD_cc:
        !          2943:                    qf_jump(0, addr_count ? (int)line2 : 0);
        !          2944:                    break;
        !          2945:
        !          2946:        case CMD_cfile:
        !          2947:                    if (*arg != NUL)
        !          2948:                    {
        !          2949:                        /*
        !          2950:                         * Great trick: Insert 'ef=' before arg.
        !          2951:                         * Always ok, because "cf " must be there.
        !          2952:                         */
        !          2953:                        arg -= 3;
        !          2954:                        arg[0] = 'e';
        !          2955:                        arg[1] = 'f';
        !          2956:                        arg[2] = '=';
        !          2957:                        (void)do_set(arg);
        !          2958:                    }
        !          2959:                    if (qf_init() == OK)
        !          2960:                        qf_jump(0, 0);          /* display first error */
        !          2961:                    break;
        !          2962:
        !          2963:        case CMD_clist:
        !          2964:                    qf_list(forceit);
        !          2965:                    break;
        !          2966:
        !          2967:        case CMD_cnext:
        !          2968:                    qf_jump(FORWARD, addr_count ? (int)line2 : 1);
        !          2969:                    break;
        !          2970:
        !          2971:        case CMD_cNext:
        !          2972:        case CMD_cprevious:
        !          2973:                    qf_jump(BACKWARD, addr_count ? (int)line2 : 1);
        !          2974:                    break;
        !          2975:
        !          2976:        case CMD_cquit:
        !          2977:                    getout(1);      /* this does not always work. why? */
        !          2978:
        !          2979:        case CMD_mark:
        !          2980:        case CMD_k:
        !          2981:                    pos = curwin->w_cursor;         /* save curwin->w_cursor */
        !          2982:                    curwin->w_cursor.lnum = line2;
        !          2983:                    beginline(MAYBE);
        !          2984:                    (void)setmark(*arg);            /* set mark */
        !          2985:                    curwin->w_cursor = pos;         /* restore curwin->w_cursor */
        !          2986:                    break;
        !          2987:
        !          2988:        case CMD_center:
        !          2989:        case CMD_right:
        !          2990:        case CMD_left:
        !          2991:                    do_align(line1, line2, atoi((char *)arg),
        !          2992:                            cmdidx == CMD_center ? 0 : cmdidx == CMD_right ? 1 : -1);
        !          2993:                    break;
        !          2994:
        !          2995:        case CMD_retab:
        !          2996:                n = getdigits(&arg);
        !          2997:                do_retab(line1, line2, (int)n, forceit);
        !          2998:                u_clearline();
        !          2999:                updateScreen(NOT_VALID);
        !          3000:                break;
        !          3001:
        !          3002:        case CMD_make:
        !          3003:                do_make(arg);
        !          3004:                break;
        !          3005:
        !          3006:                /*
        !          3007:                 * :normal[!] {commands} - execute normal mode commands
        !          3008:                 * Mostly used for ":autocmd".
        !          3009:                 */
        !          3010:        case CMD_normal:
        !          3011:                /*
        !          3012:                 * Stuff the argument into the typeahead buffer.
        !          3013:                 * Execute normal() until there is no more typeahead than
        !          3014:                 * there was before this command.
        !          3015:                 */
        !          3016:                len = typelen;
        !          3017:                ins_typebuf(arg, forceit ? -1 : 0, 0, TRUE);
        !          3018:                while ((!stuff_empty() ||
        !          3019:                             (!typebuf_typed() && typelen > len)) && !got_int)
        !          3020:                {
        !          3021:                    adjust_cursor();    /* put cursor on an existing line */
        !          3022:                    cursupdate();       /* update cursor position */
        !          3023:                    normal();    /* get and execute a normal mode command */
        !          3024:                }
        !          3025:                break;
        !          3026:
        !          3027:        case CMD_isearch:
        !          3028:        case CMD_dsearch:
        !          3029:                i = ACTION_SHOW;
        !          3030:                goto find_pat;
        !          3031:
        !          3032:        case CMD_ilist:
        !          3033:        case CMD_dlist:
        !          3034:                i = ACTION_SHOW_ALL;
        !          3035:                goto find_pat;
        !          3036:
        !          3037:        case CMD_ijump:
        !          3038:        case CMD_djump:
        !          3039:                i = ACTION_GOTO;
        !          3040:                goto find_pat;
        !          3041:
        !          3042:        case CMD_isplit:
        !          3043:        case CMD_dsplit:
        !          3044:                i = ACTION_SPLIT;
        !          3045: find_pat:
        !          3046:                {
        !          3047:                    int     whole = TRUE;
        !          3048:
        !          3049:                    n = 1;
        !          3050:                    if (isdigit(*arg))      /* get count */
        !          3051:                    {
        !          3052:                        n = getdigits(&arg);
        !          3053:                        arg = skipwhite(arg);
        !          3054:                    }
        !          3055:                    if (*arg == '/')    /* Match regexp, not just whole words */
        !          3056:                    {
        !          3057:                        whole = FALSE;
        !          3058:                        ++arg;
        !          3059:                        for (p = arg; *p && *p != '/'; p++)
        !          3060:                            if (*p == '\\' && p[1] != NUL)
        !          3061:                                p++;
        !          3062:                        if (*p)
        !          3063:                        {
        !          3064:                            *p++ = NUL;
        !          3065:                            p = skipwhite(p);
        !          3066:
        !          3067:                            /* Check for trailing illegal characters */
        !          3068:                            if (*p && vim_strchr((char_u *)"|\"\n", *p) == NULL)
        !          3069:                                errormsg = e_trailing;
        !          3070:                            else
        !          3071:                                nextcomm = p;
        !          3072:                        }
        !          3073:                    }
        !          3074:                    find_pattern_in_path(arg, (int)STRLEN(arg), whole, !forceit,
        !          3075:                        *cmd == 'd' ?  FIND_DEFINE : FIND_ANY,
        !          3076:                        n, i, line1, line2);
        !          3077:                }
        !          3078:                break;
        !          3079:
        !          3080:        default:
        !          3081:                    /* Normal illegal commands have already been handled */
        !          3082:                errormsg = (char_u *)"Sorry, this command is not implemented";
        !          3083:    }
        !          3084:
        !          3085:
        !          3086: doend:
        !          3087:    if (errormsg != NULL)
        !          3088:    {
        !          3089:        emsg(errormsg);
        !          3090:        if (sourcing)
        !          3091:        {
        !          3092:            MSG_OUTSTR(": ");
        !          3093:            msg_outtrans(*cmdlinep);
        !          3094:        }
        !          3095:    }
        !          3096:    if (did_emsg)
        !          3097:        nextcomm = NULL;                /* cancel nextcomm at an error */
        !          3098:    forceit = FALSE;        /* reset now so it can be used in getfile() */
        !          3099:    if (nextcomm && *nextcomm == NUL)       /* not really a next command */
        !          3100:        nextcomm = NULL;
        !          3101:    return nextcomm;
        !          3102: }
        !          3103:
        !          3104: /*
        !          3105:  * If 'autowrite' option set, try to write the file.
        !          3106:  *
        !          3107:  * return FAIL for failure, OK otherwise
        !          3108:  */
        !          3109:    int
        !          3110: autowrite(buf)
        !          3111:    BUF     *buf;
        !          3112: {
        !          3113:    if (!p_aw || (!forceit && buf->b_p_ro) || buf->b_filename == NULL)
        !          3114:        return FAIL;
        !          3115:    return buf_write_all(buf);
        !          3116: }
        !          3117:
        !          3118: /*
        !          3119:  * flush all buffers, except the ones that are readonly
        !          3120:  */
        !          3121:    void
        !          3122: autowrite_all()
        !          3123: {
        !          3124:    BUF     *buf;
        !          3125:
        !          3126:    if (!p_aw)
        !          3127:        return;
        !          3128:    for (buf = firstbuf; buf; buf = buf->b_next)
        !          3129:        if (buf->b_changed && !buf->b_p_ro)
        !          3130:            (void)buf_write_all(buf);
        !          3131: }
        !          3132:
        !          3133: /*
        !          3134:  * flush the contents of a buffer, unless it has no file name
        !          3135:  *
        !          3136:  * return FAIL for failure, OK otherwise
        !          3137:  */
        !          3138:    static int
        !          3139: buf_write_all(buf)
        !          3140:    BUF     *buf;
        !          3141: {
        !          3142:    return (buf_write(buf, buf->b_filename, buf->b_sfilename,
        !          3143:                     (linenr_t)1, buf->b_ml.ml_line_count, 0, 0, TRUE, FALSE));
        !          3144: }
        !          3145:
        !          3146: /*
        !          3147:  * write current buffer to file 'fname'
        !          3148:  * if 'append' is TRUE, append to the file
        !          3149:  *
        !          3150:  * if *fname == NUL write to current file
        !          3151:  * if b_notedited is TRUE, check for overwriting current file
        !          3152:  *
        !          3153:  * return FAIL for failure, OK otherwise
        !          3154:  */
        !          3155:    static int
        !          3156: do_write(fname, append)
        !          3157:    char_u  *fname;
        !          3158:    int     append;
        !          3159: {
        !          3160:    int     other;
        !          3161:    char_u  *sfname = NULL;             /* init to shut up gcc */
        !          3162:
        !          3163:    if (*fname == NUL)
        !          3164:        other = FALSE;
        !          3165:    else
        !          3166:    {
        !          3167:        sfname = fname;
        !          3168:        fname = fix_fname(fname);
        !          3169:        other = otherfile(fname);
        !          3170:    }
        !          3171:
        !          3172:    /*
        !          3173:     * if we have a new file name put it in the list of alternate file names
        !          3174:     */
        !          3175:    if (other)
        !          3176:        setaltfname(fname, sfname, (linenr_t)1);
        !          3177:
        !          3178:    /*
        !          3179:     * writing to the current file is not allowed in readonly mode
        !          3180:     * and need a file name
        !          3181:     */
        !          3182:    if (!other && (check_readonly() || check_fname() == FAIL))
        !          3183:        return FAIL;
        !          3184:
        !          3185:    if (!other)
        !          3186:    {
        !          3187:        fname = curbuf->b_filename;
        !          3188:        sfname = curbuf->b_sfilename;
        !          3189:        /*
        !          3190:         * Not writing the whole file is only allowed with '!'.
        !          3191:         */
        !          3192:        if ((line1 != 1 || line2 != curbuf->b_ml.ml_line_count) &&
        !          3193:                                                 !forceit && !append && !p_wa)
        !          3194:        {
        !          3195:            EMSG("Use ! to write partial buffer");
        !          3196:            return FAIL;
        !          3197:        }
        !          3198:    }
        !          3199:
        !          3200:    /*
        !          3201:     * write to other file or b_notedited set or not writing the whole file:
        !          3202:     * overwriting only allowed with '!'
        !          3203:     */
        !          3204:    if ((other || curbuf->b_notedited) && !forceit &&
        !          3205:                                       !append && !p_wa && vim_fexists(fname))
        !          3206:    {                               /* don't overwrite existing file */
        !          3207: #ifdef UNIX
        !          3208:            /* with UNIX it is possible to open a directory */
        !          3209:        if (mch_isdir(fname))
        !          3210:            EMSG2("\"%s\" is a directory", fname);
        !          3211:        else
        !          3212: #endif
        !          3213:            emsg(e_exists);
        !          3214:        return FAIL;
        !          3215:    }
        !          3216:    return (buf_write(curbuf, fname, sfname, line1, line2,
        !          3217:                                                append, forceit, TRUE, FALSE));
        !          3218: }
        !          3219:
        !          3220: /*
        !          3221:  * start editing a new file
        !          3222:  *
        !          3223:  *     fnum: file number; if zero use fname/sfname
        !          3224:  *    fname: the file name
        !          3225:  *             - full path if sfname used,
        !          3226:  *             - any file name if sfname is NULL
        !          3227:  *             - empty string to re-edit with the same file name (but may be
        !          3228:  *                 in a different directory)
        !          3229:  *             - NULL to start an empty buffer
        !          3230:  *   sfname: the short file name (or NULL)
        !          3231:  *  command: the command to be executed after loading the file
        !          3232:  *     hide: if TRUE don't free the current buffer
        !          3233:  *  newlnum: put cursor on this line number (if possible)
        !          3234:  * set_help: set b_help flag of (new) buffer before opening file
        !          3235:  *
        !          3236:  * return FAIL for failure, OK otherwise
        !          3237:  */
        !          3238:    int
        !          3239: do_ecmd(fnum, fname, sfname, command, hide, newlnum, set_help)
        !          3240:    int         fnum;
        !          3241:    char_u      *fname;
        !          3242:    char_u      *sfname;
        !          3243:    char_u      *command;
        !          3244:    int         hide;
        !          3245:    linenr_t    newlnum;
        !          3246:    int         set_help;
        !          3247: {
        !          3248:    int         other_file;             /* TRUE if editing another file */
        !          3249:    int         oldbuf = FALSE;         /* TRUE if using existing buffer */
        !          3250:    BUF         *buf;
        !          3251:
        !          3252:    if (fnum != 0)
        !          3253:    {
        !          3254:        if (fnum == curbuf->b_fnum)     /* file is already being edited */
        !          3255:            return OK;                  /* nothing to do */
        !          3256:        other_file = TRUE;
        !          3257:    }
        !          3258:    else
        !          3259:    {
        !          3260:            /* if no short name given, use fname for short name */
        !          3261:        if (sfname == NULL)
        !          3262:            sfname = fname;
        !          3263: #ifdef USE_FNAME_CASE
        !          3264: # ifdef USE_LONG_FNAME
        !          3265:        if (USE_LONG_FNAME)
        !          3266: # endif
        !          3267:            fname_case(sfname);         /* set correct case for short filename */
        !          3268: #endif
        !          3269:
        !          3270:        if (fname == NULL)
        !          3271:            other_file = TRUE;
        !          3272:                                            /* there is no file name */
        !          3273:        else if (*fname == NUL && curbuf->b_filename == NULL)
        !          3274:            other_file = FALSE;
        !          3275:        else
        !          3276:        {
        !          3277:            if (*fname == NUL)              /* re-edit with same file name */
        !          3278:            {
        !          3279:                fname = curbuf->b_filename;
        !          3280:                sfname = curbuf->b_sfilename;
        !          3281:            }
        !          3282:            fname = fix_fname(fname);       /* may expand to full path name */
        !          3283:            other_file = otherfile(fname);
        !          3284:        }
        !          3285:    }
        !          3286: /*
        !          3287:  * if the file was changed we may not be allowed to abandon it
        !          3288:  * - if we are going to re-edit the same file
        !          3289:  * - or if we are the only window on this file and if hide is FALSE
        !          3290:  */
        !          3291:    if ((!other_file || (curbuf->b_nwindows == 1 && !hide)) &&
        !          3292:                        check_changed(curbuf, FALSE, !other_file))
        !          3293:    {
        !          3294:        if (fnum == 0 && other_file && fname != NULL)
        !          3295:            setaltfname(fname, sfname, (linenr_t)1);
        !          3296:        return FAIL;
        !          3297:    }
        !          3298:
        !          3299: /*
        !          3300:  * End Visual mode before switching to another buffer, so the text can be
        !          3301:  * copied into the GUI selection buffer.
        !          3302:  */
        !          3303:    if (VIsual_active)
        !          3304:        end_visual_mode();
        !          3305:
        !          3306: /*
        !          3307:  * If we are starting to edit another file, open a (new) buffer.
        !          3308:  * Otherwise we re-use the current buffer.
        !          3309:  */
        !          3310:    if (other_file)
        !          3311:    {
        !          3312:        curwin->w_alt_fnum = curbuf->b_fnum;
        !          3313:        buflist_altlnum();
        !          3314:
        !          3315:        if (fnum)
        !          3316:            buf = buflist_findnr(fnum);
        !          3317:        else
        !          3318:            buf = buflist_new(fname, sfname, 1L, TRUE);
        !          3319:        if (buf == NULL)
        !          3320:            return FAIL;
        !          3321:        if (buf->b_ml.ml_mfp == NULL)       /* no memfile yet */
        !          3322:        {
        !          3323:            oldbuf = FALSE;
        !          3324:            buf->b_nwindows = 1;
        !          3325:        }
        !          3326:        else                                /* existing memfile */
        !          3327:        {
        !          3328:            oldbuf = TRUE;
        !          3329:            ++buf->b_nwindows;
        !          3330:            buf_check_timestamp(buf);
        !          3331:        }
        !          3332:
        !          3333:        /*
        !          3334:         * make the (new) buffer the one used by the current window
        !          3335:         * if the old buffer becomes unused, free it if hide is FALSE
        !          3336:         * If the current buffer was empty and has no file name, curbuf
        !          3337:         * is returned by buflist_new().
        !          3338:         */
        !          3339:        if (buf != curbuf)
        !          3340:        {
        !          3341: #ifdef AUTOCMD
        !          3342:            apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
        !          3343: #endif
        !          3344: #ifdef VIMINFO
        !          3345:            curbuf->b_last_cursor = curwin->w_cursor;
        !          3346: #endif
        !          3347:            buf_copy_options(curbuf, buf, TRUE);
        !          3348:            close_buffer(curwin, curbuf, !hide, FALSE);
        !          3349:            curwin->w_buffer = buf;
        !          3350:            curbuf = buf;
        !          3351:        }
        !          3352:
        !          3353:        curwin->w_pcmark.lnum = 1;
        !          3354:        curwin->w_pcmark.col = 0;
        !          3355:    }
        !          3356:    else if (check_fname() == FAIL)
        !          3357:        return FAIL;
        !          3358:
        !          3359: /*
        !          3360:  * If we get here we are sure to start editing
        !          3361:  */
        !          3362:        /* don't redraw until the cursor is in the right line */
        !          3363:    ++RedrawingDisabled;
        !          3364:    if (set_help)
        !          3365:        curbuf->b_help = TRUE;
        !          3366:
        !          3367: /*
        !          3368:  * other_file  oldbuf
        !          3369:  * FALSE       FALSE       re-edit same file, buffer is re-used
        !          3370:  * FALSE       TRUE        not posible
        !          3371:  *  TRUE       FALSE       start editing new file, new buffer
        !          3372:  *  TRUE       TRUE        start editing in existing buffer (nothing to do)
        !          3373:  */
        !          3374:    if (!other_file)                    /* re-use the buffer */
        !          3375:    {
        !          3376:        if (newlnum == 0)
        !          3377:            newlnum = curwin->w_cursor.lnum;
        !          3378:        buf_freeall(curbuf);            /* free all things for buffer */
        !          3379:        buf_clear(curbuf);
        !          3380:        curbuf->b_op_start.lnum = 0;    /* clear '[ and '] marks */
        !          3381:        curbuf->b_op_end.lnum = 0;
        !          3382:    }
        !          3383:
        !          3384:    /*
        !          3385:     * Check if we are editing the w_arg_idx file in the argument list.
        !          3386:     */
        !          3387:    check_arg_idx();
        !          3388:
        !          3389:    if (!oldbuf)                        /* need to read the file */
        !          3390:        (void)open_buffer();
        !          3391: #ifdef AUTOCMD
        !          3392:    else
        !          3393:        apply_autocmds(EVENT_BUFENTER, NULL, NULL);
        !          3394: #endif
        !          3395:    win_init(curwin);
        !          3396:    maketitle();
        !          3397:
        !          3398:    if (command == NULL)
        !          3399:    {
        !          3400:        if (newlnum)
        !          3401:        {
        !          3402:            curwin->w_cursor.lnum = newlnum;
        !          3403:            check_cursor();
        !          3404:            beginline(MAYBE);
        !          3405:        }
        !          3406:        else
        !          3407:            beginline(TRUE);
        !          3408:    }
        !          3409:
        !          3410:    /*
        !          3411:     * Did not read the file, need to show some info about the file.
        !          3412:     * Do this after setting the cursor.
        !          3413:     */
        !          3414:    if (oldbuf)
        !          3415:        fileinfo(did_cd, TRUE, FALSE);
        !          3416:
        !          3417:    if (command != NULL)
        !          3418:        do_cmdline(command, TRUE, FALSE);
        !          3419:    --RedrawingDisabled;
        !          3420:    if (!skip_redraw)
        !          3421:        updateScreen(CURSUPD);          /* redraw now */
        !          3422:
        !          3423:    if (p_im)
        !          3424:        need_start_insertmode = TRUE;
        !          3425:    return OK;
        !          3426: }
        !          3427:
        !          3428: /*
        !          3429:  * get + command from ex argument
        !          3430:  */
        !          3431:    static char_u *
        !          3432: getargcmd(argp)
        !          3433:    char_u **argp;
        !          3434: {
        !          3435:    char_u *arg = *argp;
        !          3436:    char_u *command = NULL;
        !          3437:
        !          3438:    if (*arg == '+')        /* +[command] */
        !          3439:    {
        !          3440:        ++arg;
        !          3441:        if (vim_isspace(*arg))
        !          3442:            command = (char_u *)"$";
        !          3443:        else
        !          3444:        {
        !          3445:            /*
        !          3446:             * should check for "\ " (but vi has a bug that prevents it to work)
        !          3447:             */
        !          3448:            command = arg;
        !          3449:            arg = skiptowhite(command);
        !          3450:            if (*arg)
        !          3451:                *arg++ = NUL;   /* terminate command with NUL */
        !          3452:        }
        !          3453:
        !          3454:        arg = skipwhite(arg);   /* skip over spaces */
        !          3455:        *argp = arg;
        !          3456:    }
        !          3457:    return command;
        !          3458: }
        !          3459:
        !          3460: /*
        !          3461:  * Halve the number of backslashes in a file name argument.
        !          3462:  * For MS-DOS we only do this if the character after the backslash
        !          3463:  * is not a normal file character.
        !          3464:  * For Unix, when wildcards are going to be expanded, don't remove
        !          3465:  * backslashes before special characters.
        !          3466:  */
        !          3467:    static void
        !          3468: backslash_halve(p, expand_wildcards)
        !          3469:    char_u  *p;
        !          3470:    int     expand_wildcards;       /* going to expand wildcards later */
        !          3471: {
        !          3472:    for ( ; *p; ++p)
        !          3473:        if (is_backslash(p)
        !          3474: #if defined(MSDOS) || defined(WIN32)
        !          3475:                && p[1] != '*' && p[1] != '?'
        !          3476: #endif
        !          3477: #if defined(UNIX) || defined(OS2)
        !          3478:                && !(expand_wildcards &&
        !          3479:                        vim_strchr((char_u *)" *?[{`$\\", p[1]))
        !          3480: #endif
        !          3481:                                               )
        !          3482:            STRCPY(p, p + 1);
        !          3483: }
        !          3484:
        !          3485:    static void
        !          3486: do_make(arg)
        !          3487:    char_u *arg;
        !          3488: {
        !          3489:    if (*p_ef == NUL)
        !          3490:    {
        !          3491:        EMSG("errorfile option not set");
        !          3492:        return;
        !          3493:    }
        !          3494:
        !          3495:    autowrite_all();
        !          3496:    vim_remove(p_ef);
        !          3497:
        !          3498:    sprintf((char *)IObuff, "%s %s %s", arg, p_sp, p_ef);
        !          3499:    MSG_OUTSTR(":!");
        !          3500:    msg_outtrans(IObuff);               /* show what we are doing */
        !          3501:    do_shell(IObuff);
        !          3502:
        !          3503: #ifdef AMIGA
        !          3504:    flushbuf();
        !          3505:                /* read window status report and redraw before message */
        !          3506:    (void)char_avail();
        !          3507: #endif
        !          3508:
        !          3509:    if (qf_init() == OK)
        !          3510:        qf_jump(0, 0);          /* display first error */
        !          3511:
        !          3512:    vim_remove(p_ef);
        !          3513: }
        !          3514:
        !          3515: /*
        !          3516:  * Redefine the argument list to 'str'.
        !          3517:  *
        !          3518:  * Return FAIL for failure, OK otherwise.
        !          3519:  */
        !          3520:    static int
        !          3521: do_arglist(str)
        !          3522:    char_u *str;
        !          3523: {
        !          3524:    int     new_count = 0;
        !          3525:    char_u  **new_files = NULL;
        !          3526:    int     exp_count;
        !          3527:    char_u  **exp_files;
        !          3528:    char_u  **t;
        !          3529:    char_u  *p;
        !          3530:    int     inquote;
        !          3531:    int     i;
        !          3532:
        !          3533:    while (*str)
        !          3534:    {
        !          3535:        /*
        !          3536:         * create a new entry in new_files[]
        !          3537:         */
        !          3538:        t = (char_u **)lalloc((long_u)(sizeof(char_u *) * (new_count + 1)), TRUE);
        !          3539:        if (t != NULL)
        !          3540:            for (i = new_count; --i >= 0; )
        !          3541:                t[i] = new_files[i];
        !          3542:        vim_free(new_files);
        !          3543:        if (t == NULL)
        !          3544:            return FAIL;
        !          3545:        new_files = t;
        !          3546:        new_files[new_count++] = str;
        !          3547:
        !          3548:        /*
        !          3549:         * isolate one argument, taking quotes
        !          3550:         */
        !          3551:        inquote = FALSE;
        !          3552:        for (p = str; *str; ++str)
        !          3553:        {
        !          3554:            /*
        !          3555:             * for MSDOS et.al. a backslash is part of a file name.
        !          3556:             * Only skip ", space and tab.
        !          3557:             */
        !          3558:            if (is_backslash(str))
        !          3559:                *p++ = *++str;
        !          3560:            else
        !          3561:            {
        !          3562:                if (!inquote && vim_isspace(*str))
        !          3563:                    break;
        !          3564:                if (*str == '"')
        !          3565:                    inquote ^= TRUE;
        !          3566:                else
        !          3567:                    *p++ = *str;
        !          3568:            }
        !          3569:        }
        !          3570:        str = skipwhite(str);
        !          3571:        *p = NUL;
        !          3572:    }
        !          3573:
        !          3574:    i = ExpandWildCards(new_count, new_files, &exp_count,
        !          3575:                                                &exp_files, FALSE, TRUE);
        !          3576:    vim_free(new_files);
        !          3577:    if (i == FAIL)
        !          3578:        return FAIL;
        !          3579:    if (exp_count == 0)
        !          3580:    {
        !          3581:        emsg(e_nomatch);
        !          3582:        return FAIL;
        !          3583:    }
        !          3584:    if (arg_exp)                /* arg_files[] has been allocated, free it */
        !          3585:        FreeWild(arg_count, arg_files);
        !          3586:    else
        !          3587:        arg_exp = TRUE;
        !          3588:    arg_files = exp_files;
        !          3589:    arg_count = exp_count;
        !          3590:    arg_had_last = FALSE;
        !          3591:
        !          3592:    /*
        !          3593:     * put all file names in the buffer list
        !          3594:     */
        !          3595:    for (i = 0; i < arg_count; ++i)
        !          3596:        (void)buflist_add(arg_files[i]);
        !          3597:
        !          3598:    return OK;
        !          3599: }
        !          3600:
        !          3601: /*
        !          3602:  * Return TRUE if "str" starts with a backslash that should be removed.
        !          3603:  * For MS-DOS, WIN32 and OS/2 this is only done when the character after the
        !          3604:  * backslash is not a normal file name character.
        !          3605:  */
        !          3606:    static int
        !          3607: is_backslash(str)
        !          3608:    char_u  *str;
        !          3609: {
        !          3610: #ifdef BACKSLASH_IN_FILENAME
        !          3611:    return (str[0] == '\\' && str[1] != NUL &&
        !          3612:                                     !(isfilechar(str[1]) && str[1] != '\\'));
        !          3613: #else
        !          3614:    return (str[0] == '\\' && str[1] != NUL);
        !          3615: #endif
        !          3616: }
        !          3617:
        !          3618: /*
        !          3619:  * Check if we are editing the w_arg_idx file in the argument list.
        !          3620:  */
        !          3621:    void
        !          3622: check_arg_idx()
        !          3623: {
        !          3624:    int     t;
        !          3625:
        !          3626:    if (arg_count > 1 && (curbuf->b_filename == NULL ||
        !          3627:                          curwin->w_arg_idx >= arg_count ||
        !          3628:                (t = fullpathcmp(arg_files[curwin->w_arg_idx],
        !          3629:                           curbuf->b_filename)) == FPC_DIFF || t == FPC_DIFFX))
        !          3630:        curwin->w_arg_idx_invalid = TRUE;
        !          3631:    else
        !          3632:        curwin->w_arg_idx_invalid = FALSE;
        !          3633: }
        !          3634:
        !          3635:    void
        !          3636: gotocmdline(clr)
        !          3637:    int             clr;
        !          3638: {
        !          3639:    msg_start();
        !          3640:    if (clr)                /* clear the bottom line(s) */
        !          3641:        msg_clr_eos();      /* will reset clear_cmdline */
        !          3642:    windgoto(cmdline_row, 0);
        !          3643: }
        !          3644:
        !          3645:    static int
        !          3646: check_readonly()
        !          3647: {
        !          3648:    if (!forceit && curbuf->b_p_ro)
        !          3649:    {
        !          3650:        emsg(e_readonly);
        !          3651:        return TRUE;
        !          3652:    }
        !          3653:    return FALSE;
        !          3654: }
        !          3655:
        !          3656: /*
        !          3657:  * return TRUE if buffer was changed and cannot be abandoned.
        !          3658:  */
        !          3659:    static int
        !          3660: check_changed(buf, checkaw, mult_win)
        !          3661:    BUF     *buf;
        !          3662:    int     checkaw;        /* do autowrite if buffer was changed */
        !          3663:    int     mult_win;       /* check also when several windows for the buffer */
        !          3664: {
        !          3665:    if (    !forceit &&
        !          3666:            buf->b_changed && (mult_win || buf->b_nwindows <= 1) &&
        !          3667:            (!checkaw || autowrite(buf) == FAIL))
        !          3668:    {
        !          3669:        emsg(e_nowrtmsg);
        !          3670:        return TRUE;
        !          3671:    }
        !          3672:    return FALSE;
        !          3673: }
        !          3674:
        !          3675: /*
        !          3676:  * return TRUE if any buffer was changed and cannot be abandoned.
        !          3677:  * That changed buffer becomes the current buffer.
        !          3678:  */
        !          3679:    static int
        !          3680: check_changed_any()
        !          3681: {
        !          3682:    BUF     *buf;
        !          3683:    int     save;
        !          3684:
        !          3685:    if (!forceit)
        !          3686:    {
        !          3687:        for (buf = firstbuf; buf != NULL; buf = buf->b_next)
        !          3688:        {
        !          3689:            if (buf->b_changed)
        !          3690:            {
        !          3691:                /* There must be a wait_return for this message, do_buffer
        !          3692:                 * will cause a redraw */
        !          3693:                exiting = FALSE;
        !          3694:                if (EMSG2("No write since last change for buffer \"%s\"",
        !          3695:                              buf->b_xfilename == NULL ? (char_u *)"No File" :
        !          3696:                                                            buf->b_xfilename))
        !          3697:                {
        !          3698:                    save = no_wait_return;
        !          3699:                    no_wait_return = FALSE;
        !          3700:                    wait_return(FALSE);
        !          3701:                    no_wait_return = save;
        !          3702:                }
        !          3703:                (void)do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD,
        !          3704:                                                              buf->b_fnum, 0);
        !          3705:                return TRUE;
        !          3706:            }
        !          3707:        }
        !          3708:    }
        !          3709:    return FALSE;
        !          3710: }
        !          3711:
        !          3712: /*
        !          3713:  * return FAIL if there is no filename, OK if there is one
        !          3714:  * give error message for FAIL
        !          3715:  */
        !          3716:    int
        !          3717: check_fname()
        !          3718: {
        !          3719:    if (curbuf->b_filename == NULL)
        !          3720:    {
        !          3721:        emsg(e_noname);
        !          3722:        return FAIL;
        !          3723:    }
        !          3724:    return OK;
        !          3725: }
        !          3726:
        !          3727: /*
        !          3728:  * - if there are more files to edit
        !          3729:  * - and this is the last window
        !          3730:  * - and forceit not used
        !          3731:  * - and not repeated twice on a row
        !          3732:  *   return FAIL and give error message if 'message' TRUE
        !          3733:  * return OK otherwise
        !          3734:  */
        !          3735:    static int
        !          3736: check_more(message)
        !          3737:    int message;            /* when FALSE check only, no messages */
        !          3738: {
        !          3739:    if (!forceit && only_one_window() && arg_count > 1 && !arg_had_last &&
        !          3740:                                    quitmore == 0)
        !          3741:    {
        !          3742:        if (message)
        !          3743:        {
        !          3744:            EMSGN("%ld more files to edit", arg_count - curwin->w_arg_idx - 1);
        !          3745:            quitmore = 2;           /* next try to quit is allowed */
        !          3746:        }
        !          3747:        return FAIL;
        !          3748:    }
        !          3749:    return OK;
        !          3750: }
        !          3751:
        !          3752: /*
        !          3753:  * try to abandon current file and edit a new or existing file
        !          3754:  * 'fnum' is the number of the file, if zero use fname/sfname
        !          3755:  *
        !          3756:  * return 1 for "normal" error, 2 for "not written" error, 0 for success
        !          3757:  * -1 for succesfully opening another file
        !          3758:  * 'lnum' is the line number for the cursor in the new file (if non-zero).
        !          3759:  */
        !          3760:    int
        !          3761: getfile(fnum, fname, sfname, setpm, lnum)
        !          3762:    int         fnum;
        !          3763:    char_u      *fname;
        !          3764:    char_u      *sfname;
        !          3765:    int         setpm;
        !          3766:    linenr_t    lnum;
        !          3767: {
        !          3768:    int other;
        !          3769:
        !          3770:    if (fnum == 0)
        !          3771:    {
        !          3772:        fname_expand(&fname, &sfname);  /* make fname full path, set sfname */
        !          3773:        other = otherfile(fname);
        !          3774:    }
        !          3775:    else
        !          3776:        other = (fnum != curbuf->b_fnum);
        !          3777:
        !          3778:    if (other)
        !          3779:        ++no_wait_return;           /* don't wait for autowrite message */
        !          3780:    if (other && !forceit && curbuf->b_nwindows == 1 &&
        !          3781:            !p_hid && curbuf->b_changed && autowrite(curbuf) == FAIL)
        !          3782:    {
        !          3783:        if (other)
        !          3784:            --no_wait_return;
        !          3785:        emsg(e_nowrtmsg);
        !          3786:        return 2;       /* file has been changed */
        !          3787:    }
        !          3788:    if (other)
        !          3789:        --no_wait_return;
        !          3790:    if (setpm)
        !          3791:        setpcmark();
        !          3792:    if (!other)
        !          3793:    {
        !          3794:        if (lnum != 0)
        !          3795:            curwin->w_cursor.lnum = lnum;
        !          3796:        check_cursor();
        !          3797:        beginline(MAYBE);
        !          3798:
        !          3799:        return 0;       /* it's in the same file */
        !          3800:    }
        !          3801:    if (do_ecmd(fnum, fname, sfname, NULL, p_hid, lnum, FALSE) == OK)
        !          3802:        return -1;      /* opened another file */
        !          3803:    return 1;           /* error encountered */
        !          3804: }
        !          3805:
        !          3806: /*
        !          3807:  * vim_strncpy()
        !          3808:  *
        !          3809:  * This is here because strncpy() does not guarantee successful results when
        !          3810:  * the to and from strings overlap.  It is only currently called from nextwild()
        !          3811:  * which copies part of the command line to another part of the command line.
        !          3812:  * This produced garbage when expanding files etc in the middle of the command
        !          3813:  * line (on my terminal, anyway) -- webb.
        !          3814:  */
        !          3815:    static void
        !          3816: vim_strncpy(to, from, len)
        !          3817:    char_u *to;
        !          3818:    char_u *from;
        !          3819:    int len;
        !          3820: {
        !          3821:    int i;
        !          3822:
        !          3823:    if (to <= from)
        !          3824:    {
        !          3825:        while (len-- && *from)
        !          3826:            *to++ = *from++;
        !          3827:        if (len >= 0)
        !          3828:            *to = *from;    /* Copy NUL */
        !          3829:    }
        !          3830:    else
        !          3831:    {
        !          3832:        for (i = 0; i < len; i++)
        !          3833:        {
        !          3834:            to++;
        !          3835:            if (*from++ == NUL)
        !          3836:            {
        !          3837:                i++;
        !          3838:                break;
        !          3839:            }
        !          3840:        }
        !          3841:        for (; i > 0; i--)
        !          3842:            *--to = *--from;
        !          3843:    }
        !          3844: }
        !          3845:
        !          3846: /*
        !          3847:  * Return FALSE if this is not an appropriate context in which to do
        !          3848:  * completion of anything, & TRUE if it is (even if there are no matches).
        !          3849:  * For the caller, this means that the character is just passed through like a
        !          3850:  * normal character (instead of being expanded).  This allows :s/^I^D etc.
        !          3851:  */
        !          3852:    static int
        !          3853: nextwild(type)
        !          3854:    int     type;
        !          3855: {
        !          3856:    int     i;
        !          3857:    char_u  *p1;
        !          3858:    char_u  *p2;
        !          3859:    int     oldlen;
        !          3860:    int     difflen;
        !          3861:    int     v;
        !          3862:
        !          3863:    if (cmd_numfiles == -1)
        !          3864:        set_expand_context(cmdfirstc, cmdbuff);
        !          3865:    if (expand_context == EXPAND_UNSUCCESSFUL)
        !          3866:    {
        !          3867:        beep_flush();
        !          3868:        return OK;  /* Something illegal on command line */
        !          3869:    }
        !          3870:    if (expand_context == EXPAND_NOTHING)
        !          3871:    {
        !          3872:        /* Caller can use the character as a normal char instead */
        !          3873:        return FAIL;
        !          3874:    }
        !          3875:    expand_interactively = TRUE;
        !          3876:
        !          3877:    MSG_OUTSTR("...");      /* show that we are busy */
        !          3878:    flushbuf();
        !          3879:
        !          3880:    i = expand_pattern - cmdbuff;
        !          3881:    oldlen = cmdpos - i;
        !          3882:
        !          3883:    if (type == WILD_NEXT || type == WILD_PREV)
        !          3884:    {
        !          3885:        /*
        !          3886:         * Get next/previous match for a previous expanded pattern.
        !          3887:         */
        !          3888:        p2 = ExpandOne(NULL, NULL, 0, type);
        !          3889:    }
        !          3890:    else
        !          3891:    {
        !          3892:        /*
        !          3893:         * Translate string into pattern and expand it.
        !          3894:         */
        !          3895:        if ((p1 = addstar(&cmdbuff[i], oldlen)) == NULL)
        !          3896:            p2 = NULL;
        !          3897:        else
        !          3898:        {
        !          3899:            p2 = ExpandOne(p1, strnsave(&cmdbuff[i], oldlen),
        !          3900:                                                     WILD_HOME_REPLACE, type);
        !          3901:            vim_free(p1);
        !          3902:        }
        !          3903:    }
        !          3904:
        !          3905:    if (p2 != NULL)
        !          3906:    {
        !          3907:        if (cmdlen + (difflen = STRLEN(p2) - oldlen) > cmdbufflen - 4)
        !          3908:            v = realloc_cmdbuff(cmdlen + difflen);
        !          3909:        else
        !          3910:            v = OK;
        !          3911:        if (v == OK)
        !          3912:        {
        !          3913:            vim_strncpy(&cmdbuff[cmdpos + difflen], &cmdbuff[cmdpos],
        !          3914:                    cmdlen - cmdpos);
        !          3915:            STRNCPY(&cmdbuff[i], p2, STRLEN(p2));
        !          3916:            cmdlen += difflen;
        !          3917:            cmdpos += difflen;
        !          3918:        }
        !          3919:        vim_free(p2);
        !          3920:    }
        !          3921:
        !          3922:    redrawcmd();
        !          3923:    if (cmd_numfiles <= 0 && p2 == NULL)
        !          3924:        beep_flush();
        !          3925:    else if (cmd_numfiles == 1)
        !          3926:        (void)ExpandOne(NULL, NULL, 0, WILD_FREE);  /* free expanded pattern */
        !          3927:
        !          3928:    expand_interactively = FALSE;           /* reset for next call */
        !          3929:    return OK;
        !          3930: }
        !          3931:
        !          3932: #define MAXSUFLEN 30       /* maximum length of a file suffix */
        !          3933:
        !          3934: /*
        !          3935:  * Do wildcard expansion on the string 'str'.
        !          3936:  * Return a pointer to alloced memory containing the new string.
        !          3937:  * Return NULL for failure.
        !          3938:  *
        !          3939:  * mode = WILD_FREE:       just free previously expanded matches
        !          3940:  * mode = WILD_EXPAND_FREE:    normal expansion, do not keep matches
        !          3941:  * mode = WILD_EXPAND_KEEP:    normal expansion, keep matches
        !          3942:  * mode = WILD_NEXT:       use next match in multiple match, wrap to first
        !          3943:  * mode = WILD_PREV:       use previous match in multiple match, wrap to first
        !          3944:  * mode = WILD_ALL:            return all matches concatenated
        !          3945:  * mode = WILD_LONGEST:        return longest matched part
        !          3946:  *
        !          3947:  * options = WILD_LIST_NOTFOUND:   list entries without a match
        !          3948:  * options = WILD_HOME_REPLACE:        do home_replace() for buffer names
        !          3949:  */
        !          3950:    char_u *
        !          3951: ExpandOne(str, orig, options, mode)
        !          3952:    char_u  *str;
        !          3953:    char_u  *orig;          /* original string which is expanded */
        !          3954:    int     options;
        !          3955:    int     mode;
        !          3956: {
        !          3957:    char_u      *ss = NULL;
        !          3958:    static char_u **cmd_files = NULL;   /* list of input files */
        !          3959:    static int  findex;
        !          3960:    static char_u *orig_save = NULL;    /* kept value of orig */
        !          3961:    int         i, found = 0;
        !          3962:    int         multmatch = FALSE;
        !          3963:    long_u      len;
        !          3964:    char_u      *setsuf;
        !          3965:    int         fnamelen, setsuflen;
        !          3966:    char_u      suf_buf[MAXSUFLEN];
        !          3967:    char_u      *p;
        !          3968:
        !          3969: /*
        !          3970:  * first handle the case of using an old match
        !          3971:  */
        !          3972:    if (mode == WILD_NEXT || mode == WILD_PREV)
        !          3973:    {
        !          3974:        if (cmd_numfiles > 0)
        !          3975:        {
        !          3976:            if (mode == WILD_PREV)
        !          3977:            {
        !          3978:                if (findex == -1)
        !          3979:                    findex = cmd_numfiles;
        !          3980:                --findex;
        !          3981:            }
        !          3982:            else    /* mode == WILD_NEXT */
        !          3983:                ++findex;
        !          3984:
        !          3985:            /*
        !          3986:             * When wrapping around, return the original string, set findex to
        !          3987:             * -1.
        !          3988:             */
        !          3989:            if (findex < 0)
        !          3990:            {
        !          3991:                if (orig_save == NULL)
        !          3992:                    findex = cmd_numfiles - 1;
        !          3993:                else
        !          3994:                    findex = -1;
        !          3995:            }
        !          3996:            if (findex >= cmd_numfiles)
        !          3997:            {
        !          3998:                if (orig_save == NULL)
        !          3999:                    findex = 0;
        !          4000:                else
        !          4001:                    findex = -1;
        !          4002:            }
        !          4003:            if (findex == -1)
        !          4004:                return strsave(orig_save);
        !          4005:            return strsave(cmd_files[findex]);
        !          4006:        }
        !          4007:        else
        !          4008:            return NULL;
        !          4009:    }
        !          4010:
        !          4011: /* free old names */
        !          4012:    if (cmd_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST)
        !          4013:    {
        !          4014:        FreeWild(cmd_numfiles, cmd_files);
        !          4015:        cmd_numfiles = -1;
        !          4016:        vim_free(orig_save);
        !          4017:        orig_save = NULL;
        !          4018:    }
        !          4019:    findex = 0;
        !          4020:
        !          4021:    if (mode == WILD_FREE)      /* only release file name */
        !          4022:        return NULL;
        !          4023:
        !          4024:    if (cmd_numfiles == -1)
        !          4025:    {
        !          4026:        vim_free(orig_save);
        !          4027:        orig_save = orig;
        !          4028:        if (ExpandFromContext(str, &cmd_numfiles, &cmd_files, FALSE,
        !          4029:                                                             options) == FAIL)
        !          4030:            /* error: do nothing */;
        !          4031:        else if (cmd_numfiles == 0)
        !          4032:        {
        !          4033:            if (!expand_interactively)
        !          4034:                emsg(e_nomatch);
        !          4035:        }
        !          4036:        else
        !          4037:        {
        !          4038:            /*
        !          4039:             * If the pattern starts with a '~', replace the home diretory
        !          4040:             * with '~' again.
        !          4041:             */
        !          4042:            if (*str == '~' && (options & WILD_HOME_REPLACE))
        !          4043:            {
        !          4044:                for (i = 0; i < cmd_numfiles; ++i)
        !          4045:                {
        !          4046:                    p = home_replace_save(NULL, cmd_files[i]);
        !          4047:                    if (p != NULL)
        !          4048:                    {
        !          4049:                        vim_free(cmd_files[i]);
        !          4050:                        cmd_files[i] = p;
        !          4051:                    }
        !          4052:                }
        !          4053:            }
        !          4054:
        !          4055:            /*
        !          4056:             * Insert backslashes into a file name before a space, \, %, # and
        !          4057:             * wildmatch characters, except '~'.
        !          4058:             */
        !          4059:            if (expand_interactively &&
        !          4060:                    (expand_context == EXPAND_FILES ||
        !          4061:                     expand_context == EXPAND_BUFFERS ||
        !          4062:                     expand_context == EXPAND_DIRECTORIES))
        !          4063:            {
        !          4064:                for (i = 0; i < cmd_numfiles; ++i)
        !          4065:                {
        !          4066:                    p = strsave_escaped(cmd_files[i],
        !          4067: #ifdef BACKSLASH_IN_FILENAME
        !          4068:                                                    (char_u *)" *?[{`$%#");
        !          4069: #else
        !          4070:                                                    (char_u *)" *?[{`$\\%#");
        !          4071: #endif
        !          4072:                    if (p != NULL)
        !          4073:                    {
        !          4074:                        vim_free(cmd_files[i]);
        !          4075:                        cmd_files[i] = p;
        !          4076:                    }
        !          4077:                }
        !          4078:            }
        !          4079:
        !          4080:            if (mode != WILD_ALL && mode != WILD_LONGEST)
        !          4081:            {
        !          4082:                if (cmd_numfiles > 1)   /* more than one match; check suffix */
        !          4083:                {
        !          4084:                    found = -2;
        !          4085:                    for (i = 0; i < cmd_numfiles; ++i)
        !          4086:                    {
        !          4087:                        fnamelen = STRLEN(cmd_files[i]);
        !          4088:                        setsuflen = 0;
        !          4089:                        for (setsuf = p_su; *setsuf; )
        !          4090:                        {
        !          4091:                            setsuflen = copy_option_part(&setsuf, suf_buf,
        !          4092:                                                              MAXSUFLEN, ".,");
        !          4093:                            if (fnamelen >= setsuflen && STRNCMP(suf_buf,
        !          4094:                                          cmd_files[i] + fnamelen - setsuflen,
        !          4095:                                                      (size_t)setsuflen) == 0)
        !          4096:                                break;
        !          4097:                            setsuflen = 0;
        !          4098:                        }
        !          4099:                        if (setsuflen)      /* suffix matched: ignore file */
        !          4100:                            continue;
        !          4101:                        if (found >= 0)
        !          4102:                        {
        !          4103:                            multmatch = TRUE;
        !          4104:                            break;
        !          4105:                        }
        !          4106:                        found = i;
        !          4107:                    }
        !          4108:                }
        !          4109:                if (multmatch || found < 0)
        !          4110:                {
        !          4111:                    /* Can we ever get here unless it's while expanding
        !          4112:                     * interactively?  If not, we can get rid of this all
        !          4113:                     * together. Don't really want to wait for this message
        !          4114:                     * (and possibly have to hit return to continue!).
        !          4115:                     */
        !          4116:                    if (!expand_interactively)
        !          4117:                        emsg(e_toomany);
        !          4118:                    else
        !          4119:                        beep_flush();
        !          4120:                    found = 0;              /* return first one */
        !          4121:                    multmatch = TRUE;       /* for found < 0 */
        !          4122:                }
        !          4123:                if (found >= 0 && !(multmatch && mode == WILD_EXPAND_FREE))
        !          4124:                    ss = strsave(cmd_files[found]);
        !          4125:            }
        !          4126:        }
        !          4127:    }
        !          4128:
        !          4129:    /* Find longest common part */
        !          4130:    if (mode == WILD_LONGEST && cmd_numfiles > 0)
        !          4131:    {
        !          4132:        for (len = 0; cmd_files[0][len]; ++len)
        !          4133:        {
        !          4134:            for (i = 0; i < cmd_numfiles; ++i)
        !          4135:            {
        !          4136: #ifdef CASE_INSENSITIVE_FILENAME
        !          4137:                if ((expand_context == EXPAND_DIRECTORIES ||
        !          4138:                                             expand_context == EXPAND_FILES ||
        !          4139:                                          expand_context == EXPAND_BUFFERS) &&
        !          4140:                     toupper(cmd_files[i][len]) != toupper(cmd_files[0][len]))
        !          4141:                    break;
        !          4142:                else
        !          4143: #endif
        !          4144:                if (cmd_files[i][len] != cmd_files[0][len])
        !          4145:                    break;
        !          4146:            }
        !          4147:            if (i < cmd_numfiles)
        !          4148:            {
        !          4149:                vim_beep();
        !          4150:                break;
        !          4151:            }
        !          4152:        }
        !          4153:        ss = alloc((unsigned)len + 1);
        !          4154:        if (ss)
        !          4155:        {
        !          4156:            STRNCPY(ss, cmd_files[0], len);
        !          4157:            ss[len] = NUL;
        !          4158:        }
        !          4159:        findex = -1;                        /* next p_wc gets first one */
        !          4160:    }
        !          4161:
        !          4162:    /* Concatenate all matching names */
        !          4163:    if (mode == WILD_ALL && cmd_numfiles > 0)
        !          4164:    {
        !          4165:        len = 0;
        !          4166:        for (i = 0; i < cmd_numfiles; ++i)
        !          4167:            len += STRLEN(cmd_files[i]) + 1;
        !          4168:        ss = lalloc(len, TRUE);
        !          4169:        if (ss)
        !          4170:        {
        !          4171:            *ss = NUL;
        !          4172:            for (i = 0; i < cmd_numfiles; ++i)
        !          4173:            {
        !          4174:                STRCAT(ss, cmd_files[i]);
        !          4175:                if (i != cmd_numfiles - 1)
        !          4176:                    STRCAT(ss, " ");
        !          4177:            }
        !          4178:        }
        !          4179:    }
        !          4180:
        !          4181:    if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
        !          4182:    {
        !          4183:        FreeWild(cmd_numfiles, cmd_files);
        !          4184:        cmd_numfiles = -1;
        !          4185:    }
        !          4186:    return ss;
        !          4187: }
        !          4188:
        !          4189: /*
        !          4190:  * show all matches for completion on the command line
        !          4191:  */
        !          4192:    static int
        !          4193: showmatches(buff)
        !          4194:    char_u *buff;
        !          4195: {
        !          4196:    char_u      *file_str;
        !          4197:    int         num_files;
        !          4198:    char_u      **files_found;
        !          4199:    int         i, j, k;
        !          4200:    int         maxlen;
        !          4201:    int         lines;
        !          4202:    int         columns;
        !          4203:    char_u      *p;
        !          4204:    int         lastlen;
        !          4205:
        !          4206:    set_expand_context(cmdfirstc, cmdbuff);
        !          4207:    if (expand_context == EXPAND_UNSUCCESSFUL)
        !          4208:    {
        !          4209:        beep_flush();
        !          4210:        return OK;  /* Something illegal on command line */
        !          4211:    }
        !          4212:    if (expand_context == EXPAND_NOTHING)
        !          4213:    {
        !          4214:        /* Caller can use the character as a normal char instead */
        !          4215:        return FAIL;
        !          4216:    }
        !          4217:    expand_interactively = TRUE;
        !          4218:
        !          4219:    /* add star to file name, or convert to regexp if not expanding files! */
        !          4220:    file_str = addstar(expand_pattern, (int)(buff + cmdpos - expand_pattern));
        !          4221:    if (file_str == NULL)
        !          4222:    {
        !          4223:        expand_interactively = FALSE;
        !          4224:        return OK;
        !          4225:    }
        !          4226:
        !          4227:    msg_didany = FALSE;                 /* lines_left will be set */
        !          4228:    msg_start();                        /* prepare for paging */
        !          4229:    msg_outchar('\n');
        !          4230:    flushbuf();
        !          4231:    cmdline_row = msg_row;
        !          4232:    msg_didany = FALSE;                 /* lines_left will be set again */
        !          4233:    msg_start();                        /* prepare for paging */
        !          4234:
        !          4235:    /* find all files that match the description */
        !          4236:    if (ExpandFromContext(file_str, &num_files, &files_found, FALSE, 0) == FAIL)
        !          4237:    {
        !          4238:        num_files = 0;
        !          4239:        files_found = (char_u **)"";
        !          4240:    }
        !          4241:
        !          4242:    /* find the length of the longest file name */
        !          4243:    maxlen = 0;
        !          4244:    for (i = 0; i < num_files; ++i)
        !          4245:    {
        !          4246:        if (expand_context == EXPAND_FILES || expand_context == EXPAND_BUFFERS)
        !          4247:        {
        !          4248:            home_replace(NULL, files_found[i], NameBuff, MAXPATHL);
        !          4249:            j = strsize(NameBuff);
        !          4250:        }
        !          4251:        else
        !          4252:            j = strsize(files_found[i]);
        !          4253:        if (j > maxlen)
        !          4254:            maxlen = j;
        !          4255:    }
        !          4256:
        !          4257:    /* compute the number of columns and lines for the listing */
        !          4258:    maxlen += 2;    /* two spaces between file names */
        !          4259:    columns = ((int)Columns + 2) / maxlen;
        !          4260:    if (columns < 1)
        !          4261:        columns = 1;
        !          4262:    lines = (num_files + columns - 1) / columns;
        !          4263:
        !          4264:    (void)set_highlight('d');   /* find out highlight mode for directories */
        !          4265:
        !          4266:    /* list the files line by line */
        !          4267:    for (i = 0; i < lines; ++i)
        !          4268:    {
        !          4269:        lastlen = 999;
        !          4270:        for (k = i; k < num_files; k += lines)
        !          4271:        {
        !          4272:            for (j = maxlen - lastlen; --j >= 0; )
        !          4273:                msg_outchar(' ');
        !          4274:            if (expand_context == EXPAND_FILES ||
        !          4275:                                             expand_context == EXPAND_BUFFERS)
        !          4276:            {
        !          4277:                        /* highlight directories */
        !          4278:                j = (mch_isdir(files_found[k]));
        !          4279:                home_replace(NULL, files_found[k], NameBuff, MAXPATHL);
        !          4280:                p = NameBuff;
        !          4281:            }
        !          4282:            else
        !          4283:            {
        !          4284:                j = FALSE;
        !          4285:                p = files_found[k];
        !          4286:            }
        !          4287:            if (j)
        !          4288:                start_highlight();
        !          4289:            lastlen = msg_outtrans(p);
        !          4290:            if (j)
        !          4291:                stop_highlight();
        !          4292:        }
        !          4293:        msg_outchar('\n');
        !          4294:        flushbuf();                 /* show one line at a time */
        !          4295:        if (got_int)
        !          4296:        {
        !          4297:            got_int = FALSE;
        !          4298:            break;
        !          4299:        }
        !          4300:    }
        !          4301:    vim_free(file_str);
        !          4302:    FreeWild(num_files, files_found);
        !          4303:
        !          4304: /*
        !          4305:  * we redraw the command below the lines that we have just listed
        !          4306:  * This is a bit tricky, but it saves a lot of screen updating.
        !          4307:  */
        !          4308:    cmdline_row = msg_row;      /* will put it back later */
        !          4309:
        !          4310:    expand_interactively = FALSE;
        !          4311:    return OK;
        !          4312: }
        !          4313:
        !          4314: /*
        !          4315:  * Prepare a string for expansion.
        !          4316:  * When expanding file names:  The string will be used with ExpandWildCards().
        !          4317:  * Copy the file name into allocated memory and add a '*' at the end.
        !          4318:  * When expanding other names:  The string will be used with regcomp().  Copy
        !          4319:  * the name into allocated memory and add ".*" at the end.
        !          4320:  */
        !          4321:    char_u *
        !          4322: addstar(fname, len)
        !          4323:    char_u  *fname;
        !          4324:    int     len;
        !          4325: {
        !          4326:    char_u  *retval;
        !          4327:    int     i, j;
        !          4328:    int     new_len;
        !          4329:    char_u  *tail;
        !          4330:
        !          4331:    if (expand_interactively && expand_context != EXPAND_FILES &&
        !          4332:                                         expand_context != EXPAND_DIRECTORIES)
        !          4333:    {
        !          4334:        /*
        !          4335:         * Matching will be done internally (on something other than files).
        !          4336:         * So we convert the file-matching-type wildcards into our kind for
        !          4337:         * use with vim_regcomp().  First work out how long it will be:
        !          4338:         */
        !          4339:
        !          4340:        /* for help tags the translation is done in find_help_tags() */
        !          4341:        if (expand_context == EXPAND_HELP)
        !          4342:            retval = strnsave(fname, len);
        !          4343:        else
        !          4344:        {
        !          4345:            new_len = len + 2;          /* +2 for '^' at start, NUL at end */
        !          4346:            for (i = 0; i < len; i++)
        !          4347:            {
        !          4348:                if (fname[i] == '*' || fname[i] == '~')
        !          4349:                    new_len++;          /* '*' needs to be replaced by ".*"
        !          4350:                                           '~' needs to be replaced by "\~" */
        !          4351:
        !          4352:                /* Buffer names are like file names.  "." should be literal */
        !          4353:                if (expand_context == EXPAND_BUFFERS && fname[i] == '.')
        !          4354:                    new_len++;          /* "." becomes "\." */
        !          4355:            }
        !          4356:            retval = alloc(new_len);
        !          4357:            if (retval != NULL)
        !          4358:            {
        !          4359:                retval[0] = '^';
        !          4360:                j = 1;
        !          4361:                for (i = 0; i < len; i++, j++)
        !          4362:                {
        !          4363:                    if (fname[i] == '\\' && ++i == len) /* skip backslash */
        !          4364:                        break;
        !          4365:
        !          4366:                    switch (fname[i])
        !          4367:                    {
        !          4368:                        case '*':   retval[j++] = '.';
        !          4369:                                    break;
        !          4370:                        case '~':   retval[j++] = '\\';
        !          4371:                                    break;
        !          4372:                        case '?':   retval[j] = '.';
        !          4373:                                    continue;
        !          4374:                        case '.':   if (expand_context == EXPAND_BUFFERS)
        !          4375:                                        retval[j++] = '\\';
        !          4376:                                    break;
        !          4377:                    }
        !          4378:                    retval[j] = fname[i];
        !          4379:                }
        !          4380:                retval[j] = NUL;
        !          4381:            }
        !          4382:        }
        !          4383:    }
        !          4384:    else
        !          4385:    {
        !          4386:        retval = alloc(len + 4);
        !          4387:        if (retval != NULL)
        !          4388:        {
        !          4389:            STRNCPY(retval, fname, len);
        !          4390:            retval[len] = NUL;
        !          4391:            backslash_halve(retval, TRUE);      /* remove some backslashes */
        !          4392:            len = STRLEN(retval);
        !          4393:
        !          4394:            /*
        !          4395:             * Don't add a star to ~, ~user, $var or `cmd`.
        !          4396:             * ~ would be at the start of the tail.
        !          4397:             * $ could be anywhere in the tail.
        !          4398:             * ` could be anywhere in the file name.
        !          4399:             */
        !          4400:            tail = gettail(retval);
        !          4401:            if (*tail != '~' && vim_strchr(tail, '$') == NULL
        !          4402:                                           && vim_strchr(retval, '`') == NULL)
        !          4403:            {
        !          4404: #ifdef MSDOS
        !          4405:                /*
        !          4406:                 * if there is no dot in the file name, add "*.*" instead of
        !          4407:                 * "*".
        !          4408:                 */
        !          4409:                for (i = len - 1; i >= 0; --i)
        !          4410:                    if (vim_strchr((char_u *)".\\/:", retval[i]) != NULL)
        !          4411:                        break;
        !          4412:                if (i < 0 || retval[i] != '.')
        !          4413:                {
        !          4414:                    retval[len++] = '*';
        !          4415:                    retval[len++] = '.';
        !          4416:                }
        !          4417: #endif
        !          4418:                retval[len++] = '*';
        !          4419:            }
        !          4420:            retval[len] = NUL;
        !          4421:        }
        !          4422:    }
        !          4423:    return retval;
        !          4424: }
        !          4425:
        !          4426: /*
        !          4427:  * do_source: read the file "fname" and execute its lines as EX commands
        !          4428:  *
        !          4429:  * This function may be called recursively!
        !          4430:  *
        !          4431:  * return FAIL if file could not be opened, OK otherwise
        !          4432:  */
        !          4433:    int
        !          4434: do_source(fname, check_other)
        !          4435:    register char_u *fname;
        !          4436:    int             check_other;        /* check for .vimrc and _vimrc */
        !          4437: {
        !          4438:    register FILE   *fp;
        !          4439:    register int    len;
        !          4440: #ifdef USE_CRNL
        !          4441:    int             has_cr;
        !          4442:    int             textmode = -1;  /* -1 = unknown, 0 = NL, 1 = CR-NL */
        !          4443:    int             error = FALSE;
        !          4444: #endif
        !          4445:                                    /* use NameBuff for expanded name */
        !          4446:    expand_env(fname, NameBuff, MAXPATHL);
        !          4447:    fp = fopen((char *)NameBuff, READBIN);
        !          4448:    if (fp == NULL && check_other)
        !          4449:    {
        !          4450:        /*
        !          4451:         * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa
        !          4452:         * (if applicable)
        !          4453:         */
        !          4454:        len = STRLEN(NameBuff);
        !          4455:        if (((len > 6 && ispathsep(NameBuff[len - 7])) || len == 6) &&
        !          4456:                     (NameBuff[len - 6] == '.' || NameBuff[len - 6] == '_') &&
        !          4457:                                  (STRCMP(&NameBuff[len - 5], "vimrc") == 0))
        !          4458:        {
        !          4459:            if (NameBuff[len - 6] == '_')
        !          4460:                NameBuff[len - 6] = '.';
        !          4461:            else
        !          4462:                NameBuff[len - 6] = '_';
        !          4463:            fp = fopen((char *)NameBuff, READBIN);
        !          4464:        }
        !          4465:    }
        !          4466:
        !          4467:    if (fp == NULL)
        !          4468:        return FAIL;
        !          4469:
        !          4470: #ifdef USE_CRNL
        !          4471:        /* no automatic textmode: Set default to CR-NL */
        !          4472:    if (!p_ta)
        !          4473:        textmode = 1;
        !          4474: #endif
        !          4475:    sourcing_name = fname;
        !          4476:    sourcing_lnum = 1;
        !          4477: #ifdef SLEEP_IN_EMSG
        !          4478:    ++dont_sleep;           /* don't call sleep() in emsg() */
        !          4479: #endif
        !          4480:    len = 0;
        !          4481:    while (fgets((char *)IObuff + len, IOSIZE - len, fp) != NULL && !got_int)
        !          4482:    {
        !          4483:        len = STRLEN(IObuff) - 1;
        !          4484:        if (len >= 0 && IObuff[len] == '\n')    /* remove trailing newline */
        !          4485:        {
        !          4486: #ifdef USE_CRNL
        !          4487:            has_cr = (len > 0 && IObuff[len - 1] == '\r');
        !          4488:            if (textmode == -1)
        !          4489:            {
        !          4490:                if (has_cr)
        !          4491:                    textmode = 1;
        !          4492:                else
        !          4493:                    textmode = 0;
        !          4494:            }
        !          4495:
        !          4496:            if (textmode)
        !          4497:            {
        !          4498:                if (has_cr)         /* remove trailing CR-LF */
        !          4499:                    --len;
        !          4500:                else        /* lines like ":map xx yy^M" will have failed */
        !          4501:                {
        !          4502:                    if (!error)
        !          4503:                        EMSG("Warning: Wrong line separator, ^M may be missing");
        !          4504:                    error = TRUE;
        !          4505:                    textmode = 0;
        !          4506:                }
        !          4507:            }
        !          4508: #endif
        !          4509:                /* escaped newline, read more */
        !          4510:            if (len > 0 && len < IOSIZE && IObuff[len - 1] == Ctrl('V'))
        !          4511:            {
        !          4512:                IObuff[len - 1] = '\n';     /* remove CTRL-V */
        !          4513:                ++sourcing_lnum;
        !          4514:                continue;
        !          4515:            }
        !          4516:            IObuff[len] = NUL;
        !          4517:        }
        !          4518:            /* check for ^C here, so recursive :so will be broken */
        !          4519:        mch_breakcheck();
        !          4520:        do_cmdline(IObuff, TRUE, TRUE);
        !          4521:        len = 0;
        !          4522:        ++sourcing_lnum;
        !          4523:    }
        !          4524:    fclose(fp);
        !          4525:    if (got_int)
        !          4526:        emsg(e_interr);
        !          4527: #ifdef SLEEP_IN_EMSG
        !          4528:    --dont_sleep;
        !          4529: #endif
        !          4530:    sourcing_name = NULL;
        !          4531:    sourcing_lnum = 0;
        !          4532:    return OK;
        !          4533: }
        !          4534:
        !          4535: /*
        !          4536:  * get a single EX address
        !          4537:  *
        !          4538:  * Set ptr to the next character after the part that was interpreted.
        !          4539:  * Set ptr to NULL when an error is encountered.
        !          4540:  */
        !          4541:    static linenr_t
        !          4542: get_address(ptr)
        !          4543:    char_u      **ptr;
        !          4544: {
        !          4545:    linenr_t    cursor_lnum = curwin->w_cursor.lnum;
        !          4546:    int         c;
        !          4547:    int         i;
        !          4548:    long        n;
        !          4549:    char_u      *cmd;
        !          4550:    FPOS        pos;
        !          4551:    FPOS        *fp;
        !          4552:    linenr_t    lnum;
        !          4553:
        !          4554:    cmd = skipwhite(*ptr);
        !          4555:    lnum = MAXLNUM;
        !          4556:    do
        !          4557:    {
        !          4558:        switch (*cmd)
        !          4559:        {
        !          4560:            case '.':                       /* '.' - Cursor position */
        !          4561:                        ++cmd;
        !          4562:                        lnum = cursor_lnum;
        !          4563:                        break;
        !          4564:
        !          4565:            case '$':                       /* '$' - last line */
        !          4566:                        ++cmd;
        !          4567:                        lnum = curbuf->b_ml.ml_line_count;
        !          4568:                        break;
        !          4569:
        !          4570:            case '\'':                      /* ''' - mark */
        !          4571:                        if (*++cmd == NUL || (check_mark(
        !          4572:                                        fp = getmark(*cmd++, FALSE)) == FAIL))
        !          4573:                            goto error;
        !          4574:                        lnum = fp->lnum;
        !          4575:                        break;
        !          4576:
        !          4577:            case '/':
        !          4578:            case '?':                       /* '/' or '?' - search */
        !          4579:                        c = *cmd++;
        !          4580:                        pos = curwin->w_cursor;     /* save curwin->w_cursor */
        !          4581:                        if (c == '/')   /* forward search, start on next line */
        !          4582:                        {
        !          4583:                            ++curwin->w_cursor.lnum;
        !          4584:                            curwin->w_cursor.col = 0;
        !          4585:                        }
        !          4586:                        else           /* backward search, start on prev line */
        !          4587:                        {
        !          4588:                            --curwin->w_cursor.lnum;
        !          4589:                            curwin->w_cursor.col = MAXCOL;
        !          4590:                        }
        !          4591:                        searchcmdlen = 0;
        !          4592:                        if (!do_search(c, cmd, 1L,
        !          4593:                                      SEARCH_HIS + SEARCH_MSG + SEARCH_START))
        !          4594:                        {
        !          4595:                            cmd = NULL;
        !          4596:                            curwin->w_cursor = pos;
        !          4597:                            goto error;
        !          4598:                        }
        !          4599:                        lnum = curwin->w_cursor.lnum;
        !          4600:                        curwin->w_cursor = pos;
        !          4601:                                            /* adjust command string pointer */
        !          4602:                        cmd += searchcmdlen;
        !          4603:                        break;
        !          4604:
        !          4605:            case '\\':              /* "\?", "\/" or "\&", repeat search */
        !          4606:                        ++cmd;
        !          4607:                        if (*cmd == '&')
        !          4608:                            i = RE_SUBST;
        !          4609:                        else if (*cmd == '?' || *cmd == '/')
        !          4610:                            i = RE_SEARCH;
        !          4611:                        else
        !          4612:                        {
        !          4613:                            emsg(e_backslash);
        !          4614:                            cmd = NULL;
        !          4615:                            goto error;
        !          4616:                        }
        !          4617:
        !          4618:                                    /* forward search, start on next line */
        !          4619:                        if (*cmd != '?')
        !          4620:                        {
        !          4621:                            pos.lnum = curwin->w_cursor.lnum + 1;
        !          4622:                            pos.col = 0;
        !          4623:                        }
        !          4624:                                    /* backward search, start on prev line */
        !          4625:                        else
        !          4626:                        {
        !          4627:                            pos.lnum = curwin->w_cursor.lnum - 1;
        !          4628:                            pos.col = MAXCOL;
        !          4629:                        }
        !          4630:                        if (searchit(&pos, *cmd == '?' ? BACKWARD : FORWARD,
        !          4631:                                                             (char_u *)"", 1L,
        !          4632:                                          SEARCH_MSG + SEARCH_START, i) == OK)
        !          4633:                            lnum = pos.lnum;
        !          4634:                        else
        !          4635:                        {
        !          4636:                            cmd = NULL;
        !          4637:                            goto error;
        !          4638:                        }
        !          4639:                        ++cmd;
        !          4640:                        break;
        !          4641:
        !          4642:            default:
        !          4643:                        if (isdigit(*cmd))      /* absolute line number */
        !          4644:                            lnum = getdigits(&cmd);
        !          4645:        }
        !          4646:
        !          4647:        for (;;)
        !          4648:        {
        !          4649:            cmd = skipwhite(cmd);
        !          4650:            if (*cmd != '-' && *cmd != '+' && !isdigit(*cmd))
        !          4651:                break;
        !          4652:
        !          4653:            if (lnum == MAXLNUM)
        !          4654:                lnum = cursor_lnum;     /* "+1" is same as ".+1" */
        !          4655:            if (isdigit(*cmd))
        !          4656:                i = '+';                /* "number" is same as "+number" */
        !          4657:            else
        !          4658:                i = *cmd++;
        !          4659:            if (!isdigit(*cmd))         /* '+' is '+1', but '+0' is not '+1' */
        !          4660:                n = 1;
        !          4661:            else
        !          4662:                n = getdigits(&cmd);
        !          4663:            if (i == '-')
        !          4664:                lnum -= n;
        !          4665:            else
        !          4666:                lnum += n;
        !          4667:        }
        !          4668:        cursor_lnum = lnum;
        !          4669:    } while (*cmd == '/' || *cmd == '?');
        !          4670:
        !          4671: error:
        !          4672:    *ptr = cmd;
        !          4673:    return lnum;
        !          4674: }
        !          4675:
        !          4676:
        !          4677: /*
        !          4678:  * Must parse the command line so far to work out what context we are in.
        !          4679:  * Completion can then be done based on that context.
        !          4680:  * This routine sets two global variables:
        !          4681:  * char_u *expand_pattern  The start of the pattern to be expanded within
        !          4682:  *                             the command line (ends at the cursor).
        !          4683:  * int expand_context      The type of thing to expand.  Will be one of:
        !          4684:  *
        !          4685:  * EXPAND_UNSUCCESSFUL     Used sometimes when there is something illegal on
        !          4686:  *                         the command line, like an unknown command.  Caller
        !          4687:  *                         should beep.
        !          4688:  * EXPAND_NOTHING          Unrecognised context for completion, use char like
        !          4689:  *                         a normal char, rather than for completion.  eg
        !          4690:  *                         :s/^I/
        !          4691:  * EXPAND_COMMANDS         Cursor is still touching the command, so complete
        !          4692:  *                         it.
        !          4693:  * EXPAND_BUFFERS          Complete file names for :buf and :sbuf commands.
        !          4694:  * EXPAND_FILES            After command with XFILE set, or after setting
        !          4695:  *                         with P_EXPAND set.  eg :e ^I, :w>>^I
        !          4696:  * EXPAND_DIRECTORIES      In some cases this is used instead of the latter
        !          4697:  *                         when we know only directories are of interest.  eg
        !          4698:  *                         :set dir=^I
        !          4699:  * EXPAND_SETTINGS         Complete variable names.  eg :set d^I
        !          4700:  * EXPAND_BOOL_SETTINGS    Complete boolean variables only,  eg :set no^I
        !          4701:  * EXPAND_TAGS             Complete tags from the files in p_tags.  eg :ta a^I
        !          4702:  * EXPAND_HELP             Complete tags from the file 'helpfile'/vim_tags
        !          4703:  * EXPAND_EVENTS           Complete event names
        !          4704:  *
        !          4705:  * -- webb.
        !          4706:  */
        !          4707:    static void
        !          4708: set_expand_context(firstc, buff)
        !          4709:    int         firstc;     /* either ':', '/', or '?' */
        !          4710:    char_u      *buff;      /* buffer for command string */
        !          4711: {
        !          4712:    char_u      *nextcomm;
        !          4713:    char_u      old_char;
        !          4714:
        !          4715:    old_char = cmdbuff[cmdpos];
        !          4716:    cmdbuff[cmdpos] = NUL;
        !          4717:    nextcomm = buff;
        !          4718:    while (nextcomm != NULL)
        !          4719:        nextcomm = set_one_cmd_context(firstc, nextcomm);
        !          4720:    cmdbuff[cmdpos] = old_char;
        !          4721: }
        !          4722:
        !          4723: /*
        !          4724:  * This is all pretty much copied from do_one_cmd(), with all the extra stuff
        !          4725:  * we don't need/want deleted.  Maybe this could be done better if we didn't
        !          4726:  * repeat all this stuff.  The only problem is that they may not stay perfectly
        !          4727:  * compatible with each other, but then the command line syntax probably won't
        !          4728:  * change that much -- webb.
        !          4729:  */
        !          4730:    static char_u *
        !          4731: set_one_cmd_context(firstc, buff)
        !          4732:    int         firstc;     /* either ':', '/', or '?' */
        !          4733:    char_u      *buff;      /* buffer for command string */
        !          4734: {
        !          4735:    char_u              *p;
        !          4736:    char_u              *cmd, *arg;
        !          4737:    int                 i;
        !          4738:    int                 cmdidx;
        !          4739:    long                argt;
        !          4740:    char_u              delim;
        !          4741:    int                 forced = FALSE;
        !          4742:    int                 usefilter = FALSE;  /* filter instead of file name */
        !          4743:
        !          4744:    expand_pattern = buff;
        !          4745:    if (firstc != ':')
        !          4746:    {
        !          4747:        expand_context = EXPAND_NOTHING;
        !          4748:        return NULL;
        !          4749:    }
        !          4750:    expand_context = EXPAND_COMMANDS;   /* Default until we get past command */
        !          4751:
        !          4752: /*
        !          4753:  * 2. skip comment lines and leading space, colons or bars
        !          4754:  */
        !          4755:    for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
        !          4756:        ;
        !          4757:    expand_pattern = cmd;
        !          4758:
        !          4759:    if (*cmd == NUL)
        !          4760:        return NULL;
        !          4761:    if (*cmd == '"')        /* ignore comment lines */
        !          4762:    {
        !          4763:        expand_context = EXPAND_NOTHING;
        !          4764:        return NULL;
        !          4765:    }
        !          4766:
        !          4767: /*
        !          4768:  * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
        !          4769:  */
        !          4770:    /*
        !          4771:     * Backslashed delimiters after / or ? will be skipped, and commands will
        !          4772:     * not be expanded between /'s and ?'s or after "'". -- webb
        !          4773:     */
        !          4774:    while (*cmd != NUL && (vim_isspace(*cmd) || isdigit(*cmd) ||
        !          4775:                            vim_strchr((char_u *)".$%'/?-+,;", *cmd) != NULL))
        !          4776:    {
        !          4777:        if (*cmd == '\'')
        !          4778:        {
        !          4779:            if (*++cmd == NUL)
        !          4780:                expand_context = EXPAND_NOTHING;
        !          4781:        }
        !          4782:        else if (*cmd == '/' || *cmd == '?')
        !          4783:        {
        !          4784:            delim = *cmd++;
        !          4785:            while (*cmd != NUL && *cmd != delim)
        !          4786:                if (*cmd++ == '\\' && *cmd != NUL)
        !          4787:                    ++cmd;
        !          4788:            if (*cmd == NUL)
        !          4789:                expand_context = EXPAND_NOTHING;
        !          4790:        }
        !          4791:        if (*cmd != NUL)
        !          4792:            ++cmd;
        !          4793:    }
        !          4794:
        !          4795: /*
        !          4796:  * 4. parse command
        !          4797:  */
        !          4798:
        !          4799:    cmd = skipwhite(cmd);
        !          4800:    expand_pattern = cmd;
        !          4801:    if (*cmd == NUL)
        !          4802:        return NULL;
        !          4803:    if (*cmd == '"')
        !          4804:    {
        !          4805:        expand_context = EXPAND_NOTHING;
        !          4806:        return NULL;
        !          4807:    }
        !          4808:
        !          4809:    if (*cmd == '|' || *cmd == '\n')
        !          4810:        return cmd + 1;                 /* There's another command */
        !          4811:
        !          4812:    /*
        !          4813:     * Isolate the command and search for it in the command table.
        !          4814:     * Exeptions:
        !          4815:     * - the 'k' command can directly be followed by any character.
        !          4816:     * - the 's' command can be followed directly by 'c', 'g' or 'r'
        !          4817:     */
        !          4818:    if (*cmd == 'k')
        !          4819:    {
        !          4820:        cmdidx = CMD_k;
        !          4821:        p = cmd + 1;
        !          4822:    }
        !          4823:    else
        !          4824:    {
        !          4825:        p = cmd;
        !          4826:        while (isalpha(*p) || *p == '*')    /* Allow * wild card */
        !          4827:            ++p;
        !          4828:            /* check for non-alpha command */
        !          4829:        if (p == cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL)
        !          4830:            ++p;
        !          4831:        i = (int)(p - cmd);
        !          4832:
        !          4833:        if (i == 0)
        !          4834:        {
        !          4835:            expand_context = EXPAND_UNSUCCESSFUL;
        !          4836:            return NULL;
        !          4837:        }
        !          4838:        for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
        !          4839:            if (STRNCMP(cmdnames[cmdidx].cmd_name, cmd, (size_t)i) == 0)
        !          4840:                break;
        !          4841:    }
        !          4842:
        !          4843:    /*
        !          4844:     * If the cursor is touching the command, and it ends in an alphabetic
        !          4845:     * character, complete the command name.
        !          4846:     */
        !          4847:    if (p == cmdbuff + cmdpos && isalpha(p[-1]))
        !          4848:        return NULL;
        !          4849:
        !          4850:    if (cmdidx == CMD_SIZE)
        !          4851:    {
        !          4852:        if (*cmd == 's' && vim_strchr((char_u *)"cgr", cmd[1]) != NULL)
        !          4853:        {
        !          4854:            cmdidx = CMD_substitute;
        !          4855:            p = cmd + 1;
        !          4856:        }
        !          4857:        else
        !          4858:        {
        !          4859:            /* Not still touching the command and it was an illegal command */
        !          4860:            expand_context = EXPAND_UNSUCCESSFUL;
        !          4861:            return NULL;
        !          4862:        }
        !          4863:    }
        !          4864:
        !          4865:    expand_context = EXPAND_NOTHING; /* Default now that we're past command */
        !          4866:
        !          4867:    if (*p == '!')                  /* forced commands */
        !          4868:    {
        !          4869:        forced = TRUE;
        !          4870:        ++p;
        !          4871:    }
        !          4872:
        !          4873: /*
        !          4874:  * 5. parse arguments
        !          4875:  */
        !          4876:    argt = cmdnames[cmdidx].cmd_argt;
        !          4877:
        !          4878:    arg = skipwhite(p);
        !          4879:
        !          4880:    if (cmdidx == CMD_write)
        !          4881:    {
        !          4882:        if (*arg == '>')                        /* append */
        !          4883:        {
        !          4884:            if (*++arg == '>')              /* It should be */
        !          4885:                ++arg;
        !          4886:            arg = skipwhite(arg);
        !          4887:        }
        !          4888:        else if (*arg == '!')                   /* :w !filter */
        !          4889:        {
        !          4890:            ++arg;
        !          4891:            usefilter = TRUE;
        !          4892:        }
        !          4893:    }
        !          4894:
        !          4895:    if (cmdidx == CMD_read)
        !          4896:    {
        !          4897:        usefilter = forced;                 /* :r! filter if forced */
        !          4898:        if (*arg == '!')                        /* :r !filter */
        !          4899:        {
        !          4900:            ++arg;
        !          4901:            usefilter = TRUE;
        !          4902:        }
        !          4903:    }
        !          4904:
        !          4905:    if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
        !          4906:    {
        !          4907:        while (*arg == *cmd)        /* allow any number of '>' or '<' */
        !          4908:            ++arg;
        !          4909:        arg = skipwhite(arg);
        !          4910:    }
        !          4911:
        !          4912:    /* Does command allow "+command"? */
        !          4913:    if ((argt & EDITCMD) && !usefilter && *arg == '+')
        !          4914:    {
        !          4915:        /* Check if we're in the +command */
        !          4916:        p = arg + 1;
        !          4917:        arg = skiptowhite(arg);
        !          4918:
        !          4919:        /* Still touching the command after '+'? */
        !          4920:        if (arg >= cmdbuff + cmdpos)
        !          4921:            return p;
        !          4922:
        !          4923:        /* Skip space after +command to get to the real argument */
        !          4924:        arg = skipwhite(arg);
        !          4925:    }
        !          4926:
        !          4927:    /*
        !          4928:     * Check for '|' to separate commands and '"' to start comments.
        !          4929:     * Don't do this for ":read !cmd" and ":write !cmd".
        !          4930:     */
        !          4931:    if ((argt & TRLBAR) && !usefilter)
        !          4932:    {
        !          4933:        p = arg;
        !          4934:        while (*p)
        !          4935:        {
        !          4936:            if (*p == Ctrl('V'))
        !          4937:            {
        !          4938:                if (p[1] != NUL)
        !          4939:                    ++p;
        !          4940:            }
        !          4941:            else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|' || *p == '\n')
        !          4942:            {
        !          4943:                if (*(p - 1) != '\\')
        !          4944:                {
        !          4945:                    if (*p == '|' || *p == '\n')
        !          4946:                        return p + 1;
        !          4947:                    return NULL;    /* It's a comment */
        !          4948:                }
        !          4949:            }
        !          4950:            ++p;
        !          4951:        }
        !          4952:    }
        !          4953:
        !          4954:                                                /* no arguments allowed */
        !          4955:    if (!(argt & EXTRA) && *arg != NUL &&
        !          4956:                                    vim_strchr((char_u *)"|\"", *arg) == NULL)
        !          4957:        return NULL;
        !          4958:
        !          4959:    /* Find start of last argument (argument just before cursor): */
        !          4960:    p = cmdbuff + cmdpos;
        !          4961:    while (p != arg && *p != ' ' && *p != TAB)
        !          4962:        p--;
        !          4963:    if (*p == ' ' || *p == TAB)
        !          4964:        p++;
        !          4965:    expand_pattern = p;
        !          4966:
        !          4967:    if (argt & XFILE)
        !          4968:    {
        !          4969:        int in_quote = FALSE;
        !          4970:        char_u *bow = NULL;     /* Beginning of word */
        !          4971:
        !          4972:        /*
        !          4973:         * Allow spaces within back-quotes to count as part of the argument
        !          4974:         * being expanded.
        !          4975:         */
        !          4976:        expand_pattern = skipwhite(arg);
        !          4977:        for (p = expand_pattern; *p; ++p)
        !          4978:        {
        !          4979:            if (*p == '\\' && p[1])
        !          4980:                ++p;
        !          4981: #ifdef SPACE_IN_FILENAME
        !          4982:            else if (vim_iswhite(*p) && (!(argt & NOSPC) || usefilter))
        !          4983: #else
        !          4984:            else if (vim_iswhite(*p))
        !          4985: #endif
        !          4986:            {
        !          4987:                p = skipwhite(p);
        !          4988:                if (in_quote)
        !          4989:                    bow = p;
        !          4990:                else
        !          4991:                    expand_pattern = p;
        !          4992:                --p;
        !          4993:            }
        !          4994:            else if (*p == '`')
        !          4995:            {
        !          4996:                if (!in_quote)
        !          4997:                {
        !          4998:                    expand_pattern = p;
        !          4999:                    bow = p + 1;
        !          5000:                }
        !          5001:                in_quote = !in_quote;
        !          5002:            }
        !          5003:        }
        !          5004:
        !          5005:        /*
        !          5006:         * If we are still inside the quotes, and we passed a space, just
        !          5007:         * expand from there.
        !          5008:         */
        !          5009:        if (bow != NULL && in_quote)
        !          5010:            expand_pattern = bow;
        !          5011:        expand_context = EXPAND_FILES;
        !          5012:    }
        !          5013:
        !          5014: /*
        !          5015:  * 6. switch on command name
        !          5016:  */
        !          5017:    switch (cmdidx)
        !          5018:    {
        !          5019:        case CMD_cd:
        !          5020:        case CMD_chdir:
        !          5021:            expand_context = EXPAND_DIRECTORIES;
        !          5022:            break;
        !          5023:        case CMD_global:
        !          5024:        case CMD_vglobal:
        !          5025:            delim = *arg;           /* get the delimiter */
        !          5026:            if (delim)
        !          5027:                ++arg;              /* skip delimiter if there is one */
        !          5028:
        !          5029:            while (arg[0] != NUL && arg[0] != delim)
        !          5030:            {
        !          5031:                if (arg[0] == '\\' && arg[1] != NUL)
        !          5032:                    ++arg;
        !          5033:                ++arg;
        !          5034:            }
        !          5035:            if (arg[0] != NUL)
        !          5036:                return arg + 1;
        !          5037:            break;
        !          5038:        case CMD_and:
        !          5039:        case CMD_substitute:
        !          5040:            delim = *arg;
        !          5041:            if (delim)
        !          5042:                ++arg;
        !          5043:            for (i = 0; i < 2; i++)
        !          5044:            {
        !          5045:                while (arg[0] != NUL && arg[0] != delim)
        !          5046:                {
        !          5047:                    if (arg[0] == '\\' && arg[1] != NUL)
        !          5048:                        ++arg;
        !          5049:                    ++arg;
        !          5050:                }
        !          5051:                if (arg[0] != NUL)      /* skip delimiter */
        !          5052:                    ++arg;
        !          5053:            }
        !          5054:            while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
        !          5055:                ++arg;
        !          5056:            if (arg[0] != NUL)
        !          5057:                return arg;
        !          5058:            break;
        !          5059:        case CMD_isearch:
        !          5060:        case CMD_dsearch:
        !          5061:        case CMD_ilist:
        !          5062:        case CMD_dlist:
        !          5063:        case CMD_ijump:
        !          5064:        case CMD_djump:
        !          5065:        case CMD_isplit:
        !          5066:        case CMD_dsplit:
        !          5067:            arg = skipwhite(skipdigits(arg));       /* skip count */
        !          5068:            if (*arg == '/')    /* Match regexp, not just whole words */
        !          5069:            {
        !          5070:                for (++arg; *arg && *arg != '/'; arg++)
        !          5071:                    if (*arg == '\\' && arg[1] != NUL)
        !          5072:                        arg++;
        !          5073:                if (*arg)
        !          5074:                {
        !          5075:                    arg = skipwhite(arg + 1);
        !          5076:
        !          5077:                    /* Check for trailing illegal characters */
        !          5078:                    if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
        !          5079:                        expand_context = EXPAND_NOTHING;
        !          5080:                    else
        !          5081:                        return arg;
        !          5082:                }
        !          5083:            }
        !          5084:            break;
        !          5085: #ifdef AUTOCMD
        !          5086:        case CMD_autocmd:
        !          5087:            return set_context_in_autocmd(arg, FALSE);
        !          5088:
        !          5089:        case CMD_doautocmd:
        !          5090:            return set_context_in_autocmd(arg, TRUE);
        !          5091: #endif
        !          5092:        case CMD_set:
        !          5093:            set_context_in_set_cmd(arg);
        !          5094:            break;
        !          5095:        case CMD_stag:
        !          5096:        case CMD_tag:
        !          5097:            expand_context = EXPAND_TAGS;
        !          5098:            expand_pattern = arg;
        !          5099:            break;
        !          5100:        case CMD_help:
        !          5101:            expand_context = EXPAND_HELP;
        !          5102:            expand_pattern = arg;
        !          5103:            break;
        !          5104:        case CMD_bdelete:
        !          5105:        case CMD_bunload:
        !          5106:            while ((expand_pattern = vim_strchr(arg, ' ')) != NULL)
        !          5107:                arg = expand_pattern + 1;
        !          5108:        case CMD_buffer:
        !          5109:        case CMD_sbuffer:
        !          5110:            expand_context = EXPAND_BUFFERS;
        !          5111:            expand_pattern = arg;
        !          5112:            break;
        !          5113: #ifdef USE_GUI
        !          5114:        case CMD_menu:      case CMD_noremenu:      case CMD_unmenu:
        !          5115:        case CMD_nmenu:     case CMD_nnoremenu:     case CMD_nunmenu:
        !          5116:        case CMD_vmenu:     case CMD_vnoremenu:     case CMD_vunmenu:
        !          5117:        case CMD_imenu:     case CMD_inoremenu:     case CMD_iunmenu:
        !          5118:        case CMD_cmenu:     case CMD_cnoremenu:     case CMD_cunmenu:
        !          5119:            return gui_set_context_in_menu_cmd(cmd, arg, forced);
        !          5120:            break;
        !          5121: #endif
        !          5122:        default:
        !          5123:            break;
        !          5124:    }
        !          5125:    return NULL;
        !          5126: }
        !          5127:
        !          5128: /*
        !          5129:  * Do the expansion based on the global variables expand_context and
        !          5130:  * expand_pattern -- webb.
        !          5131:  */
        !          5132:    static int
        !          5133: ExpandFromContext(pat, num_file, file, files_only, options)
        !          5134:    char_u  *pat;
        !          5135:    int     *num_file;
        !          5136:    char_u  ***file;
        !          5137:    int     files_only;
        !          5138:    int     options;
        !          5139: {
        !          5140:    regexp  *prog;
        !          5141:    int     ret;
        !          5142:    int     i;
        !          5143:    int     count;
        !          5144:
        !          5145:    if (!expand_interactively || expand_context == EXPAND_FILES)
        !          5146:        return ExpandWildCards(1, &pat, num_file, file, files_only,
        !          5147:                                              (options & WILD_LIST_NOTFOUND));
        !          5148:    else if (expand_context == EXPAND_DIRECTORIES)
        !          5149:    {
        !          5150:        if (ExpandWildCards(1, &pat, num_file, file, files_only,
        !          5151:                                      (options & WILD_LIST_NOTFOUND)) == FAIL)
        !          5152:            return FAIL;
        !          5153:        count = 0;
        !          5154:        for (i = 0; i < *num_file; i++)
        !          5155:            if (mch_isdir((*file)[i]))
        !          5156:                (*file)[count++] = (*file)[i];
        !          5157:            else
        !          5158:                vim_free((*file)[i]);
        !          5159:        if (count == 0)
        !          5160:        {
        !          5161:            vim_free(*file);
        !          5162:            *file = (char_u **)"";
        !          5163:            *num_file = -1;
        !          5164:            return FAIL;
        !          5165:        }
        !          5166:        *num_file = count;
        !          5167:        return OK;
        !          5168:    }
        !          5169:    *file = (char_u **)"";
        !          5170:    *num_file = 0;
        !          5171:    if (expand_context == EXPAND_OLD_SETTING)
        !          5172:        return ExpandOldSetting(num_file, file);
        !          5173:
        !          5174:    if (expand_context == EXPAND_HELP)
        !          5175:        return find_help_tags(pat, num_file, file);
        !          5176:
        !          5177:    set_reg_ic(pat);        /* set reg_ic according to p_ic, p_scs and pat */
        !          5178: #ifdef AUTOCMD
        !          5179:    if (expand_context == EXPAND_EVENTS)
        !          5180:        reg_ic = TRUE;      /* always ignore case for events */
        !          5181: #endif
        !          5182:    reg_magic = p_magic;
        !          5183:
        !          5184:    if (expand_context == EXPAND_BUFFERS)
        !          5185:        return ExpandBufnames(pat, num_file, file, options);
        !          5186:
        !          5187:    prog = vim_regcomp(pat);
        !          5188:    if (prog == NULL)
        !          5189:        return FAIL;
        !          5190:
        !          5191:    if (expand_context == EXPAND_COMMANDS)
        !          5192:        ret = ExpandCommands(prog, num_file, file);
        !          5193:    else if (expand_context == EXPAND_SETTINGS ||
        !          5194:                                       expand_context == EXPAND_BOOL_SETTINGS)
        !          5195:        ret = ExpandSettings(prog, num_file, file);
        !          5196:    else if (expand_context == EXPAND_TAGS)
        !          5197:        ret = find_tags(NULL, prog, num_file, file, FALSE);
        !          5198: #ifdef AUTOCMD
        !          5199:    else if (expand_context == EXPAND_EVENTS)
        !          5200:        ret = ExpandEvents(prog, num_file, file);
        !          5201: #endif
        !          5202: #ifdef USE_GUI
        !          5203:    else if (expand_context == EXPAND_MENUS)
        !          5204:        ret = gui_ExpandMenuNames(prog, num_file, file);
        !          5205: #endif
        !          5206:    else
        !          5207:        ret = FAIL;
        !          5208:
        !          5209:    vim_free(prog);
        !          5210:    return ret;
        !          5211: }
        !          5212:
        !          5213:    static int
        !          5214: ExpandCommands(prog, num_file, file)
        !          5215:    regexp      *prog;
        !          5216:    int         *num_file;
        !          5217:    char_u      ***file;
        !          5218: {
        !          5219:    int     cmdidx;
        !          5220:    int     count;
        !          5221:    int     round;
        !          5222:
        !          5223:    /*
        !          5224:     * round == 1: Count the matches.
        !          5225:     * round == 2: Save the matches into the array.
        !          5226:     */
        !          5227:    for (round = 1; round <= 2; ++round)
        !          5228:    {
        !          5229:        count = 0;
        !          5230:        for (cmdidx = 0; cmdidx < CMD_SIZE; cmdidx++)
        !          5231:            if (vim_regexec(prog, cmdnames[cmdidx].cmd_name, TRUE))
        !          5232:            {
        !          5233:                if (round == 1)
        !          5234:                    count++;
        !          5235:                else
        !          5236:                    (*file)[count++] = strsave(cmdnames[cmdidx].cmd_name);
        !          5237:            }
        !          5238:        if (round == 1)
        !          5239:        {
        !          5240:            *num_file = count;
        !          5241:            if (count == 0 || (*file = (char_u **)
        !          5242:                         alloc((unsigned)(count * sizeof(char_u *)))) == NULL)
        !          5243:                return FAIL;
        !          5244:        }
        !          5245:    }
        !          5246:    return OK;
        !          5247: }
        !          5248:
        !          5249: #ifdef VIMINFO
        !          5250: static char_u **viminfo_history[2] = {NULL, NULL};
        !          5251: static int     viminfo_hisidx[2] = {0, 0};
        !          5252: static int     viminfo_hislen = 0;
        !          5253: static int     viminfo_add_at_front = FALSE;
        !          5254:
        !          5255:    void
        !          5256: prepare_viminfo_history(len)
        !          5257:    int len;
        !          5258: {
        !          5259:    int i;
        !          5260:    int num;
        !          5261:    int type;
        !          5262:
        !          5263:    init_history();
        !          5264:    viminfo_add_at_front = (len != 0);
        !          5265:    if (len > hislen)
        !          5266:        len = hislen;
        !          5267:
        !          5268:    for (type = 0; type <= 1; ++type)
        !          5269:    {
        !          5270:        /* If there are more spaces available than we request, then fill them
        !          5271:         * up */
        !          5272:        for (i = 0, num = 0; i < hislen; i++)
        !          5273:            if (history[type][i] == NULL)
        !          5274:                num++;
        !          5275:        if (num > len)
        !          5276:            len = num;
        !          5277:        viminfo_hisidx[type] = 0;
        !          5278:        if (len <= 0)
        !          5279:            viminfo_history[type] = NULL;
        !          5280:        else
        !          5281:            viminfo_history[type] = (char_u **)lalloc(len * sizeof(char_u *),
        !          5282:                                                                       FALSE);
        !          5283:    }
        !          5284:    viminfo_hislen = len;
        !          5285:    if (viminfo_history[0] == NULL || viminfo_history[1] == NULL)
        !          5286:        viminfo_hislen = 0;
        !          5287: }
        !          5288:
        !          5289:    int
        !          5290: read_viminfo_history(line, fp)
        !          5291:    char_u  *line;
        !          5292:    FILE    *fp;
        !          5293: {
        !          5294:    int     type;
        !          5295:
        !          5296:    type = (line[0] == ':' ? 0 : 1);
        !          5297:    if (viminfo_hisidx[type] != viminfo_hislen)
        !          5298:    {
        !          5299:        viminfo_readstring(line);
        !          5300:        if (!is_in_history(type, line + 1, viminfo_add_at_front))
        !          5301:            viminfo_history[type][viminfo_hisidx[type]++] = strsave(line + 1);
        !          5302:    }
        !          5303:    return vim_fgets(line, LSIZE, fp);
        !          5304: }
        !          5305:
        !          5306:    void
        !          5307: finish_viminfo_history()
        !          5308: {
        !          5309:    int idx;
        !          5310:    int i;
        !          5311:    int type;
        !          5312:
        !          5313:    for (type = 0; type <= 1; ++type)
        !          5314:    {
        !          5315:        if (history[type] == NULL)
        !          5316:            return;
        !          5317:        idx = hisidx[type] + viminfo_hisidx[type];
        !          5318:        if (idx >= hislen)
        !          5319:            idx -= hislen;
        !          5320:        if (viminfo_add_at_front)
        !          5321:            hisidx[type] = idx;
        !          5322:        else
        !          5323:        {
        !          5324:            if (hisidx[type] == -1)
        !          5325:                hisidx[type] = hislen - 1;
        !          5326:            do
        !          5327:            {
        !          5328:                if (history[type][idx] != NULL)
        !          5329:                    break;
        !          5330:                if (++idx == hislen)
        !          5331:                    idx = 0;
        !          5332:            } while (idx != hisidx[type]);
        !          5333:            if (idx != hisidx[type] && --idx < 0)
        !          5334:                idx = hislen - 1;
        !          5335:        }
        !          5336:        for (i = 0; i < viminfo_hisidx[type]; i++)
        !          5337:        {
        !          5338:            history[type][idx] = viminfo_history[type][i];
        !          5339:            if (--idx < 0)
        !          5340:                idx = hislen - 1;
        !          5341:        }
        !          5342:        vim_free(viminfo_history[type]);
        !          5343:        viminfo_history[type] = NULL;
        !          5344:    }
        !          5345: }
        !          5346:
        !          5347:    void
        !          5348: write_viminfo_history(fp)
        !          5349:    FILE    *fp;
        !          5350: {
        !          5351:    int     i;
        !          5352:    int     type;
        !          5353:    int     num_saved;
        !          5354:
        !          5355:    init_history();
        !          5356:    if (hislen == 0)
        !          5357:        return;
        !          5358:    for (type = 0; type <= 1; ++type)
        !          5359:    {
        !          5360:        num_saved = get_viminfo_parameter(type == 0 ? ':' : '/');
        !          5361:        if (num_saved == 0)
        !          5362:            continue;
        !          5363:        if (num_saved < 0)  /* Use default */
        !          5364:            num_saved = hislen;
        !          5365:        fprintf(fp, "\n# %s History (newest to oldest):\n",
        !          5366:                            type == 0 ? "Command Line" : "Search String");
        !          5367:        if (num_saved > hislen)
        !          5368:            num_saved = hislen;
        !          5369:        i = hisidx[type];
        !          5370:        if (i >= 0)
        !          5371:            while (num_saved--)
        !          5372:            {
        !          5373:                if (history[type][i] != NULL)
        !          5374:                {
        !          5375:                    putc(type == 0 ? ':' : '?', fp);
        !          5376:                    viminfo_writestring(fp, history[type][i]);
        !          5377:                }
        !          5378:                if (--i < 0)
        !          5379:                    i = hislen - 1;
        !          5380:            }
        !          5381:    }
        !          5382: }
        !          5383: #endif /* VIMINFO */