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