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

Annotation of src/usr.bin/vim/memline.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: /* for debugging */
                     11: /* #define CHECK(c, s) if (c) EMSG(s) */
                     12: #define CHECK(c, s)
                     13:
                     14: /*
                     15:  * memline.c: Contains the functions for appending, deleting and changing the
                     16:  * text lines. The memfile functions are used to store the information in blocks
                     17:  * of memory, backed up by a file. The structure of the information is a tree.
                     18:  * The root of the tree is a pointer block. The leaves of the tree are data
                     19:  * blocks. In between may be several layers of pointer blocks, forming branches.
                     20:  *
                     21:  * Three types of blocks are used:
                     22:  * - Block nr 0 contains information for recovery
                     23:  * - Pointer blocks contain list of pointers to other blocks.
                     24:  * - Data blocks contain the actual text.
                     25:  *
                     26:  * Block nr 0 contains the block0 structure (see below).
                     27:  *
                     28:  * Block nr 1 is the first pointer block. It is the root of the tree.
                     29:  * Other pointer blocks are branches.
                     30:  *
                     31:  *    If a line is too big to fit in a single page, the block
                     32:  *    containing that line is made big enough to hold the line. It may span
                     33:  *   several pages. Otherwise all blocks are one page.
                     34:  *
                     35:  *    A data block that was filled when starting to edit a file and was not
                     36:  *   changed since then, can have a negative block number. This means that it
                     37:  *   has not yet been assigned a place in the file. When recovering, the lines
                     38:  *       in this data block can be read from the original file. When the block is
                     39:  *    changed (lines appended/deleted/changed) or when it is flushed it gets
                     40:  *    a positive number. Use mf_trans_del() to get the new number, before
                     41:  *    calling mf_get().
                     42:  */
                     43:
                     44: /*
                     45:  * The following functions are available to work with a memline:
                     46:  *
                     47:  * ml_open()           open a new memline for a buffer
                     48:  * ml_setname()            change the file name for a memline
                     49:  * ml_close()          close the memline for a buffer
                     50:  * ml_close_all()      close all memlines
                     51:  * ml_recover()            read a memline for recovery
                     52:  * ml_sync_all()       flush changed blocks to file for all files
                     53:  * ml_preserve()       flush everything into the file for one file
                     54:  * ml_get()                get a pointer to a line
                     55:  * ml_get_pos()            get a pointer to a position in a line
                     56:  * ml_get_cursor()     get a pointer to the char under the cursor
                     57:  * ml_get_buf()            get a pointer to a line in a specific buffer
                     58:  * ml_line_alloced()   return TRUE if line was allocated
                     59:  * ml_append()         append a new line
                     60:  * ml_replace()            replace a line
                     61:  * ml_delete()         delete a line
                     62:  * ml_setmarked()      set mark for a line (for :global command)
                     63:  * ml_firstmarked()        get first line with a mark (for :global command)
                     64:  * ml_clearmarked()        clear all line marks (for :global command)
                     65:  */
                     66:
                     67: #if defined MSDOS  ||  defined WIN32
                     68: # include <io.h>
                     69: #endif
                     70:
                     71: #include "vim.h"
                     72: #include "globals.h"
                     73: #include "proto.h"
                     74: #include "option.h"
                     75: #ifdef HAVE_FCNTL_H
                     76: # include <fcntl.h>
                     77: #endif
                     78: #ifndef UNIX           /* it's in unix.h for Unix */
                     79: # include <time.h>
                     80: #endif
                     81:
                     82: #ifdef SASC
                     83: # include <proto/dos.h>        /* for Open() and Close() */
                     84: #endif
                     85:
                     86: typedef struct block0          ZERO_BL;    /* contents of the first block */
                     87: typedef struct pointer_block   PTR_BL;     /* contents of a pointer block */
                     88: typedef struct data_block      DATA_BL;    /* contents of a data block */
                     89: typedef struct pointer_entry   PTR_EN;     /* block/line-count pair */
                     90:
                     91: #define DATA_ID        (('d' << 8) + 'a')      /* data block id */
                     92: #define PTR_ID     (('p' << 8) + 't')      /* pointer block id */
                     93: #define BLOCK0_ID0 'b'                     /* block 0 id 0 */
                     94: #define BLOCK0_ID1 '0'                     /* block 0 id 1 */
                     95:
                     96: /*
                     97:  * pointer to a block, used in a pointer block
                     98:  */
                     99: struct pointer_entry
                    100: {
                    101:    blocknr_t   pe_bnum;        /* block number */
                    102:    linenr_t    pe_line_count;  /* number of lines in this branch */
                    103:    linenr_t    pe_old_lnum;    /* lnum for this block (for recovery) */
                    104:    int         pe_page_count;  /* number of pages in block pe_bnum */
                    105: };
                    106:
                    107: /*
                    108:  * A pointer block contains a list of branches in the tree.
                    109:  */
                    110: struct pointer_block
                    111: {
                    112:    short_u     pb_id;          /* ID for pointer block: PTR_ID */
                    113:    short_u     pb_count;       /* number of pointer in this block */
                    114:    short_u     pb_count_max;   /* maximum value for pb_count */
                    115:    PTR_EN      pb_pointer[1];  /* list of pointers to blocks (actually longer)
                    116:                                 * followed by empty space until end of page */
                    117: };
                    118:
                    119: /*
                    120:  * A data block is a leaf in the tree.
                    121:  *
                    122:  * The text of the lines is at the end of the block. The text of the first line
                    123:  * in the block is put at the end, the text of the second line in front of it,
                    124:  * etc. Thus the order of the lines is the opposite of the line number.
                    125:  */
                    126: struct data_block
                    127: {
                    128:    short_u     db_id;          /* ID for data block: DATA_ID */
                    129:    unsigned    db_free;        /* free space available */
                    130:    unsigned    db_txt_start;   /* byte where text starts */
                    131:    unsigned    db_txt_end;     /* byte just after data block */
                    132:    linenr_t    db_line_count;  /* number of lines in this block */
                    133:    unsigned    db_index[1];    /* index for start of line (actually bigger)
                    134:                                 * followed by empty space upto db_txt_start
                    135:                                 * followed by the text in the lines until
                    136:                                 * end of page */
                    137: };
                    138:
                    139: /*
                    140:  * The low bits of db_index hold the actual index. The topmost bit is
                    141:  * used for the global command to be able to mark a line.
                    142:  * This method is not clean, but otherwise there would be at least one extra
                    143:  * byte used for each line.
                    144:  * The mark has to be in this place to keep it with the correct line when other
                    145:  * lines are inserted or deleted.
                    146:  */
                    147: #define DB_MARKED      ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
                    148: #define DB_INDEX_MASK  (~DB_MARKED)
                    149:
                    150: #define INDEX_SIZE (sizeof(unsigned))      /* size of one db_index entry */
                    151: #define HEADER_SIZE    (sizeof(DATA_BL) - INDEX_SIZE)  /* size of data block header */
                    152:
                    153: #define B0_FNAME_SIZE  900
                    154: #define B0_UNAME_SIZE  40
                    155: #define B0_HNAME_SIZE  40
                    156: /*
                    157:  * Restrict the numbers to 32 bits, otherwise most compilers will complain.
                    158:  * This won't detect a 64 bit machine that only swaps a byte in the top 32
                    159:  * bits, but that is crazy anyway.
                    160:  */
                    161: #define B0_MAGIC_LONG  0x30313233
                    162: #define B0_MAGIC_INT   0x20212223
                    163: #define B0_MAGIC_SHORT 0x10111213
                    164: #define B0_MAGIC_CHAR  0x55
                    165:
                    166: /*
                    167:  * Block zero holds all info about the swap file.
                    168:  *
                    169:  * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE, it makes all existing swap
                    170:  * files unusable!
                    171:  *
                    172:  * If size of block0 changes anyway, adjust minimal block size
                    173:  * in mf_open()!!
                    174:  *
                    175:  * This block is built up of single bytes, to make it portable accros
                    176:  * different machines. b0_magic_* is used to check the byte order and size of
                    177:  * variables, because the rest of the swap is not portable.
                    178:  */
                    179: struct block0
                    180: {
                    181:    char_u      b0_id[2];       /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */
                    182:    char_u      b0_version[10]; /* Vim version string */
                    183:    char_u      b0_page_size[4];/* number of bytes per page */
                    184:    char_u      b0_mtime[4];    /* last modification time of file */
                    185:    char_u      b0_ino[4];      /* inode of b0_fname */
                    186:    char_u      b0_pid[4];      /* process id of creator (or 0) */
                    187:    char_u      b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
                    188:    char_u      b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
                    189:    char_u      b0_fname[B0_FNAME_SIZE]; /* name of file being edited */
                    190:    long        b0_magic_long;  /* check for byte order of long */
                    191:    int         b0_magic_int;   /* check for byte order of int */
                    192:    short       b0_magic_short; /* check for byte order of short */
                    193:    char_u      b0_magic_char;  /* check for last char */
                    194: };
                    195:
                    196: #define STACK_INCR     5       /* nr of entries added to ml_stack at a time */
                    197:
                    198: /*
                    199:  * The line number where the first mark may be is remembered.
                    200:  * If it is 0 there are no marks at all.
                    201:  * (always used for the current buffer only, no buffer change possible while
                    202:  * executing a global command).
                    203:  */
                    204: static linenr_t    lowest_marked = 0;
                    205:
                    206: /*
                    207:  * arguments for ml_find_line()
                    208:  */
                    209: #define ML_DELETE      0x11        /* delete line */
                    210: #define ML_INSERT      0x12        /* insert line */
                    211: #define ML_FIND            0x13        /* just find the line */
                    212: #define ML_FLUSH       0x02        /* flush locked block */
                    213: #define ML_SIMPLE(x)   (x & 0x10)  /* DEL, INS or FIND */
                    214:
                    215: static void ml_open_file __ARGS((BUF *));
                    216: static void set_b0_fname __ARGS((ZERO_BL *, BUF *buf));
                    217: static void swapfile_info __ARGS((char_u *));
                    218: static int get_names __ARGS((char_u **, char_u *));
                    219: static int ml_append_int __ARGS((BUF *, linenr_t, char_u *, colnr_t, int));
                    220: static int ml_delete_int __ARGS((BUF *, linenr_t, int));
                    221: static char_u *findswapname __ARGS((BUF *, char_u **, char_u *));
                    222: static void ml_flush_line __ARGS((BUF *));
                    223: static BHDR *ml_new_data __ARGS((MEMFILE *, int, int));
                    224: static BHDR *ml_new_ptr __ARGS((MEMFILE *));
                    225: static BHDR *ml_find_line __ARGS((BUF *, linenr_t, int));
                    226: static int ml_add_stack __ARGS((BUF *));
                    227: static char_u *makeswapname __ARGS((BUF *, char_u *));
                    228: static void ml_lineadd __ARGS((BUF *, int));
                    229: static int b0_magic_wrong __ARGS((ZERO_BL *));
                    230: #ifdef CHECK_INODE
                    231: static int fnamecmp_ino __ARGS((char_u *, char_u *, long));
                    232: #endif
                    233: static void long_to_char __ARGS((long, char_u *));
                    234: static long char_to_long __ARGS((char_u *));
                    235:
                    236: /*
                    237:  * open a new memline for 'curbuf'
                    238:  *
                    239:  * return FAIL for failure, OK otherwise
                    240:  */
                    241:    int
                    242: ml_open()
                    243: {
                    244:    MEMFILE     *mfp;
                    245:    char_u      *fname;
                    246:    BHDR        *hp = NULL;
                    247:    ZERO_BL     *b0p;
                    248:    PTR_BL      *pp;
                    249:    DATA_BL     *dp;
                    250:    char_u      *dirp;
                    251:
                    252: /*
                    253:  * init fields in memline struct
                    254:  */
                    255:    curbuf->b_ml.ml_stack_size = 0;     /* no stack yet */
                    256:    curbuf->b_ml.ml_stack = NULL;       /* no stack yet */
                    257:    curbuf->b_ml.ml_stack_top = 0;      /* nothing in the stack */
                    258:    curbuf->b_ml.ml_locked = NULL;      /* no cached block */
                    259:    curbuf->b_ml.ml_line_lnum = 0;      /* no cached line */
                    260:
                    261: /*
                    262:  * Make file name for swap file.
                    263:  * If we are unable to find a file name, mf_fname will be NULL
                    264:  * and the memfile will be in memory only (no recovery possible).
                    265:  * When 'updatecount' is 0 and for help files on Unix there is never a swap
                    266:  * file.
                    267:  */
                    268: #if defined(UNIX) || defined(__EMX__)
                    269: /* why only on Unix an exception for help files??? */
                    270:    if (p_uc == 0 || curbuf->b_help)
                    271: #else
                    272:    if (p_uc == 0)
                    273: #endif
                    274:        dirp = (char_u *)"";
                    275:    else
                    276:        dirp = p_dir;
                    277:
                    278: /*
                    279:  * Open the memfile.
                    280:  *
                    281:  * If no swap file is wanted *dirp will be NUL, try with fname == NULL.
                    282:  * Otherwise try all directories in 'directory' option. If that fails try
                    283:  * with fname == NULL.
                    284:  */
                    285:    for (;;)
                    286:    {
                    287:        if (*dirp == NUL)
                    288:            fname = NULL;
                    289:        else
                    290:        {
                    291:            fname = findswapname(curbuf, &dirp, NULL);
                    292:            if (fname == NULL)
                    293:                continue;
                    294:        }
                    295:        mfp = mf_open(fname, TRUE);
                    296:        /* stop when memfile opened or no other fname to try */
                    297:        if (mfp != NULL || (fname == NULL && *dirp == NUL))
                    298:            break;
                    299:        vim_free(fname);
                    300:    }
                    301:
                    302:    if (mfp == NULL)
                    303:        goto error;
                    304:    curbuf->b_ml.ml_mfp = mfp;
                    305:    curbuf->b_ml.ml_flags = ML_EMPTY;
                    306:    curbuf->b_ml.ml_line_count = 1;
                    307:
                    308:    if (!(p_uc == 0 || curbuf->b_help) && mfp->mf_fname == NULL)
                    309:    {
                    310:        need_wait_return = TRUE;        /* call wait_return later */
                    311:        ++no_wait_return;
                    312:        (void)EMSG("Unable to open swap file, recovery impossible");
                    313:        --no_wait_return;
                    314:    }
                    315: #if defined(MSDOS) || defined(WIN32)
                    316:    /*
                    317:     * set full pathname for swap file now, because a ":!cd dir" may
                    318:     * change directory without us knowing it.
                    319:     */
                    320:    mf_fullname(mfp);
                    321: #endif
                    322:
                    323: /*
                    324:  * fill block0 struct and write page 0
                    325:  */
                    326:    if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
                    327:        goto error;
                    328:    if (hp->bh_bnum != 0)
                    329:    {
                    330:        EMSG("didn't get block nr 0?");
                    331:        goto error;
                    332:    }
                    333:    b0p = (ZERO_BL *)(hp->bh_data);
                    334:
                    335:    (void)vim_memset(b0p, 0, sizeof(ZERO_BL));      /* init all to zero */
                    336:
                    337:    b0p->b0_id[0] = BLOCK0_ID0;
                    338:    b0p->b0_id[1] = BLOCK0_ID1;
                    339:    b0p->b0_magic_long = (long)B0_MAGIC_LONG;
                    340:    b0p->b0_magic_int = (int)B0_MAGIC_INT;
                    341:    b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
                    342:    b0p->b0_magic_char = B0_MAGIC_CHAR;
                    343:
                    344:    STRNCPY(b0p->b0_version, Version, 10);
                    345:    set_b0_fname(b0p, curbuf);
                    346:    long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
                    347:    (void)mch_get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
                    348:    b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
                    349:    mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
                    350:    b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
                    351:    long_to_char(mch_get_pid(), b0p->b0_pid);
                    352:
                    353:    /*
                    354:     * Always sync block number 0 to disk, so we can check the file name in
                    355:     * the swap file in findswapname(). Don't do this for help files though.
                    356:     */
                    357:    mf_put(mfp, hp, TRUE, FALSE);
                    358:    if (!curbuf->b_help)
                    359:        mf_sync(mfp, FALSE, FALSE, FALSE);
                    360:
                    361: /*
                    362:  * fill in root pointer block and write page 1
                    363:  */
                    364:    if ((hp = ml_new_ptr(mfp)) == NULL)
                    365:        goto error;
                    366:    if (hp->bh_bnum != 1)
                    367:    {
                    368:        EMSG("didn't get block nr 1?");
                    369:        goto error;
                    370:    }
                    371:    pp = (PTR_BL *)(hp->bh_data);
                    372:    pp->pb_count = 1;
                    373:    pp->pb_pointer[0].pe_bnum = 2;
                    374:    pp->pb_pointer[0].pe_page_count = 1;
                    375:    pp->pb_pointer[0].pe_old_lnum = 1;
                    376:    pp->pb_pointer[0].pe_line_count = 1;    /* line count after insertion */
                    377:    mf_put(mfp, hp, TRUE, FALSE);
                    378:
                    379: /*
                    380:  * allocate first data block and create an empty line 1.
                    381:  */
                    382:    if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
                    383:        goto error;
                    384:    if (hp->bh_bnum != 2)
                    385:    {
                    386:        EMSG("didn't get block nr 2?");
                    387:        goto error;
                    388:    }
                    389:
                    390:    dp = (DATA_BL *)(hp->bh_data);
                    391:    dp->db_index[0] = --dp->db_txt_start;       /* at end of block */
                    392:    dp->db_free -= 1 + INDEX_SIZE;
                    393:    dp->db_line_count = 1;
                    394:    *((char_u *)dp + dp->db_txt_start) = NUL;   /* emtpy line */
                    395:
                    396:    return OK;
                    397:
                    398: error:
                    399:    if (mfp != NULL)
                    400:    {
                    401:        if (hp)
                    402:            mf_put(mfp, hp, FALSE, FALSE);
                    403:        mf_close(mfp, TRUE);        /* will also free(mfp->mf_fname) */
                    404:    }
                    405:    else
                    406:        vim_free(fname);
                    407:    curbuf->b_ml.ml_mfp = NULL;
                    408:    return FAIL;
                    409: }
                    410:
                    411: /*
                    412:  * ml_setname() is called when the file name has been changed.
                    413:  * It may rename the swap file.
                    414:  */
                    415:    void
                    416: ml_setname()
                    417: {
                    418:    int         success = FALSE;
                    419:    MEMFILE     *mfp;
                    420:    char_u      *fname;
                    421:    char_u      *dirp;
                    422:
                    423: /*
                    424:  * When 'updatecount' is 0 there is never a swap file.
                    425:  * For help files we will make a swap file now.
                    426:  */
                    427:    if (p_uc == 0)
                    428:        return;
                    429:
                    430:    mfp = curbuf->b_ml.ml_mfp;
                    431:    if (mfp->mf_fd < 0)             /* there is no swap file yet */
                    432:    {
                    433:        ml_open_file(curbuf);       /* create a swap file */
                    434:        return;
                    435:    }
                    436:
                    437: /*
                    438:  * Try all directories in the 'directory' option.
                    439:  */
                    440:    dirp = p_dir;
                    441:    for (;;)
                    442:    {
                    443:        if (*dirp == NUL)           /* tried all directories, fail */
                    444:            break;
                    445:        fname = findswapname(curbuf, &dirp, mfp->mf_fname);
                    446:        if (fname == NULL)          /* no file name found for this dir */
                    447:            continue;
                    448:
                    449: #if defined(MSDOS) || defined(WIN32)
                    450:        /*
                    451:         * Set full pathname for swap file now, because a ":!cd dir" may
                    452:         * change directory without us knowing it.
                    453:         */
                    454:        if (!did_cd)
                    455:        {
                    456:            char_u      *p;
                    457:
                    458:            p = FullName_save(fname);
                    459:            vim_free(fname);
                    460:            fname = p;
                    461:            if (fname == NULL)
                    462:                continue;
                    463:        }
                    464: #endif
                    465:            /* if the file name is the same we don't have to do anything */
                    466:        if (fnamecmp(fname, mfp->mf_fname) == 0)
                    467:        {
                    468:            vim_free(fname);
                    469:            success = TRUE;
                    470:            break;
                    471:        }
                    472:            /* need to close the swap file before renaming */
                    473:        if (mfp->mf_fd >= 0)
                    474:        {
                    475:            close(mfp->mf_fd);
                    476:            mfp->mf_fd = -1;
                    477:        }
                    478:
                    479:            /* try to rename the swap file */
                    480:        if (vim_rename(mfp->mf_fname, fname) == 0)
                    481:        {
                    482:            success = TRUE;
                    483:            vim_free(mfp->mf_fname);
                    484:            mfp->mf_fname = fname;
                    485:            vim_free(mfp->mf_xfname);
                    486:            mf_set_xfname(mfp);
                    487:            break;
                    488:        }
                    489:        vim_free(fname);            /* this fname didn't work, try another */
                    490:    }
                    491:
                    492:    if (mfp->mf_fd == -1)           /* need to (re)open the swap file */
                    493:    {
                    494:        mfp->mf_fd = open((char *)mfp->mf_fname, O_RDWR | O_EXTRA);
                    495:        if (mfp->mf_fd < 0)
                    496:        {
                    497:            /* could not (re)open the swap file, what can we do???? */
                    498:            EMSG("Oops, lost the swap file!!!");
                    499:            return;
                    500:        }
                    501:    }
                    502:    if (!success)
                    503:        EMSG("Could not rename swap file");
                    504: }
                    505:
                    506: /*
                    507:  * Open a file for the memfile for all buffers.
                    508:  * Used when 'updatecount' changes from zero to non-zero.
                    509:  */
                    510:    void
                    511: ml_open_files()
                    512: {
                    513:    BUF         *buf;
                    514:
                    515:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    516:        ml_open_file(buf);
                    517: }
                    518:
                    519: /*
                    520:  * Open a swap file for an existing memfile, if there is non swap file yet.
                    521:  */
                    522:    static void
                    523: ml_open_file(buf)
                    524:    BUF         *buf;
                    525: {
                    526:    MEMFILE     *mfp;
                    527:    char_u      *fname;
                    528:    char_u      *dirp;
                    529:
                    530:    mfp = buf->b_ml.ml_mfp;
                    531:    if (mfp == NULL || mfp->mf_fd >= 0)         /* nothing to do */
                    532:        return;
                    533:
                    534:    dirp = p_dir;
                    535: /*
                    536:  * Try all directories in 'directory' option.
                    537:  */
                    538:    for (;;)
                    539:    {
                    540:        if (*dirp == NUL)
                    541:            break;
                    542:        fname = findswapname(buf, &dirp, NULL);
                    543:        if (fname == NULL)
                    544:            continue;
                    545:        if (mf_open_file(mfp, fname) == OK)
                    546:            break;
                    547:        vim_free(fname);
                    548:    }
                    549:
                    550:    if (mfp->mf_fname == NULL)          /* Failed! */
                    551:    {
                    552:        need_wait_return = TRUE;        /* call wait_return later */
                    553:        ++no_wait_return;
                    554:        (void)EMSG2("Unable to open swap file for \"%s\", recovery impossible",
                    555:                buf->b_xfilename == NULL ? (char_u *)"No File"
                    556:                                         : buf->b_xfilename);
                    557:        --no_wait_return;
                    558:    }
                    559: #if defined(MSDOS) || defined(WIN32)
                    560:    /*
                    561:     * set full pathname for swap file now, because a ":!cd dir" may
                    562:     * change directory without us knowing it.
                    563:     */
                    564:    else
                    565:        mf_fullname(mfp);
                    566: #endif
                    567: }
                    568:
                    569: /*
                    570:  * Close memline for buffer 'buf'.
                    571:  * If 'del_file' is TRUE, delete the swap file
                    572:  */
                    573:    void
                    574: ml_close(buf, del_file)
                    575:    BUF     *buf;
                    576:    int     del_file;
                    577: {
                    578:    if (buf->b_ml.ml_mfp == NULL)               /* not open */
                    579:        return;
                    580:    mf_close(buf->b_ml.ml_mfp, del_file);           /* close the .swp file */
                    581:    if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
                    582:        vim_free(buf->b_ml.ml_line_ptr);
                    583:    vim_free(buf->b_ml.ml_stack);
                    584:    buf->b_ml.ml_mfp = NULL;
                    585: }
                    586:
                    587: /*
                    588:  * Close all existing memlines and memfiles.
                    589:  * Used when exiting.
                    590:  * When 'del_file' is TRUE, delete the memfiles.
                    591:  */
                    592:    void
                    593: ml_close_all(del_file)
                    594:    int     del_file;
                    595: {
                    596:    BUF     *buf;
                    597:
                    598:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    599:        ml_close(buf, del_file);
                    600: }
                    601:
                    602: /*
                    603:  * Close all memfiles for not modified buffers.
                    604:  * Only use just before exiting!
                    605:  */
                    606:    void
                    607: ml_close_notmod()
                    608: {
                    609:    BUF     *buf;
                    610:
                    611:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                    612:        if (!buf->b_changed)
                    613:            ml_close(buf, TRUE);    /* close all not-modified buffers */
                    614: }
                    615:
                    616: /*
                    617:  * Update the timestamp in the .swp file.
                    618:  * Used when the file has been written.
                    619:  */
                    620:    void
                    621: ml_timestamp(buf)
                    622:    BUF         *buf;
                    623: {
                    624:    MEMFILE     *mfp;
                    625:    BHDR        *hp;
                    626:    ZERO_BL     *b0p;
                    627:
                    628:    mfp = buf->b_ml.ml_mfp;
                    629:
                    630:    if (mfp == NULL || (hp = mf_get(mfp, (blocknr_t)0, 1)) == NULL)
                    631:        return;
                    632:    b0p = (ZERO_BL *)(hp->bh_data);
                    633:    if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
                    634:        EMSG("ml_timestamp: Didn't get block 0??");
                    635:    else
                    636:        set_b0_fname(b0p, buf);
                    637:    mf_put(mfp, hp, TRUE, FALSE);
                    638: }
                    639:
                    640: /*
                    641:  * Write file name and timestamp into block 0 of a swap file.
                    642:  * Also set buf->b_mtime.
                    643:  * Don't use NameBuff[]!!!
                    644:  */
                    645:    static void
                    646: set_b0_fname(b0p, buf)
                    647:    ZERO_BL     *b0p;
                    648:    BUF         *buf;
                    649: {
                    650:    struct stat st;
                    651:    size_t      flen, ulen;
                    652:    char_u      uname[B0_UNAME_SIZE];
                    653:
                    654:    if (buf->b_filename == NULL)
                    655:        b0p->b0_fname[0] = NUL;
                    656:    else
                    657:    {
                    658:        /*
                    659:         * For a file under the home directory of the current user, we try to
                    660:         * replace the home directory path with "~user". This helps when
                    661:         * editing the same file on different machines over a network.
                    662:         * First replace home dir path with "~/" with home_replace().
                    663:         * Then insert the user name to get "~user/".
                    664:         */
                    665:        home_replace(NULL, buf->b_filename, b0p->b0_fname, B0_FNAME_SIZE);
                    666:        if (b0p->b0_fname[0] == '~')
                    667:        {
                    668:            flen = STRLEN(b0p->b0_fname);
                    669:            /* If there is no user name or it is too long, don't use "~/" */
                    670:            if (mch_get_user_name(uname, B0_UNAME_SIZE) == FAIL ||
                    671:                         (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
                    672:                STRNCPY(b0p->b0_fname, buf->b_filename, B0_FNAME_SIZE);
                    673:            else
                    674:            {
                    675:                vim_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
                    676:                vim_memmove(b0p->b0_fname + 1, uname, ulen);
                    677:            }
                    678:        }
                    679:        if (stat((char *)buf->b_filename, &st) >= 0)
                    680:        {
                    681:            long_to_char((long)st.st_mtime, b0p->b0_mtime);
                    682: #ifdef CHECK_INODE
                    683:            long_to_char((long)st.st_ino, b0p->b0_ino);
                    684: #endif
                    685:            buf->b_mtime = st.st_mtime;
                    686:            buf->b_mtime_read = st.st_mtime;
                    687:        }
                    688:        else
                    689:        {
                    690:            long_to_char(0L, b0p->b0_mtime);
                    691: #ifdef CHECK_INODE
                    692:            long_to_char(0L, b0p->b0_ino);
                    693: #endif
                    694:            buf->b_mtime = 0;
                    695:            buf->b_mtime_read = 0;
                    696:        }
                    697:    }
                    698: }
                    699:
                    700: /*
                    701:  * try to recover curbuf from the .swp file
                    702:  */
                    703:    void
                    704: ml_recover()
                    705: {
                    706:    BUF         *buf = NULL;
                    707:    MEMFILE     *mfp = NULL;
                    708:    char_u      *fname;
                    709:    BHDR        *hp = NULL;
                    710:    ZERO_BL     *b0p;
                    711:    PTR_BL      *pp;
                    712:    DATA_BL     *dp;
                    713:    IPTR        *ip;
                    714:    blocknr_t   bnum;
                    715:    int         page_count;
                    716:    struct stat org_stat, swp_stat;
                    717:    int         len;
                    718:    int         directly;
                    719:    linenr_t    lnum;
                    720:    char_u      *p;
                    721:    int         i;
                    722:    long        error;
                    723:    int         cannot_open;
                    724:    linenr_t    line_count;
                    725:    int         has_error;
                    726:    int         idx;
                    727:    int         top;
                    728:    int         txt_start;
                    729:    long        size;
                    730:    int         called_from_main;
                    731:    int         serious_error = TRUE;
                    732:    long        mtime;
                    733:
                    734:    called_from_main = (curbuf->b_ml.ml_mfp == NULL);
                    735: /*
                    736:  * If the file name ends in ".sw?" we use it directly.
                    737:  * Otherwise a search is done to find the swap file(s).
                    738:  */
                    739:    fname = curbuf->b_xfilename;
                    740:    if (fname == NULL)              /* When there is no file name */
                    741:        fname = (char_u *)"";
                    742:    len = STRLEN(fname);
                    743:    if (len >= 4 && vim_strnicmp(fname + len - 4,
                    744:                                    (char_u *)".sw", (size_t)3) == 0)
                    745:    {
                    746:        directly = TRUE;
                    747:        fname = strsave(fname);     /* make a copy for mf_open */
                    748:    }
                    749:    else
                    750:    {
                    751:        directly = FALSE;
                    752:
                    753:            /* count the number of matching swap files */
                    754:        len = recover_names(&fname, FALSE, 0);
                    755:        if (len == 0)               /* no swap files found */
                    756:        {
                    757:            EMSG2("No swap file found for %s", fname);
                    758:            fname = NULL;
                    759:            goto theend;
                    760:        }
                    761:        if (len == 1)               /* one swap file found, use it */
                    762:            i = 1;
                    763:        else                        /* several swap files found, choose */
                    764:        {
                    765:                /* list the names of the swap files */
                    766:            (void)recover_names(&fname, TRUE, 0);
                    767:            msg_outchar('\n');
                    768:            MSG_OUTSTR("Enter number of swap file to use (0 to quit): ");
                    769:            i = get_number();
                    770:            if (i < 1 || i > len)
                    771:            {
                    772:                fname = NULL;
                    773:                goto theend;
                    774:            }
                    775:        }
                    776:                /* get the swap file name that will be used */
                    777:        (void)recover_names(&fname, FALSE, i);
                    778:    }
                    779:    if (fname == NULL)
                    780:        goto theend;                    /* out of memory */
                    781:
                    782:    /* When called from main() still need to initialize storage structure */
                    783:    if (called_from_main && ml_open() == FAIL)
                    784:        getout(1);
                    785:
                    786: /*
                    787:  * allocate a buffer structure (only the memline in it is really used)
                    788:  */
                    789:    buf = (BUF *)alloc((unsigned)sizeof(BUF));
                    790:    if (buf == NULL)
                    791:        goto theend;
                    792:
                    793: /*
                    794:  * init fields in memline struct
                    795:  */
                    796:    buf->b_ml.ml_stack_size = 0;        /* no stack yet */
                    797:    buf->b_ml.ml_stack = NULL;          /* no stack yet */
                    798:    buf->b_ml.ml_stack_top = 0;         /* nothing in the stack */
                    799:    buf->b_ml.ml_line_lnum = 0;         /* no cached line */
                    800:    buf->b_ml.ml_locked = NULL;         /* no locked block */
                    801:    buf->b_ml.ml_flags = 0;
                    802:
                    803: /*
                    804:  * open the memfile from the old swap file
                    805:  */
                    806:    mfp = mf_open(fname, FALSE);
                    807:    if (mfp == NULL || mfp->mf_fd < 0)
                    808:    {
                    809:        EMSG2("Cannot open %s", fname);
                    810:        goto theend;
                    811:    }
                    812:    buf->b_ml.ml_mfp = mfp;
                    813: #if defined(MSDOS) || defined(WIN32)
                    814:    /*
                    815:     * set full pathname for swap file now, because a ":!cd dir" may
                    816:     * change directory without us knowing it.
                    817:     * Careful: May free fname!
                    818:     */
                    819:    mf_fullname(mfp);
                    820: #endif
                    821:
                    822: /*
                    823:  * try to read block 0
                    824:  */
                    825:    if ((hp = mf_get(mfp, (blocknr_t)0, 1)) == NULL)
                    826:    {
                    827:        msg_start();
                    828:        MSG_OUTSTR("Unable to read block 0 from ");
                    829:        msg_outtrans(mfp->mf_fname);
                    830:        MSG_OUTSTR("\nMaybe no changes were made or Vim did not update the swap file");
                    831:        msg_end();
                    832:        goto theend;
                    833:    }
                    834:    b0p = (ZERO_BL *)(hp->bh_data);
                    835:    if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
                    836:    {
                    837:        EMSG2("%s is not a swap file", mfp->mf_fname);
                    838:        goto theend;
                    839:    }
                    840:    if (b0_magic_wrong(b0p))
                    841:    {
                    842:        msg_start();
                    843:        MSG_OUTSTR("The file ");
                    844:        msg_outtrans(mfp->mf_fname);
                    845: #if defined(MSDOS) || defined(WIN32)
                    846:        if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
                    847:            MSG_OUTSTR(" cannot be used with this version of Vim.\n");
                    848:        else
                    849: #endif
                    850:            MSG_OUTSTR(" cannot be used on this computer.\n");
                    851:        MSG_OUTSTR("The file was created on ");
                    852:                /* avoid going past the end of currupted hostname */
                    853:        b0p->b0_fname[0] = NUL;
                    854:        MSG_OUTSTR(b0p->b0_hname);
                    855:        MSG_OUTSTR(",\nor the file has been damaged.");
                    856:        msg_end();
                    857:        goto theend;
                    858:    }
                    859:    /*
                    860:     * If we guessed the wrong page size, we have to recalculate the
                    861:     * highest block number in the file.
                    862:     */
                    863:    if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
                    864:    {
                    865:        mfp->mf_page_size = (unsigned)char_to_long(b0p->b0_page_size);
                    866:        if ((size = lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0)
                    867:            mfp->mf_blocknr_max = 0;        /* no file or empty file */
                    868:        else
                    869:            mfp->mf_blocknr_max = size / mfp->mf_page_size;
                    870:        mfp->mf_infile_count = mfp->mf_blocknr_max;
                    871:    }
                    872:
                    873: /*
                    874:  * If .swp file name given directly, use name from swap file for buffer.
                    875:  */
                    876:    if (directly)
                    877:    {
                    878:        expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
                    879:        if (setfname(NameBuff, NULL, TRUE) == FAIL)
                    880:            goto theend;
                    881:    }
                    882:
                    883:    home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL);
                    884:    smsg((char_u *)"Using swap file \"%s\"", NameBuff);
                    885:
                    886:    if (curbuf->b_filename == NULL)
                    887:        STRCPY(NameBuff, "No File");
                    888:    else
                    889:        home_replace(NULL, curbuf->b_filename, NameBuff, MAXPATHL);
                    890:    smsg((char_u *)"Original file \"%s\"", NameBuff);
                    891:    msg_outchar((char_u)'\n');
                    892:
                    893: /*
                    894:  * check date of swap file and original file
                    895:  */
                    896:    mtime = char_to_long(b0p->b0_mtime);
                    897:    if (curbuf->b_filename != NULL &&
                    898:            stat((char *)curbuf->b_filename, &org_stat) != -1 &&
                    899:            ((stat((char *)mfp->mf_fname, &swp_stat) != -1 &&
                    900:            org_stat.st_mtime > swp_stat.st_mtime) ||
                    901:            org_stat.st_mtime != mtime))
                    902:    {
                    903:        EMSG("Warning: Original file may have been changed");
                    904:    }
                    905:    flushbuf();
                    906:    mf_put(mfp, hp, FALSE, FALSE);      /* release block 0 */
                    907:    hp = NULL;
                    908:
                    909:    /*
                    910:     * Now that we are sure that the file is going to be recovered, clear the
                    911:     * contents of the current buffer.
                    912:     */
                    913:    while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
                    914:        ml_delete((linenr_t)1, FALSE);
                    915:
                    916:    bnum = 1;           /* start with block 1 */
                    917:    page_count = 1;     /* which is 1 page */
                    918:    lnum = 0;           /* append after line 0 in curbuf */
                    919:    line_count = 0;
                    920:    idx = 0;            /* start with first index in block 1 */
                    921:    error = 0;
                    922:    buf->b_ml.ml_stack_top = 0;
                    923:    buf->b_ml.ml_stack = NULL;
                    924:    buf->b_ml.ml_stack_size = 0;        /* no stack yet */
                    925:
                    926:    if (curbuf->b_filename == NULL)
                    927:        cannot_open = TRUE;
                    928:    else
                    929:        cannot_open = FALSE;
                    930:
                    931:    serious_error = FALSE;
                    932:    for ( ; !got_int; line_breakcheck())
                    933:    {
                    934:        if (hp != NULL)
                    935:            mf_put(mfp, hp, FALSE, FALSE);      /* release previous block */
                    936:
                    937:        /*
                    938:         * get block
                    939:         */
                    940:        if ((hp = mf_get(mfp, (blocknr_t)bnum, page_count)) == NULL)
                    941:        {
                    942:            if (bnum == 1)
                    943:            {
                    944:                EMSG2("Unable to read block 1 from %s", mfp->mf_fname);
                    945:                goto theend;
                    946:            }
                    947:            ++error;
                    948:            ml_append(lnum++, (char_u *)"???MANY LINES MISSING", (colnr_t)0, TRUE);
                    949:        }
                    950:        else            /* there is a block */
                    951:        {
                    952:            pp = (PTR_BL *)(hp->bh_data);
                    953:            if (pp->pb_id == PTR_ID)            /* it is a pointer block */
                    954:            {
                    955:                    /* check line count when using pointer block first time */
                    956:                if (idx == 0 && line_count != 0)
                    957:                {
                    958:                    for (i = 0; i < (int)pp->pb_count; ++i)
                    959:                        line_count -= pp->pb_pointer[i].pe_line_count;
                    960:                    if (line_count != 0)
                    961:                    {
                    962:                        ++error;
                    963:                        ml_append(lnum++, (char_u *)"???LINE COUNT WRONG", (colnr_t)0, TRUE);
                    964:                    }
                    965:                }
                    966:
                    967:                if (pp->pb_count == 0)
                    968:                {
                    969:                    ml_append(lnum++, (char_u *)"???EMPTY BLOCK", (colnr_t)0, TRUE);
                    970:                    ++error;
                    971:                }
                    972:                else if (idx < (int)pp->pb_count)       /* go a block deeper */
                    973:                {
                    974:                    if (pp->pb_pointer[idx].pe_bnum < 0)
                    975:                    {
                    976:                        /*
                    977:                         * Data block with negative block number.
                    978:                         * Try to read lines from the original file.
                    979:                         * This is slow, but it works.
                    980:                         */
                    981:                        if (!cannot_open)
                    982:                        {
                    983:                            line_count = pp->pb_pointer[idx].pe_line_count;
                    984:                            if (readfile(curbuf->b_filename, NULL, lnum, FALSE,
                    985:                                        pp->pb_pointer[idx].pe_old_lnum - 1,
                    986:                                        line_count, FALSE) == FAIL)
                    987:                                cannot_open = TRUE;
                    988:                            else
                    989:                                lnum += line_count;
                    990:                        }
                    991:                        if (cannot_open)
                    992:                        {
                    993:                            ++error;
                    994:                            ml_append(lnum++, (char_u *)"???LINES MISSING", (colnr_t)0, TRUE);
                    995:                        }
                    996:                        ++idx;      /* get same block again for next index */
                    997:                        continue;
                    998:                    }
                    999:
                   1000:                    /*
                   1001:                     * going one block deeper in the tree
                   1002:                     */
                   1003:                    if ((top = ml_add_stack(buf)) < 0)      /* new entry in stack */
                   1004:                    {
                   1005:                        ++error;
                   1006:                        break;              /* out of memory */
                   1007:                    }
                   1008:                    ip = &(buf->b_ml.ml_stack[top]);
                   1009:                    ip->ip_bnum = bnum;
                   1010:                    ip->ip_index = idx;
                   1011:
                   1012:                    bnum = pp->pb_pointer[idx].pe_bnum;
                   1013:                    line_count = pp->pb_pointer[idx].pe_line_count;
                   1014:                    page_count = pp->pb_pointer[idx].pe_page_count;
                   1015:                    continue;
                   1016:                }
                   1017:            }
                   1018:            else            /* not a pointer block */
                   1019:            {
                   1020:                dp = (DATA_BL *)(hp->bh_data);
                   1021:                if (dp->db_id != DATA_ID)       /* block id wrong */
                   1022:                {
                   1023:                    if (bnum == 1)
                   1024:                    {
                   1025:                        EMSG2("Block 1 ID wrong (%s not a .swp file?)",
                   1026:                                                               mfp->mf_fname);
                   1027:                        goto theend;
                   1028:                    }
                   1029:                    ++error;
                   1030:                    ml_append(lnum++, (char_u *)"???BLOCK MISSING", (colnr_t)0, TRUE);
                   1031:                }
                   1032:                else
                   1033:                {
                   1034:                    /*
                   1035:                     * it is a data block
                   1036:                     * Append all the lines in this block
                   1037:                     */
                   1038:                    has_error = FALSE;
                   1039:                        /*
                   1040:                         * check length of block
                   1041:                         * if wrong, use length in pointer block
                   1042:                         */
                   1043:                    if (page_count * mfp->mf_page_size != dp->db_txt_end)
                   1044:                    {
                   1045:                        ml_append(lnum++, (char_u *)"??? from here until ???END lines may be messed up", (colnr_t)0, TRUE);
                   1046:                        ++error;
                   1047:                        has_error = TRUE;
                   1048:                        dp->db_txt_end = page_count * mfp->mf_page_size;
                   1049:                    }
                   1050:
                   1051:                        /* make sure there is a NUL at the end of the block */
                   1052:                    *((char_u *)dp + dp->db_txt_end - 1) = NUL;
                   1053:
                   1054:                        /*
                   1055:                         * check number of lines in block
                   1056:                         * if wrong, use count in data block
                   1057:                         */
                   1058:                    if (line_count != dp->db_line_count)
                   1059:                    {
                   1060:                        ml_append(lnum++, (char_u *)"??? from here until ???END lines may have been inserted/deleted", (colnr_t)0, TRUE);
                   1061:                        ++error;
                   1062:                        has_error = TRUE;
                   1063:                    }
                   1064:
                   1065:                    for (i = 0; i < dp->db_line_count; ++i)
                   1066:                    {
                   1067:                        txt_start = (dp->db_index[i] & DB_INDEX_MASK);
                   1068:                        if (txt_start <= HEADER_SIZE || txt_start >= (int)dp->db_txt_end)
                   1069:                        {
                   1070:                            p = (char_u *)"???";
                   1071:                            ++error;
                   1072:                        }
                   1073:                        else
                   1074:                            p = (char_u *)dp + txt_start;
                   1075:                        ml_append(lnum++, p, (colnr_t)0, TRUE);
                   1076:                    }
                   1077:                    if (has_error)
                   1078:                        ml_append(lnum++, (char_u *)"???END", (colnr_t)0, TRUE);
                   1079:                }
                   1080:            }
                   1081:        }
                   1082:
                   1083:        if (buf->b_ml.ml_stack_top == 0)        /* finished */
                   1084:            break;
                   1085:
                   1086:        /*
                   1087:         * go one block up in the tree
                   1088:         */
                   1089:        ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
                   1090:        bnum = ip->ip_bnum;
                   1091:        idx = ip->ip_index + 1;     /* go to next index */
                   1092:        page_count = 1;
                   1093:    }
                   1094:
                   1095:    /*
                   1096:     * The dummy line from the empty buffer will now be after the last line in
                   1097:     * the buffer. Delete it.
                   1098:     */
                   1099:    ml_delete(curbuf->b_ml.ml_line_count, FALSE);
                   1100:
                   1101:    recoverymode = FALSE;
                   1102:    if (got_int)
                   1103:        EMSG("Recovery Interrupted");
                   1104:    else if (error)
                   1105:        EMSG("Errors detected while recovering; look for lines starting with ???");
                   1106:    else
                   1107:    {
                   1108:        MSG("Recovery completed. You should check if everything is OK.");
                   1109:        MSG_OUTSTR("\n(You might want to write out this file under another name\n");
                   1110:        MSG_OUTSTR("and run diff with the original file to check for changes)\n");
                   1111:        MSG_OUTSTR("Delete the .swp file afterwards.\n\n");
                   1112:        cmdline_row = msg_row;
                   1113:    }
                   1114:
                   1115: theend:
                   1116:    if (mfp != NULL)
                   1117:    {
                   1118:        if (hp != NULL)
                   1119:            mf_put(mfp, hp, FALSE, FALSE);
                   1120:        mf_close(mfp, FALSE);       /* will also vim_free(mfp->mf_fname) */
                   1121:    }
                   1122:    else
                   1123:        vim_free(fname);
                   1124:    vim_free(buf);
                   1125:    if (serious_error && called_from_main)
                   1126:        ml_close(curbuf, TRUE);
                   1127:    return;
                   1128: }
                   1129:
                   1130: /*
                   1131:  * Find the names of swap files in current directory and the directory given
                   1132:  * with the 'directory' option.
                   1133:  *
                   1134:  * Used to:
                   1135:  * - list the swap files for "vim -r"
                   1136:  * - count the number of swap files when recovering
                   1137:  * - list the swap files when recovering
                   1138:  * - find the name of the n'th swap file when recovering
                   1139:  */
                   1140:    int
                   1141: recover_names(fname, list, nr)
                   1142:    char_u      **fname;    /* base for swap file name */
                   1143:    int         list;       /* when TRUE, list the swap file names */
                   1144:    int         nr;         /* when non-zero, return nr'th swap file name */
                   1145: {
                   1146:    int         num_names;
                   1147:    char_u      *(names[6]);
                   1148:    char_u      *tail;
                   1149:    char_u      *p;
                   1150:    int         num_files;
                   1151:    int         file_count = 0;
                   1152:    char_u      **files;
                   1153:    int         i;
                   1154:    char_u      *dirp;
                   1155:    char_u      *dir_name;
                   1156:
                   1157:    if (list)
                   1158:    {
                   1159:            /* use msg() to start the scrolling properly */
                   1160:        msg((char_u *)"Swap files found:");
                   1161:        msg_outchar('\n');
                   1162:    }
                   1163:    expand_interactively = TRUE;
                   1164:    /*
                   1165:     * Do the loop for every directory in 'directory'.
                   1166:     */
                   1167:    dirp = p_dir;
                   1168:    while (*dirp)
                   1169:    {
                   1170:        /* find character after directory name */
                   1171:        dir_name = dirp;
                   1172:        while (*dirp && *dirp != ',')
                   1173:            ++dirp;
                   1174:        dir_name = strnsave(dir_name, (int)(dirp - dir_name));
                   1175:        if (dir_name == NULL)       /* out of memory */
                   1176:            break;
                   1177:        if (*dir_name == '.')       /* check current dir */
                   1178:        {
                   1179:            if (fname == NULL || *fname == NULL)
                   1180:            {
                   1181:                names[0] = strsave((char_u *)"*.sw?");
                   1182: #ifdef UNIX
                   1183:                    /* for Unix names starting with a dot are special */
                   1184:                names[1] = strsave((char_u *)".*.sw?");
                   1185:                names[2] = strsave((char_u *)".sw?");
                   1186:                num_names = 3;
                   1187: #else
                   1188:                num_names = 1;
                   1189: #endif
                   1190:            }
                   1191:            else
                   1192:                num_names = get_names(names, *fname);
                   1193:        }
                   1194:        else                        /* check directory dir_name */
                   1195:        {
                   1196:            if (fname == NULL || *fname == NULL)
                   1197:            {
                   1198:                names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
                   1199: #ifdef UNIX
                   1200:                    /* for Unix names starting with a dot are special */
                   1201:                names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
                   1202:                names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
                   1203:                num_names = 3;
                   1204: #else
                   1205:                num_names = 1;
                   1206: #endif
                   1207:            }
                   1208:            else
                   1209:            {
                   1210:                tail = gettail(*fname);
                   1211:                tail = concat_fnames(dir_name, tail, TRUE);
                   1212:                if (tail == NULL)
                   1213:                    num_names = 0;
                   1214:                else
                   1215:                {
                   1216:                    num_names = get_names(names, tail);
                   1217:                    vim_free(tail);
                   1218:                }
                   1219:            }
                   1220:        }
                   1221:
                   1222:            /* check for out-of-memory */
                   1223:        for (i = 0; i < num_names; ++i)
                   1224:        {
                   1225:            if (names[i] == NULL)
                   1226:            {
                   1227:                for (i = 0; i < num_names; ++i)
                   1228:                    vim_free(names[i]);
                   1229:                num_names = 0;
                   1230:            }
                   1231:        }
                   1232:        if (num_names == 0)
                   1233:            num_files = 0;
                   1234:        else if (ExpandWildCards(num_names, names,
                   1235:                                     &num_files, &files, TRUE, FALSE) == FAIL)
                   1236:        {
                   1237:            MSG_OUTSTR(files);      /* print error message */
                   1238:            num_files = 0;
                   1239:        }
                   1240:        /*
                   1241:         * remove swapfile name of the current buffer, it must be ignored
                   1242:         */
                   1243:        if (curbuf->b_ml.ml_mfp != NULL &&
                   1244:                                (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
                   1245:        {
                   1246:            for (i = 0; i < num_files; ++i)
                   1247:                if (fullpathcmp(p, files[i]) == FPC_SAME)
                   1248:                {
                   1249:                    vim_free(files[i]);
                   1250:                    --num_files;
                   1251:                    for ( ; i < num_files; ++i)
                   1252:                        files[i] = files[i + 1];
                   1253:                    break;
                   1254:                }
                   1255:        }
                   1256:        if (nr)
                   1257:        {
                   1258:            file_count += num_files;
                   1259:            if (nr <= file_count)
                   1260:            {
                   1261:                *fname = strsave(files[nr - 1 + num_files - file_count]);
                   1262:                dirp = (char_u *)"";                /* stop searching */
                   1263:            }
                   1264:        }
                   1265:        else if (list)
                   1266:        {
                   1267:            if (*dir_name == '.')
                   1268:            {
                   1269:                if (fname == NULL || *fname == NULL)
                   1270:                    MSG_OUTSTR("   In current directory:\n");
                   1271:                else
                   1272:                    MSG_OUTSTR("   Using specified name:\n");
                   1273:            }
                   1274:            else
                   1275:            {
                   1276:                MSG_OUTSTR("   In directory ");
                   1277:                msg_home_replace(dir_name);
                   1278:                MSG_OUTSTR(":\n");
                   1279:            }
                   1280:
                   1281:            if (num_files)
                   1282:            {
                   1283:                for (i = 0; i < num_files; ++i)
                   1284:                {
                   1285:                    /* print the swap file name */
                   1286:                    msg_outnum((long)++file_count);
                   1287:                    MSG_OUTSTR(".    ");
                   1288:                    msg_outstr(gettail(files[i]));
                   1289:                    msg_outchar('\n');
                   1290:                    swapfile_info(files[i]);
                   1291:                }
                   1292:            }
                   1293:            else
                   1294:                MSG_OUTSTR("      -- none --\n");
                   1295:            flushbuf();
                   1296:        }
                   1297:        else
                   1298:            file_count += num_files;
                   1299:
                   1300:        for (i = 0; i < num_names; ++i)
                   1301:            vim_free(names[i]);
                   1302:        FreeWild(num_files, files);
                   1303:
                   1304:        /* advance dirp to next directory name */
                   1305:        vim_free(dir_name);
                   1306:        if (*dirp == ',')
                   1307:            ++dirp;
                   1308:        dirp = skipwhite(dirp);
                   1309:    }
                   1310:    expand_interactively = FALSE;
                   1311:    return file_count;
                   1312: }
                   1313:
                   1314: /*
                   1315:  * Give information about an existing swap file
                   1316:  */
                   1317:    static void
                   1318: swapfile_info(fname)
                   1319:    char_u      *fname;
                   1320: {
                   1321:    struct stat     st;
                   1322:    int             fd;
                   1323:    struct block0   b0;
                   1324:    time_t          x;
                   1325:
                   1326:    /* print the swap file date */
                   1327:    if (stat((char *)fname, &st) != -1)
                   1328:    {
                   1329:        MSG_OUTSTR("             dated: ");
                   1330:        x = st.st_mtime;                    /* Manx C can't do &st.st_mtime */
                   1331:        MSG_OUTSTR(ctime(&x));
                   1332:    }
                   1333:
                   1334:    /*
                   1335:     * print the original file name
                   1336:     */
                   1337:    fd = open((char *)fname, O_RDONLY | O_EXTRA);
                   1338:    if (fd >= 0)
                   1339:    {
                   1340:        if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
                   1341:        {
                   1342:            if (b0.b0_id[0] != BLOCK0_ID0 ||
                   1343:                                b0.b0_id[1] != BLOCK0_ID1)
                   1344:                MSG_OUTSTR("         [is not a swap file]");
                   1345:            else
                   1346:            {
                   1347:                MSG_OUTSTR("         file name: ");
                   1348:                msg_outstr(b0.b0_fname);
                   1349:
                   1350:                if (*(b0.b0_hname) != NUL)
                   1351:                {
                   1352:                    MSG_OUTSTR("\n         host name: ");
                   1353:                    msg_outstr(b0.b0_hname);
                   1354:                }
                   1355:
                   1356:                if (*(b0.b0_uname) != NUL)
                   1357:                {
                   1358:                    MSG_OUTSTR("\n         user name: ");
                   1359:                    msg_outstr(b0.b0_uname);
                   1360:                }
                   1361:
                   1362:                if (char_to_long(b0.b0_pid) != 0L)
                   1363:                {
                   1364:                    MSG_OUTSTR("\n        process ID: ");
                   1365:                    msg_outnum(char_to_long(b0.b0_pid));
                   1366: #if defined(UNIX) || defined(__EMX__)
                   1367:                    /* EMX kill() not working correctly, it seems */
                   1368:                    if (kill(char_to_long(b0.b0_pid), 0) == 0)
                   1369:                        MSG_OUTSTR(" (still running)");
                   1370: #endif
                   1371:                }
                   1372:
                   1373:                if (b0_magic_wrong(&b0))
                   1374:                {
                   1375: #if defined(MSDOS) || defined(WIN32)
                   1376:                    if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
                   1377:                        MSG_OUTSTR("\n         [not usable with this version of Vim]");
                   1378:                    else
                   1379: #endif
                   1380:                        MSG_OUTSTR("\n         [not usable on this computer]");
                   1381:                }
                   1382:
                   1383:            }
                   1384:        }
                   1385:        else
                   1386:            MSG_OUTSTR("         [cannot be read]");
                   1387:        close(fd);
                   1388:    }
                   1389:    else
                   1390:        MSG_OUTSTR("         [cannot be opened]");
                   1391:    msg_outchar('\n');
                   1392: }
                   1393:
                   1394:    static int
                   1395: get_names(names, fname)
                   1396:    char_u **names;
                   1397:    char_u  *fname;
                   1398: {
                   1399:    int     num_names;
                   1400:
                   1401: #ifdef SHORT_FNAME
                   1402:    /*
                   1403:     * (MS-DOS) always short names
                   1404:     */
                   1405:    names[0] = modname(fname, (char_u *)".sw?");
                   1406:    num_names = 1;
                   1407: #else /* !SHORT_FNAME */
                   1408: # ifdef WIN32
                   1409:    /*
                   1410:     * (WIN32) never short names
                   1411:     */
                   1412:    num_names = 1;
                   1413:    names[0] = concat_fnames(fname, (char_u *)".sw?", FALSE);
                   1414: # else /* !WIN32 */
                   1415:    /*
                   1416:     * (Not MS-DOS or WIN32) maybe short name, maybe not: try both.
                   1417:     * Only use the short name if it is different.
                   1418:     */
                   1419:
                   1420:    int     i;
                   1421:
                   1422:    names[0] = concat_fnames(fname, (char_u *)".sw?", FALSE);
                   1423:    i = curbuf->b_shortname;
                   1424:    curbuf->b_shortname = TRUE;
                   1425:    names[1] = modname(fname, (char_u *)".sw?");
                   1426:    curbuf->b_shortname = i;
                   1427:    if (STRCMP(names[0], names[1]) == 0)
                   1428:    {
                   1429:        vim_free(names[1]);
                   1430:        num_names = 1;
                   1431:    }
                   1432:    else
                   1433:        num_names = 2;
                   1434: # endif /* !WIN32 */
                   1435: #endif /* !SHORT_FNAME */
                   1436:    return num_names;
                   1437: }
                   1438:
                   1439: /*
                   1440:  * sync all memlines
                   1441:  *
                   1442:  * If 'check_file' is TRUE, check if original file exists and was not changed.
                   1443:  * If 'check_char' is TRUE, stop syncing when character becomes available, but
                   1444:  * always sync at least one block.
                   1445:  */
                   1446:    void
                   1447: ml_sync_all(check_file, check_char)
                   1448:    int     check_file;
                   1449:    int     check_char;
                   1450: {
                   1451:    BUF             *buf;
                   1452:    struct stat     st;
                   1453:
                   1454:    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
                   1455:    {
                   1456:        if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
                   1457:            continue;                       /* no file */
                   1458:
                   1459:        ml_flush_line(buf);                 /* flush buffered line */
                   1460:                                            /* flush locked block */
                   1461:        (void)ml_find_line(buf, (linenr_t)0, ML_FLUSH);
                   1462:        if (buf->b_changed && check_file && mf_need_trans(buf->b_ml.ml_mfp) &&
                   1463:                                    buf->b_filename != NULL)
                   1464:        {
                   1465:            /*
                   1466:             * if original file does not exist anymore or has been changed
                   1467:             * call ml_preserve to get rid of all negative numbered blocks
                   1468:             */
                   1469:            if (stat((char *)buf->b_filename, &st) == -1 ||
                   1470:                                st.st_mtime != buf->b_mtime_read)
                   1471:            {
                   1472:                ml_preserve(buf, FALSE);
                   1473:                need_check_timestamps = TRUE;   /* give message later */
                   1474:            }
                   1475:        }
                   1476:        if (buf->b_ml.ml_mfp->mf_dirty)
                   1477:        {
                   1478:            mf_sync(buf->b_ml.ml_mfp, FALSE, check_char, buf->b_changed);
                   1479:            if (check_char && mch_char_avail()) /* character available now */
                   1480:                break;
                   1481:        }
                   1482:    }
                   1483: }
                   1484:
                   1485: /*
                   1486:  * sync one buffer, including negative blocks
                   1487:  *
                   1488:  * after this all the blocks are in the swap file
                   1489:  *
                   1490:  * Used for the :preserve command and when the original file has been
                   1491:  * changed or deleted.
                   1492:  *
                   1493:  * when message is TRUE the success of preserving is reported
                   1494:  */
                   1495:    void
                   1496: ml_preserve(buf, message)
                   1497:    BUF     *buf;
                   1498:    int     message;
                   1499: {
                   1500:    BHDR        *hp;
                   1501:    linenr_t    lnum;
                   1502:    MEMFILE     *mfp = buf->b_ml.ml_mfp;
                   1503:    int         status;
                   1504:
                   1505:    if (mfp == NULL || mfp->mf_fname == NULL)
                   1506:    {
                   1507:        if (message)
                   1508:            EMSG("Cannot preserve, there is no swap file");
                   1509:        return;
                   1510:    }
                   1511:
                   1512:    ml_flush_line(buf);                             /* flush buffered line */
                   1513:    (void)ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush locked block */
                   1514:    status = mf_sync(mfp, TRUE, FALSE, TRUE);
                   1515:
                   1516:            /* stack is invalid after mf_sync(.., TRUE, ..) */
                   1517:    buf->b_ml.ml_stack_top = 0;
                   1518:
                   1519:    /*
                   1520:     * Some of the data blocks may have been changed from negative to
                   1521:     * positive block number. In that case the pointer blocks need to be
                   1522:     * updated.
                   1523:     *
                   1524:     * We don't know in which pointer block the references are, so we visit
                   1525:     * all data blocks until there are no more translations to be done (or
                   1526:     * we hit the end of the file, which can only happen in case a write fails,
                   1527:     * e.g. when file system if full).
                   1528:     * ml_find_line() does the work by translating the negative block numbers
                   1529:     * when getting the first line of each data block.
                   1530:     */
                   1531:    if (mf_need_trans(mfp))
                   1532:    {
                   1533:        lnum = 1;
                   1534:        while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
                   1535:        {
                   1536:            hp = ml_find_line(buf, lnum, ML_FIND);
                   1537:            if (hp == NULL)
                   1538:            {
                   1539:                status = FAIL;
                   1540:                goto theend;
                   1541:            }
                   1542:            CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
                   1543:            lnum = buf->b_ml.ml_locked_high + 1;
                   1544:        }
                   1545:        (void)ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush locked block */
                   1546:        if (mf_sync(mfp, TRUE, FALSE, TRUE) == FAIL)    /* sync the updated pointer blocks */
                   1547:            status = FAIL;
                   1548:        buf->b_ml.ml_stack_top = 0;         /* stack is invalid now */
                   1549:    }
                   1550: theend:
                   1551:    if (message)
                   1552:    {
                   1553:        if (status == OK)
                   1554:            MSG("File preserved");
                   1555:        else
                   1556:            EMSG("Preserve failed");
                   1557:    }
                   1558: }
                   1559:
                   1560: /*
                   1561:  * get a pointer to a (read-only copy of a) line
                   1562:  *
                   1563:  * On failure an error message is given and IObuff is returned (to avoid
                   1564:  * having to check for error everywhere).
                   1565:  */
                   1566:    char_u  *
                   1567: ml_get(lnum)
                   1568:    linenr_t    lnum;
                   1569: {
                   1570:    return ml_get_buf(curbuf, lnum, FALSE);
                   1571: }
                   1572:
                   1573: /*
                   1574:  * ml_get_pos: get pointer to position 'pos'
                   1575:  */
                   1576:     char_u *
                   1577: ml_get_pos(pos)
                   1578:     FPOS   *pos;
                   1579: {
                   1580:    return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
                   1581: }
                   1582:
                   1583: /*
                   1584:  * ml_get_pos: get pointer to cursor line.
                   1585:  */
                   1586:    char_u *
                   1587: ml_get_curline()
                   1588: {
                   1589:    return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
                   1590: }
                   1591:
                   1592: /*
                   1593:  * ml_get_pos: get pointer to cursor position
                   1594:  */
                   1595:    char_u *
                   1596: ml_get_cursor()
                   1597: {
                   1598:    return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
                   1599:                                                        curwin->w_cursor.col);
                   1600: }
                   1601:
                   1602: /*
                   1603:  * get a pointer to a line in a specific buffer
                   1604:  *
                   1605:  *  will_change: if TRUE mark the buffer dirty (chars in the line will be
                   1606:  *  changed)
                   1607:  */
                   1608:    char_u  *
                   1609: ml_get_buf(buf, lnum, will_change)
                   1610:    BUF         *buf;
                   1611:    linenr_t    lnum;
                   1612:    int         will_change;            /* line will be changed */
                   1613: {
                   1614:    BHDR    *hp;
                   1615:    DATA_BL *dp;
                   1616:    char_u  *ptr;
                   1617:
                   1618:    if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
                   1619:    {
                   1620:        EMSGN("ml_get: invalid lnum: %ld", lnum);
                   1621: errorret:
                   1622:        STRCPY(IObuff, "???");
                   1623:        return IObuff;
                   1624:    }
                   1625:    if (lnum <= 0)                      /* pretend line 0 is line 1 */
                   1626:        lnum = 1;
                   1627:
                   1628:    if (buf->b_ml.ml_mfp == NULL)       /* there are no lines */
                   1629:        return (char_u *)"";
                   1630:
                   1631: /*
                   1632:  * See if it is the same line as requested last time.
                   1633:  * Otherwise may need to flush last used line.
                   1634:  */
                   1635:    if (buf->b_ml.ml_line_lnum != lnum)
                   1636:    {
                   1637:        ml_flush_line(buf);
                   1638:
                   1639:        /*
                   1640:         * find the data block containing the line
                   1641:         * This also fills the stack with the blocks from the root to the data block
                   1642:         * This also releases any locked block.
                   1643:         */
                   1644:        if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
                   1645:        {
                   1646:            EMSGN("ml_get: cannot find line %ld", lnum);
                   1647:            goto errorret;
                   1648:        }
                   1649:
                   1650:        dp = (DATA_BL *)(hp->bh_data);
                   1651:
                   1652:        ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
                   1653:        buf->b_ml.ml_line_ptr = ptr;
                   1654:        buf->b_ml.ml_line_lnum = lnum;
                   1655:        buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
                   1656:    }
                   1657:    if (will_change)
                   1658:        buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
                   1659:
                   1660:    return buf->b_ml.ml_line_ptr;
                   1661: }
                   1662:
                   1663: /*
                   1664:  * Check if a line that was just obtained by a call to ml_get
                   1665:  * is in allocated memory.
                   1666:  */
                   1667:    int
                   1668: ml_line_alloced()
                   1669: {
                   1670:    return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
                   1671: }
                   1672:
                   1673: /*
                   1674:  * append a line after lnum (may be 0 to insert a line in front of the file)
                   1675:  *
                   1676:  *   newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
                   1677:  *             will be set for recovery
                   1678:  *
                   1679:  * return FAIL for failure, OK otherwise
                   1680:  */
                   1681:    int
                   1682: ml_append(lnum, line, len, newfile)
                   1683:    linenr_t    lnum;           /* append after this line (can be 0) */
                   1684:    char_u      *line;          /* text of the new line */
                   1685:    colnr_t     len;            /* length of new line, including NUL, or 0 */
                   1686:    int         newfile;        /* flag, see above */
                   1687: {
                   1688:    if (curbuf->b_ml.ml_line_lnum != 0)
                   1689:        ml_flush_line(curbuf);
                   1690:    return ml_append_int(curbuf, lnum, line, len, newfile);
                   1691: }
                   1692:
                   1693:    static int
                   1694: ml_append_int(buf, lnum, line, len, newfile)
                   1695:    BUF         *buf;
                   1696:    linenr_t    lnum;           /* append after this line (can be 0) */
                   1697:    char_u      *line;          /* text of the new line */
                   1698:    colnr_t     len;            /* length of line, including NUL, or 0 */
                   1699:    int         newfile;        /* flag, see above */
                   1700: {
                   1701:    int         i;
                   1702:    int         line_count;     /* number of indexes in current block */
                   1703:    int         offset;
                   1704:    int         from, to;
                   1705:    int         space_needed;   /* space needed for new line */
                   1706:    int         page_size;
                   1707:    int         page_count;
                   1708:    int         db_idx;         /* index for lnum in data block */
                   1709:    BHDR        *hp;
                   1710:    MEMFILE     *mfp;
                   1711:    DATA_BL     *dp;
                   1712:    PTR_BL      *pp;
                   1713:    IPTR        *ip;
                   1714:
                   1715:                                        /* lnum out of range */
                   1716:    if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
                   1717:        return FAIL;
                   1718:
                   1719:    if (lowest_marked && lowest_marked > lnum)
                   1720:        lowest_marked = lnum + 1;
                   1721:
                   1722:    if (len == 0)
                   1723:        len = STRLEN(line) + 1;         /* space needed for the text */
                   1724:    space_needed = len + INDEX_SIZE;    /* space needed for text + index */
                   1725:
                   1726:    mfp = buf->b_ml.ml_mfp;
                   1727:    page_size = mfp->mf_page_size;
                   1728:
                   1729: /*
                   1730:  * find the data block containing the previous line
                   1731:  * This also fills the stack with the blocks from the root to the data block
                   1732:  * This also releases any locked block.
                   1733:  */
                   1734:    if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_t)1 : lnum,
                   1735:                                                    ML_INSERT)) == NULL)
                   1736:        return FAIL;
                   1737:
                   1738:    buf->b_ml.ml_flags &= ~ML_EMPTY;
                   1739:
                   1740:    if (lnum == 0)              /* got line one instead, correct db_idx */
                   1741:        db_idx = -1;            /* careful, it is negative! */
                   1742:    else
                   1743:        db_idx = lnum - buf->b_ml.ml_locked_low;
                   1744:                /* get line count before the insertion */
                   1745:    line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
                   1746:
                   1747:    dp = (DATA_BL *)(hp->bh_data);
                   1748:
                   1749: /*
                   1750:  * If
                   1751:  * - there is not enough room in the current block
                   1752:  * - appending to the last line in the block
                   1753:  * - not appending to the last line in the file
                   1754:  * insert in front of the next block.
                   1755:  */
                   1756:    if ((int)dp->db_free < space_needed && db_idx == line_count - 1 &&
                   1757:                                            lnum < buf->b_ml.ml_line_count)
                   1758:    {
                   1759:        /*
                   1760:         * Now that the line is not going to be inserted in the block that we
                   1761:         * expected, the line count has to be adjusted in the pointer blocks
                   1762:         * by using ml_locked_lineadd.
                   1763:         */
                   1764:        --(buf->b_ml.ml_locked_lineadd);
                   1765:        --(buf->b_ml.ml_locked_high);
                   1766:        if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
                   1767:            return FAIL;
                   1768:
                   1769:        db_idx = -1;                /* careful, it is negative! */
                   1770:                    /* get line count before the insertion */
                   1771:        line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
                   1772:        CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
                   1773:
                   1774:        dp = (DATA_BL *)(hp->bh_data);
                   1775:    }
                   1776:
                   1777:    ++buf->b_ml.ml_line_count;
                   1778:
                   1779:    if ((int)dp->db_free >= space_needed)       /* enough room in data block */
                   1780:    {
                   1781: /*
                   1782:  * Insert new line in existing data block, or in data block allocated above.
                   1783:  */
                   1784:        dp->db_txt_start -= len;
                   1785:        dp->db_free -= space_needed;
                   1786:        ++(dp->db_line_count);
                   1787:
                   1788:        /*
                   1789:         * move the text of the lines that follow to the front
                   1790:         * adjust the indexes of the lines that follow
                   1791:         */
                   1792:        if (line_count > db_idx + 1)        /* if there are following lines */
                   1793:        {
                   1794:            /*
                   1795:             * Offset is the start of the previous line.
                   1796:             * This will become the character just after the new line.
                   1797:             */
                   1798:            if (db_idx < 0)
                   1799:                offset = dp->db_txt_end;
                   1800:            else
                   1801:                offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
                   1802:            vim_memmove((char *)dp + dp->db_txt_start,
                   1803:                                          (char *)dp + dp->db_txt_start + len,
                   1804:                                 (size_t)(offset - (dp->db_txt_start + len)));
                   1805:            for (i = line_count - 1; i > db_idx; --i)
                   1806:                dp->db_index[i + 1] = dp->db_index[i] - len;
                   1807:            dp->db_index[db_idx + 1] = offset - len;
                   1808:        }
                   1809:        else                                /* add line at the end */
                   1810:            dp->db_index[db_idx + 1] = dp->db_txt_start;
                   1811:
                   1812:        /*
                   1813:         * copy the text into the block
                   1814:         */
                   1815:        vim_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
                   1816:
                   1817:        /*
                   1818:         * Mark the block dirty.
                   1819:         */
                   1820:        buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
                   1821:        if (!newfile)
                   1822:            buf->b_ml.ml_flags |= ML_LOCKED_POS;
                   1823:    }
                   1824:    else            /* not enough space in data block */
                   1825:    {
                   1826: /*
                   1827:  * If there is not enough room we have to create a new data block and copy some
                   1828:  * lines into it.
                   1829:  * Then we have to insert an entry in the pointer block.
                   1830:  * If this pointer block also is full, we go up another block, and so on, up
                   1831:  * to the root if necessary.
                   1832:  * The line counts in the pointer blocks have already been adjusted by
                   1833:  * ml_find_line().
                   1834:  */
                   1835:        long        line_count_left, line_count_right;
                   1836:        int         page_count_left, page_count_right;
                   1837:        BHDR        *hp_left;
                   1838:        BHDR        *hp_right;
                   1839:        BHDR        *hp_new;
                   1840:        int         lines_moved;
                   1841:        int         data_moved = 0;         /* init to shut up gcc */
                   1842:        int         total_moved = 0;        /* init to shut up gcc */
                   1843:        DATA_BL     *dp_right, *dp_left;
                   1844:        int         stack_idx;
                   1845:        int         in_left;
                   1846:        int         lineadd;
                   1847:        blocknr_t   bnum_left, bnum_right;
                   1848:        linenr_t    lnum_left, lnum_right;
                   1849:        int         pb_idx;
                   1850:        PTR_BL      *pp_new;
                   1851:
                   1852:        /*
                   1853:         * We are going to allocate a new data block. Depending on the
                   1854:         * situation it will be put to the left or right of the existing
                   1855:         * block.  If possible we put the new line in the left block and move
                   1856:         * the lines after it to the right block. Otherwise the new line is
                   1857:         * also put in the right block. This method is more efficient when
                   1858:         * inserting a lot of lines at one place.
                   1859:         */
                   1860:        if (db_idx < 0)         /* left block is new, right block is existing */
                   1861:        {
                   1862:            lines_moved = 0;
                   1863:            in_left = TRUE;
                   1864:            /* space_needed does not change */
                   1865:        }
                   1866:        else                    /* left block is existing, right block is new */
                   1867:        {
                   1868:            lines_moved = line_count - db_idx - 1;
                   1869:            if (lines_moved == 0)
                   1870:                in_left = FALSE;        /* put new line in right block */
                   1871:                                        /* space_needed does not change */
                   1872:            else
                   1873:            {
                   1874:                data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
                   1875:                                                            dp->db_txt_start;
                   1876:                total_moved = data_moved + lines_moved * INDEX_SIZE;
                   1877:                if ((int)dp->db_free + total_moved >= space_needed)
                   1878:                {
                   1879:                    in_left = TRUE;     /* put new line in left block */
                   1880:                    space_needed = total_moved;
                   1881:                }
                   1882:                else
                   1883:                {
                   1884:                    in_left = FALSE;        /* put new line in right block */
                   1885:                    space_needed += total_moved;
                   1886:                }
                   1887:            }
                   1888:        }
                   1889:
                   1890:        page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
                   1891:        if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
                   1892:        {
                   1893:                        /* correct line counts in pointer blocks */
                   1894:            --(buf->b_ml.ml_locked_lineadd);
                   1895:            --(buf->b_ml.ml_locked_high);
                   1896:            return FAIL;
                   1897:        }
                   1898:        if (db_idx < 0)         /* left block is new */
                   1899:        {
                   1900:            hp_left = hp_new;
                   1901:            hp_right = hp;
                   1902:            line_count_left = 0;
                   1903:            line_count_right = line_count;
                   1904:        }
                   1905:        else                    /* right block is new */
                   1906:        {
                   1907:            hp_left = hp;
                   1908:            hp_right = hp_new;
                   1909:            line_count_left = line_count;
                   1910:            line_count_right = 0;
                   1911:        }
                   1912:        dp_right = (DATA_BL *)(hp_right->bh_data);
                   1913:        dp_left = (DATA_BL *)(hp_left->bh_data);
                   1914:        bnum_left = hp_left->bh_bnum;
                   1915:        bnum_right = hp_right->bh_bnum;
                   1916:        page_count_left = hp_left->bh_page_count;
                   1917:        page_count_right = hp_right->bh_page_count;
                   1918:
                   1919:        /*
                   1920:         * May move the new line into the right/new block.
                   1921:         */
                   1922:        if (!in_left)
                   1923:        {
                   1924:            dp_right->db_txt_start -= len;
                   1925:            dp_right->db_free -= len + INDEX_SIZE;
                   1926:            dp_right->db_index[0] = dp_right->db_txt_start;
                   1927:            vim_memmove((char *)dp_right + dp_right->db_txt_start,
                   1928:                                                           line, (size_t)len);
                   1929:            ++line_count_right;
                   1930:        }
                   1931:        /*
                   1932:         * may move lines from the left/old block to the right/new one.
                   1933:         */
                   1934:        if (lines_moved)
                   1935:        {
                   1936:            /*
                   1937:             */
                   1938:            dp_right->db_txt_start -= data_moved;
                   1939:            dp_right->db_free -= total_moved;
                   1940:            vim_memmove((char *)dp_right + dp_right->db_txt_start,
                   1941:                        (char *)dp_left + dp_left->db_txt_start,
                   1942:                        (size_t)data_moved);
                   1943:            offset = dp_right->db_txt_start - dp_left->db_txt_start;
                   1944:            dp_left->db_txt_start += data_moved;
                   1945:            dp_left->db_free += total_moved;
                   1946:
                   1947:            /*
                   1948:             * update indexes in the new block
                   1949:             */
                   1950:            for (to = line_count_right, from = db_idx + 1;
                   1951:                                         from < line_count_left; ++from, ++to)
                   1952:                dp_right->db_index[to] = dp->db_index[from] + offset;
                   1953:            line_count_right += lines_moved;
                   1954:            line_count_left -= lines_moved;
                   1955:        }
                   1956:
                   1957:        /*
                   1958:         * May move the new line into the left (old or new) block.
                   1959:         */
                   1960:        if (in_left)
                   1961:        {
                   1962:            dp_left->db_txt_start -= len;
                   1963:            dp_left->db_free -= len + INDEX_SIZE;
                   1964:            dp_left->db_index[line_count_left] = dp_left->db_txt_start;
                   1965:            vim_memmove((char *)dp_left + dp_left->db_txt_start,
                   1966:                                                           line, (size_t)len);
                   1967:            ++line_count_left;
                   1968:        }
                   1969:
                   1970:        if (db_idx < 0)         /* left block is new */
                   1971:        {
                   1972:            lnum_left = lnum + 1;
                   1973:            lnum_right = 0;
                   1974:        }
                   1975:        else                    /* right block is new */
                   1976:        {
                   1977:            lnum_left = 0;
                   1978:            if (in_left)
                   1979:                lnum_right = lnum + 2;
                   1980:            else
                   1981:                lnum_right = lnum + 1;
                   1982:        }
                   1983:        dp_left->db_line_count = line_count_left;
                   1984:        dp_right->db_line_count = line_count_right;
                   1985:
                   1986:        /*
                   1987:         * release the two data blocks
                   1988:         * The new one (hp_new) already has a correct blocknumber.
                   1989:         * The old one (hp, in ml_locked) gets a positive blocknumber if
                   1990:         * we changed it and we are not editing a new file.
                   1991:         */
                   1992:        if (lines_moved || in_left)
                   1993:            buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
                   1994:        if (!newfile && db_idx >= 0 && in_left)
                   1995:            buf->b_ml.ml_flags |= ML_LOCKED_POS;
                   1996:        mf_put(mfp, hp_new, TRUE, FALSE);
                   1997:
                   1998:        /*
                   1999:         * flush the old data block
                   2000:         * set ml_locked_lineadd to 0, because the updating of the
                   2001:         * pointer blocks is done below
                   2002:         */
                   2003:        lineadd = buf->b_ml.ml_locked_lineadd;
                   2004:        buf->b_ml.ml_locked_lineadd = 0;
                   2005:        ml_find_line(buf, (linenr_t)0, ML_FLUSH);   /* flush data block */
                   2006:
                   2007:        /*
                   2008:         * update pointer blocks for the new data block
                   2009:         */
                   2010:        for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; --stack_idx)
                   2011:        {
                   2012:            ip = &(buf->b_ml.ml_stack[stack_idx]);
                   2013:            pb_idx = ip->ip_index;
                   2014:            if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
                   2015:                return FAIL;
                   2016:            pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
                   2017:            if (pp->pb_id != PTR_ID)
                   2018:            {
                   2019:                EMSG("pointer block id wrong 3");
                   2020:                mf_put(mfp, hp, FALSE, FALSE);
                   2021:                return FAIL;
                   2022:            }
                   2023:            /*
                   2024:             * TODO: If the pointer block is full and we are adding at the end
                   2025:             * try to insert in front of the next block
                   2026:             */
                   2027:            if (pp->pb_count < pp->pb_count_max)    /* block not full, add one entry */
                   2028:            {
                   2029:                if (pb_idx + 1 < (int)pp->pb_count)
                   2030:                    vim_memmove(&pp->pb_pointer[pb_idx + 2],
                   2031:                                &pp->pb_pointer[pb_idx + 1],
                   2032:                        (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
                   2033:                ++pp->pb_count;
                   2034:                pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
                   2035:                pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
                   2036:                pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
                   2037:                pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
                   2038:                pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
                   2039:                pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
                   2040:
                   2041:                if (lnum_left != 0)
                   2042:                    pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
                   2043:                if (lnum_right != 0)
                   2044:                    pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
                   2045:
                   2046:                mf_put(mfp, hp, TRUE, FALSE);
                   2047:                buf->b_ml.ml_stack_top = stack_idx + 1;     /* truncate stack */
                   2048:
                   2049:                if (lineadd)
                   2050:                {
                   2051:                    --(buf->b_ml.ml_stack_top);
                   2052:                        /* fix line count for rest of blocks in the stack */
                   2053:                    ml_lineadd(buf, lineadd);
                   2054:                                                        /* fix stack itself */
                   2055:                    buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
                   2056:                                                                      lineadd;
                   2057:                    ++(buf->b_ml.ml_stack_top);
                   2058:                }
                   2059:
                   2060:                return OK;
                   2061:            }
                   2062:            else                        /* pointer block full */
                   2063:            {
                   2064:                /*
                   2065:                 * split the pointer block
                   2066:                 * allocate a new pointer block
                   2067:                 * move some of the pointer into the new block
                   2068:                 * prepare for updating the parent block
                   2069:                 */
                   2070:                for (;;)        /* do this twice when splitting block 1 */
                   2071:                {
                   2072:                    hp_new = ml_new_ptr(mfp);
                   2073:                    if (hp_new == NULL)     /* TODO: try to fix tree */
                   2074:                        return FAIL;
                   2075:                    pp_new = (PTR_BL *)(hp_new->bh_data);
                   2076:
                   2077:                    if (hp->bh_bnum != 1)
                   2078:                        break;
                   2079:
                   2080:                    /*
                   2081:                     * if block 1 becomes full the tree is given an extra level
                   2082:                     * The pointers from block 1 are moved into the new block.
                   2083:                     * block 1 is updated to point to the new block
                   2084:                     * then continue to split the new block
                   2085:                     */
                   2086:                    vim_memmove(pp_new, pp, (size_t)page_size);
                   2087:                    pp->pb_count = 1;
                   2088:                    pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
                   2089:                    pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
                   2090:                    pp->pb_pointer[0].pe_old_lnum = 1;
                   2091:                    pp->pb_pointer[0].pe_page_count = 1;
                   2092:                    mf_put(mfp, hp, TRUE, FALSE);   /* release block 1 */
                   2093:                    hp = hp_new;                    /* new block is to be split */
                   2094:                    pp = pp_new;
                   2095:                    CHECK(stack_idx != 0, "stack_idx should be 0");
                   2096:                    ip->ip_index = 0;
                   2097:                    ++stack_idx;        /* do block 1 again later */
                   2098:                }
                   2099:                /*
                   2100:                 * move the pointers after the current one to the new block
                   2101:                 * If there are none, the new entry will be in the new block.
                   2102:                 */
                   2103:                total_moved = pp->pb_count - pb_idx - 1;
                   2104:                if (total_moved)
                   2105:                {
                   2106:                    vim_memmove(&pp_new->pb_pointer[0],
                   2107:                                &pp->pb_pointer[pb_idx + 1],
                   2108:                                (size_t)(total_moved) * sizeof(PTR_EN));
                   2109:                    pp_new->pb_count = total_moved;
                   2110:                    pp->pb_count -= total_moved - 1;
                   2111:                    pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
                   2112:                    pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
                   2113:                    pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
                   2114:                    if (lnum_right)
                   2115:                        pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
                   2116:                }
                   2117:                else
                   2118:                {
                   2119:                    pp_new->pb_count = 1;
                   2120:                    pp_new->pb_pointer[0].pe_bnum = bnum_right;
                   2121:                    pp_new->pb_pointer[0].pe_line_count = line_count_right;
                   2122:                    pp_new->pb_pointer[0].pe_page_count = page_count_right;
                   2123:                    pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
                   2124:                }
                   2125:                pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
                   2126:                pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
                   2127:                pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
                   2128:                if (lnum_left)
                   2129:                    pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
                   2130:                lnum_left = 0;
                   2131:                lnum_right = 0;
                   2132:
                   2133:                /*
                   2134:                 * recompute line counts
                   2135:                 */
                   2136:                line_count_right = 0;
                   2137:                for (i = 0; i < (int)pp_new->pb_count; ++i)
                   2138:                    line_count_right += pp_new->pb_pointer[i].pe_line_count;
                   2139:                line_count_left = 0;
                   2140:                for (i = 0; i < (int)pp->pb_count; ++i)
                   2141:                    line_count_left += pp->pb_pointer[i].pe_line_count;
                   2142:
                   2143:                bnum_left = hp->bh_bnum;
                   2144:                bnum_right = hp_new->bh_bnum;
                   2145:                page_count_left = 1;
                   2146:                page_count_right = 1;
                   2147:                mf_put(mfp, hp, TRUE, FALSE);
                   2148:                mf_put(mfp, hp_new, TRUE, FALSE);
                   2149:            }
                   2150:        }
                   2151:        EMSG("Updated too many blocks?");
                   2152:        buf->b_ml.ml_stack_top = 0;     /* invalidate stack */
                   2153:    }
                   2154:    return OK;
                   2155: }
                   2156:
                   2157: /*
                   2158:  * replace line lnum, with buffering, in current buffer
                   2159:  *
                   2160:  * If copy is TRUE, make a copy of the line, otherwise the line has been
                   2161:  * copied to allocated memory already.
                   2162:  *
                   2163:  * return FAIL for failure, OK otherwise
                   2164:  */
                   2165:    int
                   2166: ml_replace(lnum, line, copy)
                   2167:    linenr_t    lnum;
                   2168:    char_u      *line;
                   2169:    int         copy;
                   2170: {
                   2171:    if (line == NULL)           /* just checking... */
                   2172:        return FAIL;
                   2173:
                   2174:    if (curbuf->b_ml.ml_line_lnum != lnum)          /* other line buffered */
                   2175:        ml_flush_line(curbuf);                      /* flush it */
                   2176:    else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
                   2177:        vim_free(curbuf->b_ml.ml_line_ptr);         /* free it */
                   2178:    if (copy && (line = strsave(line)) == NULL)     /* allocate memory */
                   2179:        return FAIL;
                   2180:    curbuf->b_ml.ml_line_ptr = line;
                   2181:    curbuf->b_ml.ml_line_lnum = lnum;
                   2182:    curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
                   2183:
                   2184:    return OK;
                   2185: }
                   2186:
                   2187: /*
                   2188:  * delete line 'lnum'
                   2189:  *
                   2190:  * return FAIL for failure, OK otherwise
                   2191:  */
                   2192:    int
                   2193: ml_delete(lnum, message)
                   2194:    linenr_t    lnum;
                   2195:    int         message;
                   2196: {
                   2197:    ml_flush_line(curbuf);
                   2198:    return ml_delete_int(curbuf, lnum, message);
                   2199: }
                   2200:
                   2201:    static int
                   2202: ml_delete_int(buf, lnum, message)
                   2203:    BUF         *buf;
                   2204:    linenr_t    lnum;
                   2205:    int         message;
                   2206: {
                   2207:    BHDR    *hp;
                   2208:    MEMFILE *mfp;
                   2209:    DATA_BL *dp;
                   2210:    PTR_BL  *pp;
                   2211:    IPTR    *ip;
                   2212:    int     count;          /* number of entries in block */
                   2213:    int     idx;
                   2214:    int     stack_idx;
                   2215:    int     text_start;
                   2216:    int     line_start;
                   2217:    int     line_size;
                   2218:    int     i;
                   2219:
                   2220:    if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
                   2221:        return FAIL;
                   2222:
                   2223:    if (lowest_marked && lowest_marked > lnum)
                   2224:        lowest_marked--;
                   2225:
                   2226: /*
                   2227:  * If the file becomes empty the last line is replaced by an empty line.
                   2228:  */
                   2229:    if (buf->b_ml.ml_line_count == 1)       /* file becomes empty */
                   2230:    {
                   2231:        if (message)
                   2232:            keep_msg = no_lines_msg;
                   2233:        i = ml_replace((linenr_t)1, (char_u *)"", TRUE);
                   2234:        buf->b_ml.ml_flags |= ML_EMPTY;
                   2235:        return i;
                   2236:    }
                   2237:
                   2238: /*
                   2239:  * find the data block containing the line
                   2240:  * This also fills the stack with the blocks from the root to the data block
                   2241:  * This also releases any locked block.
                   2242:  */
                   2243:    mfp = buf->b_ml.ml_mfp;
                   2244:    if (mfp == NULL)
                   2245:        return FAIL;
                   2246:
                   2247:    if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
                   2248:        return FAIL;
                   2249:
                   2250:    dp = (DATA_BL *)(hp->bh_data);
                   2251:            /* compute line count before the delete */
                   2252:    count = (long)(buf->b_ml.ml_locked_high) - (long)(buf->b_ml.ml_locked_low) + 2;
                   2253:    idx = lnum - buf->b_ml.ml_locked_low;
                   2254:
                   2255:    --buf->b_ml.ml_line_count;
                   2256:
                   2257: /*
                   2258:  * special case: If there is only one line in the data block it becomes empty.
                   2259:  * Then we have to remove the entry, pointing to this data block, from the
                   2260:  * pointer block. If this pointer block also becomes empty, we go up another
                   2261:  * block, and so on, up to the root if necessary.
                   2262:  * The line counts in the pointer blocks have already been adjusted by
                   2263:  * ml_find_line().
                   2264:  */
                   2265:    if (count == 1)
                   2266:    {
                   2267:        mf_free(mfp, hp);       /* free the data block */
                   2268:        buf->b_ml.ml_locked = NULL;
                   2269:
                   2270:        for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; --stack_idx)
                   2271:        {
                   2272:            buf->b_ml.ml_stack_top = 0;     /* stack is invalid when failing */
                   2273:            ip = &(buf->b_ml.ml_stack[stack_idx]);
                   2274:            idx = ip->ip_index;
                   2275:            if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
                   2276:                return FAIL;
                   2277:            pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
                   2278:            if (pp->pb_id != PTR_ID)
                   2279:            {
                   2280:                EMSG("pointer block id wrong 4");
                   2281:                mf_put(mfp, hp, FALSE, FALSE);
                   2282:                return FAIL;
                   2283:            }
                   2284:            count = --(pp->pb_count);
                   2285:            if (count == 0)         /* the pointer block becomes empty! */
                   2286:                mf_free(mfp, hp);
                   2287:            else
                   2288:            {
                   2289:                if (count != idx)       /* move entries after the deleted one */
                   2290:                    vim_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
                   2291:                                      (size_t)(count - idx) * sizeof(PTR_EN));
                   2292:                mf_put(mfp, hp, TRUE, FALSE);
                   2293:
                   2294:                buf->b_ml.ml_stack_top = stack_idx;     /* truncate stack */
                   2295:                    /* fix line count for rest of blocks in the stack */
                   2296:                if (buf->b_ml.ml_locked_lineadd)
                   2297:                {
                   2298:                    ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
                   2299:                    buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
                   2300:                                                buf->b_ml.ml_locked_lineadd;
                   2301:                }
                   2302:                ++(buf->b_ml.ml_stack_top);
                   2303:
                   2304:                return OK;
                   2305:            }
                   2306:        }
                   2307:        CHECK(1, "deleted block 1?");
                   2308:
                   2309:        return OK;
                   2310:    }
                   2311:
                   2312:    /*
                   2313:     * delete the text by moving the next lines forwards
                   2314:     */
                   2315:    text_start = dp->db_txt_start;
                   2316:    line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
                   2317:    if (idx == 0)               /* first line in block, text at the end */
                   2318:        line_size = dp->db_txt_end - line_start;
                   2319:    else
                   2320:        line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
                   2321:    vim_memmove((char *)dp + text_start + line_size, (char *)dp + text_start,
                   2322:                                           (size_t)(line_start - text_start));
                   2323:
                   2324:    /*
                   2325:     * delete the index by moving the next indexes backwards
                   2326:     * Adjust the indexes for the text movement.
                   2327:     */
                   2328:    for (i = idx; i < count - 1; ++i)
                   2329:        dp->db_index[i] = dp->db_index[i + 1] + line_size;
                   2330:
                   2331:    dp->db_free += line_size + INDEX_SIZE;
                   2332:    dp->db_txt_start += line_size;
                   2333:    --(dp->db_line_count);
                   2334:
                   2335:    /*
                   2336:     * mark the block dirty and make sure it is in the file (for recovery)
                   2337:     */
                   2338:    buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
                   2339:
                   2340:    return OK;
                   2341: }
                   2342:
                   2343: /*
                   2344:  * set the B_MARKED flag for line 'lnum'
                   2345:  */
                   2346:    void
                   2347: ml_setmarked(lnum)
                   2348:    linenr_t lnum;
                   2349: {
                   2350:    BHDR    *hp;
                   2351:    DATA_BL *dp;
                   2352:                                    /* invalid line number */
                   2353:    if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count ||
                   2354:                                                curbuf->b_ml.ml_mfp == NULL)
                   2355:        return;                     /* give error message? */
                   2356:
                   2357:    if (lowest_marked == 0 || lowest_marked > lnum)
                   2358:        lowest_marked = lnum;
                   2359:
                   2360:    /*
                   2361:     * find the data block containing the line
                   2362:     * This also fills the stack with the blocks from the root to the data block
                   2363:     * This also releases any locked block.
                   2364:     */
                   2365:    if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
                   2366:        return;             /* give error message? */
                   2367:
                   2368:    dp = (DATA_BL *)(hp->bh_data);
                   2369:    dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
                   2370:    curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
                   2371: }
                   2372:
                   2373: /*
                   2374:  * find the first line with its B_MARKED flag set
                   2375:  */
                   2376:    linenr_t
                   2377: ml_firstmarked()
                   2378: {
                   2379:    BHDR        *hp;
                   2380:    DATA_BL     *dp;
                   2381:    linenr_t    lnum;
                   2382:    int         i;
                   2383:
                   2384:    if (curbuf->b_ml.ml_mfp == NULL)
                   2385:        return (linenr_t) 0;
                   2386:
                   2387:    /*
                   2388:     * The search starts with lowest_marked line. This is the last line where
                   2389:     * a mark was found, adjusted by inserting/deleting lines.
                   2390:     */
                   2391:    for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
                   2392:    {
                   2393:        /*
                   2394:         * Find the data block containing the line.
                   2395:         * This also fills the stack with the blocks from the root to the data
                   2396:         * block This also releases any locked block.
                   2397:         */
                   2398:        if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
                   2399:            return (linenr_t)0;             /* give error message? */
                   2400:
                   2401:        dp = (DATA_BL *)(hp->bh_data);
                   2402:
                   2403:        for (i = lnum - curbuf->b_ml.ml_locked_low;
                   2404:                            lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
                   2405:            if ((dp->db_index[i]) & DB_MARKED)
                   2406:            {
                   2407:                (dp->db_index[i]) &= DB_INDEX_MASK;
                   2408:                curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
                   2409:                lowest_marked = lnum + 1;
                   2410:                return lnum;
                   2411:            }
                   2412:    }
                   2413:
                   2414:    return (linenr_t) 0;
                   2415: }
                   2416:
                   2417: /*
                   2418:  * return TRUE if line 'lnum' has a mark
                   2419:  */
                   2420:    int
                   2421: ml_has_mark(lnum)
                   2422:    linenr_t    lnum;
                   2423: {
                   2424:    BHDR        *hp;
                   2425:    DATA_BL     *dp;
                   2426:
                   2427:    if (curbuf->b_ml.ml_mfp == NULL ||
                   2428:                        (hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
                   2429:        return FALSE;
                   2430:
                   2431:    dp = (DATA_BL *)(hp->bh_data);
                   2432:    return (int)((dp->db_index[lnum - curbuf->b_ml.ml_locked_low]) & DB_MARKED);
                   2433: }
                   2434:
                   2435: /*
                   2436:  * clear all DB_MARKED flags
                   2437:  */
                   2438:    void
                   2439: ml_clearmarked()
                   2440: {
                   2441:    BHDR        *hp;
                   2442:    DATA_BL     *dp;
                   2443:    linenr_t    lnum;
                   2444:    int         i;
                   2445:
                   2446:    if (curbuf->b_ml.ml_mfp == NULL)        /* nothing to do */
                   2447:        return;
                   2448:
                   2449:    /*
                   2450:     * The search starts with line lowest_marked.
                   2451:     */
                   2452:    for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
                   2453:    {
                   2454:        /*
                   2455:         * Find the data block containing the line.
                   2456:         * This also fills the stack with the blocks from the root to the data block
                   2457:         * This also releases any locked block.
                   2458:         */
                   2459:        if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
                   2460:            return;             /* give error message? */
                   2461:
                   2462:        dp = (DATA_BL *)(hp->bh_data);
                   2463:
                   2464:        for (i = lnum - curbuf->b_ml.ml_locked_low;
                   2465:                            lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
                   2466:            if ((dp->db_index[i]) & DB_MARKED)
                   2467:            {
                   2468:                (dp->db_index[i]) &= DB_INDEX_MASK;
                   2469:                curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
                   2470:            }
                   2471:    }
                   2472:
                   2473:    lowest_marked = 0;
                   2474:    return;
                   2475: }
                   2476:
                   2477: /*
                   2478:  * flush ml_line if necessary
                   2479:  */
                   2480:    static void
                   2481: ml_flush_line(buf)
                   2482:    BUF     *buf;
                   2483: {
                   2484:    BHDR        *hp;
                   2485:    DATA_BL     *dp;
                   2486:    linenr_t    lnum;
                   2487:    char_u      *new_line;
                   2488:    char_u      *old_line;
                   2489:    colnr_t     new_len;
                   2490:    int         old_len;
                   2491:    int         extra;
                   2492:    int         idx;
                   2493:    int         start;
                   2494:    int         count;
                   2495:    int         i;
                   2496:
                   2497:    if (buf->b_ml.ml_line_lnum == 0 ||
                   2498:                        buf->b_ml.ml_mfp == NULL)       /* nothing to do */
                   2499:        return;
                   2500:
                   2501:    if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
                   2502:    {
                   2503:        lnum = buf->b_ml.ml_line_lnum;
                   2504:        new_line = buf->b_ml.ml_line_ptr;
                   2505:
                   2506:        hp = ml_find_line(buf, lnum, ML_FIND);
                   2507:        if (hp == NULL)
                   2508:            EMSGN("Cannot find line %ld", lnum);
                   2509:        else
                   2510:        {
                   2511:            dp = (DATA_BL *)(hp->bh_data);
                   2512:            idx = lnum - buf->b_ml.ml_locked_low;
                   2513:            start = ((dp->db_index[idx]) & DB_INDEX_MASK);
                   2514:            old_line = (char_u *)dp + start;
                   2515:            if (idx == 0)       /* line is last in block */
                   2516:                old_len = dp->db_txt_end - start;
                   2517:            else                /* text of previous line follows */
                   2518:                old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
                   2519:            new_len = STRLEN(new_line) + 1;
                   2520:            extra = new_len - old_len;      /* negative if lines gets smaller */
                   2521:
                   2522:            /*
                   2523:             * if new line fits in data block, replace directly
                   2524:             */
                   2525:            if ((int)dp->db_free >= extra)
                   2526:            {
                   2527:                    /* if the length changes and there are following lines */
                   2528:                count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
                   2529:                if (extra != 0 && idx < count - 1)
                   2530:                {
                   2531:                        /* move text of following lines */
                   2532:                    vim_memmove((char *)dp + dp->db_txt_start - extra,
                   2533:                                (char *)dp + dp->db_txt_start,
                   2534:                                (size_t)(start - dp->db_txt_start));
                   2535:
                   2536:                        /* adjust pointers of this and following lines */
                   2537:                    for (i = idx + 1; i < count; ++i)
                   2538:                        dp->db_index[i] -= extra;
                   2539:                }
                   2540:                dp->db_index[idx] -= extra;
                   2541:
                   2542:                    /* adjust free space */
                   2543:                dp->db_free -= extra;
                   2544:                dp->db_txt_start -= extra;
                   2545:
                   2546:                    /* copy new line into the data block */
                   2547:                vim_memmove(old_line - extra, new_line, (size_t)new_len);
                   2548:                buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
                   2549:            }
                   2550:            else
                   2551:            {
                   2552:                /*
                   2553:                 * Cannot do it in one data block: delete and append.
                   2554:                 */
                   2555:                    /* How about handling errors??? */
                   2556:                (void)ml_delete_int(buf, lnum, FALSE);
                   2557:                (void)ml_append_int(buf, lnum - 1, new_line, new_len, FALSE);
                   2558:            }
                   2559:        }
                   2560:        vim_free(new_line);
                   2561:    }
                   2562:
                   2563:    buf->b_ml.ml_line_lnum = 0;
                   2564: }
                   2565:
                   2566: /*
                   2567:  * create a new, empty, data block
                   2568:  */
                   2569:    static BHDR *
                   2570: ml_new_data(mfp, negative, page_count)
                   2571:    MEMFILE     *mfp;
                   2572:    int         negative;
                   2573:    int         page_count;
                   2574: {
                   2575:    BHDR        *hp;
                   2576:    DATA_BL     *dp;
                   2577:
                   2578:    if ((hp = mf_new(mfp, negative, page_count)) == NULL)
                   2579:        return NULL;
                   2580:
                   2581:    dp = (DATA_BL *)(hp->bh_data);
                   2582:    dp->db_id = DATA_ID;
                   2583:    dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
                   2584:    dp->db_free = dp->db_txt_start - HEADER_SIZE;
                   2585:    dp->db_line_count = 0;
                   2586:
                   2587:    return hp;
                   2588: }
                   2589:
                   2590: /*
                   2591:  * create a new, empty, pointer block
                   2592:  */
                   2593:    static BHDR *
                   2594: ml_new_ptr(mfp)
                   2595:    MEMFILE     *mfp;
                   2596: {
                   2597:    BHDR        *hp;
                   2598:    PTR_BL      *pp;
                   2599:
                   2600:    if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
                   2601:        return NULL;
                   2602:
                   2603:    pp = (PTR_BL *)(hp->bh_data);
                   2604:    pp->pb_id = PTR_ID;
                   2605:    pp->pb_count = 0;
                   2606:    pp->pb_count_max = (mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1;
                   2607:
                   2608:    return hp;
                   2609: }
                   2610:
                   2611: /*
                   2612:  * lookup line 'lnum' in a memline
                   2613:  *
                   2614:  *   action: if ML_DELETE or ML_INSERT the line count is updated while searching
                   2615:  *          if ML_FLUSH only flush a locked block
                   2616:  *          if ML_FIND just find the line
                   2617:  *
                   2618:  * If the block was found it is locked and put in ml_locked.
                   2619:  * The stack is updated to lead to the locked block. The ip_high field in
                   2620:  * the stack is updated to reflect the last line in the block AFTER the
                   2621:  * insert or delete, also if the pointer block has not been updated yet. But
                   2622:  * if if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
                   2623:  *
                   2624:  * return: NULL for failure, pointer to block header otherwise
                   2625:  */
                   2626:    static BHDR *
                   2627: ml_find_line(buf, lnum, action)
                   2628:    BUF         *buf;
                   2629:    linenr_t    lnum;
                   2630:    int         action;
                   2631: {
                   2632:    DATA_BL     *dp;
                   2633:    PTR_BL      *pp;
                   2634:    IPTR        *ip;
                   2635:    BHDR        *hp;
                   2636:    MEMFILE     *mfp;
                   2637:    linenr_t    t;
                   2638:    blocknr_t   bnum, bnum2;
                   2639:    int         dirty;
                   2640:    linenr_t    low, high;
                   2641:    int         top;
                   2642:    int         page_count;
                   2643:    int         idx;
                   2644:
                   2645:    mfp = buf->b_ml.ml_mfp;
                   2646:
                   2647:    /*
                   2648:     * If there is a locked block check if the wanted line is in it.
                   2649:     * If not, flush and release the locked block.
                   2650:     * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
                   2651:     * Don't do this for ML_FLUSH, because we want to flush the locked block.
                   2652:     */
                   2653:    if (buf->b_ml.ml_locked)
                   2654:    {
                   2655:        if (ML_SIMPLE(action) && buf->b_ml.ml_locked_low <= lnum &&
                   2656:                                    buf->b_ml.ml_locked_high >= lnum)
                   2657:        {
                   2658:                /* remember to update pointer blocks and stack later */
                   2659:            if (action == ML_INSERT)
                   2660:            {
                   2661:                ++(buf->b_ml.ml_locked_lineadd);
                   2662:                ++(buf->b_ml.ml_locked_high);
                   2663:            }
                   2664:            else if (action == ML_DELETE)
                   2665:            {
                   2666:                --(buf->b_ml.ml_locked_lineadd);
                   2667:                --(buf->b_ml.ml_locked_high);
                   2668:            }
                   2669:            return (buf->b_ml.ml_locked);
                   2670:        }
                   2671:
                   2672:        mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
                   2673:                                            buf->b_ml.ml_flags & ML_LOCKED_POS);
                   2674:        buf->b_ml.ml_locked = NULL;
                   2675:
                   2676:            /*
                   2677:             * if lines have been added or deleted in the locked block, need to
                   2678:             * update the line count in pointer blocks
                   2679:             */
                   2680:        if (buf->b_ml.ml_locked_lineadd)
                   2681:            ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
                   2682:    }
                   2683:
                   2684:    if (action == ML_FLUSH)         /* nothing else to do */
                   2685:        return NULL;
                   2686:
                   2687:    bnum = 1;                       /* start at the root of the tree */
                   2688:    page_count = 1;
                   2689:    low = 1;
                   2690:    high = buf->b_ml.ml_line_count;
                   2691:
                   2692:    if (action == ML_FIND)      /* first try stack entries */
                   2693:    {
                   2694:        for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
                   2695:        {
                   2696:            ip = &(buf->b_ml.ml_stack[top]);
                   2697:            if (ip->ip_low <= lnum && ip->ip_high >= lnum)
                   2698:            {
                   2699:                bnum = ip->ip_bnum;
                   2700:                low = ip->ip_low;
                   2701:                high = ip->ip_high;
                   2702:                buf->b_ml.ml_stack_top = top;   /* truncate stack at prev entry */
                   2703:                break;
                   2704:            }
                   2705:        }
                   2706:        if (top < 0)
                   2707:            buf->b_ml.ml_stack_top = 0;         /* not found, start at the root */
                   2708:    }
                   2709:    else        /* ML_DELETE or ML_INSERT */
                   2710:        buf->b_ml.ml_stack_top = 0;     /* start at the root */
                   2711:
                   2712: /*
                   2713:  * search downwards in the tree until a data block is found
                   2714:  */
                   2715:    for (;;)
                   2716:    {
                   2717:        if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
                   2718:            goto error_noblock;
                   2719:
                   2720:        /*
                   2721:         * update high for insert/delete
                   2722:         */
                   2723:        if (action == ML_INSERT)
                   2724:            ++high;
                   2725:        else if (action == ML_DELETE)
                   2726:            --high;
                   2727:
                   2728:        dp = (DATA_BL *)(hp->bh_data);
                   2729:        if (dp->db_id == DATA_ID)       /* data block */
                   2730:        {
                   2731:            buf->b_ml.ml_locked = hp;
                   2732:            buf->b_ml.ml_locked_low = low;
                   2733:            buf->b_ml.ml_locked_high = high;
                   2734:            buf->b_ml.ml_locked_lineadd = 0;
                   2735:            buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
                   2736:            return hp;
                   2737:        }
                   2738:
                   2739:        pp = (PTR_BL *)(dp);            /* must be pointer block */
                   2740:        if (pp->pb_id != PTR_ID)
                   2741:        {
                   2742:            EMSG("pointer block id wrong");
                   2743:            goto error_block;
                   2744:        }
                   2745:
                   2746:        if ((top = ml_add_stack(buf)) < 0)      /* add new entry to stack */
                   2747:            goto error_block;
                   2748:        ip = &(buf->b_ml.ml_stack[top]);
                   2749:        ip->ip_bnum = bnum;
                   2750:        ip->ip_low = low;
                   2751:        ip->ip_high = high;
                   2752:        ip->ip_index = -1;              /* index not known yet */
                   2753:
                   2754:        dirty = FALSE;
                   2755:        for (idx = 0; idx < (int)pp->pb_count; ++idx)
                   2756:        {
                   2757:            t = pp->pb_pointer[idx].pe_line_count;
                   2758:            CHECK(t == 0, "pe_line_count is zero");
                   2759:            if ((low += t) > lnum)
                   2760:            {
                   2761:                ip->ip_index = idx;
                   2762:                bnum = pp->pb_pointer[idx].pe_bnum;
                   2763:                page_count = pp->pb_pointer[idx].pe_page_count;
                   2764:                high = low - 1;
                   2765:                low -= t;
                   2766:
                   2767:                /*
                   2768:                 * a negative block number may have been changed
                   2769:                 */
                   2770:                if (bnum < 0)
                   2771:                {
                   2772:                    bnum2 = mf_trans_del(mfp, bnum);
                   2773:                    if (bnum != bnum2)
                   2774:                    {
                   2775:                        bnum = bnum2;
                   2776:                        pp->pb_pointer[idx].pe_bnum = bnum;
                   2777:                        dirty = TRUE;
                   2778:                    }
                   2779:                }
                   2780:
                   2781:                break;
                   2782:            }
                   2783:        }
                   2784:        if (idx >= (int)pp->pb_count)       /* past the end: something wrong! */
                   2785:        {
                   2786:            if (lnum > buf->b_ml.ml_line_count)
                   2787:                EMSGN("line number out of range: %ld past the end",
                   2788:                                              lnum - buf->b_ml.ml_line_count);
                   2789:
                   2790:            else
                   2791:                EMSGN("line count wrong in block %ld", bnum);
                   2792:            goto error_block;
                   2793:        }
                   2794:        if (action == ML_DELETE)
                   2795:        {
                   2796:            pp->pb_pointer[idx].pe_line_count--;
                   2797:            dirty = TRUE;
                   2798:        }
                   2799:        else if (action == ML_INSERT)
                   2800:        {
                   2801:            pp->pb_pointer[idx].pe_line_count++;
                   2802:            dirty = TRUE;
                   2803:        }
                   2804:        mf_put(mfp, hp, dirty, FALSE);
                   2805:    }
                   2806:
                   2807: error_block:
                   2808:    mf_put(mfp, hp, FALSE, FALSE);
                   2809: error_noblock:
                   2810: /*
                   2811:  * If action is ML_DELETE or ML_INSERT we have to correct the tree for
                   2812:  * the incremented/decremented line counts, because there won't be a line
                   2813:  * inserted/deleted after all.
                   2814:  */
                   2815:    if (action == ML_DELETE)
                   2816:        ml_lineadd(buf, 1);
                   2817:    else if (action == ML_INSERT)
                   2818:        ml_lineadd(buf, -1);
                   2819:    buf->b_ml.ml_stack_top = 0;
                   2820:    return NULL;
                   2821: }
                   2822:
                   2823: /*
                   2824:  * add an entry to the info pointer stack
                   2825:  *
                   2826:  * return -1 for failure, number of the new entry otherwise
                   2827:  */
                   2828:    static int
                   2829: ml_add_stack(buf)
                   2830:    BUF     *buf;
                   2831: {
                   2832:    int     top;
                   2833:    IPTR    *newstack;
                   2834:
                   2835:    top = buf->b_ml.ml_stack_top;
                   2836:
                   2837:        /* may have to increase the stack size */
                   2838:    if (top == buf->b_ml.ml_stack_size)
                   2839:    {
                   2840:        CHECK(top > 0, "Stack size increases"); /* more than 5 levels??? */
                   2841:
                   2842:        newstack = (IPTR *)alloc((unsigned)sizeof(IPTR) *
                   2843:                                        (buf->b_ml.ml_stack_size + STACK_INCR));
                   2844:        if (newstack == NULL)
                   2845:            return -1;
                   2846:        vim_memmove(newstack, buf->b_ml.ml_stack, (size_t)top * sizeof(IPTR));
                   2847:        vim_free(buf->b_ml.ml_stack);
                   2848:        buf->b_ml.ml_stack = newstack;
                   2849:        buf->b_ml.ml_stack_size += STACK_INCR;
                   2850:    }
                   2851:
                   2852:    buf->b_ml.ml_stack_top++;
                   2853:    return top;
                   2854: }
                   2855:
                   2856: /*
                   2857:  * Update the pointer blocks on the stack for inserted/deleted lines.
                   2858:  * The stack itself is also updated.
                   2859:  *
                   2860:  * When a insert/delete line action fails, the line is not inserted/deleted,
                   2861:  * but the pointer blocks have already been updated. That is fixed here by
                   2862:  * walking through the stack.
                   2863:  *
                   2864:  * Count is the number of lines added, negative if lines have been deleted.
                   2865:  */
                   2866:    static void
                   2867: ml_lineadd(buf, count)
                   2868:    BUF         *buf;
                   2869:    int         count;
                   2870: {
                   2871:    int         idx;
                   2872:    IPTR        *ip;
                   2873:    PTR_BL      *pp;
                   2874:    MEMFILE     *mfp = buf->b_ml.ml_mfp;
                   2875:    BHDR        *hp;
                   2876:
                   2877:    for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
                   2878:    {
                   2879:        ip = &(buf->b_ml.ml_stack[idx]);
                   2880:        if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
                   2881:            break;
                   2882:        pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
                   2883:        if (pp->pb_id != PTR_ID)
                   2884:        {
                   2885:            mf_put(mfp, hp, FALSE, FALSE);
                   2886:            EMSG("pointer block id wrong 2");
                   2887:            break;
                   2888:        }
                   2889:        pp->pb_pointer[ip->ip_index].pe_line_count += count;
                   2890:        ip->ip_high += count;
                   2891:        mf_put(mfp, hp, TRUE, FALSE);
                   2892:    }
                   2893: }
                   2894:
                   2895: /*
                   2896:  * make swap file name out of the filename and a directory name
                   2897:  */
                   2898:    static char_u *
                   2899: makeswapname(buf, dir_name)
                   2900:    BUF     *buf;
                   2901:    char_u  *dir_name;
                   2902: {
                   2903:    char_u      *r, *s, *fname;
                   2904:
                   2905: #ifdef VMS
                   2906:    r = modname(buf->b_xfilename, (char_u *)"_swp");
                   2907: #else
                   2908:    r = modname(buf->b_xfilename, (char_u *)".swp");
                   2909: #endif
                   2910:    /*
                   2911:     * do not use dir_name
                   2912:     * - if dir_name starts with '.' (use current directory)
                   2913:     * - if out of memory
                   2914:     */
                   2915:    if (*dir_name == '.' || r == NULL)
                   2916:        return r;
                   2917:
                   2918:    fname = gettail(r);
                   2919:    s = concat_fnames(dir_name, fname, TRUE);
                   2920:    vim_free(r);
                   2921:    return s;
                   2922: }
                   2923:
                   2924: /*
                   2925:  * Find out what name to use for the swap file for buffer 'buf'.
                   2926:  *
                   2927:  * Several names are tried to find one that does not exist
                   2928:  *
                   2929:  * Note: if MAXNAMLEN is not correct, you will get error messages for
                   2930:  *       not being able to open the swapfile
                   2931:  */
                   2932:    static char_u *
                   2933: findswapname(buf, dirp, old_fname)
                   2934:    BUF     *buf;
                   2935:    char_u  **dirp;         /* pointer to list of directories */
                   2936:    char_u  *old_fname;     /* don't give warning for this filename */
                   2937: {
                   2938:    char_u      *fname;
                   2939:    int         n;
                   2940:    time_t      x;
                   2941:    char_u      *dir_name;
                   2942:
                   2943: #ifdef AMIGA
                   2944:    BPTR        fh;
                   2945: #endif
                   2946:
                   2947: #ifndef SHORT_FNAME
                   2948:    int         r;
                   2949:    FILE        *dummyfd = NULL;
                   2950:
                   2951: /*
                   2952:  * If we start editing a new file, e.g. "test.doc", which resides on an MSDOS
                   2953:  * compatible filesystem, it is possible that the file "test.doc.swp" which we
                   2954:  * create will be exactly the same file. To avoid this problem we temporarily
                   2955:  * create "test.doc".
                   2956:  */
                   2957:    if (!(buf->b_p_sn || buf->b_shortname) && buf->b_xfilename &&
                   2958:                                                getperm(buf->b_xfilename) < 0)
                   2959:        dummyfd = fopen((char *)buf->b_xfilename, "w");
                   2960: #endif
                   2961:
                   2962: /*
                   2963:  * Isolate a directory name from *dirp and put it in dir_name.
                   2964:  * First allocate some memore to put the directory name in.
                   2965:  */
                   2966:    dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
                   2967:    if (dir_name != NULL)
                   2968:        (void)copy_option_part(dirp, dir_name, 31000, ",");
                   2969:
                   2970: /*
                   2971:  * we try different names until we find one that does not exist yet
                   2972:  */
                   2973:    if (dir_name == NULL)           /* out of memory */
                   2974:        fname = NULL;
                   2975:    else
                   2976:        fname = makeswapname(buf, dir_name);
                   2977:
                   2978:    for (;;)
                   2979:    {
                   2980:        if (fname == NULL)      /* must be out of memory */
                   2981:            break;
                   2982:        if ((n = STRLEN(fname)) == 0)   /* safety check */
                   2983:        {
                   2984:            vim_free(fname);
                   2985:            fname = NULL;
                   2986:            break;
                   2987:        }
                   2988: #if (defined(UNIX) || defined(OS2)) && !defined(ARCHIE) && !defined(SHORT_FNAME)
                   2989: /*
                   2990:  * Some systems have a MS-DOS compatible filesystem that use 8.3 character
                   2991:  * file names. If this is the first try and the swap file name does not fit in
                   2992:  * 8.3, detect if this is the case, set shortname and try again.
                   2993:  */
                   2994:        if (fname[n - 1] == 'p' && !(buf->b_p_sn || buf->b_shortname))
                   2995:        {
                   2996:            char_u          *tail;
                   2997:            char_u          *fname2;
                   2998:            struct stat     s1, s2;
                   2999:            int             f1, f2;
                   3000:            int             created1 = FALSE, created2 = FALSE;
                   3001:            int             same = FALSE;
                   3002:
                   3003:            /*
                   3004:             * Check if swapfilename does not fit in 8.3:
                   3005:             * It either contains two dots or it is longer than 8 chars.
                   3006:             */
                   3007:            tail = gettail(buf->b_xfilename);
                   3008:            if (vim_strchr(tail, '.') != NULL || STRLEN(tail) > (size_t)8)
                   3009:            {
                   3010:                fname2 = alloc(n + 1);
                   3011:                if (fname2 != NULL)
                   3012:                {
                   3013:                    STRCPY(fname2, fname);
                   3014:                    if (vim_strchr(tail, '.') != NULL)
                   3015:                        fname2[n - 1] = 'x';    /* change ".swp" to ".swx" */
                   3016:                    else
                   3017:                        fname2[n - 5] += 1;     /* change "x.swp" to "y.swp" */
                   3018:                    /*
                   3019:                     * may need to create the files to be able to use stat()
                   3020:                     */
                   3021:                    f1 = open((char *)fname, O_RDONLY | O_EXTRA);
                   3022:                    if (f1 < 0)
                   3023:                    {
                   3024:                        f1 = open((char *)fname, O_RDWR|O_CREAT|O_EXCL|O_EXTRA
                   3025: #ifdef AMIGA               /* Amiga has no mode argument */
                   3026:                                                                            );
                   3027: #endif
                   3028: #ifdef UNIX                    /* open in rw------- mode */
                   3029:                                                              , (mode_t)0600);
                   3030: #endif
                   3031: #if defined(MSDOS) || defined(WIN32) || defined(OS2)  /* open read/write */
                   3032:                                                        , S_IREAD | S_IWRITE);
                   3033: #endif
                   3034: #if defined(OS2)
                   3035:                        if (f1 < 0 && errno == ENOENT)
                   3036:                            same = TRUE;
                   3037: #endif
                   3038:                        created1 = TRUE;
                   3039:                    }
                   3040:                    if (f1 >= 0)
                   3041:                    {
                   3042:                        f2 = open((char *)fname2, O_RDONLY | O_EXTRA);
                   3043:                        if (f2 < 0)
                   3044:                        {
                   3045:                            f2 = open((char *)fname2,
                   3046:                                                 O_RDWR|O_CREAT|O_EXCL|O_EXTRA
                   3047: #ifdef AMIGA               /* Amiga has no mode argument */
                   3048:                                                                            );
                   3049: #endif
                   3050: #ifdef UNIX                    /* open in rw------- mode */
                   3051:                                                              , (mode_t)0600);
                   3052: #endif
                   3053: #if defined(MSDOS) || defined(WIN32) || defined(OS2)  /* open read/write */
                   3054:                                                        , S_IREAD | S_IWRITE);
                   3055: #endif
                   3056:                            created2 = TRUE;
                   3057:                        }
                   3058:                        if (f2 >= 0)
                   3059:                        {
                   3060:                            /*
                   3061:                             * Both files exist now. If stat() returns the
                   3062:                             * same device and inode they are the same file.
                   3063:                             */
                   3064:                            if (fstat(f1, &s1) != -1 &&
                   3065:                                        fstat(f2, &s2) != -1 &&
                   3066:                                        s1.st_dev == s2.st_dev &&
                   3067:                                        s1.st_ino == s2.st_ino)
                   3068:                                same = TRUE;
                   3069:                            close(f2);
                   3070:                            if (created2)
                   3071:                                vim_remove(fname2);
                   3072:                        }
                   3073:                        close(f1);
                   3074:                        if (created1)
                   3075:                            vim_remove(fname);
                   3076:                    }
                   3077:                    vim_free(fname2);
                   3078:                    if (same)
                   3079:                    {
                   3080:                        buf->b_shortname = TRUE;
                   3081:                        vim_free(fname);
                   3082:                        fname = makeswapname(buf, dir_name);
                   3083:                        continue;       /* try again with b_shortname set */
                   3084:                    }
                   3085:                }
                   3086:            }
                   3087:        }
                   3088: #endif
                   3089:        /*
                   3090:         * check if the swapfile already exists
                   3091:         */
                   3092:        if (getperm(fname) < 0)     /* it does not exist */
                   3093:        {
                   3094: #ifdef AMIGA
                   3095:            fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
                   3096:            /*
                   3097:             * on the Amiga getperm() will return -1 when the file exists but
                   3098:             * is being used by another program. This happens if you edit
                   3099:             * a file twice.
                   3100:             */
                   3101:            if (fh != (BPTR)NULL)       /* can open file, OK */
                   3102:            {
                   3103:                Close(fh);
                   3104:                break;
                   3105:            }
                   3106:            if (IoErr() != ERROR_OBJECT_IN_USE &&
                   3107:                                               IoErr() != ERROR_OBJECT_EXISTS)
                   3108: #endif
                   3109:                break;
                   3110:        }
                   3111:        /*
                   3112:         * A file name equal to old_fname is OK to use.
                   3113:         */
                   3114:        if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
                   3115:            break;
                   3116:
                   3117:        /*
                   3118:         * get here when file already exists
                   3119:         */
                   3120:        if (fname[n - 1] == 'p')        /* first try */
                   3121:        {
                   3122: #ifndef SHORT_FNAME
                   3123:            /*
                   3124:             * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
                   3125:             * and file.doc are the same file. To guess if this problem is
                   3126:             * present try if file.doc.swx exists. If it does, we set
                   3127:             * buf->b_shortname and try file_doc.swp (dots replaced by
                   3128:             * underscores for this file), and try again. If it doesn't we
                   3129:             * assume that "file.doc.swp" already exists.
                   3130:             */
                   3131:            if (!(buf->b_p_sn || buf->b_shortname))     /* not tried yet */
                   3132:            {
                   3133:                fname[n - 1] = 'x';
                   3134:                r = getperm(fname);         /* try "file.swx" */
                   3135:                fname[n - 1] = 'p';
                   3136:                if (r >= 0)                 /* "file.swx" seems to exist */
                   3137:                {
                   3138:                    buf->b_shortname = TRUE;
                   3139:                    vim_free(fname);
                   3140:                    fname = makeswapname(buf, dir_name);
                   3141:                    continue;       /* try again with '.' replaced by '_' */
                   3142:                }
                   3143:            }
                   3144: #endif
                   3145:            /*
                   3146:             * If we get here the ".swp" file really exists.
                   3147:             * Give an error message, unless recovering, no file name, we are
                   3148:             * viewing a help file or when the path of the file is different
                   3149:             * (happens when all .swp files are in one directory).
                   3150:             */
                   3151:            if (!recoverymode && buf->b_xfilename != NULL && !buf->b_help)
                   3152:            {
                   3153:                int             fd;
                   3154:                struct block0   b0;
                   3155:                int             differ = FALSE;
                   3156:
                   3157:                /*
                   3158:                 * Try to read block 0 from the swap file to get the original
                   3159:                 * file name (and inode number).
                   3160:                 */
                   3161:                fd = open((char *)fname, O_RDONLY | O_EXTRA);
                   3162:                if (fd >= 0)
                   3163:                {
                   3164:                    if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
                   3165:                    {
                   3166:                        /*
                   3167:                         * The name in the swap file may be "~user/path/file".
                   3168:                         * Expand it first.
                   3169:                         */
                   3170:                        expand_env(b0.b0_fname, NameBuff, MAXPATHL);
                   3171: #ifdef CHECK_INODE
                   3172:                        if (fnamecmp_ino(buf->b_filename, NameBuff,
                   3173:                                                     char_to_long(b0.b0_ino)))
                   3174:                            differ = TRUE;
                   3175: #else
                   3176:                        if (fnamecmp(NameBuff, buf->b_filename) != 0)
                   3177:                            differ = TRUE;
                   3178: #endif
                   3179:                    }
                   3180:                    close(fd);
                   3181:                }
                   3182:                if (differ == FALSE)
                   3183:                {
                   3184:                    struct stat st;
                   3185:
                   3186:                    ++no_wait_return;
                   3187: #ifdef SLEEP_IN_EMSG
                   3188:                    ++dont_sleep;
                   3189: #endif
                   3190:                    (void)EMSG("ATTENTION");
                   3191: #ifdef SLEEP_IN_EMSG
                   3192:                    --dont_sleep;
                   3193: #endif
                   3194:                    MSG_OUTSTR("\nFound a swap file by the name \"");
                   3195:                    msg_home_replace(fname);
                   3196:                    MSG_OUTSTR("\"\n");
                   3197:                    swapfile_info(fname);
                   3198:                    MSG_OUTSTR("While opening file \"");
                   3199:                    msg_outtrans(buf->b_xfilename);
                   3200:                    MSG_OUTSTR("\"\n");
                   3201:                    if (stat((char *)buf->b_xfilename, &st) != -1)
                   3202:                    {
                   3203:                        MSG_OUTSTR("             dated: ");
                   3204:                        x = st.st_mtime;    /* Manx C can't do &st.st_mtime */
                   3205:                        MSG_OUTSTR(ctime(&x));
                   3206:                    }
                   3207:                    MSG_OUTSTR("\n(1) Another program may be editing the same file.\n");
                   3208:                    MSG_OUTSTR("    If this is the case, quit this edit session to avoid having\n");
                   3209:                    MSG_OUTSTR("    two different instances of the same file when making changes.\n");
                   3210:                    MSG_OUTSTR("\n(2) An edit session for this file crashed.\n");
                   3211:                    MSG_OUTSTR("    If this is the case, use \":recover\" or \"vim -r ");
                   3212:                    msg_outtrans(buf->b_xfilename);
                   3213:                    MSG_OUTSTR("\"\n    to recover the changes (see \":help recovery)\".\n");
                   3214:                    MSG_OUTSTR("    If you did this already, delete the swap file \"");
                   3215:                    msg_outtrans(fname);
                   3216:                    MSG_OUTSTR("\"\n    to avoid this message.\n\n");
                   3217:                    cmdline_row = msg_row;
                   3218:                    --no_wait_return;
                   3219:                    need_wait_return = TRUE;        /* call wait_return later */
                   3220:                }
                   3221:            }
                   3222:        }
                   3223:
                   3224:        if (fname[n - 1] == 'a')    /* tried enough names, give up */
                   3225:        {
                   3226:            vim_free(fname);
                   3227:            fname = NULL;
                   3228:            break;
                   3229:        }
                   3230:        --fname[n - 1];             /* change last char of the name */
                   3231:    }
                   3232:
                   3233:    vim_free(dir_name);
                   3234: #ifndef SHORT_FNAME
                   3235:    if (dummyfd)        /* file has been created temporarily */
                   3236:    {
                   3237:        fclose(dummyfd);
                   3238:        vim_remove(buf->b_xfilename);
                   3239:    }
                   3240: #endif
                   3241:    return fname;
                   3242: }
                   3243:
                   3244:    static int
                   3245: b0_magic_wrong(b0p)
                   3246:    ZERO_BL *b0p;
                   3247: {
                   3248:    return (b0p->b0_magic_long != (long)B0_MAGIC_LONG ||
                   3249:            b0p->b0_magic_int != (int)B0_MAGIC_INT ||
                   3250:            b0p->b0_magic_short != (short)B0_MAGIC_SHORT ||
                   3251:            b0p->b0_magic_char != B0_MAGIC_CHAR);
                   3252: }
                   3253:
                   3254: #ifdef CHECK_INODE
                   3255: /*
                   3256:  * Compare current file name with file name from swap file.
                   3257:  * Try to use inode numbers when possible.
                   3258:  * Return non-zero when files are different.
                   3259:  *
                   3260:  * When comparing file names a few things have to be taken into consideration:
                   3261:  * - When working over a network the full path of a file depends on the host.
                   3262:  *   We check the inode number if possible.  It is not 100% reliable though,
                   3263:  *   because the device number cannot be used over a network.
                   3264:  * - When a file does not exist yet (editing a new file) there is no inode
                   3265:  *   number.
                   3266:  * - The file name in a swap file may not be valid on the current host.  The
                   3267:  *  "~user" form is used whenever possible to avoid this.
                   3268:  *
                   3269:  * This is getting complicated, let's make a table:
                   3270:  *
                   3271:  *             ino_c  ino_s  fname_c  fname_s  differ =
                   3272:  *
                   3273:  * both files exist -> compare inode numbers:
                   3274:  *             != 0   != 0     X        X      ino_c != ino_s
                   3275:  *
                   3276:  * inode number(s) unknown, file names available -> compare file names
                   3277:  *             == 0    X       OK       OK     fname_c != fname_s
                   3278:  *              X     == 0     OK       OK     fname_c != fname_s
                   3279:  *
                   3280:  * current file doesn't exist, file for swap file exist, file name(s) not
                   3281:  * available -> probably different
                   3282:  *             == 0   != 0    FAIL      X      TRUE
                   3283:  *             == 0   != 0     X       FAIL    TRUE
                   3284:  *
                   3285:  * current file exists, inode for swap unknown, file name(s) not
                   3286:  * available -> probably different
                   3287:  *             != 0   == 0    FAIL      X      TRUE
                   3288:  *             != 0   == 0     X       FAIL    TRUE
                   3289:  *
                   3290:  * current file doesn't exist, inode for swap unknown, one file name not
                   3291:  * available -> probably different
                   3292:  *             == 0   == 0    FAIL      OK     TRUE
                   3293:  *             == 0   == 0     OK      FAIL    TRUE
                   3294:  *
                   3295:  * current file doesn't exist, inode for swap unknown, both file names not
                   3296:  * available -> probably same file
                   3297:  *             == 0   == 0    FAIL     FAIL    FALSE
                   3298:  */
                   3299:
                   3300:    static int
                   3301: fnamecmp_ino(fname_c, fname_s, ino_block0)
                   3302:    char_u      *fname_c;           /* current file name */
                   3303:    char_u      *fname_s;           /* file name from swap file */
                   3304:    long        ino_block0;
                   3305: {
                   3306:    struct stat st;
                   3307:    long        ino_c = 0;          /* ino of current file */
                   3308:    long        ino_s;              /* ino of file from swap file */
                   3309:    char_u      buf_c[MAXPATHL];    /* full path of fname_c */
                   3310:    char_u      buf_s[MAXPATHL];    /* full path of fname_s */
                   3311:    int         retval_c;           /* flag: buf_c valid */
                   3312:    int         retval_s;           /* flag: buf_s valid */
                   3313:
                   3314:
                   3315:    if (stat((char *)fname_c, &st) == 0)
                   3316:        ino_c = st.st_ino;
                   3317:
                   3318:    /*
                   3319:     * First we try to get the inode from the file name, because the inode in
                   3320:     * the swap file may be outdated.  If that fails (e.g. this path is not
                   3321:     * valid on this machine), use the inode from block 0.
                   3322:     */
                   3323:    if (stat((char *)fname_s, &st) == 0)
                   3324:        ino_s = st.st_ino;
                   3325:    else
                   3326:        ino_s = ino_block0;
                   3327:
                   3328:    if (ino_c && ino_s)
                   3329:        return (ino_c != ino_s);
                   3330:
                   3331:    /*
                   3332:     * One of the inode numbers is unknown, try a forced FullName() and
                   3333:     * compare the file names.
                   3334:     */
                   3335:    retval_c = FullName(fname_c, buf_c, MAXPATHL, TRUE);
                   3336:    retval_s = FullName(fname_s, buf_s, MAXPATHL, TRUE);
                   3337:    if (retval_c == OK && retval_s == OK)
                   3338:        return (STRCMP(buf_c, buf_s) != 0);
                   3339:
                   3340:    /*
                   3341:     * Can't compare inodes or filenames, guess that the files are different,
                   3342:     * unless both appear not to exist at all.
                   3343:     */
                   3344:    if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
                   3345:        return FALSE;
                   3346:    return TRUE;
                   3347: }
                   3348: #endif /* CHECK_INODE */
                   3349:
                   3350: /*
                   3351:  * Move a long integer into a four byte character array.
                   3352:  * Used for machine independency in block zero.
                   3353:  */
                   3354:    static void
                   3355: long_to_char(n, s)
                   3356:    long    n;
                   3357:    char_u  *s;
                   3358: {
                   3359:    s[0] = (n & 0xff);
                   3360:    n >>= 8;
                   3361:    s[1] = (n & 0xff);
                   3362:    n >>= 8;
                   3363:    s[2] = (n & 0xff);
                   3364:    n >>= 8;
                   3365:    s[3] = (n & 0xff);
                   3366: }
                   3367:
                   3368:    static long
                   3369: char_to_long(s)
                   3370:    char_u  *s;
                   3371: {
                   3372:    long    retval;
                   3373:
                   3374:    retval = s[3];
                   3375:    retval <<= 8;
                   3376:    retval += s[2];
                   3377:    retval <<= 8;
                   3378:    retval += s[1];
                   3379:    retval <<= 8;
                   3380:    retval += s[0];
                   3381:
                   3382:    return retval;
                   3383: }