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

Annotation of src/usr.bin/vim/buffer.c, Revision 1.1.1.1

1.1       downsj      1: /* $OpenBSD$   */
                      2: /* vi:set ts=4 sw=4:
                      3:  *
                      4:  * VIM - Vi IMproved       by Bram Moolenaar
                      5:  *
                      6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
                      7:  * Do ":help credits" in Vim to see a list of people who contributed.
                      8:  */
                      9:
                     10: /*
                     11:  * buffer.c: functions for dealing with the buffer structure
                     12:  */
                     13:
                     14: /*
                     15:  * The buffer list is a double linked list of all buffers.
                     16:  * Each buffer can be in one of these states:
                     17:  * never loaded: b_neverloaded == TRUE, only the file name is valid
                     18:  *   not loaded: b_ml.ml_mfp == NULL, no memfile allocated
                     19:  *       hidden: b_nwindows == 0, loaded but not displayed in a window
                     20:  *       normal: loaded and displayed in a window
                     21:  *
                     22:  * Instead of storing file names all over the place, each file name is
                     23:  * stored in the buffer list. It can be referenced by a number.
                     24:  *
                     25:  * The current implementation remembers all file names ever used.
                     26:  */
                     27:
                     28: #include "vim.h"
                     29: #include "globals.h"
                     30: #include "proto.h"
                     31: #include "option.h"
                     32:
                     33: static void        enter_buffer __ARGS((BUF *));
                     34: static void        free_buf_options __ARGS((BUF *));
                     35: static char_u  *buflist_match __ARGS((regexp *prog, BUF *buf));
                     36: static void        buflist_setlnum __ARGS((BUF *, linenr_t));
                     37: static linenr_t buflist_findlnum __ARGS((BUF *));
                     38: static void        append_arg_number __ARGS((char_u *, int));
                     39:
                     40: /*
                     41:  * Open current buffer, that is: open the memfile and read the file into memory
                     42:  * return FAIL for failure, OK otherwise
                     43:  */
                     44:    int
                     45: open_buffer()
                     46: {
                     47:    int     retval = OK;
                     48:
                     49:    /*
                     50:     * The 'readonly' flag is only set when b_neverloaded is being reset.
                     51:     * When re-entering the same buffer, it should not change, because the
                     52:     * user may have reset the flag by hand.
                     53:     */
                     54:    if (readonlymode && curbuf->b_filename != NULL && curbuf->b_neverloaded)
                     55:        curbuf->b_p_ro = TRUE;
                     56:
                     57:    if (ml_open() == FAIL)
                     58:    {
                     59:        /*
                     60:         * There MUST be a memfile, otherwise we can't do anything
                     61:         * If we can't create one for the current buffer, take another buffer
                     62:         */
                     63:        close_buffer(NULL, curbuf, FALSE, FALSE);
                     64:        for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
                     65:            if (curbuf->b_ml.ml_mfp != NULL)
                     66:                break;
                     67:        /*
                     68:         * if there is no memfile at all, exit
                     69:         * This is OK, since there are no changes to loose.
                     70:         */
                     71:        if (curbuf == NULL)
                     72:        {
                     73:            EMSG("Cannot allocate buffer, exiting...");
                     74:            getout(2);
                     75:        }
                     76:        EMSG("Cannot allocate buffer, using other one...");
                     77:        enter_buffer(curbuf);
                     78:        return FAIL;
                     79:    }
                     80:    if (curbuf->b_filename != NULL)
                     81:        retval = readfile(curbuf->b_filename, curbuf->b_sfilename,
                     82:                              (linenr_t)0, TRUE, (linenr_t)0, MAXLNUM, FALSE);
                     83:    else
                     84:    {
                     85:        MSG("Empty Buffer");
                     86:        msg_col = 0;
                     87:        msg_didout = FALSE;     /* overwrite this message whenever you like */
                     88:    }
                     89:
                     90:    /* if first time loading this buffer, init chartab */
                     91:    if (curbuf->b_neverloaded)
                     92:        init_chartab();
                     93:
                     94:    /*
                     95:     * Reset the Changed flag first, autocmds may change the buffer.
                     96:     * Apply the automatic commands, before processing the modelines.
                     97:     * So the modelines have priority over auto commands.
                     98:     */
                     99:    if (retval != FAIL)
                    100:        UNCHANGED(curbuf);
                    101:
                    102: #ifdef AUTOCMD
                    103:    apply_autocmds(EVENT_BUFENTER, NULL, NULL);
                    104: #endif
                    105:
                    106:    if (retval != FAIL)
                    107:    {
                    108:        do_modelines();
                    109:        curbuf->b_neverloaded = FALSE;
                    110:    }
                    111:
                    112:    return retval;
                    113: }
                    114:
                    115: /*
                    116:  * Close the link to a buffer. If "free_buf" is TRUE free the buffer if it
                    117:  * becomes unreferenced. The caller should get a new buffer very soon!
                    118:  * if 'del_buf' is TRUE, remove the buffer from the buffer list.
                    119:  */
                    120:    void
                    121: close_buffer(win, buf, free_buf, del_buf)
                    122:    WIN     *win;           /* if not NULL, set b_last_cursor */
                    123:    BUF     *buf;
                    124:    int     free_buf;
                    125:    int     del_buf;
                    126: {
                    127:    if (buf->b_nwindows > 0)
                    128:        --buf->b_nwindows;
                    129:    if (buf->b_nwindows == 0 && win != NULL)
                    130:        set_last_cursor(win);   /* may set b_last_cursor */
                    131:    if (buf->b_nwindows > 0 || !free_buf)
                    132:    {
                    133:        if (buf == curbuf)
                    134:            u_sync();       /* sync undo before going to another buffer */
                    135:        return;
                    136:    }
                    137:
                    138:    buf_freeall(buf);       /* free all things allocated for this buffer */
                    139:    /*
                    140:     * If there is no file name, remove the buffer from the list
                    141:     */
                    142:    if (buf->b_filename == NULL || del_buf)
                    143:    {
                    144:        vim_free(buf->b_filename);
                    145:        vim_free(buf->b_sfilename);
                    146:        if (buf->b_prev == NULL)
                    147:            firstbuf = buf->b_next;
                    148:        else
                    149:            buf->b_prev->b_next = buf->b_next;
                    150:        if (buf->b_next == NULL)
                    151:            lastbuf = buf->b_prev;
                    152:        else
                    153:            buf->b_next->b_prev = buf->b_prev;
                    154:        free_buf_options(buf);
                    155:    }
                    156:    else
                    157:        buf_clear(buf);
                    158: }
                    159:
                    160: /*
                    161:  * buf_clear() - make buffer empty
                    162:  */
                    163:    void
                    164: buf_clear(buf)
                    165:    BUF     *buf;
                    166: {
                    167:    buf->b_ml.ml_line_count = 1;
                    168:    buf->b_changed = FALSE;
                    169: #ifndef SHORT_FNAME
                    170:    buf->b_shortname = FALSE;
                    171: #endif
                    172:    buf->b_p_eol = TRUE;
                    173:    buf->b_ml.ml_mfp = NULL;
                    174:    buf->b_ml.ml_flags = ML_EMPTY;              /* empty buffer */
                    175: }
                    176:
                    177: /*
                    178:  * buf_freeall() - free all things allocated for the buffer
                    179:  */
                    180:    void
                    181: buf_freeall(buf)
                    182:    BUF     *buf;
                    183: {
                    184:    u_blockfree(buf);               /* free the memory allocated for undo */
                    185:    ml_close(buf, TRUE);            /* close and delete the memline/memfile */
                    186:    buf->b_ml.ml_line_count = 0;    /* no lines in buffer */
                    187:    u_clearall(buf);                /* reset all undo information */
                    188: }
                    189:
                    190: /*
                    191:  * do_bufdel() - delete or unload buffer(s)
                    192:  *
                    193:  * addr_count == 0:    ":bdel" - delete current buffer
                    194:  * addr_count == 1: ":N bdel" or ":bdel N [N ..] - first delete
                    195:  *                 buffer "end_bnr", then any other arguments.
                    196:  * addr_count == 2: ":N,N bdel" - delete buffers in range
                    197:  *
                    198:  * command can be DOBUF_UNLOAD (":bunload") or DOBUF_DEL (":bdel")
                    199:  *
                    200:  * Returns error message or NULL
                    201:  */
                    202:    char_u *
                    203: do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit)
                    204:    int     command;
                    205:    char_u  *arg;       /* pointer to extra arguments */
                    206:    int     addr_count;
                    207:    int     start_bnr;  /* first buffer number in a range */
                    208:    int     end_bnr;    /* buffer number or last buffer number in a range */
                    209:    int     forceit;
                    210: {
                    211:    int     do_current = 0;     /* delete current buffer? */
                    212:    int     deleted = 0;        /* number of buffers deleted */
                    213:    char_u  *errormsg = NULL;   /* return value */
                    214:    int     bnr;                /* buffer number */
                    215:    char_u  *p;
                    216:
                    217:    if (addr_count == 0)
                    218:        (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
                    219:    else
                    220:    {
                    221:        if (addr_count == 2)
                    222:        {
                    223:            if (*arg)           /* both range and argument is not allowed */
                    224:                return e_trailing;
                    225:            bnr = start_bnr;
                    226:        }
                    227:        else    /* addr_count == 1 */
                    228:            bnr = end_bnr;
                    229:
                    230:        for ( ;!got_int; mch_breakcheck())
                    231:        {
                    232:            /*
                    233:             * delete the current buffer last, otherwise when the
                    234:             * current buffer is deleted, the next buffer becomes
                    235:             * the current one and will be loaded, which may then
                    236:             * also be deleted, etc.
                    237:             */
                    238:            if (bnr == curbuf->b_fnum)
                    239:                do_current = bnr;
                    240:            else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
                    241:                    forceit) == OK)
                    242:                ++deleted;
                    243:
                    244:            /*
                    245:             * find next buffer number to delete/unload
                    246:             */
                    247:            if (addr_count == 2)
                    248:            {
                    249:                if (++bnr > end_bnr)
                    250:                    break;
                    251:            }
                    252:            else    /* addr_count == 1 */
                    253:            {
                    254:                arg = skipwhite(arg);
                    255:                if (*arg == NUL)
                    256:                    break;
                    257:                if (!isdigit(*arg))
                    258:                {
                    259:                    p = skiptowhite_esc(arg);
                    260:                    bnr = buflist_findpat(arg, p);
                    261:                    if (bnr < 0)            /* failed */
                    262:                        break;
                    263:                    arg = p;
                    264:                }
                    265:                else
                    266:                    bnr = getdigits(&arg);
                    267:            }
                    268:        }
                    269:        if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
                    270:                FORWARD, do_current, forceit) == OK)
                    271:            ++deleted;
                    272:
                    273:        if (deleted == 0)
                    274:        {
                    275:            sprintf((char *)IObuff, "No buffers were %s",
                    276:                    command == DOBUF_UNLOAD ? "unloaded" : "deleted");
                    277:            errormsg = IObuff;
                    278:        }
                    279:        else
                    280:            smsg((char_u *)"%d buffer%s %s", deleted,
                    281:                    plural((long)deleted),
                    282:                    command == DOBUF_UNLOAD ? "unloaded" : "deleted");
                    283:    }
                    284:
                    285:    return errormsg;
                    286: }
                    287:
                    288: /*
                    289:  * Implementation of the command for the buffer list
                    290:  *
                    291:  * action == DOBUF_GOTO        go to specified buffer
                    292:  * action == DOBUF_SPLIT   split window and go to specified buffer
                    293:  * action == DOBUF_UNLOAD  unload specified buffer(s)
                    294:  * action == DOBUF_DEL     delete specified buffer(s)
                    295:  *
                    296:  * start == DOBUF_CURRENT  go to "count" buffer from current buffer
                    297:  * start == DOBUF_FIRST        go to "count" buffer from first buffer
                    298:  * start == DOBUF_LAST     go to "count" buffer from last buffer
                    299:  * start == DOBUF_MOD      go to "count" modified buffer from current buffer
                    300:  *
                    301:  * Return FAIL or OK.
                    302:  */
                    303:    int
                    304: do_buffer(action, start, dir, count, forceit)
                    305:    int     action;
                    306:    int     start;
                    307:    int     dir;        /* FORWARD or BACKWARD */
                    308:    int     count;      /* buffer number or number of buffers */
                    309:    int     forceit;    /* TRUE for :bdelete! */
                    310: {
                    311:    BUF     *buf;
                    312:    BUF     *delbuf;
                    313:    int     retval;
                    314:
                    315:    switch (start)
                    316:    {
                    317:        case DOBUF_FIRST:   buf = firstbuf; break;
                    318:        case DOBUF_LAST:    buf = lastbuf;  break;
                    319:        default:            buf = curbuf;   break;
                    320:    }
                    321:    if (start == DOBUF_MOD)         /* find next modified buffer */
                    322:    {
                    323:        while (count-- > 0)
                    324:        {
                    325:            do
                    326:            {
                    327:                buf = buf->b_next;
                    328:                if (buf == NULL)
                    329:                    buf = firstbuf;
                    330:            }
                    331:            while (buf != curbuf && !buf->b_changed);
                    332:        }
                    333:        if (!buf->b_changed)
                    334:        {
                    335:            EMSG("No modified buffer found");
                    336:            return FAIL;
                    337:        }
                    338:    }
                    339:    else if (start == DOBUF_FIRST && count) /* find specified buffer number */
                    340:    {
                    341:        while (buf != NULL && buf->b_fnum != count)
                    342:            buf = buf->b_next;
                    343:    }
                    344:    else
                    345:    {
                    346:        while (count-- > 0)
                    347:        {
                    348:            if (dir == FORWARD)
                    349:            {
                    350:                buf = buf->b_next;
                    351:                if (buf == NULL)
                    352:                    buf = firstbuf;
                    353:            }
                    354:            else
                    355:            {
                    356:                buf = buf->b_prev;
                    357:                if (buf == NULL)
                    358:                    buf = lastbuf;
                    359:            }
                    360:        }
                    361:    }
                    362:
                    363:    if (buf == NULL)        /* could not find it */
                    364:    {
                    365:        if (start == DOBUF_FIRST)
                    366:        {
                    367:                                            /* don't warn when deleting */
                    368:            if (action != DOBUF_UNLOAD && action != DOBUF_DEL)
                    369:                EMSGN("Cannot go to buffer %ld", count);
                    370:        }
                    371:        else if (dir == FORWARD)
                    372:            EMSG("Cannot go beyond last buffer");
                    373:        else
                    374:            EMSG("Cannot go before first buffer");
                    375:        return FAIL;
                    376:    }
                    377:
                    378:    /*
                    379:     * delete buffer buf from memory and/or the list
                    380:     */
                    381:    if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
                    382:    {
                    383:        if (!forceit && buf->b_changed)
                    384:        {
                    385:            EMSGN("No write since last change for buffer %ld (use ! to override)",
                    386:                        buf->b_fnum);
                    387:            return FAIL;
                    388:        }
                    389:
                    390:        /*
                    391:         * If deleting last buffer, make it empty.
                    392:         * The last buffer cannot be unloaded.
                    393:         */
                    394:        if (firstbuf->b_next == NULL)
                    395:        {
                    396:            if (action == DOBUF_UNLOAD)
                    397:            {
                    398:                EMSG("Cannot unload last buffer");
                    399:                return FAIL;
                    400:            }
                    401:            /* Close any other windows on this buffer */
                    402:            close_others(FALSE);
                    403:            buf = curbuf;
                    404:            setpcmark();
                    405:            retval = do_ecmd(0, NULL, NULL, NULL, FALSE, (linenr_t)1, FALSE);
                    406:            /*
                    407:             * The do_ecmd() may create a new buffer, then we have to delete
                    408:             * the old one.  But do_ecmd() may have done that already, check
                    409:             * if the buffer still exists (it will be the first or second in
                    410:             * the buffer list).
                    411:             */
                    412:            if (buf != curbuf && (buf == firstbuf || buf == firstbuf->b_next))
                    413:                close_buffer(NULL, buf, TRUE, TRUE);
                    414:            return retval;
                    415:        }
                    416:
                    417:        /*
                    418:         * If the deleted buffer is the current one, close the current window
                    419:         * (unless it's the only window).
                    420:         */
                    421:        while (buf == curbuf && firstwin != lastwin)
                    422:            close_window(curwin, FALSE);
                    423:
                    424:        /*
                    425:         * If the buffer to be deleted is not current one, delete it here.
                    426:         */
                    427:        if (buf != curbuf)
                    428:        {
                    429:            close_windows(buf);
                    430:            close_buffer(NULL, buf, TRUE, action == DOBUF_DEL);
                    431:            return OK;
                    432:        }
                    433:
                    434:        /*
                    435:         * Deleting the current buffer: Need to find another buffer to go to.
                    436:         * There must be another, otherwise it would have been handled above.
                    437:         */
                    438:        if (curbuf->b_next != NULL)
                    439:            buf = curbuf->b_next;
                    440:        else
                    441:            buf = curbuf->b_prev;
                    442:    }
                    443:
                    444:    /*
                    445:     * make buf current buffer
                    446:     */
                    447:    setpcmark();
                    448:    if (action == DOBUF_SPLIT)      /* split window first */
                    449:    {
                    450:        if (win_split(0, FALSE) == FAIL)
                    451:            return FAIL;
                    452:    }
                    453:    curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
                    454:    buflist_altlnum();                   /* remember curpos.lnum */
                    455:
                    456: #ifdef AUTOCMD
                    457:    apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
                    458: #endif
                    459:    delbuf = curbuf;        /* close_windows() may change curbuf */
                    460:    if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
                    461:        close_windows(curbuf);
                    462:    close_buffer(NULL, delbuf, action == DOBUF_UNLOAD || action == DOBUF_DEL,
                    463:                                                         action == DOBUF_DEL);
                    464:    enter_buffer(buf);
                    465:    return OK;
                    466: }
                    467:
                    468: /*
                    469:  * enter a new current buffer.
                    470:  * (old curbuf must have been freed already)
                    471:  */
                    472:    static void
                    473: enter_buffer(buf)
                    474:    BUF     *buf;
                    475: {
                    476:    buf_copy_options(curbuf, buf, TRUE);
                    477:    curwin->w_buffer = buf;
                    478:    curbuf = buf;
                    479:    ++curbuf->b_nwindows;
                    480:    if (curbuf->b_ml.ml_mfp == NULL)    /* need to load the file */
                    481:        open_buffer();
                    482:    else
                    483:    {
                    484:        need_fileinfo = TRUE;           /* display file info after redraw */
                    485:        buf_check_timestamp(curbuf);    /* check if file has changed */
                    486: #ifdef AUTOCMD
                    487:        apply_autocmds(EVENT_BUFENTER, NULL, NULL);
                    488: #endif
                    489:    }
                    490:    buflist_getlnum();                  /* restore curpos.lnum */
                    491:    check_arg_idx();                    /* check for valid arg_idx */
                    492:    maketitle();
                    493:    scroll_cursor_halfway(FALSE);       /* redisplay at correct position */
                    494:    updateScreen(NOT_VALID);
                    495: }
                    496:
                    497: /*
                    498:  * functions for dealing with the buffer list
                    499:  */
                    500:
                    501: /*
                    502:  * Add a file name to the buffer list. Return a pointer to the buffer.
                    503:  * If the same file name already exists return a pointer to that buffer.
                    504:  * If it does not exist, or if fname == NULL, a new entry is created.
                    505:  * If use_curbuf is TRUE, may use current buffer.
                    506:  * This is the ONLY way to create a new buffer.
                    507:  */
                    508:    BUF *
                    509: buflist_new(fname, sfname, lnum, use_curbuf)
                    510:    char_u      *fname;
                    511:    char_u      *sfname;
                    512:    linenr_t    lnum;
                    513:    int         use_curbuf;
                    514: {
                    515:    static int  top_file_num = 1;           /* highest file number */
                    516:    BUF         *buf;
                    517:
                    518:    fname_expand(&fname, &sfname);
                    519:
                    520: /*
                    521:  * If file name already exists in the list, update the entry
                    522:  */
                    523:    if (fname != NULL && (buf = buflist_findname(fname)) != NULL)
                    524:    {
                    525:        if (lnum != 0)
                    526:            buflist_setlnum(buf, lnum);
                    527:        /* copy the options now, if 'cpo' doesn't have 's' and not done
                    528:         * already */
                    529:        buf_copy_options(curbuf, buf, FALSE);
                    530:        return buf;
                    531:    }
                    532:
                    533: /*
                    534:  * If the current buffer has no name and no contents, use the current buffer.
                    535:  * Otherwise: Need to allocate a new buffer structure.
                    536:  *
                    537:  * This is the ONLY place where a new buffer structure is allocated!
                    538:  */
                    539:    if (use_curbuf && curbuf != NULL && curbuf->b_filename == NULL &&
                    540:                curbuf->b_nwindows <= 1 &&
                    541:                (curbuf->b_ml.ml_mfp == NULL || bufempty()))
                    542:        buf = curbuf;
                    543:    else
                    544:    {
                    545:        buf = (BUF *)alloc((unsigned)sizeof(BUF));
                    546:        if (buf == NULL)
                    547:            return NULL;
                    548:        (void)vim_memset(buf, 0, sizeof(BUF));
                    549:    }
                    550:
                    551:    if (fname != NULL)
                    552:    {
                    553:        buf->b_filename = strsave(fname);
                    554:        buf->b_sfilename = strsave(sfname);
                    555:    }
                    556:    if (buf->b_winlnum == NULL)
                    557:        buf->b_winlnum = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
                    558:    if ((fname != NULL && (buf->b_filename == NULL ||
                    559:                         buf->b_sfilename == NULL)) || buf->b_winlnum == NULL)
                    560:    {
                    561:        vim_free(buf->b_filename);
                    562:        buf->b_filename = NULL;
                    563:        vim_free(buf->b_sfilename);
                    564:        buf->b_sfilename = NULL;
                    565:        if (buf != curbuf)
                    566:        {
                    567:            vim_free(buf->b_winlnum);
                    568:            free_buf_options(buf);
                    569:        }
                    570:        return NULL;
                    571:    }
                    572:
                    573:    if (buf == curbuf)
                    574:    {
                    575:        buf_freeall(buf);       /* free all things allocated for this buffer */
                    576:        buf->b_nwindows = 0;
                    577:    }
                    578:    else
                    579:    {
                    580:        /*
                    581:         * Copy the options from the current buffer.
                    582:         */
                    583:        buf_copy_options(curbuf, buf, FALSE);
                    584:
                    585:        /*
                    586:         * put new buffer at the end of the buffer list
                    587:         */
                    588:        buf->b_next = NULL;
                    589:        if (firstbuf == NULL)           /* buffer list is empty */
                    590:        {
                    591:            buf->b_prev = NULL;
                    592:            firstbuf = buf;
                    593:        }
                    594:        else                            /* append new buffer at end of list */
                    595:        {
                    596:            lastbuf->b_next = buf;
                    597:            buf->b_prev = lastbuf;
                    598:        }
                    599:        lastbuf = buf;
                    600:
                    601:        buf->b_fnum = top_file_num++;
                    602:        if (top_file_num < 0)           /* wrap around (may cause duplicates) */
                    603:        {
                    604:            EMSG("Warning: List of file names overflow");
                    605:            mch_delay(3000L, TRUE);     /* make sure it is noticed */
                    606:            top_file_num = 1;
                    607:        }
                    608:
                    609:        buf->b_winlnum->wl_lnum = lnum;
                    610:        buf->b_winlnum->wl_next = NULL;
                    611:        buf->b_winlnum->wl_prev = NULL;
                    612:        buf->b_winlnum->wl_win = curwin;
                    613:    }
                    614:
                    615:    if (did_cd)
                    616:        buf->b_xfilename = buf->b_filename;
                    617:    else
                    618:        buf->b_xfilename = buf->b_sfilename;
                    619:    buf->b_u_synced = TRUE;
                    620:    buf->b_neverloaded = TRUE;
                    621:    buf_clear(buf);
                    622:    clrallmarks(buf);               /* clear marks */
                    623:    fmarks_check_names(buf);        /* check file marks for this file */
                    624:
                    625:    return buf;
                    626: }
                    627:
                    628: /*
                    629:  * Free the memory for a BUF structure and its options
                    630:  */
                    631:    static void
                    632: free_buf_options(buf)
                    633:    BUF     *buf;
                    634: {
                    635:    free_string_option(buf->b_p_fo);
                    636:    free_string_option(buf->b_p_isk);
                    637:    free_string_option(buf->b_p_com);
                    638: #ifdef CINDENT
                    639:    free_string_option(buf->b_p_cink);
                    640:    free_string_option(buf->b_p_cino);
                    641: #endif
                    642: #if defined(CINDENT) || defined(SMARTINDENT)
                    643:    free_string_option(buf->b_p_cinw);
                    644: #endif
                    645:    vim_free(buf);
                    646: }
                    647:
                    648: /*
                    649:  * get alternate file n
                    650:  * set linenr to lnum or altlnum if lnum == 0
                    651:  * if (options & GETF_SETMARK) call setpcmark()
                    652:  * if (options & GETF_ALT) we are jumping to an alternate file.
                    653:  *
                    654:  * return FAIL for failure, OK for success
                    655:  */
                    656:    int
                    657: buflist_getfile(n, lnum, options)
                    658:    int         n;
                    659:    linenr_t    lnum;
                    660:    int         options;
                    661: {
                    662:    BUF     *buf;
                    663:
                    664:    buf = buflist_findnr(n);
                    665:    if (buf == NULL)
                    666:    {
                    667:        if ((options & GETF_ALT) && n == 0)
                    668:            emsg(e_noalt);
                    669:        else
                    670:            EMSGN("buffer %ld not found", n);
                    671:        return FAIL;
                    672:    }
                    673:
                    674:    /* if alternate file is the current buffer, nothing to do */
                    675:    if (buf == curbuf)
                    676:        return OK;
                    677:
                    678:    /* altlnum may be changed by getfile(), get it now */
                    679:    if (lnum == 0)
                    680:        lnum = buflist_findlnum(buf);
                    681:    ++RedrawingDisabled;
                    682:    if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK), lnum) <= 0)
                    683:    {
                    684:        --RedrawingDisabled;
                    685:        return OK;
                    686:    }
                    687:    --RedrawingDisabled;
                    688:    return FAIL;
                    689: }
                    690:
                    691: /*
                    692:  * go to the last know line number for the current buffer
                    693:  */
                    694:    void
                    695: buflist_getlnum()
                    696: {
                    697:    linenr_t    lnum;
                    698:
                    699:    curwin->w_cursor.lnum = 1;
                    700:    curwin->w_cursor.col = 0;
                    701:    lnum = buflist_findlnum(curbuf);
                    702:    if (lnum != 0 && lnum <= curbuf->b_ml.ml_line_count)
                    703:        curwin->w_cursor.lnum = lnum;
                    704: }
                    705:
                    706: /*
                    707:  * find file in buffer list by name (it has to be for the current window)
                    708:  * 'fname' must have a full path.
                    709:  */
                    710:    BUF *
                    711: buflist_findname(fname)
                    712:    char_u      *fname;
                    713: {
                    714:    BUF         *buf;
                    715:
                    716:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    717:        if (buf->b_filename != NULL && fnamecmp(fname, buf->b_filename) == 0)
                    718:            return (buf);
                    719:    return NULL;
                    720: }
                    721:
                    722: /*
                    723:  * Find file in buffer list by a regexppattern.
                    724:  * Return fnum of the found buffer, < 0 for error.
                    725:  */
                    726:    int
                    727: buflist_findpat(pattern, pattern_end)
                    728:    char_u      *pattern;
                    729:    char_u      *pattern_end;       /* pointer to first char after pattern */
                    730: {
                    731:    BUF         *buf;
                    732:    regexp      *prog;
                    733:    int         fnum = -1;
                    734:    char_u      *pat;
                    735:    char_u      *match;
                    736:    int         attempt;
                    737:    char_u      *p;
                    738:
                    739:    if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
                    740:    {
                    741:        if (*pattern == '%')
                    742:            fnum = curbuf->b_fnum;
                    743:        else
                    744:            fnum = curwin->w_alt_fnum;
                    745:    }
                    746:
                    747:    /*
                    748:     * Try four ways of matching:
                    749:     * attempt == 0: without '^' or '$' (at any position)
                    750:     * attempt == 1: with '^' at start (only at postion 0)
                    751:     * attempt == 2: with '$' at end (only match at end)
                    752:     * attempt == 3: with '^' at start and '$' at end (only full match)
                    753:     */
                    754:    else for (attempt = 0; attempt <= 3; ++attempt)
                    755:    {
                    756:        /* may add '^' and '$' */
                    757:        pat = file_pat_to_reg_pat(pattern, pattern_end, NULL);
                    758:        if (pat == NULL)
                    759:            return -1;
                    760:        if (attempt < 2)
                    761:        {
                    762:            p = pat + STRLEN(pat) - 1;
                    763:            if (p > pat && *p == '$')               /* remove '$' */
                    764:                *p = NUL;
                    765:        }
                    766:        p = pat;
                    767:        if (*p == '^' && !(attempt & 1))            /* remove '^' */
                    768:            ++p;
                    769:        prog = vim_regcomp(p);
                    770:        vim_free(pat);
                    771:        if (prog == NULL)
                    772:            return -1;
                    773:
                    774:        for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    775:        {
                    776:            match = buflist_match(prog, buf);
                    777:            if (match != NULL)
                    778:            {
                    779:                if (fnum >= 0)          /* already found a match */
                    780:                {
                    781:                    fnum = -2;
                    782:                    break;
                    783:                }
                    784:                fnum = buf->b_fnum;     /* remember first match */
                    785:            }
                    786:        }
                    787:        vim_free(prog);
                    788:        if (fnum >= 0)                  /* found one match */
                    789:            break;
                    790:    }
                    791:
                    792:    if (fnum == -2)
                    793:        EMSG2("More than one match for %s", pattern);
                    794:    if (fnum < 1)
                    795:        EMSG2("No matching buffer for %s", pattern);
                    796:    return fnum;
                    797: }
                    798:
                    799: /*
                    800:  * Find all buffer names that match.
                    801:  * For command line expansion of ":buf" and ":sbuf".
                    802:  * Return OK if matches found, FAIL otherwise.
                    803:  */
                    804:    int
                    805: ExpandBufnames(pat, num_file, file, options)
                    806:    char_u      *pat;
                    807:    int         *num_file;
                    808:    char_u      ***file;
                    809:    int         options;
                    810: {
                    811:    int         count = 0;
                    812:    BUF         *buf;
                    813:    int         round;
                    814:    char_u      *p;
                    815:    int         attempt;
                    816:    regexp      *prog;
                    817:
                    818:    *num_file = 0;                  /* return values in case of FAIL */
                    819:    *file = NULL;
                    820:
                    821:    /*
                    822:     * attempt == 1: try match with    '^', match at start
                    823:     * attempt == 2: try match without '^', match anywhere
                    824:     */
                    825:    for (attempt = 1; attempt <= 2; ++attempt)
                    826:    {
                    827:        if (attempt == 2)
                    828:        {
                    829:            if (*pat != '^')        /* there's no '^', no need to try again */
                    830:                break;
                    831:            ++pat;                  /* skip the '^' */
                    832:        }
                    833:        prog = vim_regcomp(pat);
                    834:        if (prog == NULL)
                    835:            return FAIL;
                    836:
                    837:        /*
                    838:         * round == 1: Count the matches.
                    839:         * round == 2: Build the array to keep the matches.
                    840:         */
                    841:        for (round = 1; round <= 2; ++round)
                    842:        {
                    843:            count = 0;
                    844:            for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    845:            {
                    846:                p = buflist_match(prog, buf);
                    847:                if (p != NULL)
                    848:                {
                    849:                    if (round == 1)
                    850:                        ++count;
                    851:                    else
                    852:                    {
                    853:                        if (options & WILD_HOME_REPLACE)
                    854:                            p = home_replace_save(buf, p);
                    855:                        else
                    856:                            p = strsave(p);
                    857:                        (*file)[count++] = p;
                    858:                    }
                    859:                }
                    860:            }
                    861:            if (count == 0)     /* no match found, break here */
                    862:                break;
                    863:            if (round == 1)
                    864:            {
                    865:                *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
                    866:                if (*file == NULL)
                    867:                {
                    868:                    vim_free(prog);
                    869:                    return FAIL;
                    870:                }
                    871:            }
                    872:        }
                    873:        vim_free(prog);
                    874:        if (count)              /* match(es) found, break here */
                    875:            break;
                    876:    }
                    877:
                    878:    *num_file = count;
                    879:    return (count == 0 ? FAIL : OK);
                    880: }
                    881:
                    882: /*
                    883:  * Check for a match on the file name for buffer "buf" with regex prog "prog".
                    884:  */
                    885:    static char_u *
                    886: buflist_match(prog, buf)
                    887:    regexp      *prog;
                    888:    BUF         *buf;
                    889: {
                    890:    char_u  *match = NULL;
                    891:
                    892:    if (buf->b_sfilename != NULL &&
                    893:                               vim_regexec(prog, buf->b_sfilename, TRUE) != 0)
                    894:        match = buf->b_sfilename;
                    895:    else if (buf->b_filename != NULL)
                    896:    {
                    897:        if (vim_regexec(prog, buf->b_filename, TRUE) != 0)
                    898:            match = buf->b_filename;
                    899:        else
                    900:        {
                    901:            home_replace(NULL, buf->b_filename, NameBuff, MAXPATHL);
                    902:            if (vim_regexec(prog, NameBuff, TRUE) != 0)
                    903:                match = buf->b_filename;
                    904:        }
                    905:    }
                    906:    return match;
                    907: }
                    908:
                    909: /*
                    910:  * find file in buffer name list by number
                    911:  */
                    912:    BUF *
                    913: buflist_findnr(nr)
                    914:    int         nr;
                    915: {
                    916:    BUF         *buf;
                    917:
                    918:    if (nr == 0)
                    919:        nr = curwin->w_alt_fnum;
                    920:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    921:        if (buf->b_fnum == nr)
                    922:            return (buf);
                    923:    return NULL;
                    924: }
                    925:
                    926: /*
                    927:  * get name of file 'n' in the buffer list
                    928:  */
                    929:    char_u *
                    930: buflist_nr2name(n, fullname, helptail)
                    931:    int n;
                    932:    int fullname;
                    933:    int helptail;           /* for help buffers return tail only */
                    934: {
                    935:    BUF     *buf;
                    936:    char_u  *fname;
                    937:
                    938:    buf = buflist_findnr(n);
                    939:    if (buf == NULL)
                    940:        return NULL;
                    941:    if (fullname)
                    942:        fname = buf->b_filename;
                    943:    else
                    944:        fname = buf->b_xfilename;
                    945:    home_replace(helptail ? buf : NULL, fname, NameBuff, MAXPATHL);
                    946:    return NameBuff;
                    947: }
                    948:
                    949: /*
                    950:  * set the lnum for the buffer 'buf' and the current window
                    951:  */
                    952:    static void
                    953: buflist_setlnum(buf, lnum)
                    954:    BUF         *buf;
                    955:    linenr_t    lnum;
                    956: {
                    957:    WINLNUM     *wlp;
                    958:
                    959:    for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
                    960:        if (wlp->wl_win == curwin)
                    961:            break;
                    962:    if (wlp == NULL)            /* make new entry */
                    963:    {
                    964:        wlp = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
                    965:        if (wlp == NULL)
                    966:            return;
                    967:        wlp->wl_win = curwin;
                    968:    }
                    969:    else                        /* remove entry from list */
                    970:    {
                    971:        if (wlp->wl_prev)
                    972:            wlp->wl_prev->wl_next = wlp->wl_next;
                    973:        else
                    974:            buf->b_winlnum = wlp->wl_next;
                    975:        if (wlp->wl_next)
                    976:            wlp->wl_next->wl_prev = wlp->wl_prev;
                    977:    }
                    978:    wlp->wl_lnum = lnum;
                    979: /*
                    980:  * insert entry in front of the list
                    981:  */
                    982:    wlp->wl_next = buf->b_winlnum;
                    983:    buf->b_winlnum = wlp;
                    984:    wlp->wl_prev = NULL;
                    985:    if (wlp->wl_next)
                    986:        wlp->wl_next->wl_prev = wlp;
                    987:
                    988:    return;
                    989: }
                    990:
                    991: /*
                    992:  * find the lnum for the buffer 'buf' for the current window
                    993:  */
                    994:    static linenr_t
                    995: buflist_findlnum(buf)
                    996:    BUF     *buf;
                    997: {
                    998:    WINLNUM     *wlp;
                    999:
                   1000:    for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
                   1001:        if (wlp->wl_win == curwin)
                   1002:            break;
                   1003:
                   1004:    if (wlp == NULL)        /* if no lnum for curwin, use the first in the list */
                   1005:        wlp = buf->b_winlnum;
                   1006:
                   1007:    if (wlp)
                   1008:        return wlp->wl_lnum;
                   1009:    else
                   1010:        return (linenr_t)1;
                   1011: }
                   1012:
                   1013: /*
                   1014:  * list all know file names (for :files and :buffers command)
                   1015:  */
                   1016:    void
                   1017: buflist_list()
                   1018: {
                   1019:    BUF         *buf;
                   1020:    int         len;
                   1021:
                   1022:    for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
                   1023:    {
                   1024:        msg_outchar('\n');
                   1025:        if (buf->b_xfilename == NULL)
                   1026:            STRCPY(NameBuff, "No File");
                   1027:        else
                   1028:            /* careful: home_replace calls vim_getenv(), which uses IObuff! */
                   1029:            home_replace(buf, buf->b_xfilename, NameBuff, MAXPATHL);
                   1030:
                   1031:        sprintf((char *)IObuff, "%3d %c%c%c \"",
                   1032:                buf->b_fnum,
                   1033:                buf == curbuf ? '%' :
                   1034:                        (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
                   1035:                buf->b_ml.ml_mfp == NULL ? '-' :
                   1036:                        (buf->b_nwindows == 0 ? 'h' : ' '),
                   1037:                buf->b_changed ? '+' : ' ');
                   1038:
                   1039:        len = STRLEN(IObuff);
                   1040:        STRNCPY(IObuff + len, NameBuff, IOSIZE - 20 - len);
                   1041:
                   1042:        len = STRLEN(IObuff);
                   1043:        IObuff[len++] = '"';
                   1044:        /*
                   1045:         * try to put the "line" strings in column 40
                   1046:         */
                   1047:        do
                   1048:        {
                   1049:            IObuff[len++] = ' ';
                   1050:        } while (len < 40 && len < IOSIZE - 18);
                   1051:        sprintf((char *)IObuff + len, "line %ld",
                   1052:                buf == curbuf ? curwin->w_cursor.lnum :
                   1053:                                (long)buflist_findlnum(buf));
                   1054:        msg_outtrans(IObuff);
                   1055:        flushbuf();         /* output one line at a time */
                   1056:        mch_breakcheck();
                   1057:    }
                   1058: }
                   1059:
                   1060: /*
                   1061:  * get file name and line number for file 'fnum'
                   1062:  * used by DoOneCmd() for translating '%' and '#'
                   1063:  * return FAIL if not found, OK for success
                   1064:  */
                   1065:    int
                   1066: buflist_name_nr(fnum, fname, lnum)
                   1067:    int         fnum;
                   1068:    char_u      **fname;
                   1069:    linenr_t    *lnum;
                   1070: {
                   1071:    BUF         *buf;
                   1072:
                   1073:    buf = buflist_findnr(fnum);
                   1074:    if (buf == NULL || buf->b_filename == NULL)
                   1075:        return FAIL;
                   1076:
                   1077:    if (did_cd)
                   1078:        *fname = buf->b_filename;
                   1079:    else
                   1080:        *fname = buf->b_sfilename;
                   1081:    *lnum = buflist_findlnum(buf);
                   1082:
                   1083:    return OK;
                   1084: }
                   1085:
                   1086: /*
                   1087:  * Set the current file name to 's', short file name to 'ss'.
                   1088:  * The file name with the full path is also remembered, for when :cd is used.
                   1089:  * Returns FAIL for failure (file name already in use by other buffer)
                   1090:  *         OK otherwise.
                   1091:  */
                   1092:    int
                   1093: setfname(fname, sfname, message)
                   1094:    char_u *fname, *sfname;
                   1095:    int     message;
                   1096: {
                   1097:    BUF     *buf;
                   1098:
                   1099:    if (fname == NULL || *fname == NUL)
                   1100:    {
                   1101:        vim_free(curbuf->b_filename);
                   1102:        vim_free(curbuf->b_sfilename);
                   1103:        curbuf->b_filename = NULL;
                   1104:        curbuf->b_sfilename = NULL;
                   1105:    }
                   1106:    else
                   1107:    {
                   1108:        fname_expand(&fname, &sfname);
                   1109: #ifdef USE_FNAME_CASE
                   1110: # ifdef USE_LONG_FNAME
                   1111:        if (USE_LONG_FNAME)
                   1112: # endif
                   1113:            fname_case(sfname);     /* set correct case for short filename */
                   1114: #endif
                   1115:        /*
                   1116:         * if the file name is already used in another buffer:
                   1117:         * - if the buffer is loaded, fail
                   1118:         * - if the buffer is not loaded, delete it from the list
                   1119:         */
                   1120:        buf = buflist_findname(fname);
                   1121:        if (buf != NULL && buf != curbuf)
                   1122:        {
                   1123:            if (buf->b_ml.ml_mfp != NULL)       /* it's loaded, fail */
                   1124:            {
                   1125:                if (message)
                   1126:                    EMSG("Buffer with this name already exists");
                   1127:                return FAIL;
                   1128:            }
                   1129:            close_buffer(NULL, buf, TRUE, TRUE);    /* delete from the list */
                   1130:        }
                   1131:        fname = strsave(fname);
                   1132:        sfname = strsave(sfname);
                   1133:        if (fname == NULL || sfname == NULL)
                   1134:        {
                   1135:            vim_free(sfname);
                   1136:            vim_free(fname);
                   1137:            return FAIL;
                   1138:        }
                   1139:        vim_free(curbuf->b_filename);
                   1140:        vim_free(curbuf->b_sfilename);
                   1141:        curbuf->b_filename = fname;
                   1142:        curbuf->b_sfilename = sfname;
                   1143:    }
                   1144:    if (did_cd)
                   1145:        curbuf->b_xfilename = curbuf->b_filename;
                   1146:    else
                   1147:        curbuf->b_xfilename = curbuf->b_sfilename;
                   1148:
                   1149: #ifndef SHORT_FNAME
                   1150:    curbuf->b_shortname = FALSE;
                   1151: #endif
                   1152:    /*
                   1153:     * If the file name changed, also change the name of the swapfile
                   1154:     */
                   1155:    if (curbuf->b_ml.ml_mfp != NULL)
                   1156:        ml_setname();
                   1157:
                   1158:    check_arg_idx();            /* check file name for arg list */
                   1159:    maketitle();                /* set window title */
                   1160:    status_redraw_all();        /* status lines need to be redrawn */
                   1161:    fmarks_check_names(curbuf); /* check named file marks */
                   1162:    ml_timestamp(curbuf);       /* reset timestamp */
                   1163:    return OK;
                   1164: }
                   1165:
                   1166: /*
                   1167:  * set alternate file name for current window
                   1168:  *
                   1169:  * used by dowrite() and do_ecmd()
                   1170:  */
                   1171:    void
                   1172: setaltfname(fname, sfname, lnum)
                   1173:    char_u      *fname;
                   1174:    char_u      *sfname;
                   1175:    linenr_t    lnum;
                   1176: {
                   1177:    BUF     *buf;
                   1178:
                   1179:    buf = buflist_new(fname, sfname, lnum, FALSE);
                   1180:    if (buf != NULL)
                   1181:        curwin->w_alt_fnum = buf->b_fnum;
                   1182: }
                   1183:
                   1184: /*
                   1185:  * add a file name to the buflist and return its number
                   1186:  *
                   1187:  * used by qf_init(), main() and doarglist()
                   1188:  */
                   1189:    int
                   1190: buflist_add(fname)
                   1191:    char_u      *fname;
                   1192: {
                   1193:    BUF     *buf;
                   1194:
                   1195:    buf = buflist_new(fname, NULL, (linenr_t)0, FALSE);
                   1196:    if (buf != NULL)
                   1197:        return buf->b_fnum;
                   1198:    return 0;
                   1199: }
                   1200:
                   1201: /*
                   1202:  * set alternate lnum for current window
                   1203:  */
                   1204:    void
                   1205: buflist_altlnum()
                   1206: {
                   1207:    buflist_setlnum(curbuf, curwin->w_cursor.lnum);
                   1208: }
                   1209:
                   1210: /*
                   1211:  * return nonzero if 'fname' is not the same file as current file
                   1212:  * fname must have a full path (expanded by FullName)
                   1213:  */
                   1214:    int
                   1215: otherfile(fname)
                   1216:    char_u  *fname;
                   1217: {                                  /* no name is different */
                   1218:    if (fname == NULL || *fname == NUL || curbuf->b_filename == NULL)
                   1219:        return TRUE;
                   1220:    return fnamecmp(fname, curbuf->b_filename);
                   1221: }
                   1222:
                   1223:    void
                   1224: fileinfo(fullname, shorthelp, dont_truncate)
                   1225:    int fullname;
                   1226:    int shorthelp;
                   1227:    int dont_truncate;
                   1228: {
                   1229:    char_u      *name;
                   1230:    int         n;
                   1231:    char_u      *p;
                   1232:    char_u      *buffer;
                   1233:
                   1234:    buffer = alloc(IOSIZE);
                   1235:    if (buffer == NULL)
                   1236:        return;
                   1237:
                   1238:    if (fullname > 1)       /* 2 CTRL-G: include buffer number */
                   1239:    {
                   1240:        sprintf((char *)buffer, "buf %d: ", curbuf->b_fnum);
                   1241:        p = buffer + STRLEN(buffer);
                   1242:    }
                   1243:    else
                   1244:        p = buffer;
                   1245:
                   1246:    *p++ = '"';
                   1247:    if (curbuf->b_filename == NULL)
                   1248:        STRCPY(p, "No File");
                   1249:    else
                   1250:    {
                   1251:        if (!fullname && curbuf->b_sfilename != NULL)
                   1252:            name = curbuf->b_sfilename;
                   1253:        else
                   1254:            name = curbuf->b_filename;
                   1255:        home_replace(shorthelp ? curbuf : NULL, name, p,
                   1256:                                                (int)(IOSIZE - (p - buffer)));
                   1257:    }
                   1258:
                   1259:    sprintf((char *)buffer + STRLEN(buffer),
                   1260:            "\"%s%s%s%s",
                   1261:            curbuf->b_changed ? (shortmess(SHM_MOD) ?
                   1262:                                                " [+]" : " [Modified]") : " ",
                   1263:            curbuf->b_notedited ? "[Not edited]" : "",
                   1264:            curbuf->b_p_ro ? (shortmess(SHM_RO) ? "[RO]" : "[readonly]") : "",
                   1265:            (curbuf->b_changed || curbuf->b_notedited || curbuf->b_p_ro) ?
                   1266:                                                                    " " : "");
                   1267:    n = (int)(((long)curwin->w_cursor.lnum * 100L) /
                   1268:                                            (long)curbuf->b_ml.ml_line_count);
                   1269:    if (curbuf->b_ml.ml_flags & ML_EMPTY)
                   1270:    {
                   1271:        STRCPY(buffer + STRLEN(buffer), no_lines_msg);
                   1272:    }
                   1273:    else if (p_ru)
                   1274:    {
                   1275:        /* Current line and column are already on the screen -- webb */
                   1276:        sprintf((char *)buffer + STRLEN(buffer),
                   1277:            "%ld line%s --%d%%--",
                   1278:            (long)curbuf->b_ml.ml_line_count,
                   1279:            plural((long)curbuf->b_ml.ml_line_count),
                   1280:            n);
                   1281:    }
                   1282:    else
                   1283:    {
                   1284:        sprintf((char *)buffer + STRLEN(buffer),
                   1285:            "line %ld of %ld --%d%%-- col ",
                   1286:            (long)curwin->w_cursor.lnum,
                   1287:            (long)curbuf->b_ml.ml_line_count,
                   1288:            n);
                   1289:        col_print(buffer + STRLEN(buffer),
                   1290:                   (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
                   1291:    }
                   1292:
                   1293:    append_arg_number(buffer, !shortmess(SHM_FILE));
                   1294:
                   1295:    if (dont_truncate)
                   1296:        msg(buffer);
                   1297:    else
                   1298:        msg_trunc(buffer);
                   1299:
                   1300:    vim_free(buffer);
                   1301: }
                   1302:
                   1303: /*
                   1304:  * Give some info about the position of the cursor (for "g CTRL-G").
                   1305:  */
                   1306:    void
                   1307: cursor_pos_info()
                   1308: {
                   1309:    char_u      *p;
                   1310:    char_u      buf1[20];
                   1311:    char_u      buf2[20];
                   1312:    linenr_t    lnum;
                   1313:    long        char_count = 0;
                   1314:    long        char_count_cursor = 0;
                   1315:    int     eol_size;
                   1316:
                   1317:    /*
                   1318:     * Compute the length of the file in characters.
                   1319:     */
                   1320:    if (curbuf->b_ml.ml_flags & ML_EMPTY)
                   1321:    {
                   1322:        MSG(no_lines_msg);
                   1323:    }
                   1324:    else
                   1325:    {
                   1326:        if (curbuf->b_p_tx)
                   1327:            eol_size = 2;
                   1328:        else
                   1329:            eol_size = 1;
                   1330:        for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
                   1331:        {
                   1332:            if (lnum == curwin->w_cursor.lnum)
                   1333:                char_count_cursor = char_count + curwin->w_cursor.col + 1;
                   1334:            char_count += STRLEN(ml_get(lnum)) + eol_size;
                   1335:        }
                   1336:        if (!curbuf->b_p_eol && curbuf->b_p_bin)
                   1337:            char_count -= eol_size;
                   1338:
                   1339:        p = ml_get_curline();
                   1340:        col_print(buf1, (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
                   1341:        col_print(buf2, (int)STRLEN(p), linetabsize(p));
                   1342:
                   1343:        sprintf((char *)IObuff, "Col %s of %s; Line %ld of %ld; Char %ld of %ld",
                   1344:                (char *)buf1, (char *)buf2,
                   1345:                (long)curwin->w_cursor.lnum, (long)curbuf->b_ml.ml_line_count,
                   1346:                char_count_cursor, char_count);
                   1347:        msg(IObuff);
                   1348:    }
                   1349: }
                   1350:
                   1351:    void
                   1352: col_print(buf, col, vcol)
                   1353:    char_u  *buf;
                   1354:    int     col;
                   1355:    int     vcol;
                   1356: {
                   1357:    if (col == vcol)
                   1358:        sprintf((char *)buf, "%d", col);
                   1359:    else
                   1360:        sprintf((char *)buf, "%d-%d", col, vcol);
                   1361: }
                   1362:
                   1363: /*
                   1364:  * put filename in title bar of window and in icon title
                   1365:  */
                   1366:
                   1367: static char_u *lasttitle = NULL;
                   1368: static char_u *lasticon = NULL;
                   1369:
                   1370:    void
                   1371: maketitle()
                   1372: {
                   1373:    char_u      *t_name;
                   1374:    char_u      *i_name;
                   1375:
                   1376:    if (curbuf->b_filename == NULL)
                   1377:    {
                   1378:        t_name = (char_u *)"";
                   1379:        i_name = (char_u *)"No File";
                   1380:    }
                   1381:    else
                   1382:    {
                   1383:        home_replace(curbuf, curbuf->b_filename, IObuff, IOSIZE);
                   1384:        append_arg_number(IObuff, FALSE);
                   1385:        t_name = IObuff;
                   1386:        i_name = gettail(curbuf->b_filename);   /* use filename only for icon */
                   1387:    }
                   1388:
                   1389:    vim_free(lasttitle);
                   1390:    if (p_title && (lasttitle = alloc((unsigned)(strsize(t_name) + 7))) != NULL)
                   1391:    {
                   1392:        STRCPY(lasttitle, "VIM - ");
                   1393:        while (*t_name)
                   1394:            STRCAT(lasttitle, transchar(*t_name++));
                   1395:    }
                   1396:    else
                   1397:        lasttitle = NULL;
                   1398:
                   1399:    vim_free(lasticon);
                   1400:    if (p_icon && (lasticon = alloc((unsigned)(strsize(i_name) + 1))) != NULL)
                   1401:    {
                   1402:        *lasticon = NUL;
                   1403:        while (*i_name)
                   1404:            STRCAT(lasticon, transchar(*i_name++));
                   1405:    }
                   1406:    else
                   1407:        lasticon = NULL;
                   1408:
                   1409:    resettitle();
                   1410: }
                   1411:
                   1412: /*
                   1413:  * Append (file 2 of 8) to 'buf'.
                   1414:  */
                   1415:    static void
                   1416: append_arg_number(buf, add_file)
                   1417:    char_u  *buf;
                   1418:    int     add_file;       /* Add "file" before the arg number */
                   1419: {
                   1420:    if (arg_count <= 1)     /* nothing to do */
                   1421:        return;
                   1422:
                   1423:    buf += STRLEN(buf);     /* go to the end of the buffer */
                   1424:    *buf++ = ' ';
                   1425:    *buf++ = '(';
                   1426:    if (add_file)
                   1427:    {
                   1428:        STRCPY(buf, "file ");
                   1429:        buf += 5;
                   1430:    }
                   1431:    sprintf((char *)buf, curwin->w_arg_idx_invalid ? "(%d) of %d)" :
                   1432:                                 "%d of %d)", curwin->w_arg_idx + 1, arg_count);
                   1433: }
                   1434:
                   1435: /*
                   1436:  * Put current window title back (used after calling a shell)
                   1437:  */
                   1438:    void
                   1439: resettitle()
                   1440: {
                   1441:    mch_settitle(lasttitle, lasticon);
                   1442: }
                   1443:
                   1444: /*
                   1445:  * If fname is not a full path, make it a full path
                   1446:  */
                   1447:    char_u  *
                   1448: fix_fname(fname)
                   1449:    char_u  *fname;
                   1450: {
                   1451:    if (fname != NameBuff)          /* if not already expanded */
                   1452:    {
                   1453:        if (!isFullName(fname))
                   1454:        {
                   1455:            (void)FullName(fname, NameBuff, MAXPATHL, FALSE);
                   1456:            fname = NameBuff;
                   1457:        }
                   1458: #ifdef USE_FNAME_CASE
                   1459:        else
                   1460: # ifdef USE_LONG_FNAME
                   1461:            if (USE_LONG_FNAME)
                   1462: # endif
                   1463:        {
                   1464:            STRNCPY(NameBuff, fname, MAXPATHL); /* make copy, it may change */
                   1465:            fname = NameBuff;
                   1466:            fname_case(fname);          /* set correct case for filename */
                   1467:        }
                   1468: #endif
                   1469:    }
                   1470:    return fname;
                   1471: }
                   1472:
                   1473: /*
                   1474:  * make fname a full file name, set sfname to fname if not NULL
                   1475:  */
                   1476:    void
                   1477: fname_expand(fname, sfname)
                   1478:    char_u      **fname;
                   1479:    char_u      **sfname;
                   1480: {
                   1481:    if (*fname == NULL)         /* if no file name given, nothing to do */
                   1482:        return;
                   1483:    if (*sfname == NULL)        /* if no short file name given, use fname */
                   1484:        *sfname = *fname;
                   1485:    *fname = fix_fname(*fname); /* expand to full path */
                   1486: }
                   1487:
                   1488: /*
                   1489:  * do_arg_all: open up to 'count' windows, one for each argument
                   1490:  */
                   1491:    void
                   1492: do_arg_all(count)
                   1493:    int count;
                   1494: {
                   1495:    int     i;
                   1496:
                   1497:    if (arg_count <= 1)
                   1498:    {
                   1499:        /* Don't give this obvious error message. We don't want it when the
                   1500:         * ":all" command is in the .vimrc. */
                   1501:        /* EMSG("Argument list contains less than 2 files"); */
                   1502:        return;
                   1503:    }
                   1504:    /*
                   1505:     * 1. close all but first window
                   1506:     * 2. make the desired number of windows
                   1507:     * 3. start editing in the windows
                   1508:     */
                   1509:    setpcmark();
                   1510:    close_others(FALSE);
                   1511:    curwin->w_arg_idx = 0;
                   1512:    if (count > arg_count || count <= 0)
                   1513:        count = arg_count;
                   1514:    count = make_windows(count);
                   1515:    for (i = 0; i < count; ++i)
                   1516:    {
                   1517:                                                /* edit file i */
                   1518:        (void)do_ecmd(0, arg_files[i], NULL, NULL, TRUE, (linenr_t)1, FALSE);
                   1519:        curwin->w_arg_idx = i;
                   1520:        if (i == arg_count - 1)
                   1521:            arg_had_last = TRUE;
                   1522:        if (curwin->w_next == NULL)             /* just checking */
                   1523:            break;
                   1524:        win_enter(curwin->w_next, FALSE);
                   1525:    }
                   1526:    win_enter(firstwin, FALSE);                 /* back to first window */
                   1527: }
                   1528:
                   1529: /*
                   1530:  * do_arg_all: open a window for each buffer
                   1531:  *
                   1532:  * 'count' is the maximum number of windows to open.
                   1533:  * when 'all' is TRUE, also load inactive buffers
                   1534:  */
                   1535:    void
                   1536: do_buffer_all(count, all)
                   1537:    int     count;
                   1538:    int     all;
                   1539: {
                   1540:    int     buf_count;
                   1541:    BUF     *buf;
                   1542:    int     i;
                   1543:
                   1544: /*
                   1545:  * count number of desired windows
                   1546:  */
                   1547:    buf_count = 0;
                   1548:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                   1549:        if (all || buf->b_ml.ml_mfp != NULL)
                   1550:            ++buf_count;
                   1551:
                   1552:    if (buf_count == 0)             /* Cannot happen? */
                   1553:    {
                   1554:        EMSG("No relevant entries in buffer list");
                   1555:        return;
                   1556:    }
                   1557:
                   1558:    /*
                   1559:     * 1. close all but first window
                   1560:     * 2. make the desired number of windows
                   1561:     * 3. stuff commands to fill the windows
                   1562:     */
                   1563:    close_others(FALSE);
                   1564:    curwin->w_arg_idx = 0;
                   1565:    if (buf_count > count)
                   1566:        buf_count = count;
                   1567:    buf_count = make_windows(buf_count);
                   1568:    buf = firstbuf;
                   1569:    for (i = 0; i < buf_count; ++i)
                   1570:    {
                   1571:        for ( ; buf != NULL; buf = buf->b_next)
                   1572:            if (all || buf->b_ml.ml_mfp != NULL)
                   1573:                break;
                   1574:        if (buf == NULL)            /* Cannot happen? */
                   1575:            break;
                   1576:        if (i != 0)
                   1577:            stuffReadbuff((char_u *)"\n\027\027:"); /* CTRL-W CTRL-W */
                   1578:        stuffReadbuff((char_u *)":buf ");           /* edit Nth buffer */
                   1579:        stuffnumReadbuff((long)buf->b_fnum);
                   1580:        buf = buf->b_next;
                   1581:    }
                   1582:    stuffReadbuff((char_u *)"\n100\027k");      /* back to first window */
                   1583: }
                   1584:
                   1585: /*
                   1586:  * do_modelines() - process mode lines for the current file
                   1587:  *
                   1588:  * Returns immediately if the "ml" option isn't set.
                   1589:  */
                   1590: static int     chk_modeline __ARGS((linenr_t));
                   1591:
                   1592:    void
                   1593: do_modelines()
                   1594: {
                   1595:    linenr_t        lnum;
                   1596:    int             nmlines;
                   1597:
                   1598:    if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
                   1599:        return;
                   1600:
                   1601:    for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
                   1602:                                                                       ++lnum)
                   1603:        if (chk_modeline(lnum) == FAIL)
                   1604:            nmlines = 0;
                   1605:
                   1606:    for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines &&
                   1607:                          lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
                   1608:        if (chk_modeline(lnum) == FAIL)
                   1609:            nmlines = 0;
                   1610: }
                   1611:
                   1612: /*
                   1613:  * chk_modeline() - check a single line for a mode string
                   1614:  * Return FAIL if an error encountered.
                   1615:  */
                   1616:    static int
                   1617: chk_modeline(lnum)
                   1618:    linenr_t lnum;
                   1619: {
                   1620:    register char_u *s;
                   1621:    register char_u *e;
                   1622:    char_u          *linecopy;          /* local copy of any modeline found */
                   1623:    int             prev;
                   1624:    int             end;
                   1625:    int             retval = OK;
                   1626:    char_u          *save_sourcing_name;
                   1627:
                   1628:    prev = -1;
                   1629:    for (s = ml_get(lnum); *s != NUL; ++s)
                   1630:    {
                   1631:        if (prev == -1 || vim_isspace(prev))
                   1632:        {
                   1633:            if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) ||
                   1634:                               STRNCMP(s, "vi:", (size_t)3) == 0 ||
                   1635:                               STRNCMP(s, "vim:", (size_t)4) == 0)
                   1636:                break;
                   1637:        }
                   1638:        prev = *s;
                   1639:    }
                   1640:
                   1641:    if (*s)
                   1642:    {
                   1643:        do                              /* skip over "ex:", "vi:" or "vim:" */
                   1644:            ++s;
                   1645:        while (s[-1] != ':');
                   1646:
                   1647:        s = linecopy = strsave(s);      /* copy the line, it will change */
                   1648:        if (linecopy == NULL)
                   1649:            return FAIL;
                   1650:
                   1651:        sourcing_lnum = lnum;           /* prepare for emsg() */
                   1652:        save_sourcing_name = sourcing_name;
                   1653:        sourcing_name = (char_u *)"modelines";
                   1654:
                   1655:        end = FALSE;
                   1656:        while (end == FALSE)
                   1657:        {
                   1658:            s = skipwhite(s);
                   1659:            if (*s == NUL)
                   1660:                break;
                   1661:
                   1662:            /*
                   1663:             * Find end of set command: ':' or end of line.
                   1664:             */
                   1665:            for (e = s; (*e != ':' || *(e - 1) == '\\') && *e != NUL; ++e)
                   1666:                ;
                   1667:            if (*e == NUL)
                   1668:                end = TRUE;
                   1669:
                   1670:            /*
                   1671:             * If there is a "set" command, require a terminating ':' and
                   1672:             * ignore the stuff after the ':'.
                   1673:             * "vi:set opt opt opt: foo" -- foo not interpreted
                   1674:             * "vi:opt opt opt: foo" -- foo interpreted
                   1675:             */
                   1676:            if (STRNCMP(s, "set ", (size_t)4) == 0)
                   1677:            {
                   1678:                if (*e != ':')          /* no terminating ':'? */
                   1679:                    break;
                   1680:                end = TRUE;
                   1681:                s += 4;
                   1682:            }
                   1683:
                   1684:            *e = NUL;                   /* truncate the set command */
                   1685:            if (do_set(s) == FAIL)      /* stop if error found */
                   1686:            {
                   1687:                retval = FAIL;
                   1688:                break;
                   1689:            }
                   1690:            s = e + 1;                  /* advance to next part */
                   1691:        }
                   1692:
                   1693:        sourcing_lnum = 0;
                   1694:        sourcing_name = save_sourcing_name;
                   1695:
                   1696:        vim_free(linecopy);
                   1697:    }
                   1698:    return retval;
                   1699: }