neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

memline.c (144754B)


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