[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.3

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