home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / memline.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-25  |  116.0 KB  |  4,379 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  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 containing that
  32.  *  line is made big enough to hold the line. It may span several pages.
  33.  *  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 a
  40.  *  positive number. Use mf_trans_del() to get the new number, before calling
  41.  *  mf_get().
  42.  */
  43.  
  44. #if defined(MSDOS) || defined(WIN32) || defined(_WIN64)
  45. # include <io.h>
  46. #endif
  47.  
  48. #include "vim.h"
  49.  
  50. #ifdef HAVE_FCNTL_H
  51. # include <fcntl.h>
  52. #endif
  53. #ifndef UNIX        /* it's in os_unix.h for Unix */
  54. # include <time.h>
  55. #endif
  56.  
  57. #ifdef SASC
  58. # include <proto/dos.h>        /* for Open() and Close() */
  59. #endif
  60.  
  61. typedef struct block0        ZERO_BL;    /* contents of the first block */
  62. typedef struct pointer_block    PTR_BL;        /* contents of a pointer block */
  63. typedef struct data_block    DATA_BL;    /* contents of a data block */
  64. typedef struct pointer_entry    PTR_EN;        /* block/line-count pair */
  65.  
  66. #define DATA_ID        (('d' << 8) + 'a')        /* data block id */
  67. #define PTR_ID        (('p' << 8) + 't')        /* pointer block id */
  68. #define BLOCK0_ID0  'b'                /* block 0 id 0 */
  69. #define BLOCK0_ID1  '0'                /* block 0 id 1 */
  70.  
  71. /*
  72.  * pointer to a block, used in a pointer block
  73.  */
  74. struct pointer_entry
  75. {
  76.     blocknr_T    pe_bnum;    /* block number */
  77.     linenr_T    pe_line_count;    /* number of lines in this branch */
  78.     linenr_T    pe_old_lnum;    /* lnum for this block (for recovery) */
  79.     int        pe_page_count;    /* number of pages in block pe_bnum */
  80. };
  81.  
  82. /*
  83.  * A pointer block contains a list of branches in the tree.
  84.  */
  85. struct pointer_block
  86. {
  87.     short_u    pb_id;        /* ID for pointer block: PTR_ID */
  88.     short_u    pb_count;    /* number of pointer in this block */
  89.     short_u    pb_count_max;    /* maximum value for pb_count */
  90.     PTR_EN    pb_pointer[1];    /* list of pointers to blocks (actually longer)
  91.                  * followed by empty space until end of page */
  92. };
  93.  
  94. /*
  95.  * A data block is a leaf in the tree.
  96.  *
  97.  * The text of the lines is at the end of the block. The text of the first line
  98.  * in the block is put at the end, the text of the second line in front of it,
  99.  * etc. Thus the order of the lines is the opposite of the line number.
  100.  */
  101. struct data_block
  102. {
  103.     short_u    db_id;        /* ID for data block: DATA_ID */
  104.     unsigned    db_free;    /* free space available */
  105.     unsigned    db_txt_start;    /* byte where text starts */
  106.     unsigned    db_txt_end;    /* byte just after data block */
  107.     linenr_T    db_line_count;    /* number of lines in this block */
  108.     unsigned    db_index[1];    /* index for start of line (actually bigger)
  109.                  * followed by empty space upto db_txt_start
  110.                  * followed by the text in the lines until
  111.                  * end of page */
  112. };
  113.  
  114. /*
  115.  * The low bits of db_index hold the actual index. The topmost bit is
  116.  * used for the global command to be able to mark a line.
  117.  * This method is not clean, but otherwise there would be at least one extra
  118.  * byte used for each line.
  119.  * The mark has to be in this place to keep it with the correct line when other
  120.  * lines are inserted or deleted.
  121.  */
  122. #define DB_MARKED    ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
  123. #define DB_INDEX_MASK    (~DB_MARKED)
  124.  
  125. #define INDEX_SIZE  (sizeof(unsigned))        /* size of one db_index entry */
  126. #define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE)  /* size of data block header */
  127.  
  128. #define B0_FNAME_SIZE    900
  129. #define B0_UNAME_SIZE    40
  130. #define B0_HNAME_SIZE    40
  131. /*
  132.  * Restrict the numbers to 32 bits, otherwise most compilers will complain.
  133.  * This won't detect a 64 bit machine that only swaps a byte in the top 32
  134.  * bits, but that is crazy anyway.
  135.  */
  136. #define B0_MAGIC_LONG    0x30313233L
  137. #define B0_MAGIC_INT    0x20212223L
  138. #define B0_MAGIC_SHORT    0x10111213L
  139. #define B0_MAGIC_CHAR    0x55
  140.  
  141. /*
  142.  * Block zero holds all info about the swap file.
  143.  *
  144.  * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing
  145.  * swap files unusable!
  146.  *
  147.  * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!!
  148.  *
  149.  * This block is built up of single bytes, to make it portable accros
  150.  * different machines. b0_magic_* is used to check the byte order and size of
  151.  * variables, because the rest of the swap file is not portable.
  152.  */
  153. struct block0
  154. {
  155.     char_u    b0_id[2];    /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */
  156.     char_u    b0_version[10];    /* Vim version string */
  157.     char_u    b0_page_size[4];/* number of bytes per page */
  158.     char_u    b0_mtime[4];    /* last modification time of file */
  159.     char_u    b0_ino[4];    /* inode of b0_fname */
  160.     char_u    b0_pid[4];    /* process id of creator (or 0) */
  161.     char_u    b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
  162.     char_u    b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
  163.     char_u    b0_fname[B0_FNAME_SIZE]; /* name of file being edited */
  164.     long    b0_magic_long;    /* check for byte order of long */
  165.     int        b0_magic_int;    /* check for byte order of int */
  166.     short    b0_magic_short;    /* check for byte order of short */
  167.     char_u    b0_magic_char;    /* check for last char */
  168. };
  169. #define   b0_dirty b0_fname[B0_FNAME_SIZE-1]
  170.  
  171. #define STACK_INCR    5    /* nr of entries added to ml_stack at a time */
  172.  
  173. /*
  174.  * The line number where the first mark may be is remembered.
  175.  * If it is 0 there are no marks at all.
  176.  * (always used for the current buffer only, no buffer change possible while
  177.  * executing a global command).
  178.  */
  179. static linenr_T    lowest_marked = 0;
  180.  
  181. /*
  182.  * arguments for ml_find_line()
  183.  */
  184. #define ML_DELETE    0x11        /* delete line */
  185. #define ML_INSERT    0x12        /* insert line */
  186. #define ML_FIND        0x13        /* just find the line */
  187. #define ML_FLUSH    0x02        /* flush locked block */
  188. #define ML_SIMPLE(x)    (x & 0x10)  /* DEL, INS or FIND */
  189.  
  190. static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf));
  191. static time_t swapfile_info __ARGS((char_u *));
  192. static int recov_file_names __ARGS((char_u **, char_u *, int prepend_dot));
  193. static int ml_append_int __ARGS((buf_T *, linenr_T, char_u *, colnr_T, int, int));
  194. static int ml_delete_int __ARGS((buf_T *, linenr_T, int));
  195. static char_u *findswapname __ARGS((buf_T *, char_u **, char_u *));
  196. static void ml_flush_line __ARGS((buf_T *));
  197. static bhdr_T *ml_new_data __ARGS((memfile_T *, int, int));
  198. static bhdr_T *ml_new_ptr __ARGS((memfile_T *));
  199. static bhdr_T *ml_find_line __ARGS((buf_T *, linenr_T, int));
  200. static int ml_add_stack __ARGS((buf_T *));
  201. static char_u *makeswapname __ARGS((buf_T *, char_u *));
  202. static void ml_lineadd __ARGS((buf_T *, int));
  203. static int b0_magic_wrong __ARGS((ZERO_BL *));
  204. #ifdef CHECK_INODE
  205. static int fnamecmp_ino __ARGS((char_u *, char_u *, long));
  206. #endif
  207. static void long_to_char __ARGS((long, char_u *));
  208. static long char_to_long __ARGS((char_u *));
  209. #if defined(UNIX) || defined(WIN3264)
  210. static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
  211. #endif
  212. #ifdef FEAT_BYTEOFF
  213. static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
  214. #endif
  215.  
  216. /*
  217.  * open a new memline for 'curbuf'
  218.  *
  219.  * return FAIL for failure, OK otherwise
  220.  */
  221.     int
  222. ml_open()
  223. {
  224.     memfile_T    *mfp;
  225.     bhdr_T    *hp = NULL;
  226.     ZERO_BL    *b0p;
  227.     PTR_BL    *pp;
  228.     DATA_BL    *dp;
  229.  
  230. /*
  231.  * init fields in memline struct
  232.  */
  233.     curbuf->b_ml.ml_stack_size = 0;    /* no stack yet */
  234.     curbuf->b_ml.ml_stack = NULL;    /* no stack yet */
  235.     curbuf->b_ml.ml_stack_top = 0;    /* nothing in the stack */
  236.     curbuf->b_ml.ml_locked = NULL;    /* no cached block */
  237.     curbuf->b_ml.ml_line_lnum = 0;    /* no cached line */
  238. #ifdef FEAT_BYTEOFF
  239.     curbuf->b_ml.ml_chunksize = NULL;
  240. #endif
  241.  
  242. /*
  243.  * When 'updatecount' is non-zero, flag that a swap file may be opened later.
  244.  */
  245.     if (p_uc && curbuf->b_p_swf)
  246.     curbuf->b_may_swap = TRUE;
  247.     else
  248.     curbuf->b_may_swap = FALSE;
  249.  
  250. /*
  251.  * Open the memfile.  No swap file is created yet.
  252.  */
  253.     mfp = mf_open(NULL, 0);
  254.     if (mfp == NULL)
  255.     goto error;
  256.  
  257.     curbuf->b_ml.ml_mfp = mfp;
  258.     curbuf->b_ml.ml_flags = ML_EMPTY;
  259.     curbuf->b_ml.ml_line_count = 1;
  260.  
  261. #if defined(MSDOS) && !defined(DJGPP)
  262.     /* for 16 bit MS-DOS create a swapfile now, because we run out of
  263.      * memory very quickly */
  264.     if (p_uc != 0)
  265.     ml_open_file(curbuf);
  266. #endif
  267.  
  268. /*
  269.  * fill block0 struct and write page 0
  270.  */
  271.     if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
  272.     goto error;
  273.     if (hp->bh_bnum != 0)
  274.     {
  275.     EMSG(_("E298: Didn't get block nr 0?"));
  276.     goto error;
  277.     }
  278.     b0p = (ZERO_BL *)(hp->bh_data);
  279.  
  280.     b0p->b0_id[0] = BLOCK0_ID0;
  281.     b0p->b0_id[1] = BLOCK0_ID1;
  282.     b0p->b0_dirty = curbuf->b_changed ? 0x55 : 0;
  283.     b0p->b0_magic_long = (long)B0_MAGIC_LONG;
  284.     b0p->b0_magic_int = (int)B0_MAGIC_INT;
  285.     b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
  286.     b0p->b0_magic_char = B0_MAGIC_CHAR;
  287.  
  288.     STRNCPY(b0p->b0_version, "VIM ", 4);
  289.     STRNCPY(b0p->b0_version + 4, Version, 6);
  290.     set_b0_fname(b0p, curbuf);
  291.     long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
  292.     (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
  293.     b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
  294.     mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
  295.     b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
  296.     long_to_char(mch_get_pid(), b0p->b0_pid);
  297.  
  298.     /*
  299.      * Always sync block number 0 to disk, so we can check the file name in
  300.      * the swap file in findswapname(). Don't do this for help files though.
  301.      * Only works when there's a swapfile, otherwise it's done when the file
  302.      * is created.
  303.      */
  304.     mf_put(mfp, hp, TRUE, FALSE);
  305.     if (!curbuf->b_help)
  306.     (void)mf_sync(mfp, 0);
  307.  
  308. /*
  309.  * fill in root pointer block and write page 1
  310.  */
  311.     if ((hp = ml_new_ptr(mfp)) == NULL)
  312.     goto error;
  313.     if (hp->bh_bnum != 1)
  314.     {
  315.     EMSG(_("E298: Didn't get block nr 1?"));
  316.     goto error;
  317.     }
  318.     pp = (PTR_BL *)(hp->bh_data);
  319.     pp->pb_count = 1;
  320.     pp->pb_pointer[0].pe_bnum = 2;
  321.     pp->pb_pointer[0].pe_page_count = 1;
  322.     pp->pb_pointer[0].pe_old_lnum = 1;
  323.     pp->pb_pointer[0].pe_line_count = 1;    /* line count after insertion */
  324.     mf_put(mfp, hp, TRUE, FALSE);
  325.  
  326. /*
  327.  * allocate first data block and create an empty line 1.
  328.  */
  329.     if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
  330.     goto error;
  331.     if (hp->bh_bnum != 2)
  332.     {
  333.     EMSG(_("E298: Didn't get block nr 2?"));
  334.     goto error;
  335.     }
  336.  
  337.     dp = (DATA_BL *)(hp->bh_data);
  338.     dp->db_index[0] = --dp->db_txt_start;    /* at end of block */
  339.     dp->db_free -= 1 + INDEX_SIZE;
  340.     dp->db_line_count = 1;
  341.     *((char_u *)dp + dp->db_txt_start) = NUL;    /* emtpy line */
  342.  
  343.     return OK;
  344.  
  345. error:
  346.     if (mfp != NULL)
  347.     {
  348.     if (hp)
  349.         mf_put(mfp, hp, FALSE, FALSE);
  350.     mf_close(mfp, TRUE);        /* will also free(mfp->mf_fname) */
  351.     }
  352.     curbuf->b_ml.ml_mfp = NULL;
  353.     return FAIL;
  354. }
  355.  
  356. /*
  357.  * ml_setname() is called when the file name has been changed.
  358.  * It may rename the swap file.
  359.  */
  360.     void
  361. ml_setname()
  362. {
  363.     int        success = FALSE;
  364.     memfile_T    *mfp;
  365.     char_u    *fname;
  366.     char_u    *dirp;
  367. #if defined(MSDOS) || defined(MSWIN)
  368.     char_u    *p;
  369. #endif
  370.  
  371.     mfp = curbuf->b_ml.ml_mfp;
  372.     if (mfp->mf_fd < 0)            /* there is no swap file yet */
  373.     {
  374.     /*
  375.      * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
  376.      * For help files we will make a swap file now.
  377.      */
  378.     if (p_uc != 0)
  379.         ml_open_file(curbuf);    /* create a swap file */
  380.     return;
  381.     }
  382.  
  383.     /*
  384.      * Try all directories in the 'directory' option.
  385.      */
  386.     dirp = p_dir;
  387.     for (;;)
  388.     {
  389.     if (*dirp == NUL)        /* tried all directories, fail */
  390.         break;
  391.     fname = findswapname(curbuf, &dirp, mfp->mf_fname); /* alloc's fname */
  392.     if (fname == NULL)        /* no file name found for this dir */
  393.         continue;
  394.  
  395. #if defined(MSDOS) || defined(MSWIN)
  396.     /*
  397.      * Set full pathname for swap file now, because a ":!cd dir" may
  398.      * change directory without us knowing it.
  399.      */
  400.     p = FullName_save(fname, FALSE);
  401.     vim_free(fname);
  402.     fname = p;
  403.     if (fname == NULL)
  404.         continue;
  405. #endif
  406.     /* if the file name is the same we don't have to do anything */
  407.     if (fnamecmp(fname, mfp->mf_fname) == 0)
  408.     {
  409.         vim_free(fname);
  410.         success = TRUE;
  411.         break;
  412.     }
  413.     /* need to close the swap file before renaming */
  414.     if (mfp->mf_fd >= 0)
  415.     {
  416.         close(mfp->mf_fd);
  417.         mfp->mf_fd = -1;
  418.     }
  419.  
  420.     /* try to rename the swap file */
  421.     if (vim_rename(mfp->mf_fname, fname) == 0)
  422.     {
  423.         success = TRUE;
  424.         vim_free(mfp->mf_fname);
  425.         mfp->mf_fname = fname;
  426.         vim_free(mfp->mf_ffname);
  427. #if defined(MSDOS) || defined(MSWIN)
  428.         mfp->mf_ffname = NULL;  /* mf_fname is full pathname already */
  429. #else
  430.         mf_set_ffname(mfp);
  431. #endif
  432.         break;
  433.     }
  434.     vim_free(fname);        /* this fname didn't work, try another */
  435.     }
  436.  
  437.     if (mfp->mf_fd == -1)        /* need to (re)open the swap file */
  438.     {
  439.     mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
  440.     if (mfp->mf_fd < 0)
  441.     {
  442.         /* could not (re)open the swap file, what can we do???? */
  443.         EMSG(_("E301: Oops, lost the swap file!!!"));
  444.         return;
  445.     }
  446.     }
  447.     if (!success)
  448.     EMSG(_("E302: Could not rename swap file"));
  449. }
  450.  
  451. /*
  452.  * Open a file for the memfile for all buffers that are not readonly or have
  453.  * been modified.
  454.  * Used when 'updatecount' changes from zero to non-zero.
  455.  */
  456.     void
  457. ml_open_files()
  458. {
  459.     buf_T    *buf;
  460.  
  461.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  462.     if (!buf->b_p_ro || buf->b_changed)
  463.         ml_open_file(buf);
  464. }
  465.  
  466. /*
  467.  * Open a swap file for an existing memfile, if there is no swap file yet.
  468.  * If we are unable to find a file name, mf_fname will be NULL
  469.  * and the memfile will be in memory only (no recovery possible).
  470.  */
  471.     void
  472. ml_open_file(buf)
  473.     buf_T    *buf;
  474. {
  475.     memfile_T    *mfp;
  476.     char_u    *fname;
  477.     char_u    *dirp;
  478.  
  479.     mfp = buf->b_ml.ml_mfp;
  480.     if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf)
  481.     return;        /* nothing to do */
  482.  
  483.     /*
  484.      * Try all directories in 'directory' option.
  485.      */
  486.     dirp = p_dir;
  487.     for (;;)
  488.     {
  489.     if (*dirp == NUL)
  490.         break;
  491.     /* There is a small chance that between chosing the swap file name and
  492.      * creating it, another Vim creates the file.  In that case the
  493.      * creation will fail and we will use another directory. */
  494.     fname = findswapname(buf, &dirp, NULL);    /* allocates fname */
  495.     if (fname == NULL)
  496.         continue;
  497.     if (mf_open_file(mfp, fname) == OK)    /* consumes fname! */
  498.     {
  499. #if defined(MSDOS) || defined(MSWIN) || defined(RISCOS)
  500.         /*
  501.          * set full pathname for swap file now, because a ":!cd dir" may
  502.          * change directory without us knowing it.
  503.          */
  504.         mf_fullname(mfp);
  505. #endif
  506.         /* Flush block zero, so others can read it */
  507.         if (mf_sync(mfp, MFS_ZERO) == OK)
  508.         break;
  509.         /* Writing block 0 failed: close the file and try another dir */
  510.         mf_close_file(buf, FALSE);
  511.     }
  512.     }
  513.  
  514.     if (mfp->mf_fname == NULL)        /* Failed! */
  515.     {
  516.     need_wait_return = TRUE;    /* call wait_return later */
  517.     ++no_wait_return;
  518.     (void)EMSG2(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
  519.             buf_spname(buf) != NULL
  520.             ? (char_u *)buf_spname(buf)
  521.             : buf->b_fname);
  522.     --no_wait_return;
  523.     }
  524.  
  525.     /* don't try to open a swap file again */
  526.     buf->b_may_swap = FALSE;
  527. }
  528.  
  529. /*
  530.  * If still need to create a swap file, and starting to edit a not-readonly
  531.  * file, or reading into an existing buffer, create a swap file now.
  532.  */
  533.     void
  534. check_need_swap(newfile)
  535.     int        newfile;        /* reading file into new buffer */
  536. {
  537.     if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
  538.     ml_open_file(curbuf);
  539. }
  540.  
  541. /*
  542.  * Close memline for buffer 'buf'.
  543.  * If 'del_file' is TRUE, delete the swap file
  544.  */
  545.     void
  546. ml_close(buf, del_file)
  547.     buf_T    *buf;
  548.     int        del_file;
  549. {
  550.     if (buf->b_ml.ml_mfp == NULL)        /* not open */
  551.     return;
  552.     mf_close(buf->b_ml.ml_mfp, del_file);    /* close the .swp file */
  553.     if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
  554.     vim_free(buf->b_ml.ml_line_ptr);
  555.     vim_free(buf->b_ml.ml_stack);
  556. #ifdef FEAT_BYTEOFF
  557.     vim_free(buf->b_ml.ml_chunksize);
  558.     buf->b_ml.ml_chunksize = NULL;
  559. #endif
  560.     buf->b_ml.ml_mfp = NULL;
  561.  
  562.     /* Reset the "recovered" flag, give the ATTENTION prompt the next time
  563.      * this buffer is loaded. */
  564.     buf->b_flags &= ~BF_RECOVERED;
  565. }
  566.  
  567. /*
  568.  * Close all existing memlines and memfiles.
  569.  * Only used when exiting.
  570.  * When 'del_file' is TRUE, delete the memfiles.
  571.  */
  572.     void
  573. ml_close_all(del_file)
  574.     int        del_file;
  575. {
  576.     buf_T    *buf;
  577.  
  578.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  579.     ml_close(buf, del_file);
  580. #ifdef TEMPDIRNAMES
  581.     vim_deltempdir();        /* delete created temp directory */
  582. #endif
  583. }
  584.  
  585. /*
  586.  * Close all memfiles for not modified buffers.
  587.  * Only use just before exiting!
  588.  */
  589.     void
  590. ml_close_notmod()
  591. {
  592.     buf_T    *buf;
  593.  
  594.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  595.     if (!bufIsChanged(buf))
  596.         ml_close(buf, TRUE);    /* close all not-modified buffers */
  597. }
  598.  
  599. /*
  600.  * Update the timestamp in the .swp file.
  601.  * Used when the file has been written.
  602.  */
  603.     void
  604. ml_timestamp(buf)
  605.     buf_T    *buf;
  606. {
  607.     memfile_T    *mfp;
  608.     bhdr_T    *hp;
  609.     ZERO_BL    *b0p;
  610.  
  611.     mfp = buf->b_ml.ml_mfp;
  612.  
  613.     if (mfp == NULL || (hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
  614.     return;
  615.     b0p = (ZERO_BL *)(hp->bh_data);
  616.     if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
  617.     EMSG(_("E304: ml_timestamp: Didn't get block 0??"));
  618.     else
  619.     set_b0_fname(b0p, buf);
  620.     mf_put(mfp, hp, TRUE, FALSE);
  621. }
  622.  
  623. /*
  624.  * Write file name and timestamp into block 0 of a swap file.
  625.  * Also set buf->b_mtime.
  626.  * Don't use NameBuff[]!!!
  627.  */
  628.     static void
  629. set_b0_fname(b0p, buf)
  630.     ZERO_BL    *b0p;
  631.     buf_T    *buf;
  632. {
  633.     struct stat    st;
  634.  
  635.     if (buf->b_ffname == NULL)
  636.     b0p->b0_fname[0] = NUL;
  637.     else
  638.     {
  639. #if defined(MSDOS) || defined(MSWIN) || defined(AMIGA) || defined(RISCOS)
  640.     /* systems that cannot translate "~user" back into a path: copy the
  641.      * file name unmodified */
  642.     STRNCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE);
  643. #else
  644.     size_t    flen, ulen;
  645.     char_u    uname[B0_UNAME_SIZE];
  646.  
  647.     /*
  648.      * For a file under the home directory of the current user, we try to
  649.      * replace the home directory path with "~user". This helps when
  650.      * editing the same file on different machines over a network.
  651.      * First replace home dir path with "~/" with home_replace().
  652.      * Then insert the user name to get "~user/".
  653.      */
  654.     home_replace(NULL, buf->b_ffname, b0p->b0_fname, B0_FNAME_SIZE, TRUE);
  655.     if (b0p->b0_fname[0] == '~')
  656.     {
  657.         flen = STRLEN(b0p->b0_fname);
  658.         /* If there is no user name or it is too long, don't use "~/" */
  659.         if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
  660.              || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
  661.         STRNCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE);
  662.         else
  663.         {
  664.         mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
  665.         mch_memmove(b0p->b0_fname + 1, uname, ulen);
  666.         }
  667.     }
  668. #endif
  669.     if (mch_stat((char *)buf->b_ffname, &st) >= 0)
  670.     {
  671.         long_to_char((long)st.st_mtime, b0p->b0_mtime);
  672. #ifdef CHECK_INODE
  673.         long_to_char((long)st.st_ino, b0p->b0_ino);
  674. #endif
  675.         buf_store_time(buf, &st, buf->b_ffname);
  676.         buf->b_mtime_read = buf->b_mtime;
  677.     }
  678.     else
  679.     {
  680.         long_to_char(0L, b0p->b0_mtime);
  681. #ifdef CHECK_INODE
  682.         long_to_char(0L, b0p->b0_ino);
  683. #endif
  684.         buf->b_mtime = 0;
  685.         buf->b_mtime_read = 0;
  686.         buf->b_orig_size = 0;
  687.         buf->b_orig_mode = 0;
  688.     }
  689.     }
  690. }
  691.  
  692. /*
  693.  * try to recover curbuf from the .swp file
  694.  */
  695.     void
  696. ml_recover()
  697. {
  698.     buf_T    *buf = NULL;
  699.     memfile_T    *mfp = NULL;
  700.     char_u    *fname;
  701.     bhdr_T    *hp = NULL;
  702.     ZERO_BL    *b0p;
  703.     PTR_BL    *pp;
  704.     DATA_BL    *dp;
  705.     infoptr_T    *ip;
  706.     blocknr_T    bnum;
  707.     int        page_count;
  708.     struct stat    org_stat, swp_stat;
  709.     int        len;
  710.     int        directly;
  711.     linenr_T    lnum;
  712.     char_u    *p;
  713.     int        i;
  714.     long    error;
  715.     int        cannot_open;
  716.     linenr_T    line_count;
  717.     int        has_error;
  718.     int        idx;
  719.     int        top;
  720.     int        txt_start;
  721.     off_t    size;
  722.     int        called_from_main;
  723.     int        serious_error = TRUE;
  724.     long    mtime;
  725.     int        attr;
  726.  
  727.     recoverymode = TRUE;
  728.     called_from_main = (curbuf->b_ml.ml_mfp == NULL);
  729.     attr = hl_attr(HLF_E);
  730. /*
  731.  * If the file name ends in ".sw?" we use it directly.
  732.  * Otherwise a search is done to find the swap file(s).
  733.  */
  734.     fname = curbuf->b_fname;
  735.     if (fname == NULL)            /* When there is no file name */
  736.     fname = (char_u *)"";
  737.     len = (int)STRLEN(fname);
  738.     if (len >= 4 &&
  739. #if defined(VMS) || defined(RISCOS)
  740.         STRNICMP(fname + len - 4, "_sw" , 3)
  741. #else
  742.         STRNICMP(fname + len - 4, ".sw" , 3)
  743. #endif
  744.         == 0)
  745.     {
  746.     directly = TRUE;
  747.     fname = vim_strsave(fname); /* make a copy for mf_open() */
  748.     }
  749.     else
  750.     {
  751.     directly = FALSE;
  752.  
  753.     /* count the number of matching swap files */
  754.     len = recover_names(&fname, FALSE, 0);
  755.     if (len == 0)            /* no swap files found */
  756.     {
  757.         EMSG2(_("E305: No swap file found for %s"), fname);
  758.         goto theend;
  759.     }
  760.     if (len == 1)            /* one swap file found, use it */
  761.         i = 1;
  762.     else                /* several swap files found, choose */
  763.     {
  764.         /* list the names of the swap files */
  765.         (void)recover_names(&fname, TRUE, 0);
  766.         msg_putchar('\n');
  767.         MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
  768.         i = get_number(FALSE);
  769.         if (i < 1 || i > len)
  770.         goto theend;
  771.     }
  772.     /* get the swap file name that will be used */
  773.     (void)recover_names(&fname, FALSE, i);
  774.     }
  775.     if (fname == NULL)
  776.     goto theend;            /* out of memory */
  777.  
  778.     /* When called from main() still need to initialize storage structure */
  779.     if (called_from_main && ml_open() == FAIL)
  780.     getout(1);
  781.  
  782. /*
  783.  * allocate a buffer structure (only the memline in it is really used)
  784.  */
  785.     buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
  786.     if (buf == NULL)
  787.     {
  788.     vim_free(fname);
  789.     goto theend;
  790.     }
  791.  
  792. /*
  793.  * init fields in memline struct
  794.  */
  795.     buf->b_ml.ml_stack_size = 0;    /* no stack yet */
  796.     buf->b_ml.ml_stack = NULL;        /* no stack yet */
  797.     buf->b_ml.ml_stack_top = 0;        /* nothing in the stack */
  798.     buf->b_ml.ml_line_lnum = 0;        /* no cached line */
  799.     buf->b_ml.ml_locked = NULL;        /* no locked block */
  800.     buf->b_ml.ml_flags = 0;
  801.  
  802. /*
  803.  * open the memfile from the old swap file
  804.  */
  805.     p = vim_strsave(fname);        /* save fname for the message
  806.                        (mf_open() may free fname) */
  807.     mfp = mf_open(fname, O_RDONLY);    /* consumes fname! */
  808.     if (mfp == NULL || mfp->mf_fd < 0)
  809.     {
  810.     if (p != NULL)
  811.     {
  812.         EMSG2(_("E306: Cannot open %s"), p);
  813.         vim_free(p);
  814.     }
  815.     goto theend;
  816.     }
  817.     vim_free(p);
  818.     buf->b_ml.ml_mfp = mfp;
  819.  
  820.     /*
  821.      * The page size set in mf_open() might be different from the page size
  822.      * used in the swap file, we must get it from block 0.  But to read block
  823.      * 0 we need a page size.  Use the minimal size for block 0 here, it will
  824.      * be set to the real value below.
  825.      */
  826.     mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
  827.  
  828. /*
  829.  * try to read block 0
  830.  */
  831.     if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
  832.     {
  833.     msg_start();
  834.     MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
  835.     msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
  836.     MSG_PUTS_ATTR(
  837.        _("\nMaybe no changes were made or Vim did not update the swap file."),
  838.         attr | MSG_HIST);
  839.     msg_end();
  840.     goto theend;
  841.     }
  842.     b0p = (ZERO_BL *)(hp->bh_data);
  843.     if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
  844.     {
  845.     msg_start();
  846.     msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
  847.     MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
  848.                                     MSG_HIST);
  849.     MSG_PUTS_ATTR(_("Use Vim version 3.0.\n"), MSG_HIST);
  850.     msg_end();
  851.     goto theend;
  852.     }
  853.     if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
  854.     {
  855.     EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
  856.     goto theend;
  857.     }
  858.     if (b0_magic_wrong(b0p))
  859.     {
  860.     msg_start();
  861.     msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
  862. #if defined(MSDOS) || defined(MSWIN)
  863.     if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
  864.         MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
  865.                                  attr | MSG_HIST);
  866.     else
  867. #endif
  868.         MSG_PUTS_ATTR(_(" cannot be used on this computer.\n"),
  869.                                  attr | MSG_HIST);
  870.     MSG_PUTS_ATTR(_("The file was created on "), attr | MSG_HIST);
  871.     /* avoid going past the end of a currupted hostname */
  872.     b0p->b0_fname[0] = NUL;
  873.     MSG_PUTS_ATTR(b0p->b0_hname, attr | MSG_HIST);
  874.     MSG_PUTS_ATTR(_(",\nor the file has been damaged."), attr | MSG_HIST);
  875.     msg_end();
  876.     goto theend;
  877.     }
  878.     /*
  879.      * If we guessed the wrong page size, we have to recalculate the
  880.      * highest block number in the file.
  881.      */
  882.     if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
  883.     {
  884.     mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
  885.     if ((size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
  886.         mfp->mf_blocknr_max = 0;        /* no file or empty file */
  887.     else
  888.         mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
  889.     mfp->mf_infile_count = mfp->mf_blocknr_max;
  890.     }
  891.  
  892. /*
  893.  * If .swp file name given directly, use name from swap file for buffer.
  894.  */
  895.     if (directly)
  896.     {
  897.     expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
  898.     if (setfname(NameBuff, NULL, TRUE) == FAIL)
  899.         goto theend;
  900.     }
  901.  
  902.     home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
  903.     msg_str((char_u *)_("Using swap file \"%s\""), NameBuff);
  904.  
  905.     if (buf_spname(curbuf) != NULL)
  906.     STRCPY(NameBuff, buf_spname(curbuf));
  907.     else
  908.     home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
  909.     msg_str((char_u *)_("Original file \"%s\""), NameBuff);
  910.     msg_putchar('\n');
  911.  
  912. /*
  913.  * check date of swap file and original file
  914.  */
  915.     mtime = char_to_long(b0p->b0_mtime);
  916.     if (curbuf->b_ffname != NULL
  917.         && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
  918.         && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
  919.             && org_stat.st_mtime > swp_stat.st_mtime)
  920.         || org_stat.st_mtime != mtime))
  921.     {
  922.     EMSG(_("E308: Warning: Original file may have been changed"));
  923.     }
  924.     out_flush();
  925.     mf_put(mfp, hp, FALSE, FALSE);    /* release block 0 */
  926.     hp = NULL;
  927.  
  928.     /*
  929.      * Now that we are sure that the file is going to be recovered, clear the
  930.      * contents of the current buffer.
  931.      */
  932.     while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
  933.     ml_delete((linenr_T)1, FALSE);
  934.  
  935.     bnum = 1;        /* start with block 1 */
  936.     page_count = 1;    /* which is 1 page */
  937.     lnum = 0;        /* append after line 0 in curbuf */
  938.     line_count = 0;
  939.     idx = 0;        /* start with first index in block 1 */
  940.     error = 0;
  941.     buf->b_ml.ml_stack_top = 0;
  942.     buf->b_ml.ml_stack = NULL;
  943.     buf->b_ml.ml_stack_size = 0;    /* no stack yet */
  944.  
  945.     if (curbuf->b_ffname == NULL)
  946.     cannot_open = TRUE;
  947.     else
  948.     cannot_open = FALSE;
  949.  
  950.     serious_error = FALSE;
  951.     for ( ; !got_int; line_breakcheck())
  952.     {
  953.     if (hp != NULL)
  954.         mf_put(mfp, hp, FALSE, FALSE);    /* release previous block */
  955.  
  956.     /*
  957.      * get block
  958.      */
  959.     if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
  960.     {
  961.         if (bnum == 1)
  962.         {
  963.         EMSG2(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
  964.         goto theend;
  965.         }
  966.         ++error;
  967.         ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
  968.                                 (colnr_T)0, TRUE);
  969.     }
  970.     else        /* there is a block */
  971.     {
  972.         pp = (PTR_BL *)(hp->bh_data);
  973.         if (pp->pb_id == PTR_ID)        /* it is a pointer block */
  974.         {
  975.         /* check line count when using pointer block first time */
  976.         if (idx == 0 && line_count != 0)
  977.         {
  978.             for (i = 0; i < (int)pp->pb_count; ++i)
  979.             line_count -= pp->pb_pointer[i].pe_line_count;
  980.             if (line_count != 0)
  981.             {
  982.             ++error;
  983.             ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
  984.                                 (colnr_T)0, TRUE);
  985.             }
  986.         }
  987.  
  988.         if (pp->pb_count == 0)
  989.         {
  990.             ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
  991.                                 (colnr_T)0, TRUE);
  992.             ++error;
  993.         }
  994.         else if (idx < (int)pp->pb_count)    /* go a block deeper */
  995.         {
  996.             if (pp->pb_pointer[idx].pe_bnum < 0)
  997.             {
  998.             /*
  999.              * Data block with negative block number.
  1000.              * Try to read lines from the original file.
  1001.              * This is slow, but it works.
  1002.              */
  1003.             if (!cannot_open)
  1004.             {
  1005.                 line_count = pp->pb_pointer[idx].pe_line_count;
  1006.                 if (readfile(curbuf->b_ffname, NULL, lnum,
  1007.                     pp->pb_pointer[idx].pe_old_lnum - 1,
  1008.                     line_count, NULL, 0) == FAIL)
  1009.                 cannot_open = TRUE;
  1010.                 else
  1011.                 lnum += line_count;
  1012.             }
  1013.             if (cannot_open)
  1014.             {
  1015.                 ++error;
  1016.                 ml_append(lnum++, (char_u *)_("???LINES MISSING"),
  1017.                                 (colnr_T)0, TRUE);
  1018.             }
  1019.             ++idx;        /* get same block again for next index */
  1020.             continue;
  1021.             }
  1022.  
  1023.             /*
  1024.              * going one block deeper in the tree
  1025.              */
  1026.             if ((top = ml_add_stack(buf)) < 0)    /* new entry in stack */
  1027.             {
  1028.             ++error;
  1029.             break;            /* out of memory */
  1030.             }
  1031.             ip = &(buf->b_ml.ml_stack[top]);
  1032.             ip->ip_bnum = bnum;
  1033.             ip->ip_index = idx;
  1034.  
  1035.             bnum = pp->pb_pointer[idx].pe_bnum;
  1036.             line_count = pp->pb_pointer[idx].pe_line_count;
  1037.             page_count = pp->pb_pointer[idx].pe_page_count;
  1038.             continue;
  1039.         }
  1040.         }
  1041.         else        /* not a pointer block */
  1042.         {
  1043.         dp = (DATA_BL *)(hp->bh_data);
  1044.         if (dp->db_id != DATA_ID)    /* block id wrong */
  1045.         {
  1046.             if (bnum == 1)
  1047.             {
  1048.             EMSG2(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
  1049.                                    mfp->mf_fname);
  1050.             goto theend;
  1051.             }
  1052.             ++error;
  1053.             ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
  1054.                                 (colnr_T)0, TRUE);
  1055.         }
  1056.         else
  1057.         {
  1058.             /*
  1059.              * it is a data block
  1060.              * Append all the lines in this block
  1061.              */
  1062.             has_error = FALSE;
  1063.             /*
  1064.              * check length of block
  1065.              * if wrong, use length in pointer block
  1066.              */
  1067.             if (page_count * mfp->mf_page_size != dp->db_txt_end)
  1068.             {
  1069.             ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
  1070.                                 (colnr_T)0, TRUE);
  1071.             ++error;
  1072.             has_error = TRUE;
  1073.             dp->db_txt_end = page_count * mfp->mf_page_size;
  1074.             }
  1075.  
  1076.             /* make sure there is a NUL at the end of the block */
  1077.             *((char_u *)dp + dp->db_txt_end - 1) = NUL;
  1078.  
  1079.             /*
  1080.              * check number of lines in block
  1081.              * if wrong, use count in data block
  1082.              */
  1083.             if (line_count != dp->db_line_count)
  1084.             {
  1085.             ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
  1086.                                 (colnr_T)0, TRUE);
  1087.             ++error;
  1088.             has_error = TRUE;
  1089.             }
  1090.  
  1091.             for (i = 0; i < dp->db_line_count; ++i)
  1092.             {
  1093.             txt_start = (dp->db_index[i] & DB_INDEX_MASK);
  1094.             if (txt_start <= HEADER_SIZE
  1095.                       || txt_start >= (int)dp->db_txt_end)
  1096.             {
  1097.                 p = (char_u *)"???";
  1098.                 ++error;
  1099.             }
  1100.             else
  1101.                 p = (char_u *)dp + txt_start;
  1102.             ml_append(lnum++, p, (colnr_T)0, TRUE);
  1103.             }
  1104.             if (has_error)
  1105.             ml_append(lnum++, (char_u *)_("???END"), (colnr_T)0, TRUE);
  1106.         }
  1107.         }
  1108.     }
  1109.  
  1110.     if (buf->b_ml.ml_stack_top == 0)    /* finished */
  1111.         break;
  1112.  
  1113.     /*
  1114.      * go one block up in the tree
  1115.      */
  1116.     ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
  1117.     bnum = ip->ip_bnum;
  1118.     idx = ip->ip_index + 1;        /* go to next index */
  1119.     page_count = 1;
  1120.     }
  1121.  
  1122.     /*
  1123.      * The dummy line from the empty buffer will now be after the last line in
  1124.      * the buffer. Delete it.
  1125.      */
  1126.     ml_delete(curbuf->b_ml.ml_line_count, FALSE);
  1127.     curbuf->b_flags |= BF_RECOVERED;
  1128.  
  1129.     recoverymode = FALSE;
  1130.     if (got_int)
  1131.     EMSG(_("E311: Recovery Interrupted"));
  1132.     else if (error)
  1133.     EMSG(_("E312: Errors detected while recovering; look for lines starting with ???"));
  1134.     else
  1135.     {
  1136.     MSG(_("Recovery completed. You should check if everything is OK."));
  1137.     MSG_PUTS(_("\n(You might want to write out this file under another name\n"));
  1138.     MSG_PUTS(_("and run diff with the original file to check for changes)\n"));
  1139.     MSG_PUTS(_("Delete the .swp file afterwards.\n\n"));
  1140.     cmdline_row = msg_row;
  1141.     }
  1142.     redraw_curbuf_later(NOT_VALID);
  1143.  
  1144. theend:
  1145.     recoverymode = FALSE;
  1146.     if (mfp != NULL)
  1147.     {
  1148.     if (hp != NULL)
  1149.         mf_put(mfp, hp, FALSE, FALSE);
  1150.     mf_close(mfp, FALSE);        /* will also vim_free(mfp->mf_fname) */
  1151.     }
  1152.     vim_free(buf);
  1153.     if (serious_error && called_from_main)
  1154.     ml_close(curbuf, TRUE);
  1155. #ifdef FEAT_AUTOCMD
  1156.     else
  1157.     {
  1158.     apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
  1159.     apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
  1160.     }
  1161. #endif
  1162.     return;
  1163. }
  1164.  
  1165. /*
  1166.  * Find the names of swap files in current directory and the directory given
  1167.  * with the 'directory' option.
  1168.  *
  1169.  * Used to:
  1170.  * - list the swap files for "vim -r"
  1171.  * - count the number of swap files when recovering
  1172.  * - list the swap files when recovering
  1173.  * - find the name of the n'th swap file when recovering
  1174.  */
  1175.     int
  1176. recover_names(fname, list, nr)
  1177.     char_u    **fname;    /* base for swap file name */
  1178.     int        list;        /* when TRUE, list the swap file names */
  1179.     int        nr;        /* when non-zero, return nr'th swap file name */
  1180. {
  1181.     int        num_names;
  1182.     char_u    *(names[6]);
  1183.     char_u    *tail;
  1184.     char_u    *p;
  1185.     int        num_files;
  1186.     int        file_count = 0;
  1187.     char_u    **files;
  1188.     int        i;
  1189.     char_u    *dirp;
  1190.     char_u    *dir_name;
  1191.  
  1192.     if (list)
  1193.     {
  1194.         /* use msg() to start the scrolling properly */
  1195.     msg((char_u *)_("Swap files found:"));
  1196.     msg_putchar('\n');
  1197.     }
  1198.  
  1199.     /*
  1200.      * Do the loop for every directory in 'directory'.
  1201.      * First allocate some memory to put the directory name in.
  1202.      */
  1203.     dir_name = alloc((unsigned)STRLEN(p_dir) + 1);
  1204.     dirp = p_dir;
  1205.     while (dir_name != NULL && *dirp)
  1206.     {
  1207.     /*
  1208.      * Isolate a directory name from *dirp and put it in dir_name (we know
  1209.      * it is large enough, so use 31000 for length).
  1210.      * Advance dirp to next directory name.
  1211.      */
  1212.     (void)copy_option_part(&dirp, dir_name, 31000, ",");
  1213.  
  1214.     if (dir_name[0] == '.' && dir_name[1] == NUL)    /* check current dir */
  1215.     {
  1216.         if (fname == NULL || *fname == NULL)
  1217.         {
  1218. #ifdef VMS
  1219.         names[0] = vim_strsave((char_u *)"*_sw%");
  1220. #else
  1221. # ifdef RISCOS
  1222.         names[0] = vim_strsave((char_u *)"*_sw#");
  1223. # else
  1224.         names[0] = vim_strsave((char_u *)"*.sw?");
  1225. # endif
  1226. #endif
  1227. #ifdef UNIX
  1228.         /* for Unix names starting with a dot are special */
  1229.         names[1] = vim_strsave((char_u *)".*.sw?");
  1230.         names[2] = vim_strsave((char_u *)".sw?");
  1231.         num_names = 3;
  1232. #else
  1233. # ifdef VMS
  1234.         names[1] = vim_strsave((char_u *)".*_sw%");
  1235.         num_names = 2;
  1236. # else
  1237.         num_names = 1;
  1238. # endif
  1239. #endif
  1240.         }
  1241.         else
  1242.         num_names = recov_file_names(names, *fname, TRUE);
  1243.     }
  1244.     else                /* check directory dir_name */
  1245.     {
  1246.         if (fname == NULL || *fname == NULL)
  1247.         {
  1248. #ifdef VMS
  1249.         names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
  1250. #else
  1251. # ifdef RISCOS
  1252.         names[0] = concat_fnames(dir_name, (char_u *)"*_sw#", TRUE);
  1253. # else
  1254.         names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
  1255. # endif
  1256. #endif
  1257. #ifdef UNIX
  1258.         /* for Unix names starting with a dot are special */
  1259.         names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
  1260.         names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
  1261.         num_names = 3;
  1262. #else
  1263. # ifdef VMS
  1264.         names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
  1265.         num_names = 2;
  1266. # else
  1267.         num_names = 1;
  1268. # endif
  1269. #endif
  1270.         }
  1271.         else
  1272.         {
  1273. #if defined(UNIX) || defined(WIN3264)
  1274.         p = dir_name + STRLEN(dir_name);
  1275.         if (vim_ispathsep(p[-1]) && p[-1] == p[-2])
  1276.         {
  1277.             /* Ends with '//', Use Full path for swap name */
  1278.             tail = make_percent_swname(dir_name, *fname);
  1279.         }
  1280.         else
  1281. #endif
  1282.         {
  1283.             tail = gettail(*fname);
  1284.             tail = concat_fnames(dir_name, tail, TRUE);
  1285.         }
  1286.         if (tail == NULL)
  1287.             num_names = 0;
  1288.         else
  1289.         {
  1290.             num_names = recov_file_names(names, tail, FALSE);
  1291.             vim_free(tail);
  1292.         }
  1293.         }
  1294.     }
  1295.  
  1296.         /* check for out-of-memory */
  1297.     for (i = 0; i < num_names; ++i)
  1298.     {
  1299.         if (names[i] == NULL)
  1300.         {
  1301.         for (i = 0; i < num_names; ++i)
  1302.             vim_free(names[i]);
  1303.         num_names = 0;
  1304.         }
  1305.     }
  1306.     if (num_names == 0)
  1307.         num_files = 0;
  1308.     else if (expand_wildcards(num_names, names, &num_files, &files,
  1309.                     EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
  1310.         num_files = 0;
  1311.  
  1312.     /*
  1313.      * When no swap file found, wildcard expansion might have failed (e.g.
  1314.      * not able to execute the shell).
  1315.      * Try finding a swap file by simply adding ".swp" to the file name.
  1316.      */
  1317.     if (*dirp == NUL && file_count + num_files == 0
  1318.                        && fname != NULL && *fname != NULL)
  1319.     {
  1320.         struct stat        st;
  1321.         char_u        *swapname;
  1322.  
  1323. #if defined(VMS) || defined(RISCOS)
  1324.         swapname = modname(*fname, (char_u *)"_swp", FALSE);
  1325. #else
  1326.         swapname = modname(*fname, (char_u *)".swp", TRUE);
  1327. #endif
  1328.         if (swapname != NULL)
  1329.         {
  1330.         if (mch_stat((char *)swapname, &st) != -1)        /* It exists! */
  1331.         {
  1332.             files = (char_u **)alloc((unsigned)sizeof(char_u *));
  1333.             if (files != NULL)
  1334.             {
  1335.             files[0] = swapname;
  1336.             swapname = NULL;
  1337.             num_files = 1;
  1338.             }
  1339.         }
  1340.         vim_free(swapname);
  1341.         }
  1342.     }
  1343.  
  1344.     /*
  1345.      * remove swapfile name of the current buffer, it must be ignored
  1346.      */
  1347.     if (curbuf->b_ml.ml_mfp != NULL
  1348.                    && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
  1349.     {
  1350.         for (i = 0; i < num_files; ++i)
  1351.         if (fullpathcmp(p, files[i], TRUE) & FPC_SAME)
  1352.         {
  1353.             vim_free(files[i]);
  1354.             --num_files;
  1355.             for ( ; i < num_files; ++i)
  1356.             files[i] = files[i + 1];
  1357.         }
  1358.     }
  1359.     if (nr)
  1360.     {
  1361.         file_count += num_files;
  1362.         if (nr <= file_count)
  1363.         {
  1364.         *fname = vim_strsave(files[nr - 1 + num_files - file_count]);
  1365.         dirp = (char_u *)"";            /* stop searching */
  1366.         }
  1367.     }
  1368.     else if (list)
  1369.     {
  1370.         if (dir_name[0] == '.' && dir_name[1] == NUL)
  1371.         {
  1372.         if (fname == NULL || *fname == NULL)
  1373.             MSG_PUTS(_("   In current directory:\n"));
  1374.         else
  1375.             MSG_PUTS(_("   Using specified name:\n"));
  1376.         }
  1377.         else
  1378.         {
  1379.         MSG_PUTS(_("   In directory "));
  1380.         msg_home_replace(dir_name);
  1381.         MSG_PUTS(":\n");
  1382.         }
  1383.  
  1384.         if (num_files)
  1385.         {
  1386.         for (i = 0; i < num_files; ++i)
  1387.         {
  1388.             /* print the swap file name */
  1389.             msg_outnum((long)++file_count);
  1390.             MSG_PUTS(".    ");
  1391.             msg_puts(gettail(files[i]));
  1392.             msg_putchar('\n');
  1393.             (void)swapfile_info(files[i]);
  1394.         }
  1395.         }
  1396.         else
  1397.         MSG_PUTS(_("      -- none --\n"));
  1398.         out_flush();
  1399.     }
  1400.     else
  1401.         file_count += num_files;
  1402.  
  1403.     for (i = 0; i < num_names; ++i)
  1404.         vim_free(names[i]);
  1405.     FreeWild(num_files, files);
  1406.     }
  1407.     vim_free(dir_name);
  1408.     return file_count;
  1409. }
  1410.  
  1411. #if defined(UNIX) || defined(WIN3264)  /* Need _very_ long file names */
  1412. /*
  1413.  * Append the full path to name with path separators made into percent
  1414.  * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
  1415.  */
  1416.     static char_u *
  1417. make_percent_swname(dir, name)
  1418.     char_u    *dir;
  1419.     char_u    *name;
  1420. {
  1421.     char_u *d, *s, *f, *p;
  1422.  
  1423.     f = fix_fname(name != NULL ? name : (char_u *) "");
  1424.     d = NULL;
  1425.     if (f != NULL)
  1426.     {
  1427.     s = alloc((unsigned)(STRLEN(f) + 1));
  1428.     if (s != NULL)
  1429.     {
  1430.         for (d = s, p = f; *p; p++, d++)
  1431.         *d = vim_ispathsep(*p) ? '%' : *p;
  1432.         *d = 0;
  1433.         d = concat_fnames(dir, s, TRUE);
  1434.         vim_free(s);
  1435.     }
  1436.     vim_free(f);
  1437.     }
  1438.     return d;
  1439. }
  1440. #endif
  1441.  
  1442. #if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  1443. static int process_still_running;
  1444. #endif
  1445.  
  1446. /*
  1447.  * Give information about an existing swap file
  1448.  * Returns timestamp (0 when unknown).
  1449.  */
  1450.     static time_t
  1451. swapfile_info(fname)
  1452.     char_u    *fname;
  1453. {
  1454.     struct stat        st;
  1455.     int            fd;
  1456.     struct block0   b0;
  1457.     time_t        x = (time_t)0;
  1458. #ifdef UNIX
  1459.     char_u        uname[B0_UNAME_SIZE];
  1460. #endif
  1461.  
  1462.     /* print the swap file date */
  1463.     if (mch_stat((char *)fname, &st) != -1)
  1464.     {
  1465. #ifdef UNIX
  1466.     /* print name of owner of the file */
  1467.     if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
  1468.     {
  1469.         MSG_PUTS(_("          owned by: "));
  1470.         msg_outtrans(uname);
  1471.         MSG_PUTS(_("   dated: "));
  1472.     }
  1473.     else
  1474. #endif
  1475.         MSG_PUTS(_("             dated: "));
  1476.     x = st.st_mtime;            /* Manx C can't do &st.st_mtime */
  1477.     MSG_PUTS(ctime(&x));            /* includes '\n' */
  1478.  
  1479.     }
  1480.  
  1481.     /*
  1482.      * print the original file name
  1483.      */
  1484.     fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
  1485.     if (fd >= 0)
  1486.     {
  1487.     if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
  1488.     {
  1489.         if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
  1490.         {
  1491.         MSG_PUTS(_("         [from Vim version 3.0]"));
  1492.         }
  1493.         else if (b0.b0_id[0] != BLOCK0_ID0 || b0.b0_id[1] != BLOCK0_ID1)
  1494.         {
  1495.         MSG_PUTS(_("         [does not look like a Vim swap file]"));
  1496.         }
  1497.         else
  1498.         {
  1499.         MSG_PUTS(_("         file name: "));
  1500.         if (b0.b0_fname[0] == NUL)
  1501.             MSG_PUTS(_("[No File]"));
  1502.         else
  1503.             msg_outtrans(b0.b0_fname);
  1504.  
  1505.         MSG_PUTS(_("\n          modified: "));
  1506.         MSG_PUTS(b0.b0_dirty ? _("YES") : _("no"));
  1507.  
  1508.         if (*(b0.b0_uname) != NUL)
  1509.         {
  1510.             MSG_PUTS(_("\n         user name: "));
  1511.             msg_outtrans(b0.b0_uname);
  1512.         }
  1513.  
  1514.         if (*(b0.b0_hname) != NUL)
  1515.         {
  1516.             if (*(b0.b0_uname) != NUL)
  1517.             MSG_PUTS(_("   host name: "));
  1518.             else
  1519.             MSG_PUTS(_("\n         host name: "));
  1520.             msg_outtrans(b0.b0_hname);
  1521.         }
  1522.  
  1523.         if (char_to_long(b0.b0_pid) != 0L)
  1524.         {
  1525.             MSG_PUTS(_("\n        process ID: "));
  1526.             msg_outnum(char_to_long(b0.b0_pid));
  1527. #if defined(UNIX) || defined(__EMX__)
  1528.             /* EMX kill() not working correctly, it seems */
  1529.             if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
  1530.             {
  1531.             MSG_PUTS(_(" (still running)"));
  1532. # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  1533.             process_still_running = TRUE;
  1534. # endif
  1535.             }
  1536. #endif
  1537.         }
  1538.  
  1539.         if (b0_magic_wrong(&b0))
  1540.         {
  1541. #if defined(MSDOS) || defined(MSWIN)
  1542.             if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
  1543.             MSG_PUTS(_("\n         [not usable with this version of Vim]"));
  1544.             else
  1545. #endif
  1546.             MSG_PUTS(_("\n         [not usable on this computer]"));
  1547.         }
  1548.         }
  1549.     }
  1550.     else
  1551.         MSG_PUTS(_("         [cannot be read]"));
  1552.     close(fd);
  1553.     }
  1554.     else
  1555.     MSG_PUTS(_("         [cannot be opened]"));
  1556.     msg_putchar('\n');
  1557.  
  1558.     return x;
  1559. }
  1560.  
  1561.     static int
  1562. recov_file_names(names, path, prepend_dot)
  1563.     char_u    **names;
  1564.     char_u    *path;
  1565.     int        prepend_dot;
  1566. {
  1567.     int        num_names;
  1568.  
  1569. #ifdef SHORT_FNAME
  1570.     /*
  1571.      * (MS-DOS) always short names
  1572.      */
  1573.     names[0] = modname(path, (char_u *)".sw?", FALSE);
  1574.     num_names = 1;
  1575. #else /* !SHORT_FNAME */
  1576.     /*
  1577.      * (Win32 and Win64) never short names, but do prepend a dot.
  1578.      * (Not MS-DOS or Win32 or Win64) maybe short name, maybe not: Try both.
  1579.      * Only use the short name if it is different.
  1580.      */
  1581.     char_u    *p;
  1582.     int        i;
  1583. # ifndef WIN3264
  1584.     int        shortname = curbuf->b_shortname;
  1585.  
  1586.     curbuf->b_shortname = FALSE;
  1587. # endif
  1588.  
  1589.     num_names = 0;
  1590.  
  1591.     /*
  1592.      * May also add the file name with a dot prepended, for swap file in same
  1593.      * dir as original file.
  1594.      */
  1595.     if (prepend_dot)
  1596.     {
  1597.     names[num_names] = modname(path, (char_u *)".sw?", TRUE);
  1598.     if (names[num_names] == NULL)
  1599.         goto end;
  1600.     ++num_names;
  1601.     }
  1602.  
  1603.     /*
  1604.      * Form the normal swap file name pattern by appending ".sw?".
  1605.      */
  1606. #ifdef VMS
  1607.     names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
  1608. #else
  1609. # ifdef RISCOS
  1610.     names[num_names] = concat_fnames(path, (char_u *)"_sw#", FALSE);
  1611. # else
  1612.     names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
  1613. # endif
  1614. #endif
  1615.     if (names[num_names] == NULL)
  1616.     goto end;
  1617.     if (num_names >= 1)        /* check if we have the same name twice */
  1618.     {
  1619.     p = names[num_names - 1];
  1620.     i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
  1621.     if (i > 0)
  1622.         p += i;        /* file name has been expanded to full path */
  1623.  
  1624.     if (STRCMP(p, names[num_names]) != 0)
  1625.         ++num_names;
  1626.     else
  1627.         vim_free(names[num_names]);
  1628.     }
  1629.     else
  1630.     ++num_names;
  1631.  
  1632. # ifndef WIN3264
  1633.     /*
  1634.      * Also try with 'shortname' set, in case the file is on a DOS filesystem.
  1635.      */
  1636.     curbuf->b_shortname = TRUE;
  1637. #ifdef VMS
  1638.     names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
  1639. #else
  1640. # ifdef RISCOS
  1641.     names[num_names] = modname(path, (char_u *)"_sw#", FALSE);
  1642. # else
  1643.     names[num_names] = modname(path, (char_u *)".sw?", FALSE);
  1644. # endif
  1645. #endif
  1646.     if (names[num_names] == NULL)
  1647.     goto end;
  1648.  
  1649.     /*
  1650.      * Remove the one from 'shortname', if it's the same as with 'noshortname'.
  1651.      */
  1652.     p = names[num_names];
  1653.     i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
  1654.     if (i > 0)
  1655.     p += i;        /* file name has been expanded to full path */
  1656.     if (STRCMP(names[num_names - 1], p) == 0)
  1657.     vim_free(names[num_names]);
  1658.     else
  1659.     ++num_names;
  1660. # endif
  1661.  
  1662. end:
  1663. # ifndef WIN3264
  1664.     curbuf->b_shortname = shortname;
  1665. # endif
  1666.  
  1667. #endif /* !SHORT_FNAME */
  1668.  
  1669.     return num_names;
  1670. }
  1671.  
  1672. /*
  1673.  * sync all memlines
  1674.  *
  1675.  * If 'check_file' is TRUE, check if original file exists and was not changed.
  1676.  * If 'check_char' is TRUE, stop syncing when character becomes available, but
  1677.  * always sync at least one block.
  1678.  */
  1679.     void
  1680. ml_sync_all(check_file, check_char)
  1681.     int        check_file;
  1682.     int        check_char;
  1683. {
  1684.     buf_T        *buf;
  1685.     struct stat        st;
  1686.  
  1687.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1688.     {
  1689.     if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
  1690.         continue;                /* no file */
  1691.  
  1692.     ml_flush_line(buf);            /* flush buffered line */
  1693.                         /* flush locked block */
  1694.     (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
  1695.     if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
  1696.                              && buf->b_ffname != NULL)
  1697.     {
  1698.         /*
  1699.          * If the original file does not exist anymore or has been changed
  1700.          * call ml_preserve() to get rid of all negative numbered blocks.
  1701.          */
  1702.         if (mch_stat((char *)buf->b_ffname, &st) == -1
  1703.             || st.st_mtime != buf->b_mtime_read
  1704.             || (size_t)st.st_size != buf->b_orig_size)
  1705.         {
  1706.         ml_preserve(buf, FALSE);
  1707.         did_check_timestamps = FALSE;
  1708.         need_check_timestamps = TRUE;    /* give message later */
  1709.         }
  1710.     }
  1711.     if (buf->b_ml.ml_mfp->mf_dirty)
  1712.     {
  1713.         (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
  1714.                     | (bufIsChanged(buf) ? MFS_FLUSH : 0));
  1715.         if (check_char && ui_char_avail())    /* character available now */
  1716.         break;
  1717.     }
  1718.     }
  1719. }
  1720.  
  1721. /*
  1722.  * sync one buffer, including negative blocks
  1723.  *
  1724.  * after this all the blocks are in the swap file
  1725.  *
  1726.  * Used for the :preserve command and when the original file has been
  1727.  * changed or deleted.
  1728.  *
  1729.  * when message is TRUE the success of preserving is reported
  1730.  */
  1731.     void
  1732. ml_preserve(buf, message)
  1733.     buf_T    *buf;
  1734.     int        message;
  1735. {
  1736.     bhdr_T    *hp;
  1737.     linenr_T    lnum;
  1738.     memfile_T    *mfp = buf->b_ml.ml_mfp;
  1739.     int        status;
  1740.     int        got_int_save = got_int;
  1741.  
  1742.     if (mfp == NULL || mfp->mf_fname == NULL)
  1743.     {
  1744.     if (message)
  1745.         EMSG(_("E313: Cannot preserve, there is no swap file"));
  1746.     return;
  1747.     }
  1748.  
  1749.     /* We only want to stop when interrupted here, not when interrupted
  1750.      * before. */
  1751.     got_int = FALSE;
  1752.  
  1753.     ml_flush_line(buf);                    /* flush buffered line */
  1754.     (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
  1755.     status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
  1756.  
  1757.     /* stack is invalid after mf_sync(.., MFS_ALL) */
  1758.     buf->b_ml.ml_stack_top = 0;
  1759.  
  1760.     /*
  1761.      * Some of the data blocks may have been changed from negative to
  1762.      * positive block number. In that case the pointer blocks need to be
  1763.      * updated.
  1764.      *
  1765.      * We don't know in which pointer block the references are, so we visit
  1766.      * all data blocks until there are no more translations to be done (or
  1767.      * we hit the end of the file, which can only happen in case a write fails,
  1768.      * e.g. when file system if full).
  1769.      * ml_find_line() does the work by translating the negative block numbers
  1770.      * when getting the first line of each data block.
  1771.      */
  1772.     if (mf_need_trans(mfp) && !got_int)
  1773.     {
  1774.     lnum = 1;
  1775.     while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
  1776.     {
  1777.         hp = ml_find_line(buf, lnum, ML_FIND);
  1778.         if (hp == NULL)
  1779.         {
  1780.         status = FAIL;
  1781.         goto theend;
  1782.         }
  1783.         CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
  1784.         lnum = buf->b_ml.ml_locked_high + 1;
  1785.     }
  1786.     (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);    /* flush locked block */
  1787.     /* sync the updated pointer blocks */
  1788.     if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
  1789.         status = FAIL;
  1790.     buf->b_ml.ml_stack_top = 0;        /* stack is invalid now */
  1791.     }
  1792. theend:
  1793.     got_int |= got_int_save;
  1794.  
  1795.     if (message)
  1796.     {
  1797.     if (status == OK)
  1798.         MSG(_("File preserved"));
  1799.     else
  1800.         EMSG(_("E314: Preserve failed"));
  1801.     }
  1802. }
  1803.  
  1804. /*
  1805.  * NOTE: The pointer returned by the ml_get_*() functions only remains valid
  1806.  * until the next call!
  1807.  *  line1 = ml_get(1);
  1808.  *  line2 = ml_get(2);    // line1 is now invalid!
  1809.  * Make a copy of the line if necessary.
  1810.  */
  1811. /*
  1812.  * get a pointer to a (read-only copy of a) line
  1813.  *
  1814.  * On failure an error message is given and IObuff is returned (to avoid
  1815.  * having to check for error everywhere).
  1816.  */
  1817.     char_u  *
  1818. ml_get(lnum)
  1819.     linenr_T    lnum;
  1820. {
  1821.     return ml_get_buf(curbuf, lnum, FALSE);
  1822. }
  1823.  
  1824. /*
  1825.  * ml_get_pos: get pointer to position 'pos'
  1826.  */
  1827.     char_u *
  1828. ml_get_pos(pos)
  1829.     pos_T    *pos;
  1830. {
  1831.     return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
  1832. }
  1833.  
  1834. /*
  1835.  * ml_get_curline: get pointer to cursor line.
  1836.  */
  1837.     char_u *
  1838. ml_get_curline()
  1839. {
  1840.     return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
  1841. }
  1842.  
  1843. /*
  1844.  * ml_get_cursor: get pointer to cursor position
  1845.  */
  1846.     char_u *
  1847. ml_get_cursor()
  1848. {
  1849.     return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
  1850.                             curwin->w_cursor.col);
  1851. }
  1852.  
  1853. /*
  1854.  * get a pointer to a line in a specific buffer
  1855.  *
  1856.  * "will_change": if TRUE mark the buffer dirty (chars in the line will be
  1857.  * changed)
  1858.  */
  1859.     char_u  *
  1860. ml_get_buf(buf, lnum, will_change)
  1861.     buf_T    *buf;
  1862.     linenr_T    lnum;
  1863.     int        will_change;        /* line will be changed */
  1864. {
  1865.     bhdr_T    *hp;
  1866.     DATA_BL *dp;
  1867.     char_u  *ptr;
  1868.  
  1869.     if (lnum > buf->b_ml.ml_line_count)    /* invalid line number */
  1870.     {
  1871.     EMSGN(_("E315: ml_get: invalid lnum: %ld"), lnum);
  1872. errorret:
  1873.     STRCPY(IObuff, "???");
  1874.     return IObuff;
  1875.     }
  1876.     if (lnum <= 0)            /* pretend line 0 is line 1 */
  1877.     lnum = 1;
  1878.  
  1879.     if (buf->b_ml.ml_mfp == NULL)    /* there are no lines */
  1880.     return (char_u *)"";
  1881.  
  1882. /*
  1883.  * See if it is the same line as requested last time.
  1884.  * Otherwise may need to flush last used line.
  1885.  */
  1886.     if (buf->b_ml.ml_line_lnum != lnum)
  1887.     {
  1888.     ml_flush_line(buf);
  1889.  
  1890.     /*
  1891.      * Find the data block containing the line.
  1892.      * This also fills the stack with the blocks from the root to the data
  1893.      * block and releases any locked block.
  1894.      */
  1895.     if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
  1896.     {
  1897.         EMSGN(_("E316: ml_get: cannot find line %ld"), lnum);
  1898.         goto errorret;
  1899.     }
  1900.  
  1901.     dp = (DATA_BL *)(hp->bh_data);
  1902.  
  1903.     ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
  1904.     buf->b_ml.ml_line_ptr = ptr;
  1905.     buf->b_ml.ml_line_lnum = lnum;
  1906.     buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
  1907.     }
  1908.     if (will_change)
  1909.     buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
  1910.  
  1911.     return buf->b_ml.ml_line_ptr;
  1912. }
  1913.  
  1914. /*
  1915.  * Check if a line that was just obtained by a call to ml_get
  1916.  * is in allocated memory.
  1917.  */
  1918.     int
  1919. ml_line_alloced()
  1920. {
  1921.     return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
  1922. }
  1923.  
  1924. /*
  1925.  * Append a line after lnum (may be 0 to insert a line in front of the file).
  1926.  * "line" does not need to be allocated, but can't be another line in a
  1927.  * buffer, unlocking may make it invalid.
  1928.  *
  1929.  *   newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
  1930.  *        will be set for recovery
  1931.  * Check: The caller of this function should probably also call
  1932.  * appended_lines().
  1933.  *
  1934.  * return FAIL for failure, OK otherwise
  1935.  */
  1936.     int
  1937. ml_append(lnum, line, len, newfile)
  1938.     linenr_T    lnum;        /* append after this line (can be 0) */
  1939.     char_u    *line;        /* text of the new line */
  1940.     colnr_T    len;        /* length of new line, including NUL, or 0 */
  1941.     int        newfile;    /* flag, see above */
  1942. {
  1943.     /* When starting up, we might still need to create the memfile */
  1944.     if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL) == FAIL)
  1945.     return FAIL;
  1946.  
  1947.     if (curbuf->b_ml.ml_line_lnum != 0)
  1948.     ml_flush_line(curbuf);
  1949.     return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
  1950. }
  1951.  
  1952.     static int
  1953. ml_append_int(buf, lnum, line, len, newfile, mark)
  1954.     buf_T    *buf;
  1955.     linenr_T    lnum;        /* append after this line (can be 0) */
  1956.     char_u    *line;        /* text of the new line */
  1957.     colnr_T    len;        /* length of line, including NUL, or 0 */
  1958.     int        newfile;    /* flag, see above */
  1959.     int        mark;        /* mark the new line */
  1960. {
  1961.     int        i;
  1962.     int        line_count;    /* number of indexes in current block */
  1963.     int        offset;
  1964.     int        from, to;
  1965.     int        space_needed;    /* space needed for new line */
  1966.     int        page_size;
  1967.     int        page_count;
  1968.     int        db_idx;        /* index for lnum in data block */
  1969.     bhdr_T    *hp;
  1970.     memfile_T    *mfp;
  1971.     DATA_BL    *dp;
  1972.     PTR_BL    *pp;
  1973.     infoptr_T    *ip;
  1974.  
  1975.                     /* lnum out of range */
  1976.     if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
  1977.     return FAIL;
  1978.  
  1979.     if (lowest_marked && lowest_marked > lnum)
  1980.     lowest_marked = lnum + 1;
  1981.  
  1982.     if (len == 0)
  1983.     len = (colnr_T)STRLEN(line) + 1;    /* space needed for the text */
  1984.     space_needed = len + INDEX_SIZE;    /* space needed for text + index */
  1985.  
  1986.     mfp = buf->b_ml.ml_mfp;
  1987.     page_size = mfp->mf_page_size;
  1988.  
  1989. /*
  1990.  * find the data block containing the previous line
  1991.  * This also fills the stack with the blocks from the root to the data block
  1992.  * This also releases any locked block.
  1993.  */
  1994.     if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
  1995.                               ML_INSERT)) == NULL)
  1996.     return FAIL;
  1997.  
  1998.     buf->b_ml.ml_flags &= ~ML_EMPTY;
  1999.  
  2000.     if (lnum == 0)        /* got line one instead, correct db_idx */
  2001.     db_idx = -1;        /* careful, it is negative! */
  2002.     else
  2003.     db_idx = lnum - buf->b_ml.ml_locked_low;
  2004.         /* get line count before the insertion */
  2005.     line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
  2006.  
  2007.     dp = (DATA_BL *)(hp->bh_data);
  2008.  
  2009. /*
  2010.  * If
  2011.  * - there is not enough room in the current block
  2012.  * - appending to the last line in the block
  2013.  * - not appending to the last line in the file
  2014.  * insert in front of the next block.
  2015.  */
  2016.     if ((int)dp->db_free < space_needed && db_idx == line_count - 1
  2017.                         && lnum < buf->b_ml.ml_line_count)
  2018.     {
  2019.     /*
  2020.      * Now that the line is not going to be inserted in the block that we
  2021.      * expected, the line count has to be adjusted in the pointer blocks
  2022.      * by using ml_locked_lineadd.
  2023.      */
  2024.     --(buf->b_ml.ml_locked_lineadd);
  2025.     --(buf->b_ml.ml_locked_high);
  2026.     if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
  2027.         return FAIL;
  2028.  
  2029.     db_idx = -1;            /* careful, it is negative! */
  2030.             /* get line count before the insertion */
  2031.     line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
  2032.     CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
  2033.  
  2034.     dp = (DATA_BL *)(hp->bh_data);
  2035.     }
  2036.  
  2037.     ++buf->b_ml.ml_line_count;
  2038.  
  2039.     if ((int)dp->db_free >= space_needed)    /* enough room in data block */
  2040.     {
  2041. /*
  2042.  * Insert new line in existing data block, or in data block allocated above.
  2043.  */
  2044.     dp->db_txt_start -= len;
  2045.     dp->db_free -= space_needed;
  2046.     ++(dp->db_line_count);
  2047.  
  2048.     /*
  2049.      * move the text of the lines that follow to the front
  2050.      * adjust the indexes of the lines that follow
  2051.      */
  2052.     if (line_count > db_idx + 1)        /* if there are following lines */
  2053.     {
  2054.         /*
  2055.          * Offset is the start of the previous line.
  2056.          * This will become the character just after the new line.
  2057.          */
  2058.         if (db_idx < 0)
  2059.         offset = dp->db_txt_end;
  2060.         else
  2061.         offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
  2062.         mch_memmove((char *)dp + dp->db_txt_start,
  2063.                       (char *)dp + dp->db_txt_start + len,
  2064.                  (size_t)(offset - (dp->db_txt_start + len)));
  2065.         for (i = line_count - 1; i > db_idx; --i)
  2066.         dp->db_index[i + 1] = dp->db_index[i] - len;
  2067.         dp->db_index[db_idx + 1] = offset - len;
  2068.     }
  2069.     else                    /* add line at the end */
  2070.         dp->db_index[db_idx + 1] = dp->db_txt_start;
  2071.  
  2072.     /*
  2073.      * copy the text into the block
  2074.      */
  2075.     mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
  2076.     if (mark)
  2077.         dp->db_index[db_idx + 1] |= DB_MARKED;
  2078.  
  2079.     /*
  2080.      * Mark the block dirty.
  2081.      */
  2082.     buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2083.     if (!newfile)
  2084.         buf->b_ml.ml_flags |= ML_LOCKED_POS;
  2085.     }
  2086.     else        /* not enough space in data block */
  2087.     {
  2088. /*
  2089.  * If there is not enough room we have to create a new data block and copy some
  2090.  * lines into it.
  2091.  * Then we have to insert an entry in the pointer block.
  2092.  * If this pointer block also is full, we go up another block, and so on, up
  2093.  * to the root if necessary.
  2094.  * The line counts in the pointer blocks have already been adjusted by
  2095.  * ml_find_line().
  2096.  */
  2097.     long        line_count_left, line_count_right;
  2098.     int        page_count_left, page_count_right;
  2099.     bhdr_T        *hp_left;
  2100.     bhdr_T        *hp_right;
  2101.     bhdr_T        *hp_new;
  2102.     int        lines_moved;
  2103.     int        data_moved = 0;        /* init to shut up gcc */
  2104.     int        total_moved = 0;        /* init to shut up gcc */
  2105.     DATA_BL        *dp_right, *dp_left;
  2106.     int        stack_idx;
  2107.     int        in_left;
  2108.     int        lineadd;
  2109.     blocknr_T   bnum_left, bnum_right;
  2110.     linenr_T    lnum_left, lnum_right;
  2111.     int        pb_idx;
  2112.     PTR_BL        *pp_new;
  2113.  
  2114.     /*
  2115.      * We are going to allocate a new data block. Depending on the
  2116.      * situation it will be put to the left or right of the existing
  2117.      * block.  If possible we put the new line in the left block and move
  2118.      * the lines after it to the right block. Otherwise the new line is
  2119.      * also put in the right block. This method is more efficient when
  2120.      * inserting a lot of lines at one place.
  2121.      */
  2122.     if (db_idx < 0)        /* left block is new, right block is existing */
  2123.     {
  2124.         lines_moved = 0;
  2125.         in_left = TRUE;
  2126.         /* space_needed does not change */
  2127.     }
  2128.     else            /* left block is existing, right block is new */
  2129.     {
  2130.         lines_moved = line_count - db_idx - 1;
  2131.         if (lines_moved == 0)
  2132.         in_left = FALSE;    /* put new line in right block */
  2133.                     /* space_needed does not change */
  2134.         else
  2135.         {
  2136.         data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
  2137.                                 dp->db_txt_start;
  2138.         total_moved = data_moved + lines_moved * INDEX_SIZE;
  2139.         if ((int)dp->db_free + total_moved >= space_needed)
  2140.         {
  2141.             in_left = TRUE;    /* put new line in left block */
  2142.             space_needed = total_moved;
  2143.         }
  2144.         else
  2145.         {
  2146.             in_left = FALSE;        /* put new line in right block */
  2147.             space_needed += total_moved;
  2148.         }
  2149.         }
  2150.     }
  2151.  
  2152.     page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
  2153.     if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
  2154.     {
  2155.             /* correct line counts in pointer blocks */
  2156.         --(buf->b_ml.ml_locked_lineadd);
  2157.         --(buf->b_ml.ml_locked_high);
  2158.         return FAIL;
  2159.     }
  2160.     if (db_idx < 0)        /* left block is new */
  2161.     {
  2162.         hp_left = hp_new;
  2163.         hp_right = hp;
  2164.         line_count_left = 0;
  2165.         line_count_right = line_count;
  2166.     }
  2167.     else            /* right block is new */
  2168.     {
  2169.         hp_left = hp;
  2170.         hp_right = hp_new;
  2171.         line_count_left = line_count;
  2172.         line_count_right = 0;
  2173.     }
  2174.     dp_right = (DATA_BL *)(hp_right->bh_data);
  2175.     dp_left = (DATA_BL *)(hp_left->bh_data);
  2176.     bnum_left = hp_left->bh_bnum;
  2177.     bnum_right = hp_right->bh_bnum;
  2178.     page_count_left = hp_left->bh_page_count;
  2179.     page_count_right = hp_right->bh_page_count;
  2180.  
  2181.     /*
  2182.      * May move the new line into the right/new block.
  2183.      */
  2184.     if (!in_left)
  2185.     {
  2186.         dp_right->db_txt_start -= len;
  2187.         dp_right->db_free -= len + INDEX_SIZE;
  2188.         dp_right->db_index[0] = dp_right->db_txt_start;
  2189.         if (mark)
  2190.         dp_right->db_index[0] |= DB_MARKED;
  2191.  
  2192.         mch_memmove((char *)dp_right + dp_right->db_txt_start,
  2193.                                line, (size_t)len);
  2194.         ++line_count_right;
  2195.     }
  2196.     /*
  2197.      * may move lines from the left/old block to the right/new one.
  2198.      */
  2199.     if (lines_moved)
  2200.     {
  2201.         /*
  2202.          */
  2203.         dp_right->db_txt_start -= data_moved;
  2204.         dp_right->db_free -= total_moved;
  2205.         mch_memmove((char *)dp_right + dp_right->db_txt_start,
  2206.             (char *)dp_left + dp_left->db_txt_start,
  2207.             (size_t)data_moved);
  2208.         offset = dp_right->db_txt_start - dp_left->db_txt_start;
  2209.         dp_left->db_txt_start += data_moved;
  2210.         dp_left->db_free += total_moved;
  2211.  
  2212.         /*
  2213.          * update indexes in the new block
  2214.          */
  2215.         for (to = line_count_right, from = db_idx + 1;
  2216.                      from < line_count_left; ++from, ++to)
  2217.         dp_right->db_index[to] = dp->db_index[from] + offset;
  2218.         line_count_right += lines_moved;
  2219.         line_count_left -= lines_moved;
  2220.     }
  2221.  
  2222.     /*
  2223.      * May move the new line into the left (old or new) block.
  2224.      */
  2225.     if (in_left)
  2226.     {
  2227.         dp_left->db_txt_start -= len;
  2228.         dp_left->db_free -= len + INDEX_SIZE;
  2229.         dp_left->db_index[line_count_left] = dp_left->db_txt_start;
  2230.         if (mark)
  2231.         dp_left->db_index[line_count_left] |= DB_MARKED;
  2232.         mch_memmove((char *)dp_left + dp_left->db_txt_start,
  2233.                                line, (size_t)len);
  2234.         ++line_count_left;
  2235.     }
  2236.  
  2237.     if (db_idx < 0)        /* left block is new */
  2238.     {
  2239.         lnum_left = lnum + 1;
  2240.         lnum_right = 0;
  2241.     }
  2242.     else            /* right block is new */
  2243.     {
  2244.         lnum_left = 0;
  2245.         if (in_left)
  2246.         lnum_right = lnum + 2;
  2247.         else
  2248.         lnum_right = lnum + 1;
  2249.     }
  2250.     dp_left->db_line_count = line_count_left;
  2251.     dp_right->db_line_count = line_count_right;
  2252.  
  2253.     /*
  2254.      * release the two data blocks
  2255.      * The new one (hp_new) already has a correct blocknumber.
  2256.      * The old one (hp, in ml_locked) gets a positive blocknumber if
  2257.      * we changed it and we are not editing a new file.
  2258.      */
  2259.     if (lines_moved || in_left)
  2260.         buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2261.     if (!newfile && db_idx >= 0 && in_left)
  2262.         buf->b_ml.ml_flags |= ML_LOCKED_POS;
  2263.     mf_put(mfp, hp_new, TRUE, FALSE);
  2264.  
  2265.     /*
  2266.      * flush the old data block
  2267.      * set ml_locked_lineadd to 0, because the updating of the
  2268.      * pointer blocks is done below
  2269.      */
  2270.     lineadd = buf->b_ml.ml_locked_lineadd;
  2271.     buf->b_ml.ml_locked_lineadd = 0;
  2272.     ml_find_line(buf, (linenr_T)0, ML_FLUSH);   /* flush data block */
  2273.  
  2274.     /*
  2275.      * update pointer blocks for the new data block
  2276.      */
  2277.     for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
  2278.                                   --stack_idx)
  2279.     {
  2280.         ip = &(buf->b_ml.ml_stack[stack_idx]);
  2281.         pb_idx = ip->ip_index;
  2282.         if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
  2283.         return FAIL;
  2284.         pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
  2285.         if (pp->pb_id != PTR_ID)
  2286.         {
  2287.         EMSG(_("E317: pointer block id wrong 3"));
  2288.         mf_put(mfp, hp, FALSE, FALSE);
  2289.         return FAIL;
  2290.         }
  2291.         /*
  2292.          * TODO: If the pointer block is full and we are adding at the end
  2293.          * try to insert in front of the next block
  2294.          */
  2295.         /* block not full, add one entry */
  2296.         if (pp->pb_count < pp->pb_count_max)
  2297.         {
  2298.         if (pb_idx + 1 < (int)pp->pb_count)
  2299.             mch_memmove(&pp->pb_pointer[pb_idx + 2],
  2300.                 &pp->pb_pointer[pb_idx + 1],
  2301.             (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
  2302.         ++pp->pb_count;
  2303.         pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
  2304.         pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
  2305.         pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
  2306.         pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
  2307.         pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
  2308.         pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
  2309.  
  2310.         if (lnum_left != 0)
  2311.             pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
  2312.         if (lnum_right != 0)
  2313.             pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
  2314.  
  2315.         mf_put(mfp, hp, TRUE, FALSE);
  2316.         buf->b_ml.ml_stack_top = stack_idx + 1;        /* truncate stack */
  2317.  
  2318.         if (lineadd)
  2319.         {
  2320.             --(buf->b_ml.ml_stack_top);
  2321.             /* fix line count for rest of blocks in the stack */
  2322.             ml_lineadd(buf, lineadd);
  2323.                             /* fix stack itself */
  2324.             buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
  2325.                                       lineadd;
  2326.             ++(buf->b_ml.ml_stack_top);
  2327.         }
  2328.  
  2329.         /*
  2330.          * We are finished, break the loop here.
  2331.          */
  2332.         break;
  2333.         }
  2334.         else            /* pointer block full */
  2335.         {
  2336.         /*
  2337.          * split the pointer block
  2338.          * allocate a new pointer block
  2339.          * move some of the pointer into the new block
  2340.          * prepare for updating the parent block
  2341.          */
  2342.         for (;;)    /* do this twice when splitting block 1 */
  2343.         {
  2344.             hp_new = ml_new_ptr(mfp);
  2345.             if (hp_new == NULL)        /* TODO: try to fix tree */
  2346.             return FAIL;
  2347.             pp_new = (PTR_BL *)(hp_new->bh_data);
  2348.  
  2349.             if (hp->bh_bnum != 1)
  2350.             break;
  2351.  
  2352.             /*
  2353.              * if block 1 becomes full the tree is given an extra level
  2354.              * The pointers from block 1 are moved into the new block.
  2355.              * block 1 is updated to point to the new block
  2356.              * then continue to split the new block
  2357.              */
  2358.             mch_memmove(pp_new, pp, (size_t)page_size);
  2359.             pp->pb_count = 1;
  2360.             pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
  2361.             pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
  2362.             pp->pb_pointer[0].pe_old_lnum = 1;
  2363.             pp->pb_pointer[0].pe_page_count = 1;
  2364.             mf_put(mfp, hp, TRUE, FALSE);   /* release block 1 */
  2365.             hp = hp_new;        /* new block is to be split */
  2366.             pp = pp_new;
  2367.             CHECK(stack_idx != 0, _("stack_idx should be 0"));
  2368.             ip->ip_index = 0;
  2369.             ++stack_idx;    /* do block 1 again later */
  2370.         }
  2371.         /*
  2372.          * move the pointers after the current one to the new block
  2373.          * If there are none, the new entry will be in the new block.
  2374.          */
  2375.         total_moved = pp->pb_count - pb_idx - 1;
  2376.         if (total_moved)
  2377.         {
  2378.             mch_memmove(&pp_new->pb_pointer[0],
  2379.                 &pp->pb_pointer[pb_idx + 1],
  2380.                 (size_t)(total_moved) * sizeof(PTR_EN));
  2381.             pp_new->pb_count = total_moved;
  2382.             pp->pb_count -= total_moved - 1;
  2383.             pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
  2384.             pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
  2385.             pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
  2386.             if (lnum_right)
  2387.             pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
  2388.         }
  2389.         else
  2390.         {
  2391.             pp_new->pb_count = 1;
  2392.             pp_new->pb_pointer[0].pe_bnum = bnum_right;
  2393.             pp_new->pb_pointer[0].pe_line_count = line_count_right;
  2394.             pp_new->pb_pointer[0].pe_page_count = page_count_right;
  2395.             pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
  2396.         }
  2397.         pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
  2398.         pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
  2399.         pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
  2400.         if (lnum_left)
  2401.             pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
  2402.         lnum_left = 0;
  2403.         lnum_right = 0;
  2404.  
  2405.         /*
  2406.          * recompute line counts
  2407.          */
  2408.         line_count_right = 0;
  2409.         for (i = 0; i < (int)pp_new->pb_count; ++i)
  2410.             line_count_right += pp_new->pb_pointer[i].pe_line_count;
  2411.         line_count_left = 0;
  2412.         for (i = 0; i < (int)pp->pb_count; ++i)
  2413.             line_count_left += pp->pb_pointer[i].pe_line_count;
  2414.  
  2415.         bnum_left = hp->bh_bnum;
  2416.         bnum_right = hp_new->bh_bnum;
  2417.         page_count_left = 1;
  2418.         page_count_right = 1;
  2419.         mf_put(mfp, hp, TRUE, FALSE);
  2420.         mf_put(mfp, hp_new, TRUE, FALSE);
  2421.         }
  2422.     }
  2423.  
  2424.     /*
  2425.      * Safety check: fallen out of for loop?
  2426.      */
  2427.     if (stack_idx < 0)
  2428.     {
  2429.         EMSG(_("E318: Updated too many blocks?"));
  2430.         buf->b_ml.ml_stack_top = 0;    /* invalidate stack */
  2431.     }
  2432.     }
  2433.  
  2434. #ifdef FEAT_BYTEOFF
  2435.     /* The line was inserted below 'lnum' */
  2436.     ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
  2437. #endif
  2438. #ifdef FEAT_NETBEANS_INTG
  2439.     if (usingNetbeans)
  2440.     {
  2441.     if (STRLEN(line) > 0)
  2442.         netbeans_inserted(buf, lnum+1, (colnr_T)0, 0, line, STRLEN(line));
  2443.     netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line), 0,
  2444.                                (char_u *)"\n", 1);
  2445.     }
  2446. #endif
  2447.     return OK;
  2448. }
  2449.  
  2450. /*
  2451.  * replace line lnum, with buffering, in current buffer
  2452.  *
  2453.  * If copy is TRUE, make a copy of the line, otherwise the line has been
  2454.  * copied to allocated memory already.
  2455.  *
  2456.  * Check: The caller of this function should probably also call
  2457.  * changed_lines(), unless update_screen(NOT_VALID) is used.
  2458.  *
  2459.  * return FAIL for failure, OK otherwise
  2460.  */
  2461.     int
  2462. ml_replace(lnum, line, copy)
  2463.     linenr_T    lnum;
  2464.     char_u    *line;
  2465.     int        copy;
  2466. {
  2467.     if (line == NULL)        /* just checking... */
  2468.     return FAIL;
  2469.  
  2470.     /* When starting up, we might still need to create the memfile */
  2471.     if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL) == FAIL)
  2472.     return FAIL;
  2473.  
  2474.     if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */
  2475.     return FAIL;
  2476. #ifdef FEAT_NETBEANS_INTG
  2477.     if (usingNetbeans)
  2478.     {
  2479.     netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
  2480.     netbeans_inserted(curbuf, lnum, 0, 0, line, STRLEN(line));
  2481.     }
  2482. #endif
  2483.     if (curbuf->b_ml.ml_line_lnum != lnum)        /* other line buffered */
  2484.     ml_flush_line(curbuf);                /* flush it */
  2485.     else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
  2486.     vim_free(curbuf->b_ml.ml_line_ptr);        /* free it */
  2487.     curbuf->b_ml.ml_line_ptr = line;
  2488.     curbuf->b_ml.ml_line_lnum = lnum;
  2489.     curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
  2490.  
  2491.     return OK;
  2492. }
  2493.  
  2494. /*
  2495.  * delete line 'lnum'
  2496.  *
  2497.  * Check: The caller of this function should probably also call
  2498.  * deleted_lines() after this.
  2499.  *
  2500.  * return FAIL for failure, OK otherwise
  2501.  */
  2502.     int
  2503. ml_delete(lnum, message)
  2504.     linenr_T    lnum;
  2505.     int        message;
  2506. {
  2507.     ml_flush_line(curbuf);
  2508.     return ml_delete_int(curbuf, lnum, message);
  2509. }
  2510.  
  2511.     static int
  2512. ml_delete_int(buf, lnum, message)
  2513.     buf_T    *buf;
  2514.     linenr_T    lnum;
  2515.     int        message;
  2516. {
  2517.     bhdr_T    *hp;
  2518.     memfile_T    *mfp;
  2519.     DATA_BL    *dp;
  2520.     PTR_BL    *pp;
  2521.     infoptr_T    *ip;
  2522.     int        count;        /* number of entries in block */
  2523.     int        idx;
  2524.     int        stack_idx;
  2525.     int        text_start;
  2526.     int        line_start;
  2527.     long    line_size;
  2528.     int        i;
  2529.  
  2530.     if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
  2531.     return FAIL;
  2532.  
  2533.     if (lowest_marked && lowest_marked > lnum)
  2534.     lowest_marked--;
  2535.  
  2536. /*
  2537.  * If the file becomes empty the last line is replaced by an empty line.
  2538.  */
  2539.     if (buf->b_ml.ml_line_count == 1)        /* file becomes empty */
  2540.     {
  2541.     if (message
  2542. #ifdef FEAT_NETBEANS_INTG
  2543.         && !netbeansSuppressNoLines
  2544. #endif
  2545.        )
  2546.     {
  2547.         set_keep_msg((char_u *)_(no_lines_msg));
  2548.         keep_msg_attr = 0;
  2549.     }
  2550.     /* FEAT_BYTEOFF already handled in there, dont worry 'bout it below */
  2551.     i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
  2552.     buf->b_ml.ml_flags |= ML_EMPTY;
  2553.  
  2554.     return i;
  2555.     }
  2556.  
  2557. /*
  2558.  * find the data block containing the line
  2559.  * This also fills the stack with the blocks from the root to the data block
  2560.  * This also releases any locked block.
  2561.  */
  2562.     mfp = buf->b_ml.ml_mfp;
  2563.     if (mfp == NULL)
  2564.     return FAIL;
  2565.  
  2566.     if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
  2567.     return FAIL;
  2568.  
  2569.     dp = (DATA_BL *)(hp->bh_data);
  2570.     /* compute line count before the delete */
  2571.     count = (long)(buf->b_ml.ml_locked_high)
  2572.                     - (long)(buf->b_ml.ml_locked_low) + 2;
  2573.     idx = lnum - buf->b_ml.ml_locked_low;
  2574.  
  2575.     --buf->b_ml.ml_line_count;
  2576.  
  2577.     line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
  2578.     if (idx == 0)        /* first line in block, text at the end */
  2579.     line_size = dp->db_txt_end - line_start;
  2580.     else
  2581.     line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
  2582.  
  2583. #ifdef FEAT_NETBEANS_INTG
  2584.     if (usingNetbeans)
  2585.     netbeans_removed(buf, lnum, 0, line_size);
  2586. #endif
  2587.  
  2588. /*
  2589.  * special case: If there is only one line in the data block it becomes empty.
  2590.  * Then we have to remove the entry, pointing to this data block, from the
  2591.  * pointer block. If this pointer block also becomes empty, we go up another
  2592.  * block, and so on, up to the root if necessary.
  2593.  * The line counts in the pointer blocks have already been adjusted by
  2594.  * ml_find_line().
  2595.  */
  2596.     if (count == 1)
  2597.     {
  2598.     mf_free(mfp, hp);    /* free the data block */
  2599.     buf->b_ml.ml_locked = NULL;
  2600.  
  2601.     for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; --stack_idx)
  2602.     {
  2603.         buf->b_ml.ml_stack_top = 0;        /* stack is invalid when failing */
  2604.         ip = &(buf->b_ml.ml_stack[stack_idx]);
  2605.         idx = ip->ip_index;
  2606.         if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
  2607.         return FAIL;
  2608.         pp = (PTR_BL *)(hp->bh_data);   /* must be pointer block */
  2609.         if (pp->pb_id != PTR_ID)
  2610.         {
  2611.         EMSG(_("E317: pointer block id wrong 4"));
  2612.         mf_put(mfp, hp, FALSE, FALSE);
  2613.         return FAIL;
  2614.         }
  2615.         count = --(pp->pb_count);
  2616.         if (count == 0)        /* the pointer block becomes empty! */
  2617.         mf_free(mfp, hp);
  2618.         else
  2619.         {
  2620.         if (count != idx)    /* move entries after the deleted one */
  2621.             mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
  2622.                       (size_t)(count - idx) * sizeof(PTR_EN));
  2623.         mf_put(mfp, hp, TRUE, FALSE);
  2624.  
  2625.         buf->b_ml.ml_stack_top = stack_idx;    /* truncate stack */
  2626.             /* fix line count for rest of blocks in the stack */
  2627.         if (buf->b_ml.ml_locked_lineadd)
  2628.         {
  2629.             ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
  2630.             buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
  2631.                         buf->b_ml.ml_locked_lineadd;
  2632.         }
  2633.         ++(buf->b_ml.ml_stack_top);
  2634.  
  2635.         break;
  2636.         }
  2637.     }
  2638.     CHECK(stack_idx < 0, _("deleted block 1?"));
  2639.     }
  2640.     else
  2641.     {
  2642.     /*
  2643.      * delete the text by moving the next lines forwards
  2644.      */
  2645.     text_start = dp->db_txt_start;
  2646.     mch_memmove((char *)dp + text_start + line_size,
  2647.           (char *)dp + text_start, (size_t)(line_start - text_start));
  2648.  
  2649.     /*
  2650.      * delete the index by moving the next indexes backwards
  2651.      * Adjust the indexes for the text movement.
  2652.      */
  2653.     for (i = idx; i < count - 1; ++i)
  2654.         dp->db_index[i] = dp->db_index[i + 1] + line_size;
  2655.  
  2656.     dp->db_free += line_size + INDEX_SIZE;
  2657.     dp->db_txt_start += line_size;
  2658.     --(dp->db_line_count);
  2659.  
  2660.     /*
  2661.      * mark the block dirty and make sure it is in the file (for recovery)
  2662.      */
  2663.     buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
  2664.     }
  2665.  
  2666. #ifdef FEAT_BYTEOFF
  2667.     ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
  2668. #endif
  2669.     return OK;
  2670. }
  2671.  
  2672. /*
  2673.  * set the B_MARKED flag for line 'lnum'
  2674.  */
  2675.     void
  2676. ml_setmarked(lnum)
  2677.     linenr_T lnum;
  2678. {
  2679.     bhdr_T    *hp;
  2680.     DATA_BL *dp;
  2681.                     /* invalid line number */
  2682.     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
  2683.                            || curbuf->b_ml.ml_mfp == NULL)
  2684.     return;                /* give error message? */
  2685.  
  2686.     if (lowest_marked == 0 || lowest_marked > lnum)
  2687.     lowest_marked = lnum;
  2688.  
  2689.     /*
  2690.      * find the data block containing the line
  2691.      * This also fills the stack with the blocks from the root to the data block
  2692.      * This also releases any locked block.
  2693.      */
  2694.     if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2695.     return;            /* give error message? */
  2696.  
  2697.     dp = (DATA_BL *)(hp->bh_data);
  2698.     dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
  2699.     curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2700. }
  2701.  
  2702. /*
  2703.  * find the first line with its B_MARKED flag set
  2704.  */
  2705.     linenr_T
  2706. ml_firstmarked()
  2707. {
  2708.     bhdr_T    *hp;
  2709.     DATA_BL    *dp;
  2710.     linenr_T    lnum;
  2711.     int        i;
  2712.  
  2713.     if (curbuf->b_ml.ml_mfp == NULL)
  2714.     return (linenr_T) 0;
  2715.  
  2716.     /*
  2717.      * The search starts with lowest_marked line. This is the last line where
  2718.      * a mark was found, adjusted by inserting/deleting lines.
  2719.      */
  2720.     for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
  2721.     {
  2722.     /*
  2723.      * Find the data block containing the line.
  2724.      * This also fills the stack with the blocks from the root to the data
  2725.      * block This also releases any locked block.
  2726.      */
  2727.     if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2728.         return (linenr_T)0;            /* give error message? */
  2729.  
  2730.     dp = (DATA_BL *)(hp->bh_data);
  2731.  
  2732.     for (i = lnum - curbuf->b_ml.ml_locked_low;
  2733.                 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
  2734.         if ((dp->db_index[i]) & DB_MARKED)
  2735.         {
  2736.         (dp->db_index[i]) &= DB_INDEX_MASK;
  2737.         curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2738.         lowest_marked = lnum + 1;
  2739.         return lnum;
  2740.         }
  2741.     }
  2742.  
  2743.     return (linenr_T) 0;
  2744. }
  2745.  
  2746. #if 0  /* not used */
  2747. /*
  2748.  * return TRUE if line 'lnum' has a mark
  2749.  */
  2750.     int
  2751. ml_has_mark(lnum)
  2752.     linenr_T    lnum;
  2753. {
  2754.     bhdr_T    *hp;
  2755.     DATA_BL    *dp;
  2756.  
  2757.     if (curbuf->b_ml.ml_mfp == NULL
  2758.             || (hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2759.     return FALSE;
  2760.  
  2761.     dp = (DATA_BL *)(hp->bh_data);
  2762.     return (int)((dp->db_index[lnum - curbuf->b_ml.ml_locked_low]) & DB_MARKED);
  2763. }
  2764. #endif
  2765.  
  2766. /*
  2767.  * clear all DB_MARKED flags
  2768.  */
  2769.     void
  2770. ml_clearmarked()
  2771. {
  2772.     bhdr_T    *hp;
  2773.     DATA_BL    *dp;
  2774.     linenr_T    lnum;
  2775.     int        i;
  2776.  
  2777.     if (curbuf->b_ml.ml_mfp == NULL)        /* nothing to do */
  2778.     return;
  2779.  
  2780.     /*
  2781.      * The search starts with line lowest_marked.
  2782.      */
  2783.     for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
  2784.     {
  2785.     /*
  2786.      * Find the data block containing the line.
  2787.      * This also fills the stack with the blocks from the root to the data
  2788.      * block and releases any locked block.
  2789.      */
  2790.     if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
  2791.         return;        /* give error message? */
  2792.  
  2793.     dp = (DATA_BL *)(hp->bh_data);
  2794.  
  2795.     for (i = lnum - curbuf->b_ml.ml_locked_low;
  2796.                 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
  2797.         if ((dp->db_index[i]) & DB_MARKED)
  2798.         {
  2799.         (dp->db_index[i]) &= DB_INDEX_MASK;
  2800.         curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
  2801.         }
  2802.     }
  2803.  
  2804.     lowest_marked = 0;
  2805.     return;
  2806. }
  2807.  
  2808. /*
  2809.  * flush ml_line if necessary
  2810.  */
  2811.     static void
  2812. ml_flush_line(buf)
  2813.     buf_T    *buf;
  2814. {
  2815.     bhdr_T    *hp;
  2816.     DATA_BL    *dp;
  2817.     linenr_T    lnum;
  2818.     char_u    *new_line;
  2819.     char_u    *old_line;
  2820.     colnr_T    new_len;
  2821.     int        old_len;
  2822.     int        extra;
  2823.     int        idx;
  2824.     int        start;
  2825.     int        count;
  2826.     int        i;
  2827.  
  2828.     if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
  2829.     return;        /* nothing to do */
  2830.  
  2831.     if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
  2832.     {
  2833.     lnum = buf->b_ml.ml_line_lnum;
  2834.     new_line = buf->b_ml.ml_line_ptr;
  2835.  
  2836.     hp = ml_find_line(buf, lnum, ML_FIND);
  2837.     if (hp == NULL)
  2838.         EMSGN(_("E320: Cannot find line %ld"), lnum);
  2839.     else
  2840.     {
  2841.         dp = (DATA_BL *)(hp->bh_data);
  2842.         idx = lnum - buf->b_ml.ml_locked_low;
  2843.         start = ((dp->db_index[idx]) & DB_INDEX_MASK);
  2844.         old_line = (char_u *)dp + start;
  2845.         if (idx == 0)    /* line is last in block */
  2846.         old_len = dp->db_txt_end - start;
  2847.         else        /* text of previous line follows */
  2848.         old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
  2849.         new_len = (colnr_T)STRLEN(new_line) + 1;
  2850.         extra = new_len - old_len;        /* negative if lines gets smaller */
  2851.  
  2852.         /*
  2853.          * if new line fits in data block, replace directly
  2854.          */
  2855.         if ((int)dp->db_free >= extra)
  2856.         {
  2857.         /* if the length changes and there are following lines */
  2858.         count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
  2859.         if (extra != 0 && idx < count - 1)
  2860.         {
  2861.             /* move text of following lines */
  2862.             mch_memmove((char *)dp + dp->db_txt_start - extra,
  2863.                 (char *)dp + dp->db_txt_start,
  2864.                 (size_t)(start - dp->db_txt_start));
  2865.  
  2866.             /* adjust pointers of this and following lines */
  2867.             for (i = idx + 1; i < count; ++i)
  2868.             dp->db_index[i] -= extra;
  2869.         }
  2870.         dp->db_index[idx] -= extra;
  2871.  
  2872.         /* adjust free space */
  2873.         dp->db_free -= extra;
  2874.         dp->db_txt_start -= extra;
  2875.  
  2876.         /* copy new line into the data block */
  2877.         mch_memmove(old_line - extra, new_line, (size_t)new_len);
  2878.         buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
  2879. #ifdef FEAT_BYTEOFF
  2880.         /* The else case is already covered by the insert and delete */
  2881.         ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
  2882. #endif
  2883.         }
  2884.         else
  2885.         {
  2886.         /*
  2887.          * Cannot do it in one data block: Delete and append.
  2888.          * Append first, because ml_delete_int() cannot delete the
  2889.          * last line in a buffer, which causes trouble for a buffer
  2890.          * that has only one line.
  2891.          * Don't forget to copy the mark!
  2892.          */
  2893.         /* How about handling errors??? */
  2894.         (void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
  2895.                          (dp->db_index[idx] & DB_MARKED));
  2896.         (void)ml_delete_int(buf, lnum, FALSE);
  2897.         }
  2898.     }
  2899.     vim_free(new_line);
  2900.     }
  2901.  
  2902.     buf->b_ml.ml_line_lnum = 0;
  2903. }
  2904.  
  2905. /*
  2906.  * create a new, empty, data block
  2907.  */
  2908.     static bhdr_T *
  2909. ml_new_data(mfp, negative, page_count)
  2910.     memfile_T    *mfp;
  2911.     int        negative;
  2912.     int        page_count;
  2913. {
  2914.     bhdr_T    *hp;
  2915.     DATA_BL    *dp;
  2916.  
  2917.     if ((hp = mf_new(mfp, negative, page_count)) == NULL)
  2918.     return NULL;
  2919.  
  2920.     dp = (DATA_BL *)(hp->bh_data);
  2921.     dp->db_id = DATA_ID;
  2922.     dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
  2923.     dp->db_free = dp->db_txt_start - HEADER_SIZE;
  2924.     dp->db_line_count = 0;
  2925.  
  2926.     return hp;
  2927. }
  2928.  
  2929. /*
  2930.  * create a new, empty, pointer block
  2931.  */
  2932.     static bhdr_T *
  2933. ml_new_ptr(mfp)
  2934.     memfile_T    *mfp;
  2935. {
  2936.     bhdr_T    *hp;
  2937.     PTR_BL    *pp;
  2938.  
  2939.     if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
  2940.     return NULL;
  2941.  
  2942.     pp = (PTR_BL *)(hp->bh_data);
  2943.     pp->pb_id = PTR_ID;
  2944.     pp->pb_count = 0;
  2945.     pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1);
  2946.  
  2947.     return hp;
  2948. }
  2949.  
  2950. /*
  2951.  * lookup line 'lnum' in a memline
  2952.  *
  2953.  *   action: if ML_DELETE or ML_INSERT the line count is updated while searching
  2954.  *         if ML_FLUSH only flush a locked block
  2955.  *         if ML_FIND just find the line
  2956.  *
  2957.  * If the block was found it is locked and put in ml_locked.
  2958.  * The stack is updated to lead to the locked block. The ip_high field in
  2959.  * the stack is updated to reflect the last line in the block AFTER the
  2960.  * insert or delete, also if the pointer block has not been updated yet. But
  2961.  * if if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
  2962.  *
  2963.  * return: NULL for failure, pointer to block header otherwise
  2964.  */
  2965.     static bhdr_T *
  2966. ml_find_line(buf, lnum, action)
  2967.     buf_T    *buf;
  2968.     linenr_T    lnum;
  2969.     int        action;
  2970. {
  2971.     DATA_BL    *dp;
  2972.     PTR_BL    *pp;
  2973.     infoptr_T    *ip;
  2974.     bhdr_T    *hp;
  2975.     memfile_T    *mfp;
  2976.     linenr_T    t;
  2977.     blocknr_T    bnum, bnum2;
  2978.     int        dirty;
  2979.     linenr_T    low, high;
  2980.     int        top;
  2981.     int        page_count;
  2982.     int        idx;
  2983.  
  2984.     mfp = buf->b_ml.ml_mfp;
  2985.  
  2986.     /*
  2987.      * If there is a locked block check if the wanted line is in it.
  2988.      * If not, flush and release the locked block.
  2989.      * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
  2990.      * Don't do this for ML_FLUSH, because we want to flush the locked block.
  2991.      */
  2992.     if (buf->b_ml.ml_locked)
  2993.     {
  2994.     if (ML_SIMPLE(action) && buf->b_ml.ml_locked_low <= lnum
  2995.                       && buf->b_ml.ml_locked_high >= lnum)
  2996.     {
  2997.         /* remember to update pointer blocks and stack later */
  2998.         if (action == ML_INSERT)
  2999.         {
  3000.         ++(buf->b_ml.ml_locked_lineadd);
  3001.         ++(buf->b_ml.ml_locked_high);
  3002.         }
  3003.         else if (action == ML_DELETE)
  3004.         {
  3005.         --(buf->b_ml.ml_locked_lineadd);
  3006.         --(buf->b_ml.ml_locked_high);
  3007.         }
  3008.         return (buf->b_ml.ml_locked);
  3009.     }
  3010.  
  3011.     mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
  3012.                         buf->b_ml.ml_flags & ML_LOCKED_POS);
  3013.     buf->b_ml.ml_locked = NULL;
  3014.  
  3015.         /*
  3016.          * if lines have been added or deleted in the locked block, need to
  3017.          * update the line count in pointer blocks
  3018.          */
  3019.     if (buf->b_ml.ml_locked_lineadd)
  3020.         ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
  3021.     }
  3022.  
  3023.     if (action == ML_FLUSH)        /* nothing else to do */
  3024.     return NULL;
  3025.  
  3026.     bnum = 1;                /* start at the root of the tree */
  3027.     page_count = 1;
  3028.     low = 1;
  3029.     high = buf->b_ml.ml_line_count;
  3030.  
  3031.     if (action == ML_FIND)    /* first try stack entries */
  3032.     {
  3033.     for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
  3034.     {
  3035.         ip = &(buf->b_ml.ml_stack[top]);
  3036.         if (ip->ip_low <= lnum && ip->ip_high >= lnum)
  3037.         {
  3038.         bnum = ip->ip_bnum;
  3039.         low = ip->ip_low;
  3040.         high = ip->ip_high;
  3041.         buf->b_ml.ml_stack_top = top;    /* truncate stack at prev entry */
  3042.         break;
  3043.         }
  3044.     }
  3045.     if (top < 0)
  3046.         buf->b_ml.ml_stack_top = 0;        /* not found, start at the root */
  3047.     }
  3048.     else    /* ML_DELETE or ML_INSERT */
  3049.     buf->b_ml.ml_stack_top = 0;    /* start at the root */
  3050.  
  3051. /*
  3052.  * search downwards in the tree until a data block is found
  3053.  */
  3054.     for (;;)
  3055.     {
  3056.     if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
  3057.         goto error_noblock;
  3058.  
  3059.     /*
  3060.      * update high for insert/delete
  3061.      */
  3062.     if (action == ML_INSERT)
  3063.         ++high;
  3064.     else if (action == ML_DELETE)
  3065.         --high;
  3066.  
  3067.     dp = (DATA_BL *)(hp->bh_data);
  3068.     if (dp->db_id == DATA_ID)    /* data block */
  3069.     {
  3070.         buf->b_ml.ml_locked = hp;
  3071.         buf->b_ml.ml_locked_low = low;
  3072.         buf->b_ml.ml_locked_high = high;
  3073.         buf->b_ml.ml_locked_lineadd = 0;
  3074.         buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
  3075.         return hp;
  3076.     }
  3077.  
  3078.     pp = (PTR_BL *)(dp);        /* must be pointer block */
  3079.     if (pp->pb_id != PTR_ID)
  3080.     {
  3081.         EMSG(_("E317: pointer block id wrong"));
  3082.         goto error_block;
  3083.     }
  3084.  
  3085.     if ((top = ml_add_stack(buf)) < 0)    /* add new entry to stack */
  3086.         goto error_block;
  3087.     ip = &(buf->b_ml.ml_stack[top]);
  3088.     ip->ip_bnum = bnum;
  3089.     ip->ip_low = low;
  3090.     ip->ip_high = high;
  3091.     ip->ip_index = -1;        /* index not known yet */
  3092.  
  3093.     dirty = FALSE;
  3094.     for (idx = 0; idx < (int)pp->pb_count; ++idx)
  3095.     {
  3096.         t = pp->pb_pointer[idx].pe_line_count;
  3097.         CHECK(t == 0, _("pe_line_count is zero"));
  3098.         if ((low += t) > lnum)
  3099.         {
  3100.         ip->ip_index = idx;
  3101.         bnum = pp->pb_pointer[idx].pe_bnum;
  3102.         page_count = pp->pb_pointer[idx].pe_page_count;
  3103.         high = low - 1;
  3104.         low -= t;
  3105.  
  3106.         /*
  3107.          * a negative block number may have been changed
  3108.          */
  3109.         if (bnum < 0)
  3110.         {
  3111.             bnum2 = mf_trans_del(mfp, bnum);
  3112.             if (bnum != bnum2)
  3113.             {
  3114.             bnum = bnum2;
  3115.             pp->pb_pointer[idx].pe_bnum = bnum;
  3116.             dirty = TRUE;
  3117.             }
  3118.         }
  3119.  
  3120.         break;
  3121.         }
  3122.     }
  3123.     if (idx >= (int)pp->pb_count)        /* past the end: something wrong! */
  3124.     {
  3125.         if (lnum > buf->b_ml.ml_line_count)
  3126.         EMSGN(_("E322: line number out of range: %ld past the end"),
  3127.                           lnum - buf->b_ml.ml_line_count);
  3128.  
  3129.         else
  3130.         EMSGN(_("E323: line count wrong in block %ld"), bnum);
  3131.         goto error_block;
  3132.     }
  3133.     if (action == ML_DELETE)
  3134.     {
  3135.         pp->pb_pointer[idx].pe_line_count--;
  3136.         dirty = TRUE;
  3137.     }
  3138.     else if (action == ML_INSERT)
  3139.     {
  3140.         pp->pb_pointer[idx].pe_line_count++;
  3141.         dirty = TRUE;
  3142.     }
  3143.     mf_put(mfp, hp, dirty, FALSE);
  3144.     }
  3145.  
  3146. error_block:
  3147.     mf_put(mfp, hp, FALSE, FALSE);
  3148. error_noblock:
  3149. /*
  3150.  * If action is ML_DELETE or ML_INSERT we have to correct the tree for
  3151.  * the incremented/decremented line counts, because there won't be a line
  3152.  * inserted/deleted after all.
  3153.  */
  3154.     if (action == ML_DELETE)
  3155.     ml_lineadd(buf, 1);
  3156.     else if (action == ML_INSERT)
  3157.     ml_lineadd(buf, -1);
  3158.     buf->b_ml.ml_stack_top = 0;
  3159.     return NULL;
  3160. }
  3161.  
  3162. /*
  3163.  * add an entry to the info pointer stack
  3164.  *
  3165.  * return -1 for failure, number of the new entry otherwise
  3166.  */
  3167.     static int
  3168. ml_add_stack(buf)
  3169.     buf_T    *buf;
  3170. {
  3171.     int        top;
  3172.     infoptr_T    *newstack;
  3173.  
  3174.     top = buf->b_ml.ml_stack_top;
  3175.  
  3176.     /* may have to increase the stack size */
  3177.     if (top == buf->b_ml.ml_stack_size)
  3178.     {
  3179.     CHECK(top > 0, _("Stack size increases"));    /* more than 5 levels??? */
  3180.  
  3181.     newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
  3182.                     (buf->b_ml.ml_stack_size + STACK_INCR));
  3183.     if (newstack == NULL)
  3184.         return -1;
  3185.     mch_memmove(newstack, buf->b_ml.ml_stack, (size_t)top * sizeof(infoptr_T));
  3186.     vim_free(buf->b_ml.ml_stack);
  3187.     buf->b_ml.ml_stack = newstack;
  3188.     buf->b_ml.ml_stack_size += STACK_INCR;
  3189.     }
  3190.  
  3191.     buf->b_ml.ml_stack_top++;
  3192.     return top;
  3193. }
  3194.  
  3195. /*
  3196.  * Update the pointer blocks on the stack for inserted/deleted lines.
  3197.  * The stack itself is also updated.
  3198.  *
  3199.  * When a insert/delete line action fails, the line is not inserted/deleted,
  3200.  * but the pointer blocks have already been updated. That is fixed here by
  3201.  * walking through the stack.
  3202.  *
  3203.  * Count is the number of lines added, negative if lines have been deleted.
  3204.  */
  3205.     static void
  3206. ml_lineadd(buf, count)
  3207.     buf_T    *buf;
  3208.     int        count;
  3209. {
  3210.     int        idx;
  3211.     infoptr_T    *ip;
  3212.     PTR_BL    *pp;
  3213.     memfile_T    *mfp = buf->b_ml.ml_mfp;
  3214.     bhdr_T    *hp;
  3215.  
  3216.     for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
  3217.     {
  3218.     ip = &(buf->b_ml.ml_stack[idx]);
  3219.     if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
  3220.         break;
  3221.     pp = (PTR_BL *)(hp->bh_data);    /* must be pointer block */
  3222.     if (pp->pb_id != PTR_ID)
  3223.     {
  3224.         mf_put(mfp, hp, FALSE, FALSE);
  3225.         EMSG(_("E317: pointer block id wrong 2"));
  3226.         break;
  3227.     }
  3228.     pp->pb_pointer[ip->ip_index].pe_line_count += count;
  3229.     ip->ip_high += count;
  3230.     mf_put(mfp, hp, TRUE, FALSE);
  3231.     }
  3232. }
  3233.  
  3234. /*
  3235.  * make swap file name out of the file name and a directory name
  3236.  */
  3237.     static char_u *
  3238. makeswapname(buf, dir_name)
  3239.     buf_T    *buf;
  3240.     char_u    *dir_name;
  3241. {
  3242.     char_u    *r, *s;
  3243.  
  3244. #if defined(UNIX) || defined(WIN3264)  /* Need _very_ long file names */
  3245.     s = dir_name + STRLEN(dir_name);
  3246.     if (vim_ispathsep(s[-1]) && s[-1] == s[-2])
  3247.     {                   /* Ends with '//', Use Full path */
  3248.     r = NULL;
  3249.     if ((s = make_percent_swname(dir_name, buf->b_fname)) != NULL)
  3250.     {
  3251.         r = modname(s, (char_u *)".swp", FALSE);
  3252.         vim_free(s);
  3253.     }
  3254.     return r;
  3255.     }
  3256. #endif
  3257.  
  3258.     r = buf_modname(
  3259. #ifdef SHORT_FNAME
  3260.         TRUE,
  3261. #else
  3262.         (buf->b_p_sn || buf->b_shortname),
  3263. #endif
  3264. #ifdef RISCOS
  3265.         /* Avoid problems if fname has special chars, eg <Wimp$Scrap> */
  3266.         buf->b_ffname,
  3267. #else
  3268.         buf->b_fname,
  3269. #endif
  3270.         (char_u *)
  3271. #if defined(VMS) || defined(RISCOS)
  3272.         "_swp",
  3273. #else
  3274.         ".swp",
  3275. #endif
  3276. #ifdef SHORT_FNAME        /* always 8.3 file name */
  3277.         FALSE
  3278. #else
  3279.         /* Prepend a '.' to the swap file name for the current directory. */
  3280.         dir_name[0] == '.' && dir_name[1] == NUL
  3281. #endif
  3282.            );
  3283.     if (r == NULL)        /* out of memory */
  3284.     return NULL;
  3285.  
  3286.     s = get_file_in_dir(r, dir_name);
  3287.     vim_free(r);
  3288.     return s;
  3289. }
  3290.  
  3291. /*
  3292.  * Get file name to use for swap file or backup file.
  3293.  * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
  3294.  * option "dname".
  3295.  * - If "dname" is ".", return "fname" (swap file in dir of file).
  3296.  * - If "dname" starts with "./", insert "dname" in "fname" (swap file
  3297.  *   relative to dir of file).
  3298.  * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
  3299.  *   dir).
  3300.  *
  3301.  * The return value is an allocated string and can be NULL.
  3302.  */
  3303.     char_u *
  3304. get_file_in_dir(fname, dname)
  3305.     char_u  *fname;
  3306.     char_u  *dname;    /* don't use "dirname", it is a global for Alpha */
  3307. {
  3308.     char_u    *t;
  3309.     char_u    *tail;
  3310.     char_u    *retval;
  3311.     int        save_char;
  3312.  
  3313.     tail = gettail(fname);
  3314.  
  3315.     if (dname[0] == '.' && dname[1] == NUL)
  3316.     retval = vim_strsave(fname);
  3317.     else if (dname[0] == '.' && vim_ispathsep(dname[1]))
  3318.     {
  3319.     if (tail == fname)        /* no path before file name */
  3320.         retval = concat_fnames(dname + 2, tail, TRUE);
  3321.     else
  3322.     {
  3323.         save_char = *tail;
  3324.         *tail = NUL;
  3325.         t = concat_fnames(fname, dname + 2, TRUE);
  3326.         *tail = save_char;
  3327.         if (t == NULL)        /* out of memory */
  3328.         retval = NULL;
  3329.         else
  3330.         {
  3331.         retval = concat_fnames(t, tail, TRUE);
  3332.         vim_free(t);
  3333.         }
  3334.     }
  3335.     }
  3336.     else
  3337.     retval = concat_fnames(dname, tail, TRUE);
  3338.  
  3339.     return retval;
  3340. }
  3341.  
  3342. /*
  3343.  * Find out what name to use for the swap file for buffer 'buf'.
  3344.  *
  3345.  * Several names are tried to find one that does not exist
  3346.  *
  3347.  * Note: If BASENAMELEN is not correct, you will get error messages for
  3348.  *     not being able to open the swapfile
  3349.  */
  3350.     static char_u *
  3351. findswapname(buf, dirp, old_fname)
  3352.     buf_T    *buf;
  3353.     char_u    **dirp;        /* pointer to list of directories */
  3354.     char_u    *old_fname;    /* don't give warning for this file name */
  3355. {
  3356.     char_u    *fname;
  3357.     int        n;
  3358.     time_t    x, sx;
  3359.     char_u    *dir_name;
  3360. #ifdef AMIGA
  3361.     BPTR    fh;
  3362. #endif
  3363. #ifndef SHORT_FNAME
  3364.     int        r;
  3365. #endif
  3366.  
  3367. #if !defined(SHORT_FNAME) \
  3368.              && ((!defined(UNIX) && !defined(OS2)) || defined(ARCHIE))
  3369. # define CREATE_DUMMY_FILE
  3370.     FILE    *dummyfd = NULL;
  3371.  
  3372. /*
  3373.  * If we start editing a new file, e.g. "test.doc", which resides on an MSDOS
  3374.  * compatible filesystem, it is possible that the file "test.doc.swp" which we
  3375.  * create will be exactly the same file. To avoid this problem we temporarily
  3376.  * create "test.doc".
  3377.  * Don't do this when the check below for a 8.3 file name is used.
  3378.  */
  3379.     if (!(buf->b_p_sn || buf->b_shortname) && buf->b_fname != NULL
  3380.                          && mch_getperm(buf->b_fname) < 0)
  3381.     dummyfd = mch_fopen((char *)buf->b_fname, "w");
  3382. #endif
  3383.  
  3384. /*
  3385.  * Isolate a directory name from *dirp and put it in dir_name.
  3386.  * First allocate some memory to put the directory name in.
  3387.  */
  3388.     dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
  3389.     if (dir_name != NULL)
  3390.     (void)copy_option_part(dirp, dir_name, 31000, ",");
  3391.  
  3392. /*
  3393.  * we try different names until we find one that does not exist yet
  3394.  */
  3395.     if (dir_name == NULL)        /* out of memory */
  3396.     fname = NULL;
  3397.     else
  3398.     fname = makeswapname(buf, dir_name);
  3399.  
  3400.     for (;;)
  3401.     {
  3402.     if (fname == NULL)    /* must be out of memory */
  3403.         break;
  3404.     if ((n = (int)STRLEN(fname)) == 0)    /* safety check */
  3405.     {
  3406.         vim_free(fname);
  3407.         fname = NULL;
  3408.         break;
  3409.     }
  3410. #if (defined(UNIX) || defined(OS2)) && !defined(ARCHIE) && !defined(SHORT_FNAME)
  3411. /*
  3412.  * Some systems have a MS-DOS compatible filesystem that use 8.3 character
  3413.  * file names. If this is the first try and the swap file name does not fit in
  3414.  * 8.3, detect if this is the case, set shortname and try again.
  3415.  */
  3416.     if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
  3417.                     && !(buf->b_p_sn || buf->b_shortname))
  3418.     {
  3419.         char_u        *tail;
  3420.         char_u        *fname2;
  3421.         struct stat        s1, s2;
  3422.         int            f1, f2;
  3423.         int            created1 = FALSE, created2 = FALSE;
  3424.         int            same = FALSE;
  3425.  
  3426.         /*
  3427.          * Check if swapfile name does not fit in 8.3:
  3428.          * It either contains two dots, is longer than 8 chars, or starts
  3429.          * with a dot.
  3430.          */
  3431.         tail = gettail(buf->b_fname);
  3432.         if (       vim_strchr(tail, '.') != NULL
  3433.             || STRLEN(tail) > (size_t)8
  3434.             || *gettail(fname) == '.')
  3435.         {
  3436.         fname2 = alloc(n + 2);
  3437.         if (fname2 != NULL)
  3438.         {
  3439.             STRCPY(fname2, fname);
  3440.             /* if fname == "xx.xx.swp",        fname2 = "xx.xx.swx"
  3441.              * if fname == ".xx.swp",        fname2 = ".xx.swpx"
  3442.              * if fname == "123456789.swp", fname2 = "12345678x.swp"
  3443.              */
  3444.             if (vim_strchr(tail, '.') != NULL)
  3445.             fname2[n - 1] = 'x';
  3446.             else if (*gettail(fname) == '.')
  3447.             {
  3448.             fname2[n] = 'x';
  3449.             fname2[n + 1] = NUL;
  3450.             }
  3451.             else
  3452.             fname2[n - 5] += 1;
  3453.             /*
  3454.              * may need to create the files to be able to use mch_stat()
  3455.              */
  3456.             f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
  3457.             if (f1 < 0)
  3458.             {
  3459.             f1 = open(
  3460. #ifdef VMS
  3461.                 vms_fixfilename((char *)fname),
  3462. #else
  3463.                 (char *)fname,
  3464. #endif
  3465.                 O_RDWR|O_CREAT|O_EXCL|O_EXTRA
  3466. #if defined(UNIX) || defined(VMS)  /* open in rw------- mode */
  3467.                                   , (mode_t)0600
  3468. #endif
  3469. #if defined(MSDOS) || defined(MSWIN) || defined(OS2)  /* open read/write */
  3470.                             , S_IREAD | S_IWRITE
  3471. #endif
  3472.                                         );
  3473. #if defined(OS2)
  3474.             if (f1 < 0 && errno == ENOENT)
  3475.                 same = TRUE;
  3476. #endif
  3477.             created1 = TRUE;
  3478.             }
  3479.             if (f1 >= 0)
  3480.             {
  3481.             f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
  3482.             if (f2 < 0)
  3483.             {
  3484.                 f2 = open(
  3485. #ifdef VMS
  3486.                     vms_fixfilename((char *)fname2),
  3487. #else
  3488.                     (char *)fname2,
  3489. #endif
  3490.                     O_RDWR|O_CREAT|O_EXCL|O_EXTRA
  3491. #if defined(UNIX) || defined(VMS)  /* open in rw------- mode */
  3492.                                   , (mode_t)0600
  3493. #endif
  3494. #if defined(MSDOS) || defined(MSWIN) || defined(OS2)  /* open read/write */
  3495.                             , S_IREAD | S_IWRITE
  3496. #endif
  3497.                                         );
  3498.                 created2 = TRUE;
  3499.             }
  3500.             if (f2 >= 0)
  3501.             {
  3502.                 /*
  3503.                  * Both files exist now. If mch_stat() returns the
  3504.                  * same device and inode they are the same file.
  3505.                  */
  3506.                 if (mch_fstat(f1, &s1) != -1
  3507.                     && mch_fstat(f2, &s2) != -1
  3508.                     && s1.st_dev == s2.st_dev
  3509.                     && s1.st_ino == s2.st_ino)
  3510.                 same = TRUE;
  3511.                 close(f2);
  3512.                 if (created2)
  3513.                 mch_remove(fname2);
  3514.             }
  3515.             close(f1);
  3516.             if (created1)
  3517.                 mch_remove(fname);
  3518.             }
  3519.             vim_free(fname2);
  3520.             if (same)
  3521.             {
  3522.             buf->b_shortname = TRUE;
  3523.             vim_free(fname);
  3524.             fname = makeswapname(buf, dir_name);
  3525.             continue;    /* try again with b_shortname set */
  3526.             }
  3527.         }
  3528.         }
  3529.     }
  3530. #endif
  3531.     /*
  3532.      * check if the swapfile already exists
  3533.      */
  3534.     if (mch_getperm(fname) < 0)    /* it does not exist */
  3535.     {
  3536. #ifdef HAVE_LSTAT
  3537.         struct stat sb;
  3538.  
  3539.         /*
  3540.          * Extra security check: When a swap file is a symbolic link, this
  3541.          * is most likely a symlink attack.
  3542.          */
  3543.         if (mch_lstat((char *)fname, &sb) < 0)
  3544. #else
  3545. # ifdef AMIGA
  3546.         fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
  3547.         /*
  3548.          * on the Amiga mch_getperm() will return -1 when the file exists
  3549.          * but is being used by another program. This happens if you edit
  3550.          * a file twice.
  3551.          */
  3552.         if (fh != (BPTR)NULL)    /* can open file, OK */
  3553.         {
  3554.         Close(fh);
  3555.         mch_remove(fname);
  3556.         break;
  3557.         }
  3558.         if (IoErr() != ERROR_OBJECT_IN_USE
  3559.                         && IoErr() != ERROR_OBJECT_EXISTS)
  3560. # endif
  3561. #endif
  3562.         break;
  3563.     }
  3564.  
  3565.     /*
  3566.      * A file name equal to old_fname is OK to use.
  3567.      */
  3568.     if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
  3569.         break;
  3570.  
  3571.     /*
  3572.      * get here when file already exists
  3573.      */
  3574.     if (fname[n - 2] == 'w' && fname[n - 1] == 'p')    /* first try */
  3575.     {
  3576. #ifndef SHORT_FNAME
  3577.         /*
  3578.          * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
  3579.          * and file.doc are the same file. To guess if this problem is
  3580.          * present try if file.doc.swx exists. If it does, we set
  3581.          * buf->b_shortname and try file_doc.swp (dots replaced by
  3582.          * underscores for this file), and try again. If it doesn't we
  3583.          * assume that "file.doc.swp" already exists.
  3584.          */
  3585.         if (!(buf->b_p_sn || buf->b_shortname))    /* not tried yet */
  3586.         {
  3587.         fname[n - 1] = 'x';
  3588.         r = mch_getperm(fname);        /* try "file.swx" */
  3589.         fname[n - 1] = 'p';
  3590.         if (r >= 0)            /* "file.swx" seems to exist */
  3591.         {
  3592.             buf->b_shortname = TRUE;
  3593.             vim_free(fname);
  3594.             fname = makeswapname(buf, dir_name);
  3595.             continue;        /* try again with '.' replaced with '_' */
  3596.         }
  3597.         }
  3598. #endif
  3599.         /*
  3600.          * If we get here the ".swp" file really exists.
  3601.          * Give an error message, unless recovering, no file name, we are
  3602.          * viewing a help file or when the path of the file is different
  3603.          * (happens when all .swp files are in one directory).
  3604.          */
  3605.         if (!recoverymode && buf->b_fname != NULL && !buf->b_help)
  3606.         {
  3607.         int        fd;
  3608.         struct block0    b0;
  3609.         int        differ = FALSE;
  3610.  
  3611.         /*
  3612.          * Try to read block 0 from the swap file to get the original
  3613.          * file name (and inode number).
  3614.          */
  3615.         fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
  3616.         if (fd >= 0)
  3617.         {
  3618.             if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
  3619.             {
  3620.             /*
  3621.              * The name in the swap file may be "~user/path/file".
  3622.              * Expand it first.
  3623.              */
  3624.             expand_env(b0.b0_fname, NameBuff, MAXPATHL);
  3625. #ifdef CHECK_INODE
  3626.             if (fnamecmp_ino(buf->b_ffname, NameBuff,
  3627.                              char_to_long(b0.b0_ino)))
  3628.                 differ = TRUE;
  3629. #else
  3630.             if (fnamecmp(NameBuff, buf->b_ffname) != 0)
  3631.                 differ = TRUE;
  3632. #endif
  3633.             }
  3634.             close(fd);
  3635.         }
  3636. #ifdef RISCOS
  3637.         else
  3638.             /* Can't open swap file, though it does exist.
  3639.              * Assume that the user is editing two files with
  3640.              * the same name in different directories. No error.
  3641.              */
  3642.             differ = TRUE;
  3643. #endif
  3644.  
  3645.         /* give the ATTENTION message when there is an old swap file
  3646.          * for the current file, and the buffer was not recovered. */
  3647.         if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
  3648.             && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
  3649.         {
  3650.             struct stat st;
  3651. #ifdef CREATE_DUMMY_FILE
  3652.             int        did_use_dummy = FALSE;
  3653.  
  3654.             /* Avoid getting a warning for the file being created
  3655.              * outside of Vim, it was created at the start of this
  3656.              * function.  Delete the file now, because Vim might exit
  3657.              * here if the window is closed. */
  3658.             if (dummyfd != NULL)
  3659.             {
  3660.             fclose(dummyfd);
  3661.             dummyfd = NULL;
  3662.             mch_remove(buf->b_fname);
  3663.             did_use_dummy = TRUE;
  3664.             }
  3665. #endif
  3666. #ifdef FEAT_GUI
  3667.             /* If we are supposed to start the GUI but it wasn't
  3668.              * completely started yet, start it now.  This makes the
  3669.              * messages displayed in the Vim window when loading a
  3670.              * session from the .gvimrc file. */
  3671.             if (gui.starting && !gui.in_use)
  3672.             gui_start();
  3673. #endif
  3674.  
  3675. #if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
  3676.             process_still_running = FALSE;
  3677. #endif
  3678.             ++no_wait_return;
  3679.             (void)EMSG(_("E325: ATTENTION"));
  3680.             MSG_PUTS(_("\nFound a swap file by the name \""));
  3681.             msg_home_replace(fname);
  3682.             MSG_PUTS(_("\"\n"));
  3683.             sx = swapfile_info(fname);
  3684.             MSG_PUTS(_("While opening file \""));
  3685.             msg_outtrans(buf->b_fname);
  3686.             MSG_PUTS(_("\"\n"));
  3687.             if (mch_stat((char *)buf->b_fname, &st) != -1)
  3688.             {
  3689.             MSG_PUTS(_("             dated: "));
  3690.             x = st.st_mtime;    /* Manx C can't do &st.st_mtime */
  3691.             MSG_PUTS(ctime(&x));
  3692.             if (sx != 0 && x > sx)
  3693.                 MSG_PUTS(_("      NEWER than swap file!\n"));
  3694.             }
  3695.             /* Some of these messages are long to allow translation to
  3696.              * other languages. */
  3697.             MSG_PUTS(_("\n(1) Another program may be editing the same file.\n    If this is the case, be careful not to end up with two\n    different instances of the same file when making changes.\n"));
  3698.             MSG_PUTS(_("    Quit, or continue with caution.\n"));
  3699.             MSG_PUTS(_("\n(2) An edit session for this file crashed.\n"));
  3700.             MSG_PUTS(_("    If this is the case, use \":recover\" or \"vim -r "));
  3701.             msg_outtrans(buf->b_fname);
  3702.             MSG_PUTS(_("\"\n    to recover the changes (see \":help recovery\").\n"));
  3703.             MSG_PUTS(_("    If you did this already, delete the swap file \""));
  3704.             msg_outtrans(fname);
  3705.             MSG_PUTS(_("\"\n    to avoid this message.\n"));
  3706.             cmdline_row = msg_row;
  3707.             --no_wait_return;
  3708.  
  3709.             /* We don't want a 'q' typed at the more-prompt interrupt
  3710.              * loading a file. */
  3711.             got_int = FALSE;
  3712.  
  3713. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  3714.             if (swap_exists_action)
  3715.             {
  3716.             char_u    *name;
  3717.  
  3718.             name = alloc((unsigned)(STRLEN(fname)
  3719.                 + STRLEN(_("Swap file \""))
  3720.                 + STRLEN(_("\" already exists!")) + 5));
  3721.             if (name != NULL)
  3722.             {
  3723.                 STRCPY(name, _("Swap file \""));
  3724.                 home_replace(NULL, fname, name + STRLEN(name),
  3725.                                   1000, TRUE);
  3726.                 STRCAT(name, _("\" already exists!"));
  3727.             }
  3728.             switch (do_dialog(VIM_WARNING,
  3729.                     (char_u *)_("VIM - ATTENTION"),
  3730.                     name == NULL
  3731.                     ?  (char_u *)_("Swap file already exists!")
  3732.                     : name,
  3733. # if defined(UNIX) || defined(__EMX__) || defined(VMS)
  3734.                     process_still_running
  3735.                     ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit") :
  3736. # endif
  3737.                     (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Delete it"), 1, NULL))
  3738.             {
  3739.                 case 1:
  3740.                 buf->b_p_ro = TRUE;
  3741.                 break;
  3742.                 case 2:
  3743.                 break;
  3744.                 case 3:
  3745.                 swap_exists_action = SEA_RECOVER;
  3746.                 break;
  3747.                 case 4:
  3748.                 swap_exists_action = SEA_QUIT;
  3749.                 break;
  3750.                 case 5:
  3751.                 mch_remove(fname);
  3752.                 break;
  3753.             }
  3754.             vim_free(name);
  3755.  
  3756.             /* pretend screen didn't scroll, need redraw anyway */
  3757.             msg_scrolled = 0;
  3758.             redraw_all_later(NOT_VALID);
  3759.  
  3760.             /* If the file was deleted this fname can be used. */
  3761.             if (mch_getperm(fname) < 0)
  3762.                 break;
  3763.             }
  3764.             else
  3765. #endif
  3766.             {
  3767.             MSG_PUTS("\n");
  3768.             need_wait_return = TRUE; /* call wait_return later */
  3769.             }
  3770.  
  3771. #ifdef CREATE_DUMMY_FILE
  3772.             /* Going to try another name, need the dummy file again. */
  3773.             if (did_use_dummy)
  3774.             dummyfd = mch_fopen((char *)buf->b_fname, "w");
  3775. #endif
  3776.         }
  3777.         }
  3778.     }
  3779.  
  3780.     /*
  3781.      * Change the ".swp" extension to find another file that can be used.
  3782.      * First decrement the last char: ".swo", ".swn", etc.
  3783.      * If that still isn't enough decrement the last but one char: ".svz"
  3784.      * Can happen when editing many "No File" buffers.
  3785.      */
  3786.     if (fname[n - 1] == 'a')    /* ".s?a" */
  3787.     {
  3788.         if (fname[n - 2] == 'a')    /* ".saa": tried enough, give up */
  3789.         {
  3790.         EMSG(_("E326: Too many swap files found"));
  3791.         vim_free(fname);
  3792.         fname = NULL;
  3793.         break;
  3794.         }
  3795.         --fname[n - 2];        /* ".svz", ".suz", etc. */
  3796.         fname[n - 1] = 'z' + 1;
  3797.     }
  3798.     --fname[n - 1];            /* ".swo", ".swn", etc. */
  3799.     }
  3800.  
  3801.     vim_free(dir_name);
  3802. #ifdef CREATE_DUMMY_FILE
  3803.     if (dummyfd != NULL)    /* file has been created temporarily */
  3804.     {
  3805.     fclose(dummyfd);
  3806.     mch_remove(buf->b_fname);
  3807.     }
  3808. #endif
  3809.     return fname;
  3810. }
  3811.  
  3812.     static int
  3813. b0_magic_wrong(b0p)
  3814.     ZERO_BL *b0p;
  3815. {
  3816.     return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
  3817.         || b0p->b0_magic_int != (int)B0_MAGIC_INT
  3818.         || b0p->b0_magic_short != (short)B0_MAGIC_SHORT
  3819.         || b0p->b0_magic_char != B0_MAGIC_CHAR);
  3820. }
  3821.  
  3822. #ifdef CHECK_INODE
  3823. /*
  3824.  * Compare current file name with file name from swap file.
  3825.  * Try to use inode numbers when possible.
  3826.  * Return non-zero when files are different.
  3827.  *
  3828.  * When comparing file names a few things have to be taken into consideration:
  3829.  * - When working over a network the full path of a file depends on the host.
  3830.  *   We check the inode number if possible.  It is not 100% reliable though,
  3831.  *   because the device number cannot be used over a network.
  3832.  * - When a file does not exist yet (editing a new file) there is no inode
  3833.  *   number.
  3834.  * - The file name in a swap file may not be valid on the current host.  The
  3835.  *   "~user" form is used whenever possible to avoid this.
  3836.  *
  3837.  * This is getting complicated, let's make a table:
  3838.  *
  3839.  *        ino_c  ino_s  fname_c  fname_s    differ =
  3840.  *
  3841.  * both files exist -> compare inode numbers:
  3842.  *        != 0   != 0    X     X    ino_c != ino_s
  3843.  *
  3844.  * inode number(s) unknown, file names available -> compare file names
  3845.  *        == 0    X    OK     OK    fname_c != fname_s
  3846.  *         X     == 0    OK     OK    fname_c != fname_s
  3847.  *
  3848.  * current file doesn't exist, file for swap file exist, file name(s) not
  3849.  * available -> probably different
  3850.  *        == 0   != 0    FAIL     X    TRUE
  3851.  *        == 0   != 0    X    FAIL    TRUE
  3852.  *
  3853.  * current file exists, inode for swap unknown, file name(s) not
  3854.  * available -> probably different
  3855.  *        != 0   == 0    FAIL     X    TRUE
  3856.  *        != 0   == 0    X    FAIL    TRUE
  3857.  *
  3858.  * current file doesn't exist, inode for swap unknown, one file name not
  3859.  * available -> probably different
  3860.  *        == 0   == 0    FAIL     OK    TRUE
  3861.  *        == 0   == 0    OK    FAIL    TRUE
  3862.  *
  3863.  * current file doesn't exist, inode for swap unknown, both file names not
  3864.  * available -> probably same file
  3865.  *        == 0   == 0    FAIL    FAIL    FALSE
  3866.  *
  3867.  * Note that when the ino_t is 64 bits, only the last 32 will be used.  This
  3868.  * can't be changed without making the block 0 incompatible with 32 bit
  3869.  * versions.
  3870.  */
  3871.  
  3872.     static int
  3873. fnamecmp_ino(fname_c, fname_s, ino_block0)
  3874.     char_u    *fname_c;        /* current file name */
  3875.     char_u    *fname_s;        /* file name from swap file */
  3876.     long    ino_block0;
  3877. {
  3878.     struct stat    st;
  3879.     ino_t    ino_c = 0;        /* ino of current file */
  3880.     ino_t    ino_s;            /* ino of file from swap file */
  3881.     char_u    buf_c[MAXPATHL];    /* full path of fname_c */
  3882.     char_u    buf_s[MAXPATHL];    /* full path of fname_s */
  3883.     int        retval_c;        /* flag: buf_c valid */
  3884.     int        retval_s;        /* flag: buf_s valid */
  3885.  
  3886.     if (mch_stat((char *)fname_c, &st) == 0)
  3887.     ino_c = (ino_t)st.st_ino;
  3888.  
  3889.     /*
  3890.      * First we try to get the inode from the file name, because the inode in
  3891.      * the swap file may be outdated.  If that fails (e.g. this path is not
  3892.      * valid on this machine), use the inode from block 0.
  3893.      */
  3894.     if (mch_stat((char *)fname_s, &st) == 0)
  3895.     ino_s = (ino_t)st.st_ino;
  3896.     else
  3897.     ino_s = (ino_t)ino_block0;
  3898.  
  3899.     if (ino_c && ino_s)
  3900.     return (ino_c != ino_s);
  3901.  
  3902.     /*
  3903.      * One of the inode numbers is unknown, try a forced vim_FullName() and
  3904.      * compare the file names.
  3905.      */
  3906.     retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
  3907.     retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
  3908.     if (retval_c == OK && retval_s == OK)
  3909.     return (STRCMP(buf_c, buf_s) != 0);
  3910.  
  3911.     /*
  3912.      * Can't compare inodes or file names, guess that the files are different,
  3913.      * unless both appear not to exist at all.
  3914.      */
  3915.     if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
  3916.     return FALSE;
  3917.     return TRUE;
  3918. }
  3919. #endif /* CHECK_INODE */
  3920.  
  3921. /*
  3922.  * Move a long integer into a four byte character array.
  3923.  * Used for machine independency in block zero.
  3924.  */
  3925.     static void
  3926. long_to_char(n, s)
  3927.     long    n;
  3928.     char_u  *s;
  3929. {
  3930.     s[0] = (char_u)(n & 0xff);
  3931.     n = (unsigned)n >> 8;
  3932.     s[1] = (char_u)(n & 0xff);
  3933.     n = (unsigned)n >> 8;
  3934.     s[2] = (char_u)(n & 0xff);
  3935.     n = (unsigned)n >> 8;
  3936.     s[3] = (char_u)(n & 0xff);
  3937. }
  3938.  
  3939.     static long
  3940. char_to_long(s)
  3941.     char_u  *s;
  3942. {
  3943.     long    retval;
  3944.  
  3945.     retval = s[3];
  3946.     retval <<= 8;
  3947.     retval |= s[2];
  3948.     retval <<= 8;
  3949.     retval |= s[1];
  3950.     retval <<= 8;
  3951.     retval |= s[0];
  3952.  
  3953.     return retval;
  3954. }
  3955.  
  3956.     void
  3957. ml_setdirty(buf, flag)
  3958.     buf_T    *buf;
  3959.     int        flag;
  3960. {
  3961.     bhdr_T    *hp;
  3962.     ZERO_BL    *b0p;
  3963.  
  3964.     if (!buf->b_ml.ml_mfp)
  3965.     return;
  3966.     for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  3967.     {
  3968.     if (hp->bh_bnum == 0)
  3969.     {
  3970.         b0p = (ZERO_BL *)(hp->bh_data);
  3971.         b0p->b0_dirty = flag ? 0x55 : 0;
  3972.         hp->bh_flags |= BH_DIRTY;
  3973.         mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
  3974.         break;
  3975.     }
  3976.     }
  3977. }
  3978.  
  3979. #if defined(FEAT_BYTEOFF) || defined(PROTO)
  3980.  
  3981. #define MLCS_MAXL 800    /* max no of lines in chunk */
  3982. #define MLCS_MINL 400   /* should be half of MLCS_MAXL */
  3983.  
  3984. /*
  3985.  * Keep information for finding byte offset of a line, updtytpe may be one of:
  3986.  * ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
  3987.  *       Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
  3988.  * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
  3989.  * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
  3990.  */
  3991.     static void
  3992. ml_updatechunk(buf, line, len, updtype)
  3993.     buf_T    *buf;
  3994.     linenr_T    line;
  3995.     long    len;
  3996.     int        updtype;
  3997. {
  3998.     static buf_T    *ml_upd_lastbuf = NULL;
  3999.     static linenr_T    ml_upd_lastline;
  4000.     static linenr_T    ml_upd_lastcurline;
  4001.     static int        ml_upd_lastcurix;
  4002.  
  4003.     linenr_T        curline = ml_upd_lastcurline;
  4004.     int            curix = ml_upd_lastcurix;
  4005.     long        size;
  4006.     chunksize_T        *curchnk;
  4007.     int            rest;
  4008.     bhdr_T        *hp;
  4009.     DATA_BL        *dp;
  4010.  
  4011.     if (buf->b_ml.ml_usedchunks == -1 || len == 0)
  4012.     return;
  4013.     if (buf->b_ml.ml_chunksize == NULL)
  4014.     {
  4015.     buf->b_ml.ml_chunksize = (chunksize_T *)
  4016.                   alloc((unsigned)sizeof(chunksize_T) * 100);
  4017.     if (buf->b_ml.ml_chunksize == NULL)
  4018.     {
  4019.         buf->b_ml.ml_usedchunks = -1;
  4020.         return;
  4021.     }
  4022.     buf->b_ml.ml_numchunks = 100;
  4023.     buf->b_ml.ml_usedchunks = 1;
  4024.     buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
  4025.     buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
  4026.     }
  4027.  
  4028.     if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
  4029.     {
  4030.     /*
  4031.      * First line in empty buffer from ml_flush_line() -- reset
  4032.      */
  4033.     buf->b_ml.ml_usedchunks = 1;
  4034.     buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
  4035.     buf->b_ml.ml_chunksize[0].mlcs_totalsize =
  4036.                   (long)STRLEN(buf->b_ml.ml_line_ptr) + 1;
  4037.     return;
  4038.     }
  4039.  
  4040.     /*
  4041.      * Find chunk that our line belongs to, curline will be at start of the
  4042.      * chunk.
  4043.      */
  4044.     if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
  4045.         || updtype != ML_CHNK_ADDLINE)
  4046.     {
  4047.     for (curline = 1, curix = 0;
  4048.          curix < buf->b_ml.ml_usedchunks - 1
  4049.          && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4050.          curix++)
  4051.     {
  4052.         curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4053.     }
  4054.     }
  4055.     else if (line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines
  4056.          && curix < buf->b_ml.ml_usedchunks - 1)
  4057.     {
  4058.     /* Adjust cached curix & curline */
  4059.     curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4060.     curix++;
  4061.     }
  4062.     curchnk = buf->b_ml.ml_chunksize + curix;
  4063.  
  4064.     if (updtype == ML_CHNK_DELLINE)
  4065.     len *= -1;
  4066.     curchnk->mlcs_totalsize += len;
  4067.     if (updtype == ML_CHNK_ADDLINE)
  4068.     {
  4069.     curchnk->mlcs_numlines++;
  4070.  
  4071.     /* May resize here so we don't have to do it in both cases below */
  4072.     if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
  4073.     {
  4074.         buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
  4075.         buf->b_ml.ml_chunksize = (chunksize_T *)
  4076.         vim_realloc(buf->b_ml.ml_chunksize,
  4077.                 sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
  4078.         if (buf->b_ml.ml_chunksize == NULL)
  4079.         {
  4080.         /* Hmmmm, Give up on offset for this buffer */
  4081.         buf->b_ml.ml_usedchunks = -1;
  4082.         return;
  4083.         }
  4084.     }
  4085.  
  4086.     if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
  4087.     {
  4088.         int        count;        /* number of entries in block */
  4089.         int        idx;
  4090.         int        text_end;
  4091.         int        linecnt;
  4092.  
  4093.         mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
  4094.             buf->b_ml.ml_chunksize + curix,
  4095.             (buf->b_ml.ml_usedchunks - curix) *
  4096.             sizeof(chunksize_T));
  4097.         /* Compute length of first half of lines in the splitted chunk */
  4098.         size = 0;
  4099.         linecnt = 0;
  4100.         while (curline < buf->b_ml.ml_line_count
  4101.             && linecnt < MLCS_MINL)
  4102.         {
  4103.         if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
  4104.         {
  4105.             buf->b_ml.ml_usedchunks = -1;
  4106.             return;
  4107.         }
  4108.         dp = (DATA_BL *)(hp->bh_data);
  4109.         count = (long)(buf->b_ml.ml_locked_high) -
  4110.             (long)(buf->b_ml.ml_locked_low) + 1;
  4111.         idx = curline - buf->b_ml.ml_locked_low;
  4112.         curline = buf->b_ml.ml_locked_high + 1;
  4113.         if (idx == 0)/* first line in block, text at the end */
  4114.             text_end = dp->db_txt_end;
  4115.         else
  4116.             text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
  4117.         /* Compute index of last line to use in this MEMLINE */
  4118.         rest = count - idx;
  4119.         if (linecnt + rest > MLCS_MINL)
  4120.         {
  4121.             idx += MLCS_MINL - linecnt - 1;
  4122.             linecnt = MLCS_MINL;
  4123.         }
  4124.         else
  4125.         {
  4126.             idx = count - 1;
  4127.             linecnt += rest;
  4128.         }
  4129.         size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
  4130.         }
  4131.         buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
  4132.         buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
  4133.         buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
  4134.         buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
  4135.         buf->b_ml.ml_usedchunks++;
  4136.         ml_upd_lastbuf = NULL;   /* Force recalc of curix & curline */
  4137.         return;
  4138.     }
  4139.     else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
  4140.              && curix == buf->b_ml.ml_usedchunks - 1
  4141.              && buf->b_ml.ml_line_count - line <= 1)
  4142.     {
  4143.         /*
  4144.          * We are in the last chunk and it is cheap to crate a new one
  4145.          * after this. Do it now to avoid the loop above later on
  4146.          */
  4147.         curchnk = buf->b_ml.ml_chunksize + curix + 1;
  4148.         buf->b_ml.ml_usedchunks++;
  4149.         if (line == buf->b_ml.ml_line_count)
  4150.         {
  4151.         curchnk->mlcs_numlines = 0;
  4152.         curchnk->mlcs_totalsize = 0;
  4153.         }
  4154.         else
  4155.         {
  4156.         /*
  4157.          * Line is just prior to last, move count for last
  4158.          * This is the common case  when loading a new file
  4159.          */
  4160.         hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
  4161.         if (hp == NULL)
  4162.         {
  4163.             buf->b_ml.ml_usedchunks = -1;
  4164.             return;
  4165.         }
  4166.         dp = (DATA_BL *)(hp->bh_data);
  4167.         if (dp->db_line_count == 1)
  4168.             rest = dp->db_txt_end - dp->db_txt_start;
  4169.         else
  4170.             rest =
  4171.             ((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
  4172.             - dp->db_txt_start;
  4173.         curchnk->mlcs_totalsize = rest;
  4174.         curchnk->mlcs_numlines = 1;
  4175.         curchnk[-1].mlcs_totalsize -= rest;
  4176.         curchnk[-1].mlcs_numlines -= 1;
  4177.         }
  4178.     }
  4179.     }
  4180.     else if (updtype == ML_CHNK_DELLINE)
  4181.     {
  4182.     curchnk->mlcs_numlines--;
  4183.     ml_upd_lastbuf = NULL;   /* Force recalc of curix & curline */
  4184.     if (curix < (buf->b_ml.ml_usedchunks - 1)
  4185.         && (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
  4186.            <= MLCS_MINL)
  4187.     {
  4188.         curix++;
  4189.         curchnk = buf->b_ml.ml_chunksize + curix;
  4190.     }
  4191.     else if (curix == 0 && curchnk->mlcs_numlines <= 0)
  4192.     {
  4193.         buf->b_ml.ml_usedchunks--;
  4194.         mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
  4195.             buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
  4196.         return;
  4197.     }
  4198.     else if (curix == 0 || (curchnk->mlcs_numlines > 10
  4199.             && (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
  4200.                > MLCS_MINL))
  4201.     {
  4202.         return;
  4203.     }
  4204.  
  4205.     /* Collapse chunks */
  4206.     curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
  4207.     curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
  4208.     buf->b_ml.ml_usedchunks--;
  4209.     if (curix < buf->b_ml.ml_usedchunks)
  4210.     {
  4211.         mch_memmove(buf->b_ml.ml_chunksize + curix,
  4212.             buf->b_ml.ml_chunksize + curix + 1,
  4213.             (buf->b_ml.ml_usedchunks - curix) *
  4214.             sizeof(chunksize_T));
  4215.     }
  4216.     return;
  4217.     }
  4218.     ml_upd_lastbuf = buf;
  4219.     ml_upd_lastline = line;
  4220.     ml_upd_lastcurline = curline;
  4221.     ml_upd_lastcurix = curix;
  4222. }
  4223.  
  4224. /*
  4225.  * Find offset for line or line with offset.
  4226.  * Find line with offset if line is 0; return remaining offset in offp
  4227.  * Find offset of line if line > 0
  4228.  * return -1 if information is not available
  4229.  */
  4230.     long
  4231. ml_find_line_or_offset(buf, line, offp)
  4232.     buf_T    *buf;
  4233.     linenr_T    line;
  4234.     long    *offp;
  4235. {
  4236.     linenr_T    curline;
  4237.     int        curix;
  4238.     long    size;
  4239.     bhdr_T    *hp;
  4240.     DATA_BL    *dp;
  4241.     int        count;        /* number of entries in block */
  4242.     int        idx;
  4243.     int        start_idx;
  4244.     int        text_end;
  4245.     long    offset;
  4246.     int        len;
  4247.     int        ffdos = (get_fileformat(buf) == EOL_DOS);
  4248.     int        extra = 0;
  4249.  
  4250.     if (buf->b_ml.ml_usedchunks == -1
  4251.         || buf->b_ml.ml_chunksize == NULL
  4252.         || line < 0)
  4253.     return -1;
  4254.  
  4255.     if (offp == NULL)
  4256.     offset = 0;
  4257.     else
  4258.     offset = *offp;
  4259.     if (line == 0 && offset <= 0)
  4260.     return 1;   /* Not a "find offset" and offset 0 _must_ be in line 1 */
  4261.     /*
  4262.      * Find the last chunk before the one containing our line. Last chunk is
  4263.      * special because it will never qualify
  4264.      */
  4265.     curline = 1;
  4266.     curix = size = 0;
  4267.     while (curix < buf->b_ml.ml_usedchunks - 1
  4268.         && ((line != 0
  4269.          && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
  4270.         || (offset != 0
  4271.            && offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
  4272.               + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
  4273.     {
  4274.     curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4275.     size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
  4276.     if (offset && ffdos)
  4277.         size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
  4278.     curix++;
  4279.     }
  4280.  
  4281.     while ((line != 0 && curline < line) || (offset != 0 && size < offset))
  4282.     {
  4283.     if (curline > buf->b_ml.ml_line_count
  4284.         || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
  4285.         return -1;
  4286.     dp = (DATA_BL *)(hp->bh_data);
  4287.     count = (long)(buf->b_ml.ml_locked_high) -
  4288.         (long)(buf->b_ml.ml_locked_low) + 1;
  4289.     start_idx = idx = curline - buf->b_ml.ml_locked_low;
  4290.     if (idx == 0)/* first line in block, text at the end */
  4291.         text_end = dp->db_txt_end;
  4292.     else
  4293.         text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
  4294.     /* Compute index of last line to use in this MEMLINE */
  4295.     if (line != 0)
  4296.     {
  4297.         if (curline + (count - idx) >= line)
  4298.         idx += line - curline - 1;
  4299.         else
  4300.         idx = count - 1;
  4301.     }
  4302.     else
  4303.     {
  4304.         extra = 0;
  4305.         while (offset >= size
  4306.                + text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
  4307.                                       + ffdos)
  4308.         {
  4309.         if (ffdos)
  4310.             size++;
  4311.         if (idx == count - 1)
  4312.         {
  4313.             extra = 1;
  4314.             break;
  4315.         }
  4316.         idx++;
  4317.         }
  4318.     }
  4319.     len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
  4320.     size += len;
  4321.     if (offset != 0 && size >= offset)
  4322.     {
  4323.         if (size + ffdos == offset)
  4324.         *offp = 0;
  4325.         else if (idx == start_idx)
  4326.         *offp = offset - size + len;
  4327.         else
  4328.         *offp = offset - size + len
  4329.              - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
  4330.         curline += idx - start_idx + extra;
  4331.         if (curline > buf->b_ml.ml_line_count)
  4332.         return -1;    /* exactly one byte beyond the end */
  4333.         return curline;
  4334.     }
  4335.     curline = buf->b_ml.ml_locked_high + 1;
  4336.     }
  4337.  
  4338.     if (ffdos)
  4339.     size += line - 1;
  4340.     return size;
  4341. }
  4342.  
  4343. /*
  4344.  * Goto byte in buffer with offset 'cnt'.
  4345.  */
  4346.     void
  4347. goto_byte(cnt)
  4348.     long    cnt;
  4349. {
  4350.     long    boff = cnt;
  4351.     linenr_T    lnum;
  4352.  
  4353.     ml_flush_line(curbuf);    /* cached line may be dirty */
  4354.     setpcmark();
  4355.     if (boff)
  4356.     --boff;
  4357.     lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
  4358.     if (lnum < 1)    /* past the end */
  4359.     {
  4360.     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  4361.     curwin->w_curswant = MAXCOL;
  4362.     coladvance((colnr_T)MAXCOL);
  4363.     }
  4364.     else
  4365.     {
  4366.     curwin->w_cursor.lnum = lnum;
  4367.     curwin->w_cursor.col = (colnr_T)boff;
  4368.     curwin->w_set_curswant = TRUE;
  4369.     }
  4370.     check_cursor();
  4371.  
  4372. # ifdef FEAT_MBYTE
  4373.     /* Make sure the cursor is on the first byte of a multi-byte char. */
  4374.     if (has_mbyte)
  4375.     mb_adjust_cursor();
  4376. # endif
  4377. }
  4378. #endif
  4379.