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

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