xref: /vim-8.2.3635/src/memline.c (revision ed37d9b3)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 // for debugging
11 // #define CHECK(c, s)	do { if (c) emsg((s)); } while (0)
12 #define CHECK(c, s)	do { /**/ } while (0)
13 
14 /*
15  * memline.c: Contains the functions for appending, deleting and changing the
16  * text lines. The memfile functions are used to store the information in
17  * blocks of memory, backed up by a file. The structure of the information is
18  * a tree.  The root of the tree is a pointer block. The leaves of the tree
19  * are data blocks. In between may be several layers of pointer blocks,
20  * forming branches.
21  *
22  * Three types of blocks are used:
23  * - Block nr 0 contains information for recovery
24  * - Pointer blocks contain list of pointers to other blocks.
25  * - Data blocks contain the actual text.
26  *
27  * Block nr 0 contains the block0 structure (see below).
28  *
29  * Block nr 1 is the first pointer block. It is the root of the tree.
30  * Other pointer blocks are branches.
31  *
32  *  If a line is too big to fit in a single page, the block containing that
33  *  line is made big enough to hold the line. It may span several pages.
34  *  Otherwise all blocks are one page.
35  *
36  *  A data block that was filled when starting to edit a file and was not
37  *  changed since then, can have a negative block number. This means that it
38  *  has not yet been assigned a place in the file. When recovering, the lines
39  *  in this data block can be read from the original file. When the block is
40  *  changed (lines appended/deleted/changed) or when it is flushed it gets a
41  *  positive number. Use mf_trans_del() to get the new number, before calling
42  *  mf_get().
43  */
44 
45 #include "vim.h"
46 
47 #ifndef UNIX		// it's in os_unix.h for Unix
48 # include <time.h>
49 #endif
50 
51 #if defined(SASC) || defined(__amigaos4__)
52 # include <proto/dos.h>	    // for Open() and Close()
53 #endif
54 
55 typedef struct block0		ZERO_BL;    // contents of the first block
56 typedef struct pointer_block	PTR_BL;	    // contents of a pointer block
57 typedef struct data_block	DATA_BL;    // contents of a data block
58 typedef struct pointer_entry	PTR_EN;	    // block/line-count pair
59 
60 #define DATA_ID	       (('d' << 8) + 'a')   // data block id
61 #define PTR_ID	       (('p' << 8) + 't')   // pointer block id
62 #define BLOCK0_ID0     'b'		    // block 0 id 0
63 #define BLOCK0_ID1     '0'		    // block 0 id 1
64 #define BLOCK0_ID1_C0  'c'		    // block 0 id 1 'cm' 0
65 #define BLOCK0_ID1_C1  'C'		    // block 0 id 1 'cm' 1
66 #define BLOCK0_ID1_C2  'd'		    // block 0 id 1 'cm' 2
67 
68 #if defined(FEAT_CRYPT)
69 static int id1_codes[] = {
70     BLOCK0_ID1_C0,  // CRYPT_M_ZIP
71     BLOCK0_ID1_C1,  // CRYPT_M_BF
72     BLOCK0_ID1_C2,  // CRYPT_M_BF2
73 };
74 #endif
75 
76 /*
77  * pointer to a block, used in a pointer block
78  */
79 struct pointer_entry
80 {
81     blocknr_T	pe_bnum;	// block number
82     linenr_T	pe_line_count;	// number of lines in this branch
83     linenr_T	pe_old_lnum;	// lnum for this block (for recovery)
84     int		pe_page_count;	// number of pages in block pe_bnum
85 };
86 
87 /*
88  * A pointer block contains a list of branches in the tree.
89  */
90 struct pointer_block
91 {
92     short_u	pb_id;		// ID for pointer block: PTR_ID
93     short_u	pb_count;	// number of pointers in this block
94     short_u	pb_count_max;	// maximum value for pb_count
95     PTR_EN	pb_pointer[1];	// list of pointers to blocks (actually longer)
96 				// followed by empty space until end of page
97 };
98 
99 /*
100  * A data block is a leaf in the tree.
101  *
102  * The text of the lines is at the end of the block. The text of the first line
103  * in the block is put at the end, the text of the second line in front of it,
104  * etc. Thus the order of the lines is the opposite of the line number.
105  */
106 struct data_block
107 {
108     short_u	db_id;		// ID for data block: DATA_ID
109     unsigned	db_free;	// free space available
110     unsigned	db_txt_start;	// byte where text starts
111     unsigned	db_txt_end;	// byte just after data block
112     linenr_T	db_line_count;	// number of lines in this block
113     unsigned	db_index[1];	// index for start of line (actually bigger)
114 				// followed by empty space up to db_txt_start
115 				// followed by the text in the lines until
116 				// end of page
117 };
118 
119 /*
120  * The low bits of db_index hold the actual index. The topmost bit is
121  * used for the global command to be able to mark a line.
122  * This method is not clean, but otherwise there would be at least one extra
123  * byte used for each line.
124  * The mark has to be in this place to keep it with the correct line when other
125  * lines are inserted or deleted.
126  */
127 #define DB_MARKED	((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
128 #define DB_INDEX_MASK	(~DB_MARKED)
129 
130 #define INDEX_SIZE  (sizeof(unsigned))	    // size of one db_index entry
131 #define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE)  // size of data block header
132 
133 #define B0_FNAME_SIZE_ORG	900	// what it was in older versions
134 #define B0_FNAME_SIZE_NOCRYPT	898	// 2 bytes used for other things
135 #define B0_FNAME_SIZE_CRYPT	890	// 10 bytes used for other things
136 #define B0_UNAME_SIZE		40
137 #define B0_HNAME_SIZE		40
138 /*
139  * Restrict the numbers to 32 bits, otherwise most compilers will complain.
140  * This won't detect a 64 bit machine that only swaps a byte in the top 32
141  * bits, but that is crazy anyway.
142  */
143 #define B0_MAGIC_LONG	0x30313233L
144 #define B0_MAGIC_INT	0x20212223L
145 #define B0_MAGIC_SHORT	0x10111213L
146 #define B0_MAGIC_CHAR	0x55
147 
148 /*
149  * Block zero holds all info about the swap file.
150  *
151  * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing
152  * swap files unusable!
153  *
154  * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!!
155  *
156  * This block is built up of single bytes, to make it portable across
157  * different machines. b0_magic_* is used to check the byte order and size of
158  * variables, because the rest of the swap file is not portable.
159  */
160 struct block0
161 {
162     char_u	b0_id[2];	// id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
163 				// BLOCK0_ID1_C0, BLOCK0_ID1_C1, etc.
164     char_u	b0_version[10];	// Vim version string
165     char_u	b0_page_size[4];// number of bytes per page
166     char_u	b0_mtime[4];	// last modification time of file
167     char_u	b0_ino[4];	// inode of b0_fname
168     char_u	b0_pid[4];	// process id of creator (or 0)
169     char_u	b0_uname[B0_UNAME_SIZE]; // name of user (uid if no name)
170     char_u	b0_hname[B0_HNAME_SIZE]; // host name (if it has a name)
171     char_u	b0_fname[B0_FNAME_SIZE_ORG]; // name of file being edited
172     long	b0_magic_long;	// check for byte order of long
173     int		b0_magic_int;	// check for byte order of int
174     short	b0_magic_short;	// check for byte order of short
175     char_u	b0_magic_char;	// check for last char
176 };
177 
178 /*
179  * Note: b0_dirty and b0_flags are put at the end of the file name.  For very
180  * long file names in older versions of Vim they are invalid.
181  * The 'fileencoding' comes before b0_flags, with a NUL in front.  But only
182  * when there is room, for very long file names it's omitted.
183  */
184 #define B0_DIRTY	0x55
185 #define b0_dirty	b0_fname[B0_FNAME_SIZE_ORG - 1]
186 
187 /*
188  * The b0_flags field is new in Vim 7.0.
189  */
190 #define b0_flags	b0_fname[B0_FNAME_SIZE_ORG - 2]
191 
192 /*
193  * Crypt seed goes here, 8 bytes.  New in Vim 7.3.
194  * Without encryption these bytes may be used for 'fenc'.
195  */
196 #define b0_seed		b0_fname[B0_FNAME_SIZE_ORG - 2 - MF_SEED_LEN]
197 
198 // The lowest two bits contain the fileformat.  Zero means it's not set
199 // (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or
200 // EOL_MAC + 1.
201 #define B0_FF_MASK	3
202 
203 // Swap file is in directory of edited file.  Used to find the file from
204 // different mount points.
205 #define B0_SAME_DIR	4
206 
207 // The 'fileencoding' is at the end of b0_fname[], with a NUL in front of it.
208 // When empty there is only the NUL.
209 #define B0_HAS_FENC	8
210 
211 #define STACK_INCR	5	// nr of entries added to ml_stack at a time
212 
213 /*
214  * The line number where the first mark may be is remembered.
215  * If it is 0 there are no marks at all.
216  * (always used for the current buffer only, no buffer change possible while
217  * executing a global command).
218  */
219 static linenr_T	lowest_marked = 0;
220 
221 /*
222  * arguments for ml_find_line()
223  */
224 #define ML_DELETE	0x11	    // delete line
225 #define ML_INSERT	0x12	    // insert line
226 #define ML_FIND		0x13	    // just find the line
227 #define ML_FLUSH	0x02	    // flush locked block
228 #define ML_SIMPLE(x)	(x & 0x10)  // DEL, INS or FIND
229 
230 // argument for ml_upd_block0()
231 typedef enum {
232       UB_FNAME = 0	// update timestamp and filename
233     , UB_SAME_DIR       // update the B0_SAME_DIR flag
234     , UB_CRYPT		// update crypt key
235 } upd_block0_T;
236 
237 #ifdef FEAT_CRYPT
238 static void ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p);
239 #endif
240 static void ml_upd_block0(buf_T *buf, upd_block0_T what);
241 static void set_b0_fname(ZERO_BL *, buf_T *buf);
242 static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf);
243 static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf);
244 static time_t swapfile_info(char_u *);
245 static int recov_file_names(char_u **, char_u *, int prepend_dot);
246 static int ml_delete_int(buf_T *, linenr_T, int);
247 static char_u *findswapname(buf_T *, char_u **, char_u *);
248 static void ml_flush_line(buf_T *);
249 static bhdr_T *ml_new_data(memfile_T *, int, int);
250 static bhdr_T *ml_new_ptr(memfile_T *);
251 static bhdr_T *ml_find_line(buf_T *, linenr_T, int);
252 static int ml_add_stack(buf_T *);
253 static void ml_lineadd(buf_T *, int);
254 static int b0_magic_wrong(ZERO_BL *);
255 #ifdef CHECK_INODE
256 static int fnamecmp_ino(char_u *, char_u *, long);
257 #endif
258 static void long_to_char(long, char_u *);
259 static long char_to_long(char_u *);
260 #ifdef FEAT_CRYPT
261 static cryptstate_T *ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading);
262 #endif
263 #ifdef FEAT_BYTEOFF
264 static void ml_updatechunk(buf_T *buf, long line, long len, int updtype);
265 #endif
266 
267 /*
268  * Open a new memline for "buf".
269  *
270  * Return FAIL for failure, OK otherwise.
271  */
272     int
273 ml_open(buf_T *buf)
274 {
275     memfile_T	*mfp;
276     bhdr_T	*hp = NULL;
277     ZERO_BL	*b0p;
278     PTR_BL	*pp;
279     DATA_BL	*dp;
280 
281     /*
282      * init fields in memline struct
283      */
284     buf->b_ml.ml_stack_size = 0; // no stack yet
285     buf->b_ml.ml_stack = NULL;	// no stack yet
286     buf->b_ml.ml_stack_top = 0;	// nothing in the stack
287     buf->b_ml.ml_locked = NULL;	// no cached block
288     buf->b_ml.ml_line_lnum = 0;	// no cached line
289 #ifdef FEAT_BYTEOFF
290     buf->b_ml.ml_chunksize = NULL;
291 #endif
292 
293     if (cmdmod.noswapfile)
294 	buf->b_p_swf = FALSE;
295 
296     /*
297      * When 'updatecount' is non-zero swap file may be opened later.
298      */
299     if (p_uc && buf->b_p_swf)
300 	buf->b_may_swap = TRUE;
301     else
302 	buf->b_may_swap = FALSE;
303 
304     /*
305      * Open the memfile.  No swap file is created yet.
306      */
307     mfp = mf_open(NULL, 0);
308     if (mfp == NULL)
309 	goto error;
310 
311     buf->b_ml.ml_mfp = mfp;
312 #ifdef FEAT_CRYPT
313     mfp->mf_buffer = buf;
314 #endif
315     buf->b_ml.ml_flags = ML_EMPTY;
316     buf->b_ml.ml_line_count = 1;
317 #ifdef FEAT_LINEBREAK
318     curwin->w_nrwidth_line_count = 0;
319 #endif
320 
321 /*
322  * fill block0 struct and write page 0
323  */
324     if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
325 	goto error;
326     if (hp->bh_bnum != 0)
327     {
328 	iemsg(_("E298: Didn't get block nr 0?"));
329 	goto error;
330     }
331     b0p = (ZERO_BL *)(hp->bh_data);
332 
333     b0p->b0_id[0] = BLOCK0_ID0;
334     b0p->b0_id[1] = BLOCK0_ID1;
335     b0p->b0_magic_long = (long)B0_MAGIC_LONG;
336     b0p->b0_magic_int = (int)B0_MAGIC_INT;
337     b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
338     b0p->b0_magic_char = B0_MAGIC_CHAR;
339     mch_memmove(b0p->b0_version, "VIM ", 4);
340     STRNCPY(b0p->b0_version + 4, Version, 6);
341     long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
342 
343 #ifdef FEAT_SPELL
344     if (!buf->b_spell)
345 #endif
346     {
347 	b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
348 	b0p->b0_flags = get_fileformat(buf) + 1;
349 	set_b0_fname(b0p, buf);
350 	(void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
351 	b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
352 	mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
353 	b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
354 	long_to_char(mch_get_pid(), b0p->b0_pid);
355 #ifdef FEAT_CRYPT
356 	ml_set_b0_crypt(buf, b0p);
357 #endif
358     }
359 
360     /*
361      * Always sync block number 0 to disk, so we can check the file name in
362      * the swap file in findswapname(). Don't do this for a help files or
363      * a spell buffer though.
364      * Only works when there's a swapfile, otherwise it's done when the file
365      * is created.
366      */
367     mf_put(mfp, hp, TRUE, FALSE);
368     if (!buf->b_help && !B_SPELL(buf))
369 	(void)mf_sync(mfp, 0);
370 
371     /*
372      * Fill in root pointer block and write page 1.
373      */
374     if ((hp = ml_new_ptr(mfp)) == NULL)
375 	goto error;
376     if (hp->bh_bnum != 1)
377     {
378 	iemsg(_("E298: Didn't get block nr 1?"));
379 	goto error;
380     }
381     pp = (PTR_BL *)(hp->bh_data);
382     pp->pb_count = 1;
383     pp->pb_pointer[0].pe_bnum = 2;
384     pp->pb_pointer[0].pe_page_count = 1;
385     pp->pb_pointer[0].pe_old_lnum = 1;
386     pp->pb_pointer[0].pe_line_count = 1;    // line count after insertion
387     mf_put(mfp, hp, TRUE, FALSE);
388 
389     /*
390      * Allocate first data block and create an empty line 1.
391      */
392     if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
393 	goto error;
394     if (hp->bh_bnum != 2)
395     {
396 	iemsg(_("E298: Didn't get block nr 2?"));
397 	goto error;
398     }
399 
400     dp = (DATA_BL *)(hp->bh_data);
401     dp->db_index[0] = --dp->db_txt_start;	// at end of block
402     dp->db_free -= 1 + INDEX_SIZE;
403     dp->db_line_count = 1;
404     *((char_u *)dp + dp->db_txt_start) = NUL;	// empty line
405 
406     return OK;
407 
408 error:
409     if (mfp != NULL)
410     {
411 	if (hp)
412 	    mf_put(mfp, hp, FALSE, FALSE);
413 	mf_close(mfp, TRUE);	    // will also free(mfp->mf_fname)
414     }
415     buf->b_ml.ml_mfp = NULL;
416     return FAIL;
417 }
418 
419 #if defined(FEAT_CRYPT) || defined(PROTO)
420 /*
421  * Prepare encryption for "buf" for the current key and method.
422  */
423     static void
424 ml_set_mfp_crypt(buf_T *buf)
425 {
426     if (*buf->b_p_key != NUL)
427     {
428 	int method_nr = crypt_get_method_nr(buf);
429 
430 	if (method_nr > CRYPT_M_ZIP)
431 	{
432 	    // Generate a seed and store it in the memfile.
433 	    sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
434 	}
435     }
436 }
437 
438 /*
439  * Prepare encryption for "buf" with block 0 "b0p".
440  */
441     static void
442 ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p)
443 {
444     if (*buf->b_p_key == NUL)
445 	b0p->b0_id[1] = BLOCK0_ID1;
446     else
447     {
448 	int method_nr = crypt_get_method_nr(buf);
449 
450 	b0p->b0_id[1] = id1_codes[method_nr];
451 	if (method_nr > CRYPT_M_ZIP)
452 	{
453 	    // Generate a seed and store it in block 0 and in the memfile.
454 	    sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
455 	    mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
456 	}
457     }
458 }
459 
460 /*
461  * Called after the crypt key or 'cryptmethod' was changed for "buf".
462  * Will apply this to the swapfile.
463  * "old_key" is the previous key.  It is equal to buf->b_p_key when
464  * 'cryptmethod' is changed.
465  * "old_cm" is the previous 'cryptmethod'.  It is equal to the current
466  * 'cryptmethod' when 'key' is changed.
467  */
468     void
469 ml_set_crypt_key(
470     buf_T	*buf,
471     char_u	*old_key,
472     char_u	*old_cm)
473 {
474     memfile_T	*mfp = buf->b_ml.ml_mfp;
475     bhdr_T	*hp;
476     int		page_count;
477     int		idx;
478     long	error;
479     infoptr_T	*ip;
480     PTR_BL	*pp;
481     DATA_BL	*dp;
482     blocknr_T	bnum;
483     int		top;
484     int		old_method;
485 
486     if (mfp == NULL)
487 	return;  // no memfile yet, nothing to do
488     old_method = crypt_method_nr_from_name(old_cm);
489 
490     // First make sure the swapfile is in a consistent state, using the old
491     // key and method.
492     {
493 	char_u *new_key = buf->b_p_key;
494 	char_u *new_buf_cm = buf->b_p_cm;
495 
496 	buf->b_p_key = old_key;
497 	buf->b_p_cm = old_cm;
498 	ml_preserve(buf, FALSE);
499 	buf->b_p_key = new_key;
500 	buf->b_p_cm = new_buf_cm;
501     }
502 
503     // Set the key, method and seed to be used for reading, these must be the
504     // old values.
505     mfp->mf_old_key = old_key;
506     mfp->mf_old_cm = old_method;
507     if (old_method > 0 && *old_key != NUL)
508 	mch_memmove(mfp->mf_old_seed, mfp->mf_seed, MF_SEED_LEN);
509 
510     // Update block 0 with the crypt flag and may set a new seed.
511     ml_upd_block0(buf, UB_CRYPT);
512 
513     if (mfp->mf_infile_count > 2)
514     {
515 	/*
516 	 * Need to read back all data blocks from disk, decrypt them with the
517 	 * old key/method and mark them to be written. The algorithm is
518 	 * similar to what happens in ml_recover(), but we skip negative block
519 	 * numbers.
520 	 */
521 	ml_flush_line(buf);		    // flush buffered line
522 	(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); // flush locked block
523 
524 	hp = NULL;
525 	bnum = 1;		// start with block 1
526 	page_count = 1;		// which is 1 page
527 	idx = 0;		// start with first index in block 1
528 	error = 0;
529 	buf->b_ml.ml_stack_top = 0;
530 	VIM_CLEAR(buf->b_ml.ml_stack);
531 	buf->b_ml.ml_stack_size = 0;	// no stack yet
532 
533 	for ( ; !got_int; line_breakcheck())
534 	{
535 	    if (hp != NULL)
536 		mf_put(mfp, hp, FALSE, FALSE);	// release previous block
537 
538 	    // get the block (pointer or data)
539 	    if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
540 	    {
541 		if (bnum == 1)
542 		    break;
543 		++error;
544 	    }
545 	    else
546 	    {
547 		pp = (PTR_BL *)(hp->bh_data);
548 		if (pp->pb_id == PTR_ID)	// it is a pointer block
549 		{
550 		    if (pp->pb_count == 0)
551 		    {
552 			// empty block?
553 			++error;
554 		    }
555 		    else if (idx < (int)pp->pb_count)	// go a block deeper
556 		    {
557 			if (pp->pb_pointer[idx].pe_bnum < 0)
558 			{
559 			    // Skip data block with negative block number.
560 			    // Should not happen, because of the ml_preserve()
561 			    // above. Get same block again for next index.
562 			    ++idx;
563 			    continue;
564 			}
565 
566 			// going one block deeper in the tree, new entry in
567 			// stack
568 			if ((top = ml_add_stack(buf)) < 0)
569 			{
570 			    ++error;
571 			    break;		    // out of memory
572 			}
573 			ip = &(buf->b_ml.ml_stack[top]);
574 			ip->ip_bnum = bnum;
575 			ip->ip_index = idx;
576 
577 			bnum = pp->pb_pointer[idx].pe_bnum;
578 			page_count = pp->pb_pointer[idx].pe_page_count;
579 			idx = 0;
580 			continue;
581 		    }
582 		}
583 		else	    // not a pointer block
584 		{
585 		    dp = (DATA_BL *)(hp->bh_data);
586 		    if (dp->db_id != DATA_ID)	// block id wrong
587 			++error;
588 		    else
589 		    {
590 			// It is a data block, need to write it back to disk.
591 			mf_put(mfp, hp, TRUE, FALSE);
592 			hp = NULL;
593 		    }
594 		}
595 	    }
596 
597 	    if (buf->b_ml.ml_stack_top == 0)	// finished
598 		break;
599 
600 	    // go one block up in the tree
601 	    ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
602 	    bnum = ip->ip_bnum;
603 	    idx = ip->ip_index + 1;	    // go to next index
604 	    page_count = 1;
605 	}
606 	if (hp != NULL)
607 	    mf_put(mfp, hp, FALSE, FALSE);  // release previous block
608 
609 	if (error > 0)
610 	    emsg(_("E843: Error while updating swap file crypt"));
611     }
612 
613     mfp->mf_old_key = NULL;
614 }
615 #endif
616 
617 /*
618  * ml_setname() is called when the file name of "buf" has been changed.
619  * It may rename the swap file.
620  */
621     void
622 ml_setname(buf_T *buf)
623 {
624     int		success = FALSE;
625     memfile_T	*mfp;
626     char_u	*fname;
627     char_u	*dirp;
628 #if defined(MSWIN)
629     char_u	*p;
630 #endif
631 
632     mfp = buf->b_ml.ml_mfp;
633     if (mfp->mf_fd < 0)		    // there is no swap file yet
634     {
635 	/*
636 	 * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
637 	 * For help files we will make a swap file now.
638 	 */
639 	if (p_uc != 0 && !cmdmod.noswapfile)
640 	    ml_open_file(buf);	    // create a swap file
641 	return;
642     }
643 
644     /*
645      * Try all directories in the 'directory' option.
646      */
647     dirp = p_dir;
648     for (;;)
649     {
650 	if (*dirp == NUL)	    // tried all directories, fail
651 	    break;
652 	fname = findswapname(buf, &dirp, mfp->mf_fname);
653 						    // alloc's fname
654 	if (dirp == NULL)	    // out of memory
655 	    break;
656 	if (fname == NULL)	    // no file name found for this dir
657 	    continue;
658 
659 #if defined(MSWIN)
660 	/*
661 	 * Set full pathname for swap file now, because a ":!cd dir" may
662 	 * change directory without us knowing it.
663 	 */
664 	p = FullName_save(fname, FALSE);
665 	vim_free(fname);
666 	fname = p;
667 	if (fname == NULL)
668 	    continue;
669 #endif
670 	// if the file name is the same we don't have to do anything
671 	if (fnamecmp(fname, mfp->mf_fname) == 0)
672 	{
673 	    vim_free(fname);
674 	    success = TRUE;
675 	    break;
676 	}
677 	// need to close the swap file before renaming
678 	if (mfp->mf_fd >= 0)
679 	{
680 	    close(mfp->mf_fd);
681 	    mfp->mf_fd = -1;
682 	}
683 
684 	// try to rename the swap file
685 	if (vim_rename(mfp->mf_fname, fname) == 0)
686 	{
687 	    success = TRUE;
688 	    vim_free(mfp->mf_fname);
689 	    mfp->mf_fname = fname;
690 	    vim_free(mfp->mf_ffname);
691 #if defined(MSWIN)
692 	    mfp->mf_ffname = NULL;  // mf_fname is full pathname already
693 #else
694 	    mf_set_ffname(mfp);
695 #endif
696 	    ml_upd_block0(buf, UB_SAME_DIR);
697 	    break;
698 	}
699 	vim_free(fname);	    // this fname didn't work, try another
700     }
701 
702     if (mfp->mf_fd == -1)	    // need to (re)open the swap file
703     {
704 	mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
705 	if (mfp->mf_fd < 0)
706 	{
707 	    // could not (re)open the swap file, what can we do????
708 	    emsg(_("E301: Oops, lost the swap file!!!"));
709 	    return;
710 	}
711 #ifdef HAVE_FD_CLOEXEC
712 	{
713 	    int fdflags = fcntl(mfp->mf_fd, F_GETFD);
714 	    if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
715 		(void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
716 	}
717 #endif
718     }
719     if (!success)
720 	emsg(_("E302: Could not rename swap file"));
721 }
722 
723 /*
724  * Open a file for the memfile for all buffers that are not readonly or have
725  * been modified.
726  * Used when 'updatecount' changes from zero to non-zero.
727  */
728     void
729 ml_open_files(void)
730 {
731     buf_T	*buf;
732 
733     FOR_ALL_BUFFERS(buf)
734 	if (!buf->b_p_ro || buf->b_changed)
735 	    ml_open_file(buf);
736 }
737 
738 /*
739  * Open a swap file for an existing memfile, if there is no swap file yet.
740  * If we are unable to find a file name, mf_fname will be NULL
741  * and the memfile will be in memory only (no recovery possible).
742  */
743     void
744 ml_open_file(buf_T *buf)
745 {
746     memfile_T	*mfp;
747     char_u	*fname;
748     char_u	*dirp;
749 
750     mfp = buf->b_ml.ml_mfp;
751     if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || cmdmod.noswapfile)
752 	return;		// nothing to do
753 
754 #ifdef FEAT_SPELL
755     // For a spell buffer use a temp file name.
756     if (buf->b_spell)
757     {
758 	fname = vim_tempname('s', FALSE);
759 	if (fname != NULL)
760 	    (void)mf_open_file(mfp, fname);	// consumes fname!
761 	buf->b_may_swap = FALSE;
762 	return;
763     }
764 #endif
765 
766     /*
767      * Try all directories in 'directory' option.
768      */
769     dirp = p_dir;
770     for (;;)
771     {
772 	if (*dirp == NUL)
773 	    break;
774 	// There is a small chance that between choosing the swap file name
775 	// and creating it, another Vim creates the file.  In that case the
776 	// creation will fail and we will use another directory.
777 	fname = findswapname(buf, &dirp, NULL); // allocates fname
778 	if (dirp == NULL)
779 	    break;  // out of memory
780 	if (fname == NULL)
781 	    continue;
782 	if (mf_open_file(mfp, fname) == OK)	// consumes fname!
783 	{
784 #if defined(MSWIN)
785 	    /*
786 	     * set full pathname for swap file now, because a ":!cd dir" may
787 	     * change directory without us knowing it.
788 	     */
789 	    mf_fullname(mfp);
790 #endif
791 	    ml_upd_block0(buf, UB_SAME_DIR);
792 
793 	    // Flush block zero, so others can read it
794 	    if (mf_sync(mfp, MFS_ZERO) == OK)
795 	    {
796 		// Mark all blocks that should be in the swapfile as dirty.
797 		// Needed for when the 'swapfile' option was reset, so that
798 		// the swap file was deleted, and then on again.
799 		mf_set_dirty(mfp);
800 		break;
801 	    }
802 	    // Writing block 0 failed: close the file and try another dir
803 	    mf_close_file(buf, FALSE);
804 	}
805     }
806 
807     if (*p_dir != NUL && mfp->mf_fname == NULL)
808     {
809 	need_wait_return = TRUE;	// call wait_return later
810 	++no_wait_return;
811 	(void)semsg(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
812 		    buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname);
813 	--no_wait_return;
814     }
815 
816     // don't try to open a swap file again
817     buf->b_may_swap = FALSE;
818 }
819 
820 /*
821  * If still need to create a swap file, and starting to edit a not-readonly
822  * file, or reading into an existing buffer, create a swap file now.
823  */
824     void
825 check_need_swap(
826     int	    newfile)		// reading file into new buffer
827 {
828     int old_msg_silent = msg_silent; // might be reset by an E325 message
829 
830     if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
831 	ml_open_file(curbuf);
832     msg_silent = old_msg_silent;
833 }
834 
835 /*
836  * Close memline for buffer 'buf'.
837  * If 'del_file' is TRUE, delete the swap file
838  */
839     void
840 ml_close(buf_T *buf, int del_file)
841 {
842     if (buf->b_ml.ml_mfp == NULL)		// not open
843 	return;
844     mf_close(buf->b_ml.ml_mfp, del_file);	// close the .swp file
845     if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
846 	vim_free(buf->b_ml.ml_line_ptr);
847     vim_free(buf->b_ml.ml_stack);
848 #ifdef FEAT_BYTEOFF
849     VIM_CLEAR(buf->b_ml.ml_chunksize);
850 #endif
851     buf->b_ml.ml_mfp = NULL;
852 
853     // Reset the "recovered" flag, give the ATTENTION prompt the next time
854     // this buffer is loaded.
855     buf->b_flags &= ~BF_RECOVERED;
856 }
857 
858 /*
859  * Close all existing memlines and memfiles.
860  * Only used when exiting.
861  * When 'del_file' is TRUE, delete the memfiles.
862  * But don't delete files that were ":preserve"d when we are POSIX compatible.
863  */
864     void
865 ml_close_all(int del_file)
866 {
867     buf_T	*buf;
868 
869     FOR_ALL_BUFFERS(buf)
870 	ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0
871 				 || vim_strchr(p_cpo, CPO_PRESERVE) == NULL));
872 #ifdef FEAT_SPELL
873     spell_delete_wordlist();	// delete the internal wordlist
874 #endif
875 #ifdef TEMPDIRNAMES
876     vim_deltempdir();		// delete created temp directory
877 #endif
878 }
879 
880 /*
881  * Close all memfiles for not modified buffers.
882  * Only use just before exiting!
883  */
884     void
885 ml_close_notmod(void)
886 {
887     buf_T	*buf;
888 
889     FOR_ALL_BUFFERS(buf)
890 	if (!bufIsChanged(buf))
891 	    ml_close(buf, TRUE);    // close all not-modified buffers
892 }
893 
894 /*
895  * Update the timestamp in the .swp file.
896  * Used when the file has been written.
897  */
898     void
899 ml_timestamp(buf_T *buf)
900 {
901     ml_upd_block0(buf, UB_FNAME);
902 }
903 
904 /*
905  * Return FAIL when the ID of "b0p" is wrong.
906  */
907     static int
908 ml_check_b0_id(ZERO_BL *b0p)
909 {
910     if (b0p->b0_id[0] != BLOCK0_ID0
911 	    || (b0p->b0_id[1] != BLOCK0_ID1
912 		&& b0p->b0_id[1] != BLOCK0_ID1_C0
913 		&& b0p->b0_id[1] != BLOCK0_ID1_C1
914 		&& b0p->b0_id[1] != BLOCK0_ID1_C2)
915 	    )
916 	return FAIL;
917     return OK;
918 }
919 
920 /*
921  * Update the timestamp or the B0_SAME_DIR flag of the .swp file.
922  */
923     static void
924 ml_upd_block0(buf_T *buf, upd_block0_T what)
925 {
926     memfile_T	*mfp;
927     bhdr_T	*hp;
928     ZERO_BL	*b0p;
929 
930     mfp = buf->b_ml.ml_mfp;
931     if (mfp == NULL)
932 	return;
933     hp = mf_get(mfp, (blocknr_T)0, 1);
934     if (hp == NULL)
935     {
936 #ifdef FEAT_CRYPT
937 	// Possibly update the seed in the memfile before there is a block0.
938 	if (what == UB_CRYPT)
939 	    ml_set_mfp_crypt(buf);
940 #endif
941 	return;
942     }
943 
944     b0p = (ZERO_BL *)(hp->bh_data);
945     if (ml_check_b0_id(b0p) == FAIL)
946 	iemsg(_("E304: ml_upd_block0(): Didn't get block 0??"));
947     else
948     {
949 	if (what == UB_FNAME)
950 	    set_b0_fname(b0p, buf);
951 #ifdef FEAT_CRYPT
952 	else if (what == UB_CRYPT)
953 	    ml_set_b0_crypt(buf, b0p);
954 #endif
955 	else // what == UB_SAME_DIR
956 	    set_b0_dir_flag(b0p, buf);
957     }
958     mf_put(mfp, hp, TRUE, FALSE);
959 }
960 
961 /*
962  * Write file name and timestamp into block 0 of a swap file.
963  * Also set buf->b_mtime.
964  * Don't use NameBuff[]!!!
965  */
966     static void
967 set_b0_fname(ZERO_BL *b0p, buf_T *buf)
968 {
969     stat_T	st;
970 
971     if (buf->b_ffname == NULL)
972 	b0p->b0_fname[0] = NUL;
973     else
974     {
975 #if defined(MSWIN) || defined(AMIGA)
976 	// Systems that cannot translate "~user" back into a path: copy the
977 	// file name unmodified.  Do use slashes instead of backslashes for
978 	// portability.
979 	vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT - 1);
980 # ifdef BACKSLASH_IN_FILENAME
981 	forward_slash(b0p->b0_fname);
982 # endif
983 #else
984 	size_t	flen, ulen;
985 	char_u	uname[B0_UNAME_SIZE];
986 
987 	/*
988 	 * For a file under the home directory of the current user, we try to
989 	 * replace the home directory path with "~user". This helps when
990 	 * editing the same file on different machines over a network.
991 	 * First replace home dir path with "~/" with home_replace().
992 	 * Then insert the user name to get "~user/".
993 	 */
994 	home_replace(NULL, buf->b_ffname, b0p->b0_fname,
995 						   B0_FNAME_SIZE_CRYPT, TRUE);
996 	if (b0p->b0_fname[0] == '~')
997 	{
998 	    flen = STRLEN(b0p->b0_fname);
999 	    // If there is no user name or it is too long, don't use "~/"
1000 	    if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
1001 		   || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE_CRYPT - 1)
1002 		vim_strncpy(b0p->b0_fname, buf->b_ffname,
1003 						     B0_FNAME_SIZE_CRYPT - 1);
1004 	    else
1005 	    {
1006 		mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
1007 		mch_memmove(b0p->b0_fname + 1, uname, ulen);
1008 	    }
1009 	}
1010 #endif
1011 	if (mch_stat((char *)buf->b_ffname, &st) >= 0)
1012 	{
1013 	    long_to_char((long)st.st_mtime, b0p->b0_mtime);
1014 #ifdef CHECK_INODE
1015 	    long_to_char((long)st.st_ino, b0p->b0_ino);
1016 #endif
1017 	    buf_store_time(buf, &st, buf->b_ffname);
1018 	    buf->b_mtime_read = buf->b_mtime;
1019 	}
1020 	else
1021 	{
1022 	    long_to_char(0L, b0p->b0_mtime);
1023 #ifdef CHECK_INODE
1024 	    long_to_char(0L, b0p->b0_ino);
1025 #endif
1026 	    buf->b_mtime = 0;
1027 	    buf->b_mtime_read = 0;
1028 	    buf->b_orig_size = 0;
1029 	    buf->b_orig_mode = 0;
1030 	}
1031     }
1032 
1033     // Also add the 'fileencoding' if there is room.
1034     add_b0_fenc(b0p, curbuf);
1035 }
1036 
1037 /*
1038  * Update the B0_SAME_DIR flag of the swap file.  It's set if the file and the
1039  * swapfile for "buf" are in the same directory.
1040  * This is fail safe: if we are not sure the directories are equal the flag is
1041  * not set.
1042  */
1043     static void
1044 set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf)
1045 {
1046     if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
1047 	b0p->b0_flags |= B0_SAME_DIR;
1048     else
1049 	b0p->b0_flags &= ~B0_SAME_DIR;
1050 }
1051 
1052 /*
1053  * When there is room, add the 'fileencoding' to block zero.
1054  */
1055     static void
1056 add_b0_fenc(
1057     ZERO_BL	*b0p,
1058     buf_T	*buf)
1059 {
1060     int		n;
1061     int		size = B0_FNAME_SIZE_NOCRYPT;
1062 
1063 #ifdef FEAT_CRYPT
1064     // Without encryption use the same offset as in Vim 7.2 to be compatible.
1065     // With encryption it's OK to move elsewhere, the swap file is not
1066     // compatible anyway.
1067     if (*buf->b_p_key != NUL)
1068 	size = B0_FNAME_SIZE_CRYPT;
1069 #endif
1070 
1071     n = (int)STRLEN(buf->b_p_fenc);
1072     if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
1073 	b0p->b0_flags &= ~B0_HAS_FENC;
1074     else
1075     {
1076 	mch_memmove((char *)b0p->b0_fname + size - n,
1077 					    (char *)buf->b_p_fenc, (size_t)n);
1078 	*(b0p->b0_fname + size - n - 1) = NUL;
1079 	b0p->b0_flags |= B0_HAS_FENC;
1080     }
1081 }
1082 
1083 
1084 /*
1085  * Try to recover curbuf from the .swp file.
1086  * If "checkext" is TRUE, check the extension and detect whether it is
1087  * a swap file.
1088  */
1089     void
1090 ml_recover(int checkext)
1091 {
1092     buf_T	*buf = NULL;
1093     memfile_T	*mfp = NULL;
1094     char_u	*fname;
1095     char_u	*fname_used = NULL;
1096     bhdr_T	*hp = NULL;
1097     ZERO_BL	*b0p;
1098     int		b0_ff;
1099     char_u	*b0_fenc = NULL;
1100 #ifdef FEAT_CRYPT
1101     int		b0_cm = -1;
1102 #endif
1103     PTR_BL	*pp;
1104     DATA_BL	*dp;
1105     infoptr_T	*ip;
1106     blocknr_T	bnum;
1107     int		page_count;
1108     stat_T	org_stat, swp_stat;
1109     int		len;
1110     int		directly;
1111     linenr_T	lnum;
1112     char_u	*p;
1113     int		i;
1114     long	error;
1115     int		cannot_open;
1116     linenr_T	line_count;
1117     int		has_error;
1118     int		idx;
1119     int		top;
1120     int		txt_start;
1121     off_T	size;
1122     int		called_from_main;
1123     int		serious_error = TRUE;
1124     long	mtime;
1125     int		attr;
1126     int		orig_file_status = NOTDONE;
1127 
1128     recoverymode = TRUE;
1129     called_from_main = (curbuf->b_ml.ml_mfp == NULL);
1130     attr = HL_ATTR(HLF_E);
1131 
1132     /*
1133      * If the file name ends in ".s[a-w][a-z]" we assume this is the swap file.
1134      * Otherwise a search is done to find the swap file(s).
1135      */
1136     fname = curbuf->b_fname;
1137     if (fname == NULL)		    // When there is no file name
1138 	fname = (char_u *)"";
1139     len = (int)STRLEN(fname);
1140     if (checkext && len >= 4 &&
1141 #if defined(VMS)
1142 	    STRNICMP(fname + len - 4, "_s", 2)
1143 #else
1144 	    STRNICMP(fname + len - 4, ".s", 2)
1145 #endif
1146 						== 0
1147 		&& vim_strchr((char_u *)"abcdefghijklmnopqrstuvw",
1148 					   TOLOWER_ASC(fname[len - 2])) != NULL
1149 		&& ASCII_ISALPHA(fname[len - 1]))
1150     {
1151 	directly = TRUE;
1152 	fname_used = vim_strsave(fname); // make a copy for mf_open()
1153     }
1154     else
1155     {
1156 	directly = FALSE;
1157 
1158 	// count the number of matching swap files
1159 	len = recover_names(fname, FALSE, 0, NULL);
1160 	if (len == 0)		    // no swap files found
1161 	{
1162 	    semsg(_("E305: No swap file found for %s"), fname);
1163 	    goto theend;
1164 	}
1165 	if (len == 1)		    // one swap file found, use it
1166 	    i = 1;
1167 	else			    // several swap files found, choose
1168 	{
1169 	    // list the names of the swap files
1170 	    (void)recover_names(fname, TRUE, 0, NULL);
1171 	    msg_putchar('\n');
1172 	    msg_puts(_("Enter number of swap file to use (0 to quit): "));
1173 	    i = get_number(FALSE, NULL);
1174 	    if (i < 1 || i > len)
1175 		goto theend;
1176 	}
1177 	// get the swap file name that will be used
1178 	(void)recover_names(fname, FALSE, i, &fname_used);
1179     }
1180     if (fname_used == NULL)
1181 	goto theend;			// out of memory
1182 
1183     // When called from main() still need to initialize storage structure
1184     if (called_from_main && ml_open(curbuf) == FAIL)
1185 	getout(1);
1186 
1187     /*
1188      * Allocate a buffer structure for the swap file that is used for recovery.
1189      * Only the memline and crypt information in it are really used.
1190      */
1191     buf = ALLOC_ONE(buf_T);
1192     if (buf == NULL)
1193 	goto theend;
1194 
1195     /*
1196      * init fields in memline struct
1197      */
1198     buf->b_ml.ml_stack_size = 0;	// no stack yet
1199     buf->b_ml.ml_stack = NULL;		// no stack yet
1200     buf->b_ml.ml_stack_top = 0;		// nothing in the stack
1201     buf->b_ml.ml_line_lnum = 0;		// no cached line
1202     buf->b_ml.ml_locked = NULL;		// no locked block
1203     buf->b_ml.ml_flags = 0;
1204 #ifdef FEAT_CRYPT
1205     buf->b_p_key = empty_option;
1206     buf->b_p_cm = empty_option;
1207 #endif
1208 
1209     /*
1210      * open the memfile from the old swap file
1211      */
1212     p = vim_strsave(fname_used); // save "fname_used" for the message:
1213 				 // mf_open() will consume "fname_used"!
1214     mfp = mf_open(fname_used, O_RDONLY);
1215     fname_used = p;
1216     if (mfp == NULL || mfp->mf_fd < 0)
1217     {
1218 	if (fname_used != NULL)
1219 	    semsg(_("E306: Cannot open %s"), fname_used);
1220 	goto theend;
1221     }
1222     buf->b_ml.ml_mfp = mfp;
1223 #ifdef FEAT_CRYPT
1224     mfp->mf_buffer = buf;
1225 #endif
1226 
1227     /*
1228      * The page size set in mf_open() might be different from the page size
1229      * used in the swap file, we must get it from block 0.  But to read block
1230      * 0 we need a page size.  Use the minimal size for block 0 here, it will
1231      * be set to the real value below.
1232      */
1233     mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
1234 
1235     /*
1236      * try to read block 0
1237      */
1238     if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
1239     {
1240 	msg_start();
1241 	msg_puts_attr(_("Unable to read block 0 from "), attr | MSG_HIST);
1242 	msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1243 	msg_puts_attr(_("\nMaybe no changes were made or Vim did not update the swap file."),
1244 		attr | MSG_HIST);
1245 	msg_end();
1246 	goto theend;
1247     }
1248     b0p = (ZERO_BL *)(hp->bh_data);
1249     if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
1250     {
1251 	msg_start();
1252 	msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
1253 	msg_puts_attr(_(" cannot be used with this version of Vim.\n"),
1254 								    MSG_HIST);
1255 	msg_puts_attr(_("Use Vim version 3.0.\n"), MSG_HIST);
1256 	msg_end();
1257 	goto theend;
1258     }
1259     if (ml_check_b0_id(b0p) == FAIL)
1260     {
1261 	semsg(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
1262 	goto theend;
1263     }
1264     if (b0_magic_wrong(b0p))
1265     {
1266 	msg_start();
1267 	msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1268 #if defined(MSWIN)
1269 	if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
1270 	    msg_puts_attr(_(" cannot be used with this version of Vim.\n"),
1271 							     attr | MSG_HIST);
1272 	else
1273 #endif
1274 	    msg_puts_attr(_(" cannot be used on this computer.\n"),
1275 							     attr | MSG_HIST);
1276 	msg_puts_attr(_("The file was created on "), attr | MSG_HIST);
1277 	// avoid going past the end of a corrupted hostname
1278 	b0p->b0_fname[0] = NUL;
1279 	msg_puts_attr((char *)b0p->b0_hname, attr | MSG_HIST);
1280 	msg_puts_attr(_(",\nor the file has been damaged."), attr | MSG_HIST);
1281 	msg_end();
1282 	goto theend;
1283     }
1284 
1285 #ifdef FEAT_CRYPT
1286     for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
1287 	if (id1_codes[i] == b0p->b0_id[1])
1288 	    b0_cm = i;
1289     if (b0_cm > 0)
1290 	mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
1291     crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
1292 #else
1293     if (b0p->b0_id[1] != BLOCK0_ID1)
1294     {
1295 	semsg(_("E833: %s is encrypted and this version of Vim does not support encryption"), mfp->mf_fname);
1296 	goto theend;
1297     }
1298 #endif
1299 
1300     /*
1301      * If we guessed the wrong page size, we have to recalculate the
1302      * highest block number in the file.
1303      */
1304     if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
1305     {
1306 	unsigned previous_page_size = mfp->mf_page_size;
1307 
1308 	mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
1309 	if (mfp->mf_page_size < previous_page_size)
1310 	{
1311 	    msg_start();
1312 	    msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1313 	    msg_puts_attr(_(" has been damaged (page size is smaller than minimum value).\n"),
1314 			attr | MSG_HIST);
1315 	    msg_end();
1316 	    goto theend;
1317 	}
1318 	if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0)
1319 	    mfp->mf_blocknr_max = 0;	    // no file or empty file
1320 	else
1321 	    mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
1322 	mfp->mf_infile_count = mfp->mf_blocknr_max;
1323 
1324 	// need to reallocate the memory used to store the data
1325 	p = alloc(mfp->mf_page_size);
1326 	if (p == NULL)
1327 	    goto theend;
1328 	mch_memmove(p, hp->bh_data, previous_page_size);
1329 	vim_free(hp->bh_data);
1330 	hp->bh_data = p;
1331 	b0p = (ZERO_BL *)(hp->bh_data);
1332     }
1333 
1334     /*
1335      * If .swp file name given directly, use name from swap file for buffer.
1336      */
1337     if (directly)
1338     {
1339 	expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
1340 	if (setfname(curbuf, NameBuff, NULL, TRUE) == FAIL)
1341 	    goto theend;
1342     }
1343 
1344     home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
1345     smsg(_("Using swap file \"%s\""), NameBuff);
1346 
1347     if (buf_spname(curbuf) != NULL)
1348 	vim_strncpy(NameBuff, buf_spname(curbuf), MAXPATHL - 1);
1349     else
1350 	home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
1351     smsg(_("Original file \"%s\""), NameBuff);
1352     msg_putchar('\n');
1353 
1354     /*
1355      * check date of swap file and original file
1356      */
1357     mtime = char_to_long(b0p->b0_mtime);
1358     if (curbuf->b_ffname != NULL
1359 	    && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
1360 	    && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
1361 		    && org_stat.st_mtime > swp_stat.st_mtime)
1362 		|| org_stat.st_mtime != mtime))
1363 	emsg(_("E308: Warning: Original file may have been changed"));
1364     out_flush();
1365 
1366     // Get the 'fileformat' and 'fileencoding' from block zero.
1367     b0_ff = (b0p->b0_flags & B0_FF_MASK);
1368     if (b0p->b0_flags & B0_HAS_FENC)
1369     {
1370 	int fnsize = B0_FNAME_SIZE_NOCRYPT;
1371 
1372 #ifdef FEAT_CRYPT
1373 	// Use the same size as in add_b0_fenc().
1374 	if (b0p->b0_id[1] != BLOCK0_ID1)
1375 	    fnsize = B0_FNAME_SIZE_CRYPT;
1376 #endif
1377 	for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; --p)
1378 	    ;
1379 	b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + fnsize - p));
1380     }
1381 
1382     mf_put(mfp, hp, FALSE, FALSE);	// release block 0
1383     hp = NULL;
1384 
1385     /*
1386      * Now that we are sure that the file is going to be recovered, clear the
1387      * contents of the current buffer.
1388      */
1389     while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
1390 	ml_delete((linenr_T)1, FALSE);
1391 
1392     /*
1393      * Try reading the original file to obtain the values of 'fileformat',
1394      * 'fileencoding', etc.  Ignore errors.  The text itself is not used.
1395      * When the file is encrypted the user is asked to enter the key.
1396      */
1397     if (curbuf->b_ffname != NULL)
1398 	orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
1399 			      (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
1400 
1401 #ifdef FEAT_CRYPT
1402     if (b0_cm >= 0)
1403     {
1404 	// Need to ask the user for the crypt key.  If this fails we continue
1405 	// without a key, will probably get garbage text.
1406 	if (*curbuf->b_p_key != NUL)
1407 	{
1408 	    smsg(_("Swap file is encrypted: \"%s\""), fname_used);
1409 	    msg_puts(_("\nIf you entered a new crypt key but did not write the text file,"));
1410 	    msg_puts(_("\nenter the new crypt key."));
1411 	    msg_puts(_("\nIf you wrote the text file after changing the crypt key press enter"));
1412 	    msg_puts(_("\nto use the same key for text file and swap file"));
1413 	}
1414 	else
1415 	    smsg(_(need_key_msg), fname_used);
1416 	buf->b_p_key = crypt_get_key(FALSE, FALSE);
1417 	if (buf->b_p_key == NULL)
1418 	    buf->b_p_key = curbuf->b_p_key;
1419 	else if (*buf->b_p_key == NUL)
1420 	{
1421 	    vim_free(buf->b_p_key);
1422 	    buf->b_p_key = curbuf->b_p_key;
1423 	}
1424 	if (buf->b_p_key == NULL)
1425 	    buf->b_p_key = empty_option;
1426     }
1427 #endif
1428 
1429     // Use the 'fileformat' and 'fileencoding' as stored in the swap file.
1430     if (b0_ff != 0)
1431 	set_fileformat(b0_ff - 1, OPT_LOCAL);
1432     if (b0_fenc != NULL)
1433     {
1434 	set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
1435 	vim_free(b0_fenc);
1436     }
1437     unchanged(curbuf, TRUE, TRUE);
1438 
1439     bnum = 1;		// start with block 1
1440     page_count = 1;	// which is 1 page
1441     lnum = 0;		// append after line 0 in curbuf
1442     line_count = 0;
1443     idx = 0;		// start with first index in block 1
1444     error = 0;
1445     buf->b_ml.ml_stack_top = 0;
1446     buf->b_ml.ml_stack = NULL;
1447     buf->b_ml.ml_stack_size = 0;	// no stack yet
1448 
1449     if (curbuf->b_ffname == NULL)
1450 	cannot_open = TRUE;
1451     else
1452 	cannot_open = FALSE;
1453 
1454     serious_error = FALSE;
1455     for ( ; !got_int; line_breakcheck())
1456     {
1457 	if (hp != NULL)
1458 	    mf_put(mfp, hp, FALSE, FALSE);	// release previous block
1459 
1460 	/*
1461 	 * get block
1462 	 */
1463 	if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
1464 	{
1465 	    if (bnum == 1)
1466 	    {
1467 		semsg(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
1468 		goto theend;
1469 	    }
1470 	    ++error;
1471 	    ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
1472 							    (colnr_T)0, TRUE);
1473 	}
1474 	else		// there is a block
1475 	{
1476 	    pp = (PTR_BL *)(hp->bh_data);
1477 	    if (pp->pb_id == PTR_ID)		// it is a pointer block
1478 	    {
1479 		// check line count when using pointer block first time
1480 		if (idx == 0 && line_count != 0)
1481 		{
1482 		    for (i = 0; i < (int)pp->pb_count; ++i)
1483 			line_count -= pp->pb_pointer[i].pe_line_count;
1484 		    if (line_count != 0)
1485 		    {
1486 			++error;
1487 			ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
1488 							    (colnr_T)0, TRUE);
1489 		    }
1490 		}
1491 
1492 		if (pp->pb_count == 0)
1493 		{
1494 		    ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
1495 							    (colnr_T)0, TRUE);
1496 		    ++error;
1497 		}
1498 		else if (idx < (int)pp->pb_count)	// go a block deeper
1499 		{
1500 		    if (pp->pb_pointer[idx].pe_bnum < 0)
1501 		    {
1502 			/*
1503 			 * Data block with negative block number.
1504 			 * Try to read lines from the original file.
1505 			 * This is slow, but it works.
1506 			 */
1507 			if (!cannot_open)
1508 			{
1509 			    line_count = pp->pb_pointer[idx].pe_line_count;
1510 			    if (readfile(curbuf->b_ffname, NULL, lnum,
1511 					pp->pb_pointer[idx].pe_old_lnum - 1,
1512 					line_count, NULL, 0) != OK)
1513 				cannot_open = TRUE;
1514 			    else
1515 				lnum += line_count;
1516 			}
1517 			if (cannot_open)
1518 			{
1519 			    ++error;
1520 			    ml_append(lnum++, (char_u *)_("???LINES MISSING"),
1521 							    (colnr_T)0, TRUE);
1522 			}
1523 			++idx;	    // get same block again for next index
1524 			continue;
1525 		    }
1526 
1527 		    /*
1528 		     * going one block deeper in the tree
1529 		     */
1530 		    if ((top = ml_add_stack(buf)) < 0)	// new entry in stack
1531 		    {
1532 			++error;
1533 			break;		    // out of memory
1534 		    }
1535 		    ip = &(buf->b_ml.ml_stack[top]);
1536 		    ip->ip_bnum = bnum;
1537 		    ip->ip_index = idx;
1538 
1539 		    bnum = pp->pb_pointer[idx].pe_bnum;
1540 		    line_count = pp->pb_pointer[idx].pe_line_count;
1541 		    page_count = pp->pb_pointer[idx].pe_page_count;
1542 		    idx = 0;
1543 		    continue;
1544 		}
1545 	    }
1546 	    else	    // not a pointer block
1547 	    {
1548 		dp = (DATA_BL *)(hp->bh_data);
1549 		if (dp->db_id != DATA_ID)	// block id wrong
1550 		{
1551 		    if (bnum == 1)
1552 		    {
1553 			semsg(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
1554 							       mfp->mf_fname);
1555 			goto theend;
1556 		    }
1557 		    ++error;
1558 		    ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
1559 							    (colnr_T)0, TRUE);
1560 		}
1561 		else
1562 		{
1563 		    /*
1564 		     * it is a data block
1565 		     * Append all the lines in this block
1566 		     */
1567 		    has_error = FALSE;
1568 			/*
1569 			 * check length of block
1570 			 * if wrong, use length in pointer block
1571 			 */
1572 		    if (page_count * mfp->mf_page_size != dp->db_txt_end)
1573 		    {
1574 			ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
1575 							    (colnr_T)0, TRUE);
1576 			++error;
1577 			has_error = TRUE;
1578 			dp->db_txt_end = page_count * mfp->mf_page_size;
1579 		    }
1580 
1581 			// make sure there is a NUL at the end of the block
1582 		    *((char_u *)dp + dp->db_txt_end - 1) = NUL;
1583 
1584 			/*
1585 			 * check number of lines in block
1586 			 * if wrong, use count in data block
1587 			 */
1588 		    if (line_count != dp->db_line_count)
1589 		    {
1590 			ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
1591 							    (colnr_T)0, TRUE);
1592 			++error;
1593 			has_error = TRUE;
1594 		    }
1595 
1596 		    for (i = 0; i < dp->db_line_count; ++i)
1597 		    {
1598 			txt_start = (dp->db_index[i] & DB_INDEX_MASK);
1599 			if (txt_start <= (int)HEADER_SIZE
1600 					  || txt_start >= (int)dp->db_txt_end)
1601 			{
1602 			    p = (char_u *)"???";
1603 			    ++error;
1604 			}
1605 			else
1606 			    p = (char_u *)dp + txt_start;
1607 			ml_append(lnum++, p, (colnr_T)0, TRUE);
1608 		    }
1609 		    if (has_error)
1610 			ml_append(lnum++, (char_u *)_("???END"),
1611 							    (colnr_T)0, TRUE);
1612 		}
1613 	    }
1614 	}
1615 
1616 	if (buf->b_ml.ml_stack_top == 0)	// finished
1617 	    break;
1618 
1619 	/*
1620 	 * go one block up in the tree
1621 	 */
1622 	ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
1623 	bnum = ip->ip_bnum;
1624 	idx = ip->ip_index + 1;	    // go to next index
1625 	page_count = 1;
1626     }
1627 
1628     /*
1629      * Compare the buffer contents with the original file.  When they differ
1630      * set the 'modified' flag.
1631      * Lines 1 - lnum are the new contents.
1632      * Lines lnum + 1 to ml_line_count are the original contents.
1633      * Line ml_line_count + 1 in the dummy empty line.
1634      */
1635     if (orig_file_status != OK || curbuf->b_ml.ml_line_count != lnum * 2 + 1)
1636     {
1637 	// Recovering an empty file results in two lines and the first line is
1638 	// empty.  Don't set the modified flag then.
1639 	if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL))
1640 	{
1641 	    changed_internal();
1642 	    ++CHANGEDTICK(curbuf);
1643 	}
1644     }
1645     else
1646     {
1647 	for (idx = 1; idx <= lnum; ++idx)
1648 	{
1649 	    // Need to copy one line, fetching the other one may flush it.
1650 	    p = vim_strsave(ml_get(idx));
1651 	    i = STRCMP(p, ml_get(idx + lnum));
1652 	    vim_free(p);
1653 	    if (i != 0)
1654 	    {
1655 		changed_internal();
1656 		++CHANGEDTICK(curbuf);
1657 		break;
1658 	    }
1659 	}
1660     }
1661 
1662     /*
1663      * Delete the lines from the original file and the dummy line from the
1664      * empty buffer.  These will now be after the last line in the buffer.
1665      */
1666     while (curbuf->b_ml.ml_line_count > lnum
1667 				       && !(curbuf->b_ml.ml_flags & ML_EMPTY))
1668 	ml_delete(curbuf->b_ml.ml_line_count, FALSE);
1669     curbuf->b_flags |= BF_RECOVERED;
1670 
1671     recoverymode = FALSE;
1672     if (got_int)
1673 	emsg(_("E311: Recovery Interrupted"));
1674     else if (error)
1675     {
1676 	++no_wait_return;
1677 	msg(">>>>>>>>>>>>>");
1678 	emsg(_("E312: Errors detected while recovering; look for lines starting with ???"));
1679 	--no_wait_return;
1680 	msg(_("See \":help E312\" for more information."));
1681 	msg(">>>>>>>>>>>>>");
1682     }
1683     else
1684     {
1685 	if (curbuf->b_changed)
1686 	{
1687 	    msg(_("Recovery completed. You should check if everything is OK."));
1688 	    msg_puts(_("\n(You might want to write out this file under another name\n"));
1689 	    msg_puts(_("and run diff with the original file to check for changes)"));
1690 	}
1691 	else
1692 	    msg(_("Recovery completed. Buffer contents equals file contents."));
1693 	msg_puts(_("\nYou may want to delete the .swp file now.\n\n"));
1694 	cmdline_row = msg_row;
1695     }
1696 #ifdef FEAT_CRYPT
1697     if (*buf->b_p_key != NUL && STRCMP(curbuf->b_p_key, buf->b_p_key) != 0)
1698     {
1699 	msg_puts(_("Using crypt key from swap file for the text file.\n"));
1700 	set_option_value((char_u *)"key", 0L, buf->b_p_key, OPT_LOCAL);
1701     }
1702 #endif
1703     redraw_curbuf_later(NOT_VALID);
1704 
1705 theend:
1706     vim_free(fname_used);
1707     recoverymode = FALSE;
1708     if (mfp != NULL)
1709     {
1710 	if (hp != NULL)
1711 	    mf_put(mfp, hp, FALSE, FALSE);
1712 	mf_close(mfp, FALSE);	    // will also vim_free(mfp->mf_fname)
1713     }
1714     if (buf != NULL)
1715     {
1716 #ifdef FEAT_CRYPT
1717 	if (buf->b_p_key != curbuf->b_p_key)
1718 	    free_string_option(buf->b_p_key);
1719 	free_string_option(buf->b_p_cm);
1720 #endif
1721 	vim_free(buf->b_ml.ml_stack);
1722 	vim_free(buf);
1723     }
1724     if (serious_error && called_from_main)
1725 	ml_close(curbuf, TRUE);
1726     else
1727     {
1728 	apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
1729 	apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
1730     }
1731     return;
1732 }
1733 
1734 /*
1735  * Find the names of swap files in current directory and the directory given
1736  * with the 'directory' option.
1737  *
1738  * Used to:
1739  * - list the swap files for "vim -r"
1740  * - count the number of swap files when recovering
1741  * - list the swap files when recovering
1742  * - find the name of the n'th swap file when recovering
1743  */
1744     int
1745 recover_names(
1746     char_u	*fname,		// base for swap file name
1747     int		list,		// when TRUE, list the swap file names
1748     int		nr,		// when non-zero, return nr'th swap file name
1749     char_u	**fname_out)	// result when "nr" > 0
1750 {
1751     int		num_names;
1752     char_u	*(names[6]);
1753     char_u	*tail;
1754     char_u	*p;
1755     int		num_files;
1756     int		file_count = 0;
1757     char_u	**files;
1758     int		i;
1759     char_u	*dirp;
1760     char_u	*dir_name;
1761     char_u	*fname_res = NULL;
1762 #ifdef HAVE_READLINK
1763     char_u	fname_buf[MAXPATHL];
1764 #endif
1765 
1766     if (fname != NULL)
1767     {
1768 #ifdef HAVE_READLINK
1769 	// Expand symlink in the file name, because the swap file is created
1770 	// with the actual file instead of with the symlink.
1771 	if (resolve_symlink(fname, fname_buf) == OK)
1772 	    fname_res = fname_buf;
1773 	else
1774 #endif
1775 	    fname_res = fname;
1776     }
1777 
1778     if (list)
1779     {
1780 	// use msg() to start the scrolling properly
1781 	msg(_("Swap files found:"));
1782 	msg_putchar('\n');
1783     }
1784 
1785     /*
1786      * Do the loop for every directory in 'directory'.
1787      * First allocate some memory to put the directory name in.
1788      */
1789     dir_name = alloc(STRLEN(p_dir) + 1);
1790     dirp = p_dir;
1791     while (dir_name != NULL && *dirp)
1792     {
1793 	/*
1794 	 * Isolate a directory name from *dirp and put it in dir_name (we know
1795 	 * it is large enough, so use 31000 for length).
1796 	 * Advance dirp to next directory name.
1797 	 */
1798 	(void)copy_option_part(&dirp, dir_name, 31000, ",");
1799 
1800 	if (dir_name[0] == '.' && dir_name[1] == NUL)	// check current dir
1801 	{
1802 	    if (fname == NULL)
1803 	    {
1804 #ifdef VMS
1805 		names[0] = vim_strsave((char_u *)"*_sw%");
1806 #else
1807 		names[0] = vim_strsave((char_u *)"*.sw?");
1808 #endif
1809 #if defined(UNIX) || defined(MSWIN)
1810 		// For Unix names starting with a dot are special.  MS-Windows
1811 		// supports this too, on some file systems.
1812 		names[1] = vim_strsave((char_u *)".*.sw?");
1813 		names[2] = vim_strsave((char_u *)".sw?");
1814 		num_names = 3;
1815 #else
1816 # ifdef VMS
1817 		names[1] = vim_strsave((char_u *)".*_sw%");
1818 		num_names = 2;
1819 # else
1820 		num_names = 1;
1821 # endif
1822 #endif
1823 	    }
1824 	    else
1825 		num_names = recov_file_names(names, fname_res, TRUE);
1826 	}
1827 	else			    // check directory dir_name
1828 	{
1829 	    if (fname == NULL)
1830 	    {
1831 #ifdef VMS
1832 		names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
1833 #else
1834 		names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
1835 #endif
1836 #if defined(UNIX) || defined(MSWIN)
1837 		// For Unix names starting with a dot are special.  MS-Windows
1838 		// supports this too, on some file systems.
1839 		names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
1840 		names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
1841 		num_names = 3;
1842 #else
1843 # ifdef VMS
1844 		names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
1845 		num_names = 2;
1846 # else
1847 		num_names = 1;
1848 # endif
1849 #endif
1850 	    }
1851 	    else
1852 	    {
1853 #if defined(UNIX) || defined(MSWIN)
1854 		int	len = (int)STRLEN(dir_name);
1855 
1856 		p = dir_name + len;
1857 		if (after_pathsep(dir_name, p) && len > 1 && p[-1] == p[-2])
1858 		{
1859 		    // Ends with '//', Use Full path for swap name
1860 		    tail = make_percent_swname(dir_name, fname_res);
1861 		}
1862 		else
1863 #endif
1864 		{
1865 		    tail = gettail(fname_res);
1866 		    tail = concat_fnames(dir_name, tail, TRUE);
1867 		}
1868 		if (tail == NULL)
1869 		    num_names = 0;
1870 		else
1871 		{
1872 		    num_names = recov_file_names(names, tail, FALSE);
1873 		    vim_free(tail);
1874 		}
1875 	    }
1876 	}
1877 
1878 	// check for out-of-memory
1879 	for (i = 0; i < num_names; ++i)
1880 	{
1881 	    if (names[i] == NULL)
1882 	    {
1883 		for (i = 0; i < num_names; ++i)
1884 		    vim_free(names[i]);
1885 		num_names = 0;
1886 	    }
1887 	}
1888 	if (num_names == 0)
1889 	    num_files = 0;
1890 	else if (expand_wildcards(num_names, names, &num_files, &files,
1891 			    EW_NOTENV|EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
1892 	    num_files = 0;
1893 
1894 	/*
1895 	 * When no swap file found, wildcard expansion might have failed (e.g.
1896 	 * not able to execute the shell).
1897 	 * Try finding a swap file by simply adding ".swp" to the file name.
1898 	 */
1899 	if (*dirp == NUL && file_count + num_files == 0 && fname != NULL)
1900 	{
1901 	    stat_T	    st;
1902 	    char_u	    *swapname;
1903 
1904 	    swapname = modname(fname_res,
1905 #if defined(VMS)
1906 			       (char_u *)"_swp", FALSE
1907 #else
1908 			       (char_u *)".swp", TRUE
1909 #endif
1910 			      );
1911 	    if (swapname != NULL)
1912 	    {
1913 		if (mch_stat((char *)swapname, &st) != -1)    // It exists!
1914 		{
1915 		    files = ALLOC_ONE(char_u *);
1916 		    if (files != NULL)
1917 		    {
1918 			files[0] = swapname;
1919 			swapname = NULL;
1920 			num_files = 1;
1921 		    }
1922 		}
1923 		vim_free(swapname);
1924 	    }
1925 	}
1926 
1927 	/*
1928 	 * remove swapfile name of the current buffer, it must be ignored
1929 	 */
1930 	if (curbuf->b_ml.ml_mfp != NULL
1931 			       && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
1932 	{
1933 	    for (i = 0; i < num_files; ++i)
1934 		// Do not expand wildcards, on windows would try to expand
1935 		// "%tmp%" in "%tmp%file".
1936 		if (fullpathcmp(p, files[i], TRUE, FALSE) & FPC_SAME)
1937 		{
1938 		    // Remove the name from files[i].  Move further entries
1939 		    // down.  When the array becomes empty free it here, since
1940 		    // FreeWild() won't be called below.
1941 		    vim_free(files[i]);
1942 		    if (--num_files == 0)
1943 			vim_free(files);
1944 		    else
1945 			for ( ; i < num_files; ++i)
1946 			    files[i] = files[i + 1];
1947 		}
1948 	}
1949 	if (nr > 0)
1950 	{
1951 	    file_count += num_files;
1952 	    if (nr <= file_count)
1953 	    {
1954 		*fname_out = vim_strsave(
1955 				      files[nr - 1 + num_files - file_count]);
1956 		dirp = (char_u *)"";		    // stop searching
1957 	    }
1958 	}
1959 	else if (list)
1960 	{
1961 	    if (dir_name[0] == '.' && dir_name[1] == NUL)
1962 	    {
1963 		if (fname == NULL)
1964 		    msg_puts(_("   In current directory:\n"));
1965 		else
1966 		    msg_puts(_("   Using specified name:\n"));
1967 	    }
1968 	    else
1969 	    {
1970 		msg_puts(_("   In directory "));
1971 		msg_home_replace(dir_name);
1972 		msg_puts(":\n");
1973 	    }
1974 
1975 	    if (num_files)
1976 	    {
1977 		for (i = 0; i < num_files; ++i)
1978 		{
1979 		    // print the swap file name
1980 		    msg_outnum((long)++file_count);
1981 		    msg_puts(".    ");
1982 		    msg_puts((char *)gettail(files[i]));
1983 		    msg_putchar('\n');
1984 		    (void)swapfile_info(files[i]);
1985 		}
1986 	    }
1987 	    else
1988 		msg_puts(_("      -- none --\n"));
1989 	    out_flush();
1990 	}
1991 	else
1992 	    file_count += num_files;
1993 
1994 	for (i = 0; i < num_names; ++i)
1995 	    vim_free(names[i]);
1996 	if (num_files > 0)
1997 	    FreeWild(num_files, files);
1998     }
1999     vim_free(dir_name);
2000     return file_count;
2001 }
2002 
2003 #if defined(UNIX) || defined(MSWIN) || defined(PROTO)
2004 /*
2005  * Need _very_ long file names.
2006  * Append the full path to name with path separators made into percent
2007  * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
2008  */
2009     char_u *
2010 make_percent_swname(char_u *dir, char_u *name)
2011 {
2012     char_u *d = NULL, *s, *f;
2013 
2014     f = fix_fname(name != NULL ? name : (char_u *)"");
2015     if (f != NULL)
2016     {
2017 	s = alloc(STRLEN(f) + 1);
2018 	if (s != NULL)
2019 	{
2020 	    STRCPY(s, f);
2021 	    for (d = s; *d != NUL; MB_PTR_ADV(d))
2022 		if (vim_ispathsep(*d))
2023 		    *d = '%';
2024 	    d = concat_fnames(dir, s, TRUE);
2025 	    vim_free(s);
2026 	}
2027 	vim_free(f);
2028     }
2029     return d;
2030 }
2031 #endif
2032 
2033 #if (defined(UNIX) || defined(VMS) || defined(MSWIN)) \
2034 	&& (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
2035 # define HAVE_PROCESS_STILL_RUNNING
2036 static int process_still_running;
2037 #endif
2038 
2039 #if defined(FEAT_EVAL) || defined(PROTO)
2040 /*
2041  * Return information found in swapfile "fname" in dictionary "d".
2042  * This is used by the swapinfo() function.
2043  */
2044     void
2045 get_b0_dict(char_u *fname, dict_T *d)
2046 {
2047     int fd;
2048     struct block0 b0;
2049 
2050     if ((fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
2051     {
2052 	if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
2053 	{
2054 	    if (ml_check_b0_id(&b0) == FAIL)
2055 		dict_add_string(d, "error", (char_u *)"Not a swap file");
2056 	    else if (b0_magic_wrong(&b0))
2057 		dict_add_string(d, "error", (char_u *)"Magic number mismatch");
2058 	    else
2059 	    {
2060 		// we have swap information
2061 		dict_add_string_len(d, "version", b0.b0_version, 10);
2062 		dict_add_string_len(d, "user", b0.b0_uname, B0_UNAME_SIZE);
2063 		dict_add_string_len(d, "host", b0.b0_hname, B0_HNAME_SIZE);
2064 		dict_add_string_len(d, "fname", b0.b0_fname, B0_FNAME_SIZE_ORG);
2065 
2066 		dict_add_number(d, "pid", char_to_long(b0.b0_pid));
2067 		dict_add_number(d, "mtime", char_to_long(b0.b0_mtime));
2068 		dict_add_number(d, "dirty", b0.b0_dirty ? 1 : 0);
2069 # ifdef CHECK_INODE
2070 		dict_add_number(d, "inode", char_to_long(b0.b0_ino));
2071 # endif
2072 	    }
2073 	}
2074 	else
2075 	    dict_add_string(d, "error", (char_u *)"Cannot read file");
2076 	close(fd);
2077     }
2078     else
2079 	dict_add_string(d, "error", (char_u *)"Cannot open file");
2080 }
2081 #endif
2082 
2083 /*
2084  * Give information about an existing swap file.
2085  * Returns timestamp (0 when unknown).
2086  */
2087     static time_t
2088 swapfile_info(char_u *fname)
2089 {
2090     stat_T	    st;
2091     int		    fd;
2092     struct block0   b0;
2093 #ifdef UNIX
2094     char_u	    uname[B0_UNAME_SIZE];
2095 #endif
2096 
2097     // print the swap file date
2098     if (mch_stat((char *)fname, &st) != -1)
2099     {
2100 #ifdef UNIX
2101 	// print name of owner of the file
2102 	if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
2103 	{
2104 	    msg_puts(_("          owned by: "));
2105 	    msg_outtrans(uname);
2106 	    msg_puts(_("   dated: "));
2107 	}
2108 	else
2109 #endif
2110 	    msg_puts(_("             dated: "));
2111 	msg_puts(get_ctime(st.st_mtime, TRUE));
2112     }
2113     else
2114 	st.st_mtime = 0;
2115 
2116     /*
2117      * print the original file name
2118      */
2119     fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2120     if (fd >= 0)
2121     {
2122 	if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
2123 	{
2124 	    if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
2125 	    {
2126 		msg_puts(_("         [from Vim version 3.0]"));
2127 	    }
2128 	    else if (ml_check_b0_id(&b0) == FAIL)
2129 	    {
2130 		msg_puts(_("         [does not look like a Vim swap file]"));
2131 	    }
2132 	    else
2133 	    {
2134 		msg_puts(_("         file name: "));
2135 		if (b0.b0_fname[0] == NUL)
2136 		    msg_puts(_("[No Name]"));
2137 		else
2138 		    msg_outtrans(b0.b0_fname);
2139 
2140 		msg_puts(_("\n          modified: "));
2141 		msg_puts(b0.b0_dirty ? _("YES") : _("no"));
2142 
2143 		if (*(b0.b0_uname) != NUL)
2144 		{
2145 		    msg_puts(_("\n         user name: "));
2146 		    msg_outtrans(b0.b0_uname);
2147 		}
2148 
2149 		if (*(b0.b0_hname) != NUL)
2150 		{
2151 		    if (*(b0.b0_uname) != NUL)
2152 			msg_puts(_("   host name: "));
2153 		    else
2154 			msg_puts(_("\n         host name: "));
2155 		    msg_outtrans(b0.b0_hname);
2156 		}
2157 
2158 		if (char_to_long(b0.b0_pid) != 0L)
2159 		{
2160 		    msg_puts(_("\n        process ID: "));
2161 		    msg_outnum(char_to_long(b0.b0_pid));
2162 #if defined(UNIX) || defined(MSWIN)
2163 		    if (mch_process_running(char_to_long(b0.b0_pid)))
2164 		    {
2165 			msg_puts(_(" (STILL RUNNING)"));
2166 # ifdef HAVE_PROCESS_STILL_RUNNING
2167 			process_still_running = TRUE;
2168 # endif
2169 		    }
2170 #endif
2171 		}
2172 
2173 		if (b0_magic_wrong(&b0))
2174 		{
2175 #if defined(MSWIN)
2176 		    if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
2177 			msg_puts(_("\n         [not usable with this version of Vim]"));
2178 		    else
2179 #endif
2180 			msg_puts(_("\n         [not usable on this computer]"));
2181 		}
2182 	    }
2183 	}
2184 	else
2185 	    msg_puts(_("         [cannot be read]"));
2186 	close(fd);
2187     }
2188     else
2189 	msg_puts(_("         [cannot be opened]"));
2190     msg_putchar('\n');
2191 
2192     return st.st_mtime;
2193 }
2194 
2195 /*
2196  * Return TRUE if the swap file looks OK and there are no changes, thus it can
2197  * be safely deleted.
2198  */
2199     static time_t
2200 swapfile_unchanged(char_u *fname)
2201 {
2202     stat_T	    st;
2203     int		    fd;
2204     struct block0   b0;
2205     int		    ret = TRUE;
2206 #if defined(UNIX) || defined(MSWIN)
2207     long	    pid;
2208 #endif
2209 
2210     // must be able to stat the swap file
2211     if (mch_stat((char *)fname, &st) == -1)
2212 	return FALSE;
2213 
2214     // must be able to read the first block
2215     fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2216     if (fd < 0)
2217 	return FALSE;
2218     if (read_eintr(fd, &b0, sizeof(b0)) != sizeof(b0))
2219     {
2220 	close(fd);
2221 	return FALSE;
2222     }
2223 
2224     // the ID and magic number must be correct
2225     if (ml_check_b0_id(&b0) == FAIL|| b0_magic_wrong(&b0))
2226 	ret = FALSE;
2227 
2228     // must be unchanged
2229     if (b0.b0_dirty)
2230 	ret = FALSE;
2231 
2232 #if defined(UNIX) || defined(MSWIN)
2233     // process must be known and not be running
2234     pid = char_to_long(b0.b0_pid);
2235     if (pid == 0L || mch_process_running(pid))
2236 	ret = FALSE;
2237 #endif
2238 
2239     // TODO: Should we check if the swap file was created on the current
2240     // system?  And the current user?
2241 
2242     close(fd);
2243     return ret;
2244 }
2245 
2246     static int
2247 recov_file_names(char_u **names, char_u *path, int prepend_dot)
2248 {
2249     int		num_names;
2250 
2251     /*
2252      * (Win32 and Win64) never short names, but do prepend a dot.
2253      * (Not MS-DOS or Win32 or Win64) maybe short name, maybe not: Try both.
2254      * Only use the short name if it is different.
2255      */
2256     char_u	*p;
2257     int		i;
2258 # ifndef MSWIN
2259     int	    shortname = curbuf->b_shortname;
2260 
2261     curbuf->b_shortname = FALSE;
2262 # endif
2263 
2264     num_names = 0;
2265 
2266     /*
2267      * May also add the file name with a dot prepended, for swap file in same
2268      * dir as original file.
2269      */
2270     if (prepend_dot)
2271     {
2272 	names[num_names] = modname(path, (char_u *)".sw?", TRUE);
2273 	if (names[num_names] == NULL)
2274 	    goto end;
2275 	++num_names;
2276     }
2277 
2278     /*
2279      * Form the normal swap file name pattern by appending ".sw?".
2280      */
2281 #ifdef VMS
2282     names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
2283 #else
2284     names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
2285 #endif
2286     if (names[num_names] == NULL)
2287 	goto end;
2288     if (num_names >= 1)	    // check if we have the same name twice
2289     {
2290 	p = names[num_names - 1];
2291 	i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
2292 	if (i > 0)
2293 	    p += i;	    // file name has been expanded to full path
2294 
2295 	if (STRCMP(p, names[num_names]) != 0)
2296 	    ++num_names;
2297 	else
2298 	    vim_free(names[num_names]);
2299     }
2300     else
2301 	++num_names;
2302 
2303 # ifndef MSWIN
2304     /*
2305      * Also try with 'shortname' set, in case the file is on a DOS filesystem.
2306      */
2307     curbuf->b_shortname = TRUE;
2308 #ifdef VMS
2309     names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
2310 #else
2311     names[num_names] = modname(path, (char_u *)".sw?", FALSE);
2312 #endif
2313     if (names[num_names] == NULL)
2314 	goto end;
2315 
2316     /*
2317      * Remove the one from 'shortname', if it's the same as with 'noshortname'.
2318      */
2319     p = names[num_names];
2320     i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
2321     if (i > 0)
2322 	p += i;		// file name has been expanded to full path
2323     if (STRCMP(names[num_names - 1], p) == 0)
2324 	vim_free(names[num_names]);
2325     else
2326 	++num_names;
2327 # endif
2328 
2329 end:
2330 # ifndef MSWIN
2331     curbuf->b_shortname = shortname;
2332 # endif
2333 
2334     return num_names;
2335 }
2336 
2337 /*
2338  * sync all memlines
2339  *
2340  * If 'check_file' is TRUE, check if original file exists and was not changed.
2341  * If 'check_char' is TRUE, stop syncing when character becomes available, but
2342  * always sync at least one block.
2343  */
2344     void
2345 ml_sync_all(int check_file, int check_char)
2346 {
2347     buf_T		*buf;
2348     stat_T		st;
2349 
2350     FOR_ALL_BUFFERS(buf)
2351     {
2352 	if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
2353 	    continue;			    // no file
2354 
2355 	ml_flush_line(buf);		    // flush buffered line
2356 					    // flush locked block
2357 	(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
2358 	if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
2359 						     && buf->b_ffname != NULL)
2360 	{
2361 	    /*
2362 	     * If the original file does not exist anymore or has been changed
2363 	     * call ml_preserve() to get rid of all negative numbered blocks.
2364 	     */
2365 	    if (mch_stat((char *)buf->b_ffname, &st) == -1
2366 		    || st.st_mtime != buf->b_mtime_read
2367 		    || st.st_size != buf->b_orig_size)
2368 	    {
2369 		ml_preserve(buf, FALSE);
2370 		did_check_timestamps = FALSE;
2371 		need_check_timestamps = TRUE;	// give message later
2372 	    }
2373 	}
2374 	if (buf->b_ml.ml_mfp->mf_dirty)
2375 	{
2376 	    (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
2377 					| (bufIsChanged(buf) ? MFS_FLUSH : 0));
2378 	    if (check_char && ui_char_avail())	// character available now
2379 		break;
2380 	}
2381     }
2382 }
2383 
2384 /*
2385  * sync one buffer, including negative blocks
2386  *
2387  * after this all the blocks are in the swap file
2388  *
2389  * Used for the :preserve command and when the original file has been
2390  * changed or deleted.
2391  *
2392  * when message is TRUE the success of preserving is reported
2393  */
2394     void
2395 ml_preserve(buf_T *buf, int message)
2396 {
2397     bhdr_T	*hp;
2398     linenr_T	lnum;
2399     memfile_T	*mfp = buf->b_ml.ml_mfp;
2400     int		status;
2401     int		got_int_save = got_int;
2402 
2403     if (mfp == NULL || mfp->mf_fname == NULL)
2404     {
2405 	if (message)
2406 	    emsg(_("E313: Cannot preserve, there is no swap file"));
2407 	return;
2408     }
2409 
2410     // We only want to stop when interrupted here, not when interrupted
2411     // before.
2412     got_int = FALSE;
2413 
2414     ml_flush_line(buf);				    // flush buffered line
2415     (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); // flush locked block
2416     status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
2417 
2418     // stack is invalid after mf_sync(.., MFS_ALL)
2419     buf->b_ml.ml_stack_top = 0;
2420 
2421     /*
2422      * Some of the data blocks may have been changed from negative to
2423      * positive block number. In that case the pointer blocks need to be
2424      * updated.
2425      *
2426      * We don't know in which pointer block the references are, so we visit
2427      * all data blocks until there are no more translations to be done (or
2428      * we hit the end of the file, which can only happen in case a write fails,
2429      * e.g. when file system if full).
2430      * ml_find_line() does the work by translating the negative block numbers
2431      * when getting the first line of each data block.
2432      */
2433     if (mf_need_trans(mfp) && !got_int)
2434     {
2435 	lnum = 1;
2436 	while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
2437 	{
2438 	    hp = ml_find_line(buf, lnum, ML_FIND);
2439 	    if (hp == NULL)
2440 	    {
2441 		status = FAIL;
2442 		goto theend;
2443 	    }
2444 	    CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
2445 	    lnum = buf->b_ml.ml_locked_high + 1;
2446 	}
2447 	(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);	// flush locked block
2448 	// sync the updated pointer blocks
2449 	if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
2450 	    status = FAIL;
2451 	buf->b_ml.ml_stack_top = 0;	    // stack is invalid now
2452     }
2453 theend:
2454     got_int |= got_int_save;
2455 
2456     if (message)
2457     {
2458 	if (status == OK)
2459 	    msg(_("File preserved"));
2460 	else
2461 	    emsg(_("E314: Preserve failed"));
2462     }
2463 }
2464 
2465 /*
2466  * NOTE: The pointer returned by the ml_get_*() functions only remains valid
2467  * until the next call!
2468  *  line1 = ml_get(1);
2469  *  line2 = ml_get(2);	// line1 is now invalid!
2470  * Make a copy of the line if necessary.
2471  */
2472 /*
2473  * Return a pointer to a (read-only copy of a) line.
2474  *
2475  * On failure an error message is given and IObuff is returned (to avoid
2476  * having to check for error everywhere).
2477  */
2478     char_u  *
2479 ml_get(linenr_T lnum)
2480 {
2481     return ml_get_buf(curbuf, lnum, FALSE);
2482 }
2483 
2484 /*
2485  * Return pointer to position "pos".
2486  */
2487     char_u *
2488 ml_get_pos(pos_T *pos)
2489 {
2490     return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
2491 }
2492 
2493 /*
2494  * Return pointer to cursor line.
2495  */
2496     char_u *
2497 ml_get_curline(void)
2498 {
2499     return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
2500 }
2501 
2502 /*
2503  * Return pointer to cursor position.
2504  */
2505     char_u *
2506 ml_get_cursor(void)
2507 {
2508     return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
2509 							curwin->w_cursor.col);
2510 }
2511 
2512 /*
2513  * Return a pointer to a line in a specific buffer
2514  *
2515  * "will_change": if TRUE mark the buffer dirty (chars in the line will be
2516  * changed)
2517  */
2518     char_u  *
2519 ml_get_buf(
2520     buf_T	*buf,
2521     linenr_T	lnum,
2522     int		will_change)		// line will be changed
2523 {
2524     bhdr_T	*hp;
2525     DATA_BL	*dp;
2526     static int	recursive = 0;
2527 
2528     if (lnum > buf->b_ml.ml_line_count)	// invalid line number
2529     {
2530 	if (recursive == 0)
2531 	{
2532 	    // Avoid giving this message for a recursive call, may happen when
2533 	    // the GUI redraws part of the text.
2534 	    ++recursive;
2535 	    siemsg(_("E315: ml_get: invalid lnum: %ld"), lnum);
2536 	    --recursive;
2537 	}
2538 errorret:
2539 	STRCPY(IObuff, "???");
2540 	buf->b_ml.ml_line_len = 4;
2541 	return IObuff;
2542     }
2543     if (lnum <= 0)			// pretend line 0 is line 1
2544 	lnum = 1;
2545 
2546     if (buf->b_ml.ml_mfp == NULL)	// there are no lines
2547     {
2548 	buf->b_ml.ml_line_len = 1;
2549 	return (char_u *)"";
2550     }
2551 
2552     /*
2553      * See if it is the same line as requested last time.
2554      * Otherwise may need to flush last used line.
2555      * Don't use the last used line when 'swapfile' is reset, need to load all
2556      * blocks.
2557      */
2558     if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release)
2559     {
2560 	unsigned    start, end;
2561 	colnr_T	    len;
2562 	int	    idx;
2563 
2564 	ml_flush_line(buf);
2565 
2566 	/*
2567 	 * Find the data block containing the line.
2568 	 * This also fills the stack with the blocks from the root to the data
2569 	 * block and releases any locked block.
2570 	 */
2571 	if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
2572 	{
2573 	    if (recursive == 0)
2574 	    {
2575 		// Avoid giving this message for a recursive call, may happen
2576 		// when the GUI redraws part of the text.
2577 		++recursive;
2578 		get_trans_bufname(buf);
2579 		shorten_dir(NameBuff);
2580 		siemsg(_("E316: ml_get: cannot find line %ld in buffer %d %s"),
2581 						  lnum, buf->b_fnum, NameBuff);
2582 		--recursive;
2583 	    }
2584 	    goto errorret;
2585 	}
2586 
2587 	dp = (DATA_BL *)(hp->bh_data);
2588 
2589 	idx = lnum - buf->b_ml.ml_locked_low;
2590 	start = ((dp->db_index[idx]) & DB_INDEX_MASK);
2591 	// The text ends where the previous line starts.  The first line ends
2592 	// at the end of the block.
2593 	if (idx == 0)
2594 	    end = dp->db_txt_end;
2595 	else
2596 	    end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
2597 	len = end - start;
2598 
2599 	buf->b_ml.ml_line_ptr = (char_u *)dp + start;
2600 	buf->b_ml.ml_line_len = len;
2601 	buf->b_ml.ml_line_lnum = lnum;
2602 	buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
2603     }
2604     if (will_change)
2605 	buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
2606 
2607     return buf->b_ml.ml_line_ptr;
2608 }
2609 
2610 /*
2611  * Check if a line that was just obtained by a call to ml_get
2612  * is in allocated memory.
2613  */
2614     int
2615 ml_line_alloced(void)
2616 {
2617     return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
2618 }
2619 
2620 #ifdef FEAT_PROP_POPUP
2621     static void
2622 add_text_props_for_append(
2623 	    buf_T	*buf,
2624 	    linenr_T	lnum,
2625 	    char_u	**line,
2626 	    int		*len,
2627 	    char_u	**tofree)
2628 {
2629     int		round;
2630     int		new_prop_count = 0;
2631     int		count;
2632     int		n;
2633     char_u	*props;
2634     int		new_len = 0;  // init for gcc
2635     char_u	*new_line;
2636     textprop_T	prop;
2637 
2638     // Make two rounds:
2639     // 1. calculate the extra space needed
2640     // 2. allocate the space and fill it
2641     for (round = 1; round <= 2; ++round)
2642     {
2643 	if (round == 2)
2644 	{
2645 	    if (new_prop_count == 0)
2646 		return;  // nothing to do
2647 	    new_len = *len + new_prop_count * sizeof(textprop_T);
2648 	    new_line = alloc(new_len);
2649 	    if (new_line == NULL)
2650 		return;
2651 	    mch_memmove(new_line, *line, *len);
2652 	    new_prop_count = 0;
2653 	}
2654 
2655 	// Get the line above to find any props that continue in the next
2656 	// line.
2657 	count = get_text_props(buf, lnum, &props, FALSE);
2658 	for (n = 0; n < count; ++n)
2659 	{
2660 	    mch_memmove(&prop, props + n * sizeof(textprop_T), sizeof(textprop_T));
2661 	    if (prop.tp_flags & TP_FLAG_CONT_NEXT)
2662 	    {
2663 		if (round == 2)
2664 		{
2665 		    prop.tp_flags |= TP_FLAG_CONT_PREV;
2666 		    prop.tp_col = 1;
2667 		    prop.tp_len = *len;
2668 		    mch_memmove(new_line + *len + new_prop_count * sizeof(textprop_T), &prop, sizeof(textprop_T));
2669 		}
2670 		++new_prop_count;
2671 	    }
2672 	}
2673     }
2674     *line = new_line;
2675     *tofree = new_line;
2676     *len = new_len;
2677 }
2678 #endif
2679 
2680     static int
2681 ml_append_int(
2682     buf_T	*buf,
2683     linenr_T	lnum,		// append after this line (can be 0)
2684     char_u	*line_arg,	// text of the new line
2685     colnr_T	len_arg,	// length of line, including NUL, or 0
2686     int		newfile,	// flag, see above
2687     int		mark)		// mark the new line
2688 {
2689     char_u	*line = line_arg;
2690     colnr_T	len = len_arg;
2691     int		i;
2692     int		line_count;	// number of indexes in current block
2693     int		offset;
2694     int		from, to;
2695     int		space_needed;	// space needed for new line
2696     int		page_size;
2697     int		page_count;
2698     int		db_idx;		// index for lnum in data block
2699     bhdr_T	*hp;
2700     memfile_T	*mfp;
2701     DATA_BL	*dp;
2702     PTR_BL	*pp;
2703     infoptr_T	*ip;
2704 #ifdef FEAT_PROP_POPUP
2705     char_u	*tofree = NULL;
2706 #endif
2707     int		ret = FAIL;
2708 
2709     if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
2710 	return FAIL;  // lnum out of range
2711 
2712     if (lowest_marked && lowest_marked > lnum)
2713 	lowest_marked = lnum + 1;
2714 
2715     if (len == 0)
2716 	len = (colnr_T)STRLEN(line) + 1;	// space needed for the text
2717 
2718 #ifdef FEAT_PROP_POPUP
2719     if (curbuf->b_has_textprop && lnum > 0)
2720 	// Add text properties that continue from the previous line.
2721 	add_text_props_for_append(buf, lnum, &line, &len, &tofree);
2722 #endif
2723 
2724     space_needed = len + INDEX_SIZE;	// space needed for text + index
2725 
2726     mfp = buf->b_ml.ml_mfp;
2727     page_size = mfp->mf_page_size;
2728 
2729 /*
2730  * find the data block containing the previous line
2731  * This also fills the stack with the blocks from the root to the data block
2732  * This also releases any locked block.
2733  */
2734     if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
2735 							  ML_INSERT)) == NULL)
2736 	goto theend;
2737 
2738     buf->b_ml.ml_flags &= ~ML_EMPTY;
2739 
2740     if (lnum == 0)		// got line one instead, correct db_idx
2741 	db_idx = -1;		// careful, it is negative!
2742     else
2743 	db_idx = lnum - buf->b_ml.ml_locked_low;
2744 		// get line count before the insertion
2745     line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2746 
2747     dp = (DATA_BL *)(hp->bh_data);
2748 
2749 /*
2750  * If
2751  * - there is not enough room in the current block
2752  * - appending to the last line in the block
2753  * - not appending to the last line in the file
2754  * insert in front of the next block.
2755  */
2756     if ((int)dp->db_free < space_needed && db_idx == line_count - 1
2757 					    && lnum < buf->b_ml.ml_line_count)
2758     {
2759 	/*
2760 	 * Now that the line is not going to be inserted in the block that we
2761 	 * expected, the line count has to be adjusted in the pointer blocks
2762 	 * by using ml_locked_lineadd.
2763 	 */
2764 	--(buf->b_ml.ml_locked_lineadd);
2765 	--(buf->b_ml.ml_locked_high);
2766 	if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
2767 	    goto theend;
2768 
2769 	db_idx = -1;		    // careful, it is negative!
2770 		    // get line count before the insertion
2771 	line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2772 	CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
2773 
2774 	dp = (DATA_BL *)(hp->bh_data);
2775     }
2776 
2777     ++buf->b_ml.ml_line_count;
2778 
2779     if ((int)dp->db_free >= space_needed)	// enough room in data block
2780     {
2781 	/*
2782 	 * Insert the new line in an existing data block, or in the data block
2783 	 * allocated above.
2784 	 */
2785 	dp->db_txt_start -= len;
2786 	dp->db_free -= space_needed;
2787 	++(dp->db_line_count);
2788 
2789 	/*
2790 	 * move the text of the lines that follow to the front
2791 	 * adjust the indexes of the lines that follow
2792 	 */
2793 	if (line_count > db_idx + 1)	    // if there are following lines
2794 	{
2795 	    /*
2796 	     * Offset is the start of the previous line.
2797 	     * This will become the character just after the new line.
2798 	     */
2799 	    if (db_idx < 0)
2800 		offset = dp->db_txt_end;
2801 	    else
2802 		offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
2803 	    mch_memmove((char *)dp + dp->db_txt_start,
2804 					  (char *)dp + dp->db_txt_start + len,
2805 				 (size_t)(offset - (dp->db_txt_start + len)));
2806 	    for (i = line_count - 1; i > db_idx; --i)
2807 		dp->db_index[i + 1] = dp->db_index[i] - len;
2808 	    dp->db_index[db_idx + 1] = offset - len;
2809 	}
2810 	else
2811 	    // add line at the end (which is the start of the text)
2812 	    dp->db_index[db_idx + 1] = dp->db_txt_start;
2813 
2814 	/*
2815 	 * copy the text into the block
2816 	 */
2817 	mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
2818 	if (mark)
2819 	    dp->db_index[db_idx + 1] |= DB_MARKED;
2820 
2821 	/*
2822 	 * Mark the block dirty.
2823 	 */
2824 	buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2825 	if (!newfile)
2826 	    buf->b_ml.ml_flags |= ML_LOCKED_POS;
2827     }
2828     else	    // not enough space in data block
2829     {
2830 	long	    line_count_left, line_count_right;
2831 	int	    page_count_left, page_count_right;
2832 	bhdr_T	    *hp_left;
2833 	bhdr_T	    *hp_right;
2834 	bhdr_T	    *hp_new;
2835 	int	    lines_moved;
2836 	int	    data_moved = 0;	    // init to shut up gcc
2837 	int	    total_moved = 0;	    // init to shut up gcc
2838 	DATA_BL	    *dp_right, *dp_left;
2839 	int	    stack_idx;
2840 	int	    in_left;
2841 	int	    lineadd;
2842 	blocknr_T   bnum_left, bnum_right;
2843 	linenr_T    lnum_left, lnum_right;
2844 	int	    pb_idx;
2845 	PTR_BL	    *pp_new;
2846 
2847 	/*
2848 	 * There is not enough room, we have to create a new data block and
2849 	 * copy some lines into it.
2850 	 * Then we have to insert an entry in the pointer block.
2851 	 * If this pointer block also is full, we go up another block, and so
2852 	 * on, up to the root if necessary.
2853 	 * The line counts in the pointer blocks have already been adjusted by
2854 	 * ml_find_line().
2855 	 *
2856 	 * We are going to allocate a new data block. Depending on the
2857 	 * situation it will be put to the left or right of the existing
2858 	 * block.  If possible we put the new line in the left block and move
2859 	 * the lines after it to the right block. Otherwise the new line is
2860 	 * also put in the right block. This method is more efficient when
2861 	 * inserting a lot of lines at one place.
2862 	 */
2863 	if (db_idx < 0)		// left block is new, right block is existing
2864 	{
2865 	    lines_moved = 0;
2866 	    in_left = TRUE;
2867 	    // space_needed does not change
2868 	}
2869 	else			// left block is existing, right block is new
2870 	{
2871 	    lines_moved = line_count - db_idx - 1;
2872 	    if (lines_moved == 0)
2873 		in_left = FALSE;	// put new line in right block
2874 					// space_needed does not change
2875 	    else
2876 	    {
2877 		data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
2878 							    dp->db_txt_start;
2879 		total_moved = data_moved + lines_moved * INDEX_SIZE;
2880 		if ((int)dp->db_free + total_moved >= space_needed)
2881 		{
2882 		    in_left = TRUE;	// put new line in left block
2883 		    space_needed = total_moved;
2884 		}
2885 		else
2886 		{
2887 		    in_left = FALSE;	    // put new line in right block
2888 		    space_needed += total_moved;
2889 		}
2890 	    }
2891 	}
2892 
2893 	page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
2894 	if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
2895 	{
2896 			// correct line counts in pointer blocks
2897 	    --(buf->b_ml.ml_locked_lineadd);
2898 	    --(buf->b_ml.ml_locked_high);
2899 	    goto theend;
2900 	}
2901 	if (db_idx < 0)		// left block is new
2902 	{
2903 	    hp_left = hp_new;
2904 	    hp_right = hp;
2905 	    line_count_left = 0;
2906 	    line_count_right = line_count;
2907 	}
2908 	else			// right block is new
2909 	{
2910 	    hp_left = hp;
2911 	    hp_right = hp_new;
2912 	    line_count_left = line_count;
2913 	    line_count_right = 0;
2914 	}
2915 	dp_right = (DATA_BL *)(hp_right->bh_data);
2916 	dp_left = (DATA_BL *)(hp_left->bh_data);
2917 	bnum_left = hp_left->bh_bnum;
2918 	bnum_right = hp_right->bh_bnum;
2919 	page_count_left = hp_left->bh_page_count;
2920 	page_count_right = hp_right->bh_page_count;
2921 
2922 	/*
2923 	 * May move the new line into the right/new block.
2924 	 */
2925 	if (!in_left)
2926 	{
2927 	    dp_right->db_txt_start -= len;
2928 	    dp_right->db_free -= len + INDEX_SIZE;
2929 	    dp_right->db_index[0] = dp_right->db_txt_start;
2930 	    if (mark)
2931 		dp_right->db_index[0] |= DB_MARKED;
2932 
2933 	    mch_memmove((char *)dp_right + dp_right->db_txt_start,
2934 							   line, (size_t)len);
2935 	    ++line_count_right;
2936 	}
2937 	/*
2938 	 * may move lines from the left/old block to the right/new one.
2939 	 */
2940 	if (lines_moved)
2941 	{
2942 	    /*
2943 	     */
2944 	    dp_right->db_txt_start -= data_moved;
2945 	    dp_right->db_free -= total_moved;
2946 	    mch_memmove((char *)dp_right + dp_right->db_txt_start,
2947 			(char *)dp_left + dp_left->db_txt_start,
2948 			(size_t)data_moved);
2949 	    offset = dp_right->db_txt_start - dp_left->db_txt_start;
2950 	    dp_left->db_txt_start += data_moved;
2951 	    dp_left->db_free += total_moved;
2952 
2953 	    /*
2954 	     * update indexes in the new block
2955 	     */
2956 	    for (to = line_count_right, from = db_idx + 1;
2957 					 from < line_count_left; ++from, ++to)
2958 		dp_right->db_index[to] = dp->db_index[from] + offset;
2959 	    line_count_right += lines_moved;
2960 	    line_count_left -= lines_moved;
2961 	}
2962 
2963 	/*
2964 	 * May move the new line into the left (old or new) block.
2965 	 */
2966 	if (in_left)
2967 	{
2968 	    dp_left->db_txt_start -= len;
2969 	    dp_left->db_free -= len + INDEX_SIZE;
2970 	    dp_left->db_index[line_count_left] = dp_left->db_txt_start;
2971 	    if (mark)
2972 		dp_left->db_index[line_count_left] |= DB_MARKED;
2973 	    mch_memmove((char *)dp_left + dp_left->db_txt_start,
2974 							   line, (size_t)len);
2975 	    ++line_count_left;
2976 	}
2977 
2978 	if (db_idx < 0)		// left block is new
2979 	{
2980 	    lnum_left = lnum + 1;
2981 	    lnum_right = 0;
2982 	}
2983 	else			// right block is new
2984 	{
2985 	    lnum_left = 0;
2986 	    if (in_left)
2987 		lnum_right = lnum + 2;
2988 	    else
2989 		lnum_right = lnum + 1;
2990 	}
2991 	dp_left->db_line_count = line_count_left;
2992 	dp_right->db_line_count = line_count_right;
2993 
2994 	/*
2995 	 * release the two data blocks
2996 	 * The new one (hp_new) already has a correct blocknumber.
2997 	 * The old one (hp, in ml_locked) gets a positive blocknumber if
2998 	 * we changed it and we are not editing a new file.
2999 	 */
3000 	if (lines_moved || in_left)
3001 	    buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3002 	if (!newfile && db_idx >= 0 && in_left)
3003 	    buf->b_ml.ml_flags |= ML_LOCKED_POS;
3004 	mf_put(mfp, hp_new, TRUE, FALSE);
3005 
3006 	/*
3007 	 * flush the old data block
3008 	 * set ml_locked_lineadd to 0, because the updating of the
3009 	 * pointer blocks is done below
3010 	 */
3011 	lineadd = buf->b_ml.ml_locked_lineadd;
3012 	buf->b_ml.ml_locked_lineadd = 0;
3013 	ml_find_line(buf, (linenr_T)0, ML_FLUSH);   // flush data block
3014 
3015 	/*
3016 	 * update pointer blocks for the new data block
3017 	 */
3018 	for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
3019 								  --stack_idx)
3020 	{
3021 	    ip = &(buf->b_ml.ml_stack[stack_idx]);
3022 	    pb_idx = ip->ip_index;
3023 	    if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3024 		goto theend;
3025 	    pp = (PTR_BL *)(hp->bh_data);   // must be pointer block
3026 	    if (pp->pb_id != PTR_ID)
3027 	    {
3028 		iemsg(_("E317: pointer block id wrong 3"));
3029 		mf_put(mfp, hp, FALSE, FALSE);
3030 		goto theend;
3031 	    }
3032 	    /*
3033 	     * TODO: If the pointer block is full and we are adding at the end
3034 	     * try to insert in front of the next block
3035 	     */
3036 	    // block not full, add one entry
3037 	    if (pp->pb_count < pp->pb_count_max)
3038 	    {
3039 		if (pb_idx + 1 < (int)pp->pb_count)
3040 		    mch_memmove(&pp->pb_pointer[pb_idx + 2],
3041 				&pp->pb_pointer[pb_idx + 1],
3042 			(size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
3043 		++pp->pb_count;
3044 		pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
3045 		pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
3046 		pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
3047 		pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
3048 		pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
3049 		pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
3050 
3051 		if (lnum_left != 0)
3052 		    pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
3053 		if (lnum_right != 0)
3054 		    pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
3055 
3056 		mf_put(mfp, hp, TRUE, FALSE);
3057 		buf->b_ml.ml_stack_top = stack_idx + 1;	    // truncate stack
3058 
3059 		if (lineadd)
3060 		{
3061 		    --(buf->b_ml.ml_stack_top);
3062 		    // fix line count for rest of blocks in the stack
3063 		    ml_lineadd(buf, lineadd);
3064 							// fix stack itself
3065 		    buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
3066 								      lineadd;
3067 		    ++(buf->b_ml.ml_stack_top);
3068 		}
3069 
3070 		/*
3071 		 * We are finished, break the loop here.
3072 		 */
3073 		break;
3074 	    }
3075 	    else			// pointer block full
3076 	    {
3077 		/*
3078 		 * split the pointer block
3079 		 * allocate a new pointer block
3080 		 * move some of the pointer into the new block
3081 		 * prepare for updating the parent block
3082 		 */
3083 		for (;;)	// do this twice when splitting block 1
3084 		{
3085 		    hp_new = ml_new_ptr(mfp);
3086 		    if (hp_new == NULL)	    // TODO: try to fix tree
3087 			goto theend;
3088 		    pp_new = (PTR_BL *)(hp_new->bh_data);
3089 
3090 		    if (hp->bh_bnum != 1)
3091 			break;
3092 
3093 		    /*
3094 		     * if block 1 becomes full the tree is given an extra level
3095 		     * The pointers from block 1 are moved into the new block.
3096 		     * block 1 is updated to point to the new block
3097 		     * then continue to split the new block
3098 		     */
3099 		    mch_memmove(pp_new, pp, (size_t)page_size);
3100 		    pp->pb_count = 1;
3101 		    pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
3102 		    pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
3103 		    pp->pb_pointer[0].pe_old_lnum = 1;
3104 		    pp->pb_pointer[0].pe_page_count = 1;
3105 		    mf_put(mfp, hp, TRUE, FALSE);   // release block 1
3106 		    hp = hp_new;		// new block is to be split
3107 		    pp = pp_new;
3108 		    CHECK(stack_idx != 0, _("stack_idx should be 0"));
3109 		    ip->ip_index = 0;
3110 		    ++stack_idx;	// do block 1 again later
3111 		}
3112 		/*
3113 		 * move the pointers after the current one to the new block
3114 		 * If there are none, the new entry will be in the new block.
3115 		 */
3116 		total_moved = pp->pb_count - pb_idx - 1;
3117 		if (total_moved)
3118 		{
3119 		    mch_memmove(&pp_new->pb_pointer[0],
3120 				&pp->pb_pointer[pb_idx + 1],
3121 				(size_t)(total_moved) * sizeof(PTR_EN));
3122 		    pp_new->pb_count = total_moved;
3123 		    pp->pb_count -= total_moved - 1;
3124 		    pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
3125 		    pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
3126 		    pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
3127 		    if (lnum_right)
3128 			pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
3129 		}
3130 		else
3131 		{
3132 		    pp_new->pb_count = 1;
3133 		    pp_new->pb_pointer[0].pe_bnum = bnum_right;
3134 		    pp_new->pb_pointer[0].pe_line_count = line_count_right;
3135 		    pp_new->pb_pointer[0].pe_page_count = page_count_right;
3136 		    pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
3137 		}
3138 		pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
3139 		pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
3140 		pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
3141 		if (lnum_left)
3142 		    pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
3143 		lnum_left = 0;
3144 		lnum_right = 0;
3145 
3146 		/*
3147 		 * recompute line counts
3148 		 */
3149 		line_count_right = 0;
3150 		for (i = 0; i < (int)pp_new->pb_count; ++i)
3151 		    line_count_right += pp_new->pb_pointer[i].pe_line_count;
3152 		line_count_left = 0;
3153 		for (i = 0; i < (int)pp->pb_count; ++i)
3154 		    line_count_left += pp->pb_pointer[i].pe_line_count;
3155 
3156 		bnum_left = hp->bh_bnum;
3157 		bnum_right = hp_new->bh_bnum;
3158 		page_count_left = 1;
3159 		page_count_right = 1;
3160 		mf_put(mfp, hp, TRUE, FALSE);
3161 		mf_put(mfp, hp_new, TRUE, FALSE);
3162 	    }
3163 	}
3164 
3165 	/*
3166 	 * Safety check: fallen out of for loop?
3167 	 */
3168 	if (stack_idx < 0)
3169 	{
3170 	    iemsg(_("E318: Updated too many blocks?"));
3171 	    buf->b_ml.ml_stack_top = 0;	// invalidate stack
3172 	}
3173     }
3174 
3175 #ifdef FEAT_BYTEOFF
3176     // The line was inserted below 'lnum'
3177     ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
3178 #endif
3179 #ifdef FEAT_NETBEANS_INTG
3180     if (netbeans_active())
3181     {
3182 	if (STRLEN(line) > 0)
3183 	    netbeans_inserted(buf, lnum+1, (colnr_T)0, line, (int)STRLEN(line));
3184 	netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line),
3185 							   (char_u *)"\n", 1);
3186     }
3187 #endif
3188 #ifdef FEAT_JOB_CHANNEL
3189     if (buf->b_write_to_channel)
3190 	channel_write_new_lines(buf);
3191 #endif
3192     ret = OK;
3193 
3194 theend:
3195 #ifdef FEAT_PROP_POPUP
3196     vim_free(tofree);
3197 #endif
3198     return ret;
3199 }
3200 
3201 /*
3202  * Flush any pending change and call ml_append_int()
3203  */
3204     static int
3205 ml_append_flush(
3206     buf_T	*buf,
3207     linenr_T	lnum,		// append after this line (can be 0)
3208     char_u	*line,		// text of the new line
3209     colnr_T	len,		// length of line, including NUL, or 0
3210     int		newfile)	// flag, see above
3211 {
3212     if (lnum > buf->b_ml.ml_line_count)
3213 	return FAIL;  // lnum out of range
3214 
3215     if (buf->b_ml.ml_line_lnum != 0)
3216 	// This may also invoke ml_append_int().
3217 	ml_flush_line(buf);
3218 
3219 #ifdef FEAT_EVAL
3220     // When inserting above recorded changes: flush the changes before changing
3221     // the text.  Then flush the cached line, it may become invalid.
3222     may_invoke_listeners(buf, lnum + 1, lnum + 1, 1);
3223     if (buf->b_ml.ml_line_lnum != 0)
3224 	ml_flush_line(buf);
3225 #endif
3226 
3227     return ml_append_int(buf, lnum, line, len, newfile, FALSE);
3228 }
3229 
3230 /*
3231  * Append a line after lnum (may be 0 to insert a line in front of the file).
3232  * "line" does not need to be allocated, but can't be another line in a
3233  * buffer, unlocking may make it invalid.
3234  *
3235  *   newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
3236  *		will be set for recovery
3237  * Check: The caller of this function should probably also call
3238  * appended_lines().
3239  *
3240  * return FAIL for failure, OK otherwise
3241  */
3242     int
3243 ml_append(
3244     linenr_T	lnum,		// append after this line (can be 0)
3245     char_u	*line,		// text of the new line
3246     colnr_T	len,		// length of new line, including NUL, or 0
3247     int		newfile)	// flag, see above
3248 {
3249     // When starting up, we might still need to create the memfile
3250     if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
3251 	return FAIL;
3252     return ml_append_flush(curbuf, lnum, line, len, newfile);
3253 }
3254 
3255 #if defined(FEAT_SPELL) || defined(FEAT_QUICKFIX) || defined(PROTO)
3256 /*
3257  * Like ml_append() but for an arbitrary buffer.  The buffer must already have
3258  * a memline.
3259  */
3260     int
3261 ml_append_buf(
3262     buf_T	*buf,
3263     linenr_T	lnum,		// append after this line (can be 0)
3264     char_u	*line,		// text of the new line
3265     colnr_T	len,		// length of new line, including NUL, or 0
3266     int		newfile)	// flag, see above
3267 {
3268     if (buf->b_ml.ml_mfp == NULL)
3269 	return FAIL;
3270     return ml_append_flush(buf, lnum, line, len, newfile);
3271 }
3272 #endif
3273 
3274 /*
3275  * Replace line lnum, with buffering, in current buffer.
3276  *
3277  * If "copy" is TRUE, make a copy of the line, otherwise the line has been
3278  * copied to allocated memory already.
3279  *
3280  * Check: The caller of this function should probably also call
3281  * changed_lines(), unless update_screen(NOT_VALID) is used.
3282  *
3283  * return FAIL for failure, OK otherwise
3284  */
3285     int
3286 ml_replace(linenr_T lnum, char_u *line, int copy)
3287 {
3288     colnr_T len = -1;
3289 
3290     if (line != NULL)
3291 	len = (colnr_T)STRLEN(line);
3292     return ml_replace_len(lnum, line, len, FALSE, copy);
3293 }
3294 
3295 /*
3296  * Replace a line for the current buffer.  Like ml_replace() with:
3297  * "len_arg" is the length of the text, excluding NUL.
3298  * If "has_props" is TRUE then "line_arg" includes the text properties and
3299  * "len_arg" includes the NUL of the text.
3300  */
3301     int
3302 ml_replace_len(
3303 	linenr_T    lnum,
3304 	char_u	    *line_arg,
3305 	colnr_T	    len_arg,
3306 	int	    has_props,
3307 	int	    copy)
3308 {
3309     char_u *line = line_arg;
3310     colnr_T len = len_arg;
3311 
3312     if (line == NULL)		// just checking...
3313 	return FAIL;
3314 
3315     // When starting up, we might still need to create the memfile
3316     if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
3317 	return FAIL;
3318 
3319     if (!has_props)
3320 	++len;  // include the NUL after the text
3321     if (copy)
3322     {
3323 	// copy the line to allocated memory
3324 #ifdef FEAT_PROP_POPUP
3325 	if (has_props)
3326 	    line = vim_memsave(line, len);
3327 	else
3328 #endif
3329 	    line = vim_strnsave(line, len - 1);
3330 	if (line == NULL)
3331 	    return FAIL;
3332     }
3333 
3334 #ifdef FEAT_NETBEANS_INTG
3335     if (netbeans_active())
3336     {
3337 	netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
3338 	netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line));
3339     }
3340 #endif
3341     if (curbuf->b_ml.ml_line_lnum != lnum)
3342     {
3343 	// another line is buffered, flush it
3344 	ml_flush_line(curbuf);
3345 	curbuf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
3346 
3347 #ifdef FEAT_PROP_POPUP
3348 	if (curbuf->b_has_textprop && !has_props)
3349 	    // Need to fetch the old line to copy over any text properties.
3350 	    ml_get_buf(curbuf, lnum, TRUE);
3351 #endif
3352     }
3353 
3354 #ifdef FEAT_PROP_POPUP
3355     if (curbuf->b_has_textprop && !has_props)
3356     {
3357 	size_t	oldtextlen = STRLEN(curbuf->b_ml.ml_line_ptr) + 1;
3358 
3359 	if (oldtextlen < (size_t)curbuf->b_ml.ml_line_len)
3360 	{
3361 	    char_u *newline;
3362 	    size_t textproplen = curbuf->b_ml.ml_line_len - oldtextlen;
3363 
3364 	    // Need to copy over text properties, stored after the text.
3365 	    newline = alloc(len + (int)textproplen);
3366 	    if (newline != NULL)
3367 	    {
3368 		mch_memmove(newline, line, len);
3369 		mch_memmove(newline + len, curbuf->b_ml.ml_line_ptr
3370 						    + oldtextlen, textproplen);
3371 		vim_free(line);
3372 		line = newline;
3373 		len += (colnr_T)textproplen;
3374 	    }
3375 	}
3376     }
3377 #endif
3378 
3379     if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY)	// same line allocated
3380 	vim_free(curbuf->b_ml.ml_line_ptr);	// free it
3381 
3382     curbuf->b_ml.ml_line_ptr = line;
3383     curbuf->b_ml.ml_line_len = len;
3384     curbuf->b_ml.ml_line_lnum = lnum;
3385     curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
3386 
3387     return OK;
3388 }
3389 
3390 #ifdef FEAT_PROP_POPUP
3391 /*
3392  * Adjust text properties in line "lnum" for a deleted line.
3393  * When "above" is true this is the line above the deleted line.
3394  * "del_props" are the properties of the deleted line.
3395  */
3396     static void
3397 adjust_text_props_for_delete(
3398 	buf_T	    *buf,
3399 	linenr_T    lnum,
3400 	char_u	    *del_props,
3401 	int	    del_props_len,
3402 	int	    above)
3403 {
3404     int		did_get_line = FALSE;
3405     int		done_del;
3406     int		done_this;
3407     textprop_T	prop_del;
3408     textprop_T	prop_this;
3409     bhdr_T	*hp;
3410     DATA_BL	*dp;
3411     int		idx;
3412     int		line_start;
3413     long	line_size;
3414     int		this_props_len;
3415     char_u	*text;
3416     size_t	textlen;
3417     int		found;
3418 
3419     for (done_del = 0; done_del < del_props_len; done_del += sizeof(textprop_T))
3420     {
3421 	mch_memmove(&prop_del, del_props + done_del, sizeof(textprop_T));
3422 	if ((above && (prop_del.tp_flags & TP_FLAG_CONT_PREV)
3423 		    && !(prop_del.tp_flags & TP_FLAG_CONT_NEXT))
3424 		|| (!above && (prop_del.tp_flags & TP_FLAG_CONT_NEXT)
3425 		    && !(prop_del.tp_flags & TP_FLAG_CONT_PREV)))
3426 	{
3427 	    if (!did_get_line)
3428 	    {
3429 		did_get_line = TRUE;
3430 		if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
3431 		    return;
3432 
3433 		dp = (DATA_BL *)(hp->bh_data);
3434 		idx = lnum - buf->b_ml.ml_locked_low;
3435 		line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3436 		if (idx == 0)		// first line in block, text at the end
3437 		    line_size = dp->db_txt_end - line_start;
3438 		else
3439 		    line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
3440 		text = (char_u *)dp + line_start;
3441 		textlen = STRLEN(text) + 1;
3442 		if ((long)textlen >= line_size)
3443 		{
3444 		    if (above)
3445 			internal_error("no text property above deleted line");
3446 		    else
3447 			internal_error("no text property below deleted line");
3448 		    return;
3449 		}
3450 		this_props_len = line_size - (int)textlen;
3451 	    }
3452 
3453 	    found = FALSE;
3454 	    for (done_this = 0; done_this < this_props_len; done_this += sizeof(textprop_T))
3455 	    {
3456 		mch_memmove(&prop_this, text + textlen + done_del, sizeof(textprop_T));
3457 		if (prop_del.tp_id == prop_this.tp_id
3458 			&& prop_del.tp_type == prop_this.tp_type)
3459 		{
3460 		    int flag = above ? TP_FLAG_CONT_NEXT : TP_FLAG_CONT_PREV;
3461 
3462 		    found = TRUE;
3463 		    if (prop_this.tp_flags & flag)
3464 		    {
3465 			prop_this.tp_flags &= ~flag;
3466 			mch_memmove(text + textlen + done_del, &prop_this, sizeof(textprop_T));
3467 		    }
3468 		    else if (above)
3469 			internal_error("text property above deleted line does not continue");
3470 		    else
3471 			internal_error("text property below deleted line does not continue");
3472 		}
3473 	    }
3474 	    if (!found)
3475 	    {
3476 		if (above)
3477 		    internal_error("text property above deleted line not found");
3478 		else
3479 		    internal_error("text property below deleted line not found");
3480 	    }
3481 
3482 	    buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3483 	}
3484     }
3485 }
3486 #endif
3487 
3488 /*
3489  * Delete line "lnum" in the current buffer.
3490  * When "message" is TRUE may give a "No lines in buffer" message.
3491  *
3492  * Check: The caller of this function should probably also call
3493  * deleted_lines() after this.
3494  *
3495  * return FAIL for failure, OK otherwise
3496  */
3497     int
3498 ml_delete(linenr_T lnum, int message)
3499 {
3500     ml_flush_line(curbuf);
3501     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
3502 	return FAIL;
3503 
3504 #ifdef FEAT_EVAL
3505     // When inserting above recorded changes: flush the changes before changing
3506     // the text.
3507     may_invoke_listeners(curbuf, lnum, lnum + 1, -1);
3508 #endif
3509 
3510     return ml_delete_int(curbuf, lnum, message);
3511 }
3512 
3513     static int
3514 ml_delete_int(buf_T *buf, linenr_T lnum, int message)
3515 {
3516     bhdr_T	*hp;
3517     memfile_T	*mfp;
3518     DATA_BL	*dp;
3519     PTR_BL	*pp;
3520     infoptr_T	*ip;
3521     int		count;	    // number of entries in block
3522     int		idx;
3523     int		stack_idx;
3524     int		text_start;
3525     int		line_start;
3526     long	line_size;
3527     int		i;
3528     int		ret = FAIL;
3529 #ifdef FEAT_PROP_POPUP
3530     char_u	*textprop_save = NULL;
3531     int		textprop_save_len;
3532 #endif
3533 
3534     if (lowest_marked && lowest_marked > lnum)
3535 	lowest_marked--;
3536 
3537 /*
3538  * If the file becomes empty the last line is replaced by an empty line.
3539  */
3540     if (buf->b_ml.ml_line_count == 1)	    // file becomes empty
3541     {
3542 	if (message
3543 #ifdef FEAT_NETBEANS_INTG
3544 		&& !netbeansSuppressNoLines
3545 #endif
3546 	   )
3547 	    set_keep_msg((char_u *)_(no_lines_msg), 0);
3548 
3549 	// FEAT_BYTEOFF already handled in there, don't worry 'bout it below
3550 	i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
3551 	buf->b_ml.ml_flags |= ML_EMPTY;
3552 
3553 	return i;
3554     }
3555 
3556 /*
3557  * Find the data block containing the line.
3558  * This also fills the stack with the blocks from the root to the data block.
3559  * This also releases any locked block..
3560  */
3561     mfp = buf->b_ml.ml_mfp;
3562     if (mfp == NULL)
3563 	return FAIL;
3564 
3565     if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
3566 	return FAIL;
3567 
3568     dp = (DATA_BL *)(hp->bh_data);
3569     // compute line count before the delete
3570     count = (long)(buf->b_ml.ml_locked_high)
3571 					- (long)(buf->b_ml.ml_locked_low) + 2;
3572     idx = lnum - buf->b_ml.ml_locked_low;
3573 
3574     --buf->b_ml.ml_line_count;
3575 
3576     line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3577     if (idx == 0)		// first line in block, text at the end
3578 	line_size = dp->db_txt_end - line_start;
3579     else
3580 	line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
3581 
3582 #ifdef FEAT_NETBEANS_INTG
3583     if (netbeans_active())
3584 	netbeans_removed(buf, lnum, 0, (long)line_size);
3585 #endif
3586 #ifdef FEAT_PROP_POPUP
3587     // If there are text properties, make a copy, so that we can update
3588     // properties in preceding and following lines.
3589     if (buf->b_has_textprop)
3590     {
3591 	size_t	textlen = STRLEN((char_u *)dp + line_start) + 1;
3592 
3593 	if ((long)textlen < line_size)
3594 	{
3595 	    textprop_save_len = line_size - (int)textlen;
3596 	    textprop_save = vim_memsave((char_u *)dp + line_start + textlen,
3597 							  textprop_save_len);
3598 	}
3599     }
3600 #endif
3601 
3602 /*
3603  * special case: If there is only one line in the data block it becomes empty.
3604  * Then we have to remove the entry, pointing to this data block, from the
3605  * pointer block. If this pointer block also becomes empty, we go up another
3606  * block, and so on, up to the root if necessary.
3607  * The line counts in the pointer blocks have already been adjusted by
3608  * ml_find_line().
3609  */
3610     if (count == 1)
3611     {
3612 	mf_free(mfp, hp);	// free the data block
3613 	buf->b_ml.ml_locked = NULL;
3614 
3615 	for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
3616 								  --stack_idx)
3617 	{
3618 	    buf->b_ml.ml_stack_top = 0;	    // stack is invalid when failing
3619 	    ip = &(buf->b_ml.ml_stack[stack_idx]);
3620 	    idx = ip->ip_index;
3621 	    if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3622 		goto theend;
3623 	    pp = (PTR_BL *)(hp->bh_data);   // must be pointer block
3624 	    if (pp->pb_id != PTR_ID)
3625 	    {
3626 		iemsg(_("E317: pointer block id wrong 4"));
3627 		mf_put(mfp, hp, FALSE, FALSE);
3628 		goto theend;
3629 	    }
3630 	    count = --(pp->pb_count);
3631 	    if (count == 0)	    // the pointer block becomes empty!
3632 		mf_free(mfp, hp);
3633 	    else
3634 	    {
3635 		if (count != idx)	// move entries after the deleted one
3636 		    mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
3637 				      (size_t)(count - idx) * sizeof(PTR_EN));
3638 		mf_put(mfp, hp, TRUE, FALSE);
3639 
3640 		buf->b_ml.ml_stack_top = stack_idx;	// truncate stack
3641 		// fix line count for rest of blocks in the stack
3642 		if (buf->b_ml.ml_locked_lineadd != 0)
3643 		{
3644 		    ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
3645 		    buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
3646 						  buf->b_ml.ml_locked_lineadd;
3647 		}
3648 		++(buf->b_ml.ml_stack_top);
3649 
3650 		break;
3651 	    }
3652 	}
3653 	CHECK(stack_idx < 0, _("deleted block 1?"));
3654     }
3655     else
3656     {
3657 	/*
3658 	 * delete the text by moving the next lines forwards
3659 	 */
3660 	text_start = dp->db_txt_start;
3661 	mch_memmove((char *)dp + text_start + line_size,
3662 		  (char *)dp + text_start, (size_t)(line_start - text_start));
3663 
3664 	/*
3665 	 * delete the index by moving the next indexes backwards
3666 	 * Adjust the indexes for the text movement.
3667 	 */
3668 	for (i = idx; i < count - 1; ++i)
3669 	    dp->db_index[i] = dp->db_index[i + 1] + line_size;
3670 
3671 	dp->db_free += line_size + INDEX_SIZE;
3672 	dp->db_txt_start += line_size;
3673 	--(dp->db_line_count);
3674 
3675 	/*
3676 	 * mark the block dirty and make sure it is in the file (for recovery)
3677 	 */
3678 	buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3679     }
3680 
3681 #ifdef FEAT_BYTEOFF
3682     ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
3683 #endif
3684     ret = OK;
3685 
3686 theend:
3687 #ifdef FEAT_PROP_POPUP
3688     if (textprop_save != NULL)
3689     {
3690 	// Adjust text properties in the line above and below.
3691 	if (lnum > 1)
3692 	    adjust_text_props_for_delete(buf, lnum - 1, textprop_save, textprop_save_len, TRUE);
3693 	if (lnum <= buf->b_ml.ml_line_count)
3694 	    adjust_text_props_for_delete(buf, lnum, textprop_save, textprop_save_len, FALSE);
3695     }
3696     vim_free(textprop_save);
3697 #endif
3698     return ret;
3699 }
3700 
3701 /*
3702  * set the DB_MARKED flag for line 'lnum'
3703  */
3704     void
3705 ml_setmarked(linenr_T lnum)
3706 {
3707     bhdr_T    *hp;
3708     DATA_BL *dp;
3709 				    // invalid line number
3710     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
3711 					       || curbuf->b_ml.ml_mfp == NULL)
3712 	return;			    // give error message?
3713 
3714     if (lowest_marked == 0 || lowest_marked > lnum)
3715 	lowest_marked = lnum;
3716 
3717     /*
3718      * find the data block containing the line
3719      * This also fills the stack with the blocks from the root to the data block
3720      * This also releases any locked block.
3721      */
3722     if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3723 	return;		    // give error message?
3724 
3725     dp = (DATA_BL *)(hp->bh_data);
3726     dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
3727     curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3728 }
3729 
3730 /*
3731  * find the first line with its DB_MARKED flag set
3732  */
3733     linenr_T
3734 ml_firstmarked(void)
3735 {
3736     bhdr_T	*hp;
3737     DATA_BL	*dp;
3738     linenr_T	lnum;
3739     int		i;
3740 
3741     if (curbuf->b_ml.ml_mfp == NULL)
3742 	return (linenr_T) 0;
3743 
3744     /*
3745      * The search starts with lowest_marked line. This is the last line where
3746      * a mark was found, adjusted by inserting/deleting lines.
3747      */
3748     for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3749     {
3750 	/*
3751 	 * Find the data block containing the line.
3752 	 * This also fills the stack with the blocks from the root to the data
3753 	 * block This also releases any locked block.
3754 	 */
3755 	if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3756 	    return (linenr_T)0;		    // give error message?
3757 
3758 	dp = (DATA_BL *)(hp->bh_data);
3759 
3760 	for (i = lnum - curbuf->b_ml.ml_locked_low;
3761 			    lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3762 	    if ((dp->db_index[i]) & DB_MARKED)
3763 	    {
3764 		(dp->db_index[i]) &= DB_INDEX_MASK;
3765 		curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3766 		lowest_marked = lnum + 1;
3767 		return lnum;
3768 	    }
3769     }
3770 
3771     return (linenr_T) 0;
3772 }
3773 
3774 /*
3775  * clear all DB_MARKED flags
3776  */
3777     void
3778 ml_clearmarked(void)
3779 {
3780     bhdr_T	*hp;
3781     DATA_BL	*dp;
3782     linenr_T	lnum;
3783     int		i;
3784 
3785     if (curbuf->b_ml.ml_mfp == NULL)	    // nothing to do
3786 	return;
3787 
3788     /*
3789      * The search starts with line lowest_marked.
3790      */
3791     for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3792     {
3793 	/*
3794 	 * Find the data block containing the line.
3795 	 * This also fills the stack with the blocks from the root to the data
3796 	 * block and releases any locked block.
3797 	 */
3798 	if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3799 	    return;		// give error message?
3800 
3801 	dp = (DATA_BL *)(hp->bh_data);
3802 
3803 	for (i = lnum - curbuf->b_ml.ml_locked_low;
3804 			    lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3805 	    if ((dp->db_index[i]) & DB_MARKED)
3806 	    {
3807 		(dp->db_index[i]) &= DB_INDEX_MASK;
3808 		curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3809 	    }
3810     }
3811 
3812     lowest_marked = 0;
3813     return;
3814 }
3815 
3816 /*
3817  * flush ml_line if necessary
3818  */
3819     static void
3820 ml_flush_line(buf_T *buf)
3821 {
3822     bhdr_T	*hp;
3823     DATA_BL	*dp;
3824     linenr_T	lnum;
3825     char_u	*new_line;
3826     char_u	*old_line;
3827     colnr_T	new_len;
3828     int		old_len;
3829     int		extra;
3830     int		idx;
3831     int		start;
3832     int		count;
3833     int		i;
3834     static int  entered = FALSE;
3835 
3836     if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
3837 	return;		// nothing to do
3838 
3839     if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
3840     {
3841 	// This code doesn't work recursively, but Netbeans may call back here
3842 	// when obtaining the cursor position.
3843 	if (entered)
3844 	    return;
3845 	entered = TRUE;
3846 
3847 	lnum = buf->b_ml.ml_line_lnum;
3848 	new_line = buf->b_ml.ml_line_ptr;
3849 
3850 	hp = ml_find_line(buf, lnum, ML_FIND);
3851 	if (hp == NULL)
3852 	    siemsg(_("E320: Cannot find line %ld"), lnum);
3853 	else
3854 	{
3855 	    dp = (DATA_BL *)(hp->bh_data);
3856 	    idx = lnum - buf->b_ml.ml_locked_low;
3857 	    start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3858 	    old_line = (char_u *)dp + start;
3859 	    if (idx == 0)	// line is last in block
3860 		old_len = dp->db_txt_end - start;
3861 	    else		// text of previous line follows
3862 		old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
3863 	    new_len = buf->b_ml.ml_line_len;
3864 	    extra = new_len - old_len;	    // negative if lines gets smaller
3865 
3866 	    /*
3867 	     * if new line fits in data block, replace directly
3868 	     */
3869 	    if ((int)dp->db_free >= extra)
3870 	    {
3871 		// if the length changes and there are following lines
3872 		count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
3873 		if (extra != 0 && idx < count - 1)
3874 		{
3875 		    // move text of following lines
3876 		    mch_memmove((char *)dp + dp->db_txt_start - extra,
3877 				(char *)dp + dp->db_txt_start,
3878 				(size_t)(start - dp->db_txt_start));
3879 
3880 		    // adjust pointers of this and following lines
3881 		    for (i = idx + 1; i < count; ++i)
3882 			dp->db_index[i] -= extra;
3883 		}
3884 		dp->db_index[idx] -= extra;
3885 
3886 		// adjust free space
3887 		dp->db_free -= extra;
3888 		dp->db_txt_start -= extra;
3889 
3890 		// copy new line into the data block
3891 		mch_memmove(old_line - extra, new_line, (size_t)new_len);
3892 		buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3893 #ifdef FEAT_BYTEOFF
3894 		// The else case is already covered by the insert and delete
3895 		ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
3896 #endif
3897 	    }
3898 	    else
3899 	    {
3900 		/*
3901 		 * Cannot do it in one data block: Delete and append.
3902 		 * Append first, because ml_delete_int() cannot delete the
3903 		 * last line in a buffer, which causes trouble for a buffer
3904 		 * that has only one line.
3905 		 * Don't forget to copy the mark!
3906 		 */
3907 		// How about handling errors???
3908 		(void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
3909 					     (dp->db_index[idx] & DB_MARKED));
3910 		(void)ml_delete_int(buf, lnum, FALSE);
3911 	    }
3912 	}
3913 	vim_free(new_line);
3914 
3915 	entered = FALSE;
3916     }
3917 
3918     buf->b_ml.ml_line_lnum = 0;
3919 }
3920 
3921 /*
3922  * create a new, empty, data block
3923  */
3924     static bhdr_T *
3925 ml_new_data(memfile_T *mfp, int negative, int page_count)
3926 {
3927     bhdr_T	*hp;
3928     DATA_BL	*dp;
3929 
3930     if ((hp = mf_new(mfp, negative, page_count)) == NULL)
3931 	return NULL;
3932 
3933     dp = (DATA_BL *)(hp->bh_data);
3934     dp->db_id = DATA_ID;
3935     dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
3936     dp->db_free = dp->db_txt_start - HEADER_SIZE;
3937     dp->db_line_count = 0;
3938 
3939     return hp;
3940 }
3941 
3942 /*
3943  * create a new, empty, pointer block
3944  */
3945     static bhdr_T *
3946 ml_new_ptr(memfile_T *mfp)
3947 {
3948     bhdr_T	*hp;
3949     PTR_BL	*pp;
3950 
3951     if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
3952 	return NULL;
3953 
3954     pp = (PTR_BL *)(hp->bh_data);
3955     pp->pb_id = PTR_ID;
3956     pp->pb_count = 0;
3957     pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL))
3958 							/ sizeof(PTR_EN) + 1);
3959 
3960     return hp;
3961 }
3962 
3963 /*
3964  * Lookup line 'lnum' in a memline.
3965  *
3966  *   action: if ML_DELETE or ML_INSERT the line count is updated while searching
3967  *	     if ML_FLUSH only flush a locked block
3968  *	     if ML_FIND just find the line
3969  *
3970  * If the block was found it is locked and put in ml_locked.
3971  * The stack is updated to lead to the locked block. The ip_high field in
3972  * the stack is updated to reflect the last line in the block AFTER the
3973  * insert or delete, also if the pointer block has not been updated yet. But
3974  * if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
3975  *
3976  * return: NULL for failure, pointer to block header otherwise
3977  */
3978     static bhdr_T *
3979 ml_find_line(buf_T *buf, linenr_T lnum, int action)
3980 {
3981     DATA_BL	*dp;
3982     PTR_BL	*pp;
3983     infoptr_T	*ip;
3984     bhdr_T	*hp;
3985     memfile_T	*mfp;
3986     linenr_T	t;
3987     blocknr_T	bnum, bnum2;
3988     int		dirty;
3989     linenr_T	low, high;
3990     int		top;
3991     int		page_count;
3992     int		idx;
3993 
3994     mfp = buf->b_ml.ml_mfp;
3995 
3996     /*
3997      * If there is a locked block check if the wanted line is in it.
3998      * If not, flush and release the locked block.
3999      * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
4000      * Don't do this for ML_FLUSH, because we want to flush the locked block.
4001      * Don't do this when 'swapfile' is reset, we want to load all the blocks.
4002      */
4003     if (buf->b_ml.ml_locked)
4004     {
4005 	if (ML_SIMPLE(action)
4006 		&& buf->b_ml.ml_locked_low <= lnum
4007 		&& buf->b_ml.ml_locked_high >= lnum
4008 		&& !mf_dont_release)
4009 	{
4010 	    // remember to update pointer blocks and stack later
4011 	    if (action == ML_INSERT)
4012 	    {
4013 		++(buf->b_ml.ml_locked_lineadd);
4014 		++(buf->b_ml.ml_locked_high);
4015 	    }
4016 	    else if (action == ML_DELETE)
4017 	    {
4018 		--(buf->b_ml.ml_locked_lineadd);
4019 		--(buf->b_ml.ml_locked_high);
4020 	    }
4021 	    return (buf->b_ml.ml_locked);
4022 	}
4023 
4024 	mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
4025 					    buf->b_ml.ml_flags & ML_LOCKED_POS);
4026 	buf->b_ml.ml_locked = NULL;
4027 
4028 	/*
4029 	 * If lines have been added or deleted in the locked block, need to
4030 	 * update the line count in pointer blocks.
4031 	 */
4032 	if (buf->b_ml.ml_locked_lineadd != 0)
4033 	    ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
4034     }
4035 
4036     if (action == ML_FLUSH)	    // nothing else to do
4037 	return NULL;
4038 
4039     bnum = 1;			    // start at the root of the tree
4040     page_count = 1;
4041     low = 1;
4042     high = buf->b_ml.ml_line_count;
4043 
4044     if (action == ML_FIND)	// first try stack entries
4045     {
4046 	for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
4047 	{
4048 	    ip = &(buf->b_ml.ml_stack[top]);
4049 	    if (ip->ip_low <= lnum && ip->ip_high >= lnum)
4050 	    {
4051 		bnum = ip->ip_bnum;
4052 		low = ip->ip_low;
4053 		high = ip->ip_high;
4054 		buf->b_ml.ml_stack_top = top;	// truncate stack at prev entry
4055 		break;
4056 	    }
4057 	}
4058 	if (top < 0)
4059 	    buf->b_ml.ml_stack_top = 0;		// not found, start at the root
4060     }
4061     else	// ML_DELETE or ML_INSERT
4062 	buf->b_ml.ml_stack_top = 0;	// start at the root
4063 
4064 /*
4065  * search downwards in the tree until a data block is found
4066  */
4067     for (;;)
4068     {
4069 	if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
4070 	    goto error_noblock;
4071 
4072 	/*
4073 	 * update high for insert/delete
4074 	 */
4075 	if (action == ML_INSERT)
4076 	    ++high;
4077 	else if (action == ML_DELETE)
4078 	    --high;
4079 
4080 	dp = (DATA_BL *)(hp->bh_data);
4081 	if (dp->db_id == DATA_ID)	// data block
4082 	{
4083 	    buf->b_ml.ml_locked = hp;
4084 	    buf->b_ml.ml_locked_low = low;
4085 	    buf->b_ml.ml_locked_high = high;
4086 	    buf->b_ml.ml_locked_lineadd = 0;
4087 	    buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
4088 	    return hp;
4089 	}
4090 
4091 	pp = (PTR_BL *)(dp);		// must be pointer block
4092 	if (pp->pb_id != PTR_ID)
4093 	{
4094 	    iemsg(_("E317: pointer block id wrong"));
4095 	    goto error_block;
4096 	}
4097 
4098 	if ((top = ml_add_stack(buf)) < 0)	// add new entry to stack
4099 	    goto error_block;
4100 	ip = &(buf->b_ml.ml_stack[top]);
4101 	ip->ip_bnum = bnum;
4102 	ip->ip_low = low;
4103 	ip->ip_high = high;
4104 	ip->ip_index = -1;		// index not known yet
4105 
4106 	dirty = FALSE;
4107 	for (idx = 0; idx < (int)pp->pb_count; ++idx)
4108 	{
4109 	    t = pp->pb_pointer[idx].pe_line_count;
4110 	    CHECK(t == 0, _("pe_line_count is zero"));
4111 	    if ((low += t) > lnum)
4112 	    {
4113 		ip->ip_index = idx;
4114 		bnum = pp->pb_pointer[idx].pe_bnum;
4115 		page_count = pp->pb_pointer[idx].pe_page_count;
4116 		high = low - 1;
4117 		low -= t;
4118 
4119 		/*
4120 		 * a negative block number may have been changed
4121 		 */
4122 		if (bnum < 0)
4123 		{
4124 		    bnum2 = mf_trans_del(mfp, bnum);
4125 		    if (bnum != bnum2)
4126 		    {
4127 			bnum = bnum2;
4128 			pp->pb_pointer[idx].pe_bnum = bnum;
4129 			dirty = TRUE;
4130 		    }
4131 		}
4132 
4133 		break;
4134 	    }
4135 	}
4136 	if (idx >= (int)pp->pb_count)	    // past the end: something wrong!
4137 	{
4138 	    if (lnum > buf->b_ml.ml_line_count)
4139 		siemsg(_("E322: line number out of range: %ld past the end"),
4140 					      lnum - buf->b_ml.ml_line_count);
4141 
4142 	    else
4143 		siemsg(_("E323: line count wrong in block %ld"), bnum);
4144 	    goto error_block;
4145 	}
4146 	if (action == ML_DELETE)
4147 	{
4148 	    pp->pb_pointer[idx].pe_line_count--;
4149 	    dirty = TRUE;
4150 	}
4151 	else if (action == ML_INSERT)
4152 	{
4153 	    pp->pb_pointer[idx].pe_line_count++;
4154 	    dirty = TRUE;
4155 	}
4156 	mf_put(mfp, hp, dirty, FALSE);
4157     }
4158 
4159 error_block:
4160     mf_put(mfp, hp, FALSE, FALSE);
4161 error_noblock:
4162     /*
4163      * If action is ML_DELETE or ML_INSERT we have to correct the tree for
4164      * the incremented/decremented line counts, because there won't be a line
4165      * inserted/deleted after all.
4166      */
4167     if (action == ML_DELETE)
4168 	ml_lineadd(buf, 1);
4169     else if (action == ML_INSERT)
4170 	ml_lineadd(buf, -1);
4171     buf->b_ml.ml_stack_top = 0;
4172     return NULL;
4173 }
4174 
4175 /*
4176  * add an entry to the info pointer stack
4177  *
4178  * return -1 for failure, number of the new entry otherwise
4179  */
4180     static int
4181 ml_add_stack(buf_T *buf)
4182 {
4183     int		top;
4184     infoptr_T	*newstack;
4185 
4186     top = buf->b_ml.ml_stack_top;
4187 
4188     // may have to increase the stack size
4189     if (top == buf->b_ml.ml_stack_size)
4190     {
4191 	CHECK(top > 0, _("Stack size increases")); // more than 5 levels???
4192 
4193 	newstack = ALLOC_MULT(infoptr_T, buf->b_ml.ml_stack_size + STACK_INCR);
4194 	if (newstack == NULL)
4195 	    return -1;
4196 	if (top > 0)
4197 	    mch_memmove(newstack, buf->b_ml.ml_stack,
4198 					     (size_t)top * sizeof(infoptr_T));
4199 	vim_free(buf->b_ml.ml_stack);
4200 	buf->b_ml.ml_stack = newstack;
4201 	buf->b_ml.ml_stack_size += STACK_INCR;
4202     }
4203 
4204     buf->b_ml.ml_stack_top++;
4205     return top;
4206 }
4207 
4208 /*
4209  * Update the pointer blocks on the stack for inserted/deleted lines.
4210  * The stack itself is also updated.
4211  *
4212  * When a insert/delete line action fails, the line is not inserted/deleted,
4213  * but the pointer blocks have already been updated. That is fixed here by
4214  * walking through the stack.
4215  *
4216  * Count is the number of lines added, negative if lines have been deleted.
4217  */
4218     static void
4219 ml_lineadd(buf_T *buf, int count)
4220 {
4221     int		idx;
4222     infoptr_T	*ip;
4223     PTR_BL	*pp;
4224     memfile_T	*mfp = buf->b_ml.ml_mfp;
4225     bhdr_T	*hp;
4226 
4227     for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
4228     {
4229 	ip = &(buf->b_ml.ml_stack[idx]);
4230 	if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
4231 	    break;
4232 	pp = (PTR_BL *)(hp->bh_data);	// must be pointer block
4233 	if (pp->pb_id != PTR_ID)
4234 	{
4235 	    mf_put(mfp, hp, FALSE, FALSE);
4236 	    iemsg(_("E317: pointer block id wrong 2"));
4237 	    break;
4238 	}
4239 	pp->pb_pointer[ip->ip_index].pe_line_count += count;
4240 	ip->ip_high += count;
4241 	mf_put(mfp, hp, TRUE, FALSE);
4242     }
4243 }
4244 
4245 #if defined(HAVE_READLINK) || defined(PROTO)
4246 /*
4247  * Resolve a symlink in the last component of a file name.
4248  * Note that f_resolve() does it for every part of the path, we don't do that
4249  * here.
4250  * If it worked returns OK and the resolved link in "buf[MAXPATHL]".
4251  * Otherwise returns FAIL.
4252  */
4253     int
4254 resolve_symlink(char_u *fname, char_u *buf)
4255 {
4256     char_u	tmp[MAXPATHL];
4257     int		ret;
4258     int		depth = 0;
4259 
4260     if (fname == NULL)
4261 	return FAIL;
4262 
4263     // Put the result so far in tmp[], starting with the original name.
4264     vim_strncpy(tmp, fname, MAXPATHL - 1);
4265 
4266     for (;;)
4267     {
4268 	// Limit symlink depth to 100, catch recursive loops.
4269 	if (++depth == 100)
4270 	{
4271 	    semsg(_("E773: Symlink loop for \"%s\""), fname);
4272 	    return FAIL;
4273 	}
4274 
4275 	ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
4276 	if (ret <= 0)
4277 	{
4278 	    if (errno == EINVAL || errno == ENOENT)
4279 	    {
4280 		// Found non-symlink or not existing file, stop here.
4281 		// When at the first level use the unmodified name, skip the
4282 		// call to vim_FullName().
4283 		if (depth == 1)
4284 		    return FAIL;
4285 
4286 		// Use the resolved name in tmp[].
4287 		break;
4288 	    }
4289 
4290 	    // There must be some error reading links, use original name.
4291 	    return FAIL;
4292 	}
4293 	buf[ret] = NUL;
4294 
4295 	/*
4296 	 * Check whether the symlink is relative or absolute.
4297 	 * If it's relative, build a new path based on the directory
4298 	 * portion of the filename (if any) and the path the symlink
4299 	 * points to.
4300 	 */
4301 	if (mch_isFullName(buf))
4302 	    STRCPY(tmp, buf);
4303 	else
4304 	{
4305 	    char_u *tail;
4306 
4307 	    tail = gettail(tmp);
4308 	    if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
4309 		return FAIL;
4310 	    STRCPY(tail, buf);
4311 	}
4312     }
4313 
4314     /*
4315      * Try to resolve the full name of the file so that the swapfile name will
4316      * be consistent even when opening a relative symlink from different
4317      * working directories.
4318      */
4319     return vim_FullName(tmp, buf, MAXPATHL, TRUE);
4320 }
4321 #endif
4322 
4323 /*
4324  * Make swap file name out of the file name and a directory name.
4325  * Returns pointer to allocated memory or NULL.
4326  */
4327     char_u *
4328 makeswapname(
4329     char_u	*fname,
4330     char_u	*ffname UNUSED,
4331     buf_T	*buf,
4332     char_u	*dir_name)
4333 {
4334     char_u	*r, *s;
4335     char_u	*fname_res = fname;
4336 #ifdef HAVE_READLINK
4337     char_u	fname_buf[MAXPATHL];
4338 #endif
4339 
4340 #if defined(UNIX) || defined(MSWIN)  // Need _very_ long file names
4341     int		len = (int)STRLEN(dir_name);
4342 
4343     s = dir_name + len;
4344     if (after_pathsep(dir_name, s) && len > 1 && s[-1] == s[-2])
4345     {			       // Ends with '//', Use Full path
4346 	r = NULL;
4347 	if ((s = make_percent_swname(dir_name, fname)) != NULL)
4348 	{
4349 	    r = modname(s, (char_u *)".swp", FALSE);
4350 	    vim_free(s);
4351 	}
4352 	return r;
4353     }
4354 #endif
4355 
4356 #ifdef HAVE_READLINK
4357     // Expand symlink in the file name, so that we put the swap file with the
4358     // actual file instead of with the symlink.
4359     if (resolve_symlink(fname, fname_buf) == OK)
4360 	fname_res = fname_buf;
4361 #endif
4362 
4363     r = buf_modname(
4364 	    (buf->b_p_sn || buf->b_shortname),
4365 	    fname_res,
4366 	    (char_u *)
4367 #if defined(VMS)
4368 	    "_swp",
4369 #else
4370 	    ".swp",
4371 #endif
4372 	    // Prepend a '.' to the swap file name for the current directory.
4373 	    dir_name[0] == '.' && dir_name[1] == NUL);
4374     if (r == NULL)	    // out of memory
4375 	return NULL;
4376 
4377     s = get_file_in_dir(r, dir_name);
4378     vim_free(r);
4379     return s;
4380 }
4381 
4382 /*
4383  * Get file name to use for swap file or backup file.
4384  * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
4385  * option "dname".
4386  * - If "dname" is ".", return "fname" (swap file in dir of file).
4387  * - If "dname" starts with "./", insert "dname" in "fname" (swap file
4388  *   relative to dir of file).
4389  * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
4390  *   dir).
4391  *
4392  * The return value is an allocated string and can be NULL.
4393  */
4394     char_u *
4395 get_file_in_dir(
4396     char_u  *fname,
4397     char_u  *dname)	// don't use "dirname", it is a global for Alpha
4398 {
4399     char_u	*t;
4400     char_u	*tail;
4401     char_u	*retval;
4402     int		save_char;
4403 
4404     tail = gettail(fname);
4405 
4406     if (dname[0] == '.' && dname[1] == NUL)
4407 	retval = vim_strsave(fname);
4408     else if (dname[0] == '.' && vim_ispathsep(dname[1]))
4409     {
4410 	if (tail == fname)	    // no path before file name
4411 	    retval = concat_fnames(dname + 2, tail, TRUE);
4412 	else
4413 	{
4414 	    save_char = *tail;
4415 	    *tail = NUL;
4416 	    t = concat_fnames(fname, dname + 2, TRUE);
4417 	    *tail = save_char;
4418 	    if (t == NULL)	    // out of memory
4419 		retval = NULL;
4420 	    else
4421 	    {
4422 		retval = concat_fnames(t, tail, TRUE);
4423 		vim_free(t);
4424 	    }
4425 	}
4426     }
4427     else
4428 	retval = concat_fnames(dname, tail, TRUE);
4429 
4430 #ifdef MSWIN
4431     if (retval != NULL)
4432 	for (t = gettail(retval); *t != NUL; MB_PTR_ADV(t))
4433 	    if (*t == ':')
4434 		*t = '%';
4435 #endif
4436 
4437     return retval;
4438 }
4439 
4440 /*
4441  * Print the ATTENTION message: info about an existing swap file.
4442  */
4443     static void
4444 attention_message(
4445     buf_T   *buf,	// buffer being edited
4446     char_u  *fname)	// swap file name
4447 {
4448     stat_T	st;
4449     time_t	swap_mtime;
4450 
4451     ++no_wait_return;
4452     (void)emsg(_("E325: ATTENTION"));
4453     msg_puts(_("\nFound a swap file by the name \""));
4454     msg_home_replace(fname);
4455     msg_puts("\"\n");
4456     swap_mtime = swapfile_info(fname);
4457     msg_puts(_("While opening file \""));
4458     msg_outtrans(buf->b_fname);
4459     msg_puts("\"\n");
4460     if (mch_stat((char *)buf->b_fname, &st) == -1)
4461     {
4462 	msg_puts(_("      CANNOT BE FOUND"));
4463     }
4464     else
4465     {
4466 	msg_puts(_("             dated: "));
4467 	msg_puts(get_ctime(st.st_mtime, TRUE));
4468 	if (swap_mtime != 0 && st.st_mtime > swap_mtime)
4469 	    msg_puts(_("      NEWER than swap file!\n"));
4470     }
4471     // Some of these messages are long to allow translation to
4472     // other languages.
4473     msg_puts(_("\n(1) Another program may be editing the same file.  If this is the case,\n    be careful not to end up with two different instances of the same\n    file when making changes.  Quit, or continue with caution.\n"));
4474     msg_puts(_("(2) An edit session for this file crashed.\n"));
4475     msg_puts(_("    If this is the case, use \":recover\" or \"vim -r "));
4476     msg_outtrans(buf->b_fname);
4477     msg_puts(_("\"\n    to recover the changes (see \":help recovery\").\n"));
4478     msg_puts(_("    If you did this already, delete the swap file \""));
4479     msg_outtrans(fname);
4480     msg_puts(_("\"\n    to avoid this message.\n"));
4481     cmdline_row = msg_row;
4482     --no_wait_return;
4483 }
4484 
4485 #if defined(FEAT_EVAL)
4486 /*
4487  * Trigger the SwapExists autocommands.
4488  * Returns a value for equivalent to do_dialog() (see below):
4489  * 0: still need to ask for a choice
4490  * 1: open read-only
4491  * 2: edit anyway
4492  * 3: recover
4493  * 4: delete it
4494  * 5: quit
4495  * 6: abort
4496  */
4497     static int
4498 do_swapexists(buf_T *buf, char_u *fname)
4499 {
4500     set_vim_var_string(VV_SWAPNAME, fname, -1);
4501     set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
4502 
4503     // Trigger SwapExists autocommands with <afile> set to the file being
4504     // edited.  Disallow changing directory here.
4505     ++allbuf_lock;
4506     apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, FALSE, NULL);
4507     --allbuf_lock;
4508 
4509     set_vim_var_string(VV_SWAPNAME, NULL, -1);
4510 
4511     switch (*get_vim_var_str(VV_SWAPCHOICE))
4512     {
4513 	case 'o': return 1;
4514 	case 'e': return 2;
4515 	case 'r': return 3;
4516 	case 'd': return 4;
4517 	case 'q': return 5;
4518 	case 'a': return 6;
4519     }
4520 
4521     return 0;
4522 }
4523 #endif
4524 
4525 /*
4526  * Find out what name to use for the swap file for buffer 'buf'.
4527  *
4528  * Several names are tried to find one that does not exist
4529  * Returns the name in allocated memory or NULL.
4530  * When out of memory "dirp" is set to NULL.
4531  *
4532  * Note: If BASENAMELEN is not correct, you will get error messages for
4533  *	 not being able to open the swap or undo file
4534  * Note: May trigger SwapExists autocmd, pointers may change!
4535  */
4536     static char_u *
4537 findswapname(
4538     buf_T	*buf,
4539     char_u	**dirp,		// pointer to list of directories
4540     char_u	*old_fname)	// don't give warning for this file name
4541 {
4542     char_u	*fname;
4543     int		n;
4544     char_u	*dir_name;
4545 #ifdef AMIGA
4546     BPTR	fh;
4547 #endif
4548     int		r;
4549     char_u	*buf_fname = buf->b_fname;
4550 
4551 #if !defined(UNIX)
4552 # define CREATE_DUMMY_FILE
4553     FILE	*dummyfd = NULL;
4554 
4555 # ifdef MSWIN
4556     if (buf_fname != NULL && !mch_isFullName(buf_fname)
4557 				       && vim_strchr(gettail(buf_fname), ':'))
4558     {
4559 	char_u *t;
4560 
4561 	buf_fname = vim_strsave(buf_fname);
4562 	if (buf_fname == NULL)
4563 	    buf_fname = buf->b_fname;
4564 	else
4565 	    for (t = gettail(buf_fname); *t != NUL; MB_PTR_ADV(t))
4566 		if (*t == ':')
4567 		    *t = '%';
4568     }
4569 # endif
4570 
4571     /*
4572      * If we start editing a new file, e.g. "test.doc", which resides on an
4573      * MSDOS compatible filesystem, it is possible that the file
4574      * "test.doc.swp" which we create will be exactly the same file. To avoid
4575      * this problem we temporarily create "test.doc".  Don't do this when the
4576      * check below for a 8.3 file name is used.
4577      */
4578     if (!(buf->b_p_sn || buf->b_shortname) && buf_fname != NULL
4579 					     && mch_getperm(buf_fname) < 0)
4580 	dummyfd = mch_fopen((char *)buf_fname, "w");
4581 #endif
4582 
4583     /*
4584      * Isolate a directory name from *dirp and put it in dir_name.
4585      * First allocate some memory to put the directory name in.
4586      */
4587     dir_name = alloc(STRLEN(*dirp) + 1);
4588     if (dir_name == NULL)
4589 	*dirp = NULL;
4590     else
4591 	(void)copy_option_part(dirp, dir_name, 31000, ",");
4592 
4593     /*
4594      * we try different names until we find one that does not exist yet
4595      */
4596     if (dir_name == NULL)	    // out of memory
4597 	fname = NULL;
4598     else
4599 	fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name);
4600 
4601     for (;;)
4602     {
4603 	if (fname == NULL)	// must be out of memory
4604 	    break;
4605 	if ((n = (int)STRLEN(fname)) == 0)	// safety check
4606 	{
4607 	    VIM_CLEAR(fname);
4608 	    break;
4609 	}
4610 #if defined(UNIX)
4611 /*
4612  * Some systems have a MS-DOS compatible filesystem that use 8.3 character
4613  * file names. If this is the first try and the swap file name does not fit in
4614  * 8.3, detect if this is the case, set shortname and try again.
4615  */
4616 	if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
4617 					&& !(buf->b_p_sn || buf->b_shortname))
4618 	{
4619 	    char_u	    *tail;
4620 	    char_u	    *fname2;
4621 	    stat_T	    s1, s2;
4622 	    int		    f1, f2;
4623 	    int		    created1 = FALSE, created2 = FALSE;
4624 	    int		    same = FALSE;
4625 
4626 	    /*
4627 	     * Check if swapfile name does not fit in 8.3:
4628 	     * It either contains two dots, is longer than 8 chars, or starts
4629 	     * with a dot.
4630 	     */
4631 	    tail = gettail(buf_fname);
4632 	    if (       vim_strchr(tail, '.') != NULL
4633 		    || STRLEN(tail) > (size_t)8
4634 		    || *gettail(fname) == '.')
4635 	    {
4636 		fname2 = alloc(n + 2);
4637 		if (fname2 != NULL)
4638 		{
4639 		    STRCPY(fname2, fname);
4640 		    // if fname == "xx.xx.swp",	    fname2 = "xx.xx.swx"
4641 		    // if fname == ".xx.swp",	    fname2 = ".xx.swpx"
4642 		    // if fname == "123456789.swp", fname2 = "12345678x.swp"
4643 		    if (vim_strchr(tail, '.') != NULL)
4644 			fname2[n - 1] = 'x';
4645 		    else if (*gettail(fname) == '.')
4646 		    {
4647 			fname2[n] = 'x';
4648 			fname2[n + 1] = NUL;
4649 		    }
4650 		    else
4651 			fname2[n - 5] += 1;
4652 		    /*
4653 		     * may need to create the files to be able to use mch_stat()
4654 		     */
4655 		    f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
4656 		    if (f1 < 0)
4657 		    {
4658 			f1 = mch_open_rw((char *)fname,
4659 					       O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
4660 			created1 = TRUE;
4661 		    }
4662 		    if (f1 >= 0)
4663 		    {
4664 			f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
4665 			if (f2 < 0)
4666 			{
4667 			    f2 = mch_open_rw((char *)fname2,
4668 					       O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
4669 			    created2 = TRUE;
4670 			}
4671 			if (f2 >= 0)
4672 			{
4673 			    /*
4674 			     * Both files exist now. If mch_stat() returns the
4675 			     * same device and inode they are the same file.
4676 			     */
4677 			    if (mch_fstat(f1, &s1) != -1
4678 				    && mch_fstat(f2, &s2) != -1
4679 				    && s1.st_dev == s2.st_dev
4680 				    && s1.st_ino == s2.st_ino)
4681 				same = TRUE;
4682 			    close(f2);
4683 			    if (created2)
4684 				mch_remove(fname2);
4685 			}
4686 			close(f1);
4687 			if (created1)
4688 			    mch_remove(fname);
4689 		    }
4690 		    vim_free(fname2);
4691 		    if (same)
4692 		    {
4693 			buf->b_shortname = TRUE;
4694 			vim_free(fname);
4695 			fname = makeswapname(buf_fname, buf->b_ffname,
4696 							       buf, dir_name);
4697 			continue;	// try again with b_shortname set
4698 		    }
4699 		}
4700 	    }
4701 	}
4702 #endif
4703 	/*
4704 	 * check if the swapfile already exists
4705 	 */
4706 	if (mch_getperm(fname) < 0)	// it does not exist
4707 	{
4708 #ifdef HAVE_LSTAT
4709 	    stat_T	sb;
4710 
4711 	    /*
4712 	     * Extra security check: When a swap file is a symbolic link, this
4713 	     * is most likely a symlink attack.
4714 	     */
4715 	    if (mch_lstat((char *)fname, &sb) < 0)
4716 #else
4717 # ifdef AMIGA
4718 	    fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
4719 	    /*
4720 	     * on the Amiga mch_getperm() will return -1 when the file exists
4721 	     * but is being used by another program. This happens if you edit
4722 	     * a file twice.
4723 	     */
4724 	    if (fh != (BPTR)NULL)	// can open file, OK
4725 	    {
4726 		Close(fh);
4727 		mch_remove(fname);
4728 		break;
4729 	    }
4730 	    if (IoErr() != ERROR_OBJECT_IN_USE
4731 					    && IoErr() != ERROR_OBJECT_EXISTS)
4732 # endif
4733 #endif
4734 		break;
4735 	}
4736 
4737 	/*
4738 	 * A file name equal to old_fname is OK to use.
4739 	 */
4740 	if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
4741 	    break;
4742 
4743 	/*
4744 	 * get here when file already exists
4745 	 */
4746 	if (fname[n - 2] == 'w' && fname[n - 1] == 'p')	// first try
4747 	{
4748 	    /*
4749 	     * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
4750 	     * and file.doc are the same file. To guess if this problem is
4751 	     * present try if file.doc.swx exists. If it does, we set
4752 	     * buf->b_shortname and try file_doc.swp (dots replaced by
4753 	     * underscores for this file), and try again. If it doesn't we
4754 	     * assume that "file.doc.swp" already exists.
4755 	     */
4756 	    if (!(buf->b_p_sn || buf->b_shortname))	// not tried yet
4757 	    {
4758 		fname[n - 1] = 'x';
4759 		r = mch_getperm(fname);		// try "file.swx"
4760 		fname[n - 1] = 'p';
4761 		if (r >= 0)		    // "file.swx" seems to exist
4762 		{
4763 		    buf->b_shortname = TRUE;
4764 		    vim_free(fname);
4765 		    fname = makeswapname(buf_fname, buf->b_ffname,
4766 							       buf, dir_name);
4767 		    continue;	    // try again with '.' replaced with '_'
4768 		}
4769 	    }
4770 	    /*
4771 	     * If we get here the ".swp" file really exists.
4772 	     * Give an error message, unless recovering, no file name, we are
4773 	     * viewing a help file or when the path of the file is different
4774 	     * (happens when all .swp files are in one directory).
4775 	     */
4776 	    if (!recoverymode && buf_fname != NULL
4777 				&& !buf->b_help
4778 				&& !(buf->b_flags & (BF_DUMMY | BF_NO_SEA)))
4779 	    {
4780 		int		fd;
4781 		struct block0	b0;
4782 		int		differ = FALSE;
4783 
4784 		/*
4785 		 * Try to read block 0 from the swap file to get the original
4786 		 * file name (and inode number).
4787 		 */
4788 		fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
4789 		if (fd >= 0)
4790 		{
4791 		    if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
4792 		    {
4793 			/*
4794 			 * If the swapfile has the same directory as the
4795 			 * buffer don't compare the directory names, they can
4796 			 * have a different mountpoint.
4797 			 */
4798 			if (b0.b0_flags & B0_SAME_DIR)
4799 			{
4800 			    if (fnamecmp(gettail(buf->b_ffname),
4801 						   gettail(b0.b0_fname)) != 0
4802 				    || !same_directory(fname, buf->b_ffname))
4803 			    {
4804 #ifdef CHECK_INODE
4805 				// Symlinks may point to the same file even
4806 				// when the name differs, need to check the
4807 				// inode too.
4808 				expand_env(b0.b0_fname, NameBuff, MAXPATHL);
4809 				if (fnamecmp_ino(buf->b_ffname, NameBuff,
4810 						     char_to_long(b0.b0_ino)))
4811 #endif
4812 				    differ = TRUE;
4813 			    }
4814 			}
4815 			else
4816 			{
4817 			    /*
4818 			     * The name in the swap file may be
4819 			     * "~user/path/file".  Expand it first.
4820 			     */
4821 			    expand_env(b0.b0_fname, NameBuff, MAXPATHL);
4822 #ifdef CHECK_INODE
4823 			    if (fnamecmp_ino(buf->b_ffname, NameBuff,
4824 						     char_to_long(b0.b0_ino)))
4825 				differ = TRUE;
4826 #else
4827 			    if (fnamecmp(NameBuff, buf->b_ffname) != 0)
4828 				differ = TRUE;
4829 #endif
4830 			}
4831 		    }
4832 		    close(fd);
4833 		}
4834 
4835 		// give the ATTENTION message when there is an old swap file
4836 		// for the current file, and the buffer was not recovered.
4837 		if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
4838 			&& vim_strchr(p_shm, SHM_ATTENTION) == NULL)
4839 		{
4840 		    int		choice = 0;
4841 		    stat_T	st;
4842 #ifdef CREATE_DUMMY_FILE
4843 		    int		did_use_dummy = FALSE;
4844 
4845 		    // Avoid getting a warning for the file being created
4846 		    // outside of Vim, it was created at the start of this
4847 		    // function.  Delete the file now, because Vim might exit
4848 		    // here if the window is closed.
4849 		    if (dummyfd != NULL)
4850 		    {
4851 			fclose(dummyfd);
4852 			dummyfd = NULL;
4853 			mch_remove(buf_fname);
4854 			did_use_dummy = TRUE;
4855 		    }
4856 #endif
4857 
4858 #ifdef HAVE_PROCESS_STILL_RUNNING
4859 		    process_still_running = FALSE;
4860 #endif
4861 		    // It's safe to delete the swap file if all these are true:
4862 		    // - the edited file exists
4863 		    // - the swap file has no changes and looks OK
4864 		    if (mch_stat((char *)buf->b_fname, &st) == 0
4865 						  && swapfile_unchanged(fname))
4866 		    {
4867 			choice = 4;
4868 			if (p_verbose > 0)
4869 			    verb_msg(_("Found a swap file that is not useful, deleting it"));
4870 		    }
4871 
4872 #if defined(FEAT_EVAL)
4873 		    /*
4874 		     * If there is an SwapExists autocommand and we can handle
4875 		     * the response, trigger it.  It may return 0 to ask the
4876 		     * user anyway.
4877 		     */
4878 		    if (choice == 0
4879 			    && swap_exists_action != SEA_NONE
4880 			    && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
4881 			choice = do_swapexists(buf, fname);
4882 
4883 		    if (choice == 0)
4884 #endif
4885 		    {
4886 #ifdef FEAT_GUI
4887 			// If we are supposed to start the GUI but it wasn't
4888 			// completely started yet, start it now.  This makes
4889 			// the messages displayed in the Vim window when
4890 			// loading a session from the .gvimrc file.
4891 			if (gui.starting && !gui.in_use)
4892 			    gui_start(NULL);
4893 #endif
4894 			// Show info about the existing swap file.
4895 			attention_message(buf, fname);
4896 
4897 			// We don't want a 'q' typed at the more-prompt
4898 			// interrupt loading a file.
4899 			got_int = FALSE;
4900 
4901 			// If vimrc has "simalt ~x" we don't want it to
4902 			// interfere with the prompt here.
4903 			flush_buffers(FLUSH_TYPEAHEAD);
4904 		    }
4905 
4906 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
4907 		    if (swap_exists_action != SEA_NONE && choice == 0)
4908 		    {
4909 			char_u	*name;
4910 
4911 			name = alloc(STRLEN(fname)
4912 				+ STRLEN(_("Swap file \""))
4913 				+ STRLEN(_("\" already exists!")) + 5);
4914 			if (name != NULL)
4915 			{
4916 			    STRCPY(name, _("Swap file \""));
4917 			    home_replace(NULL, fname, name + STRLEN(name),
4918 								  1000, TRUE);
4919 			    STRCAT(name, _("\" already exists!"));
4920 			}
4921 			choice = do_dialog(VIM_WARNING,
4922 				    (char_u *)_("VIM - ATTENTION"),
4923 				    name == NULL
4924 					?  (char_u *)_("Swap file already exists!")
4925 					: name,
4926 # ifdef HAVE_PROCESS_STILL_RUNNING
4927 				    process_still_running
4928 					? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") :
4929 # endif
4930 					(char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, FALSE);
4931 
4932 # ifdef HAVE_PROCESS_STILL_RUNNING
4933 			if (process_still_running && choice >= 4)
4934 			    choice++;	// Skip missing "Delete it" button
4935 # endif
4936 			vim_free(name);
4937 
4938 			// pretend screen didn't scroll, need redraw anyway
4939 			msg_scrolled = 0;
4940 			redraw_all_later(NOT_VALID);
4941 		    }
4942 #endif
4943 
4944 		    if (choice > 0)
4945 		    {
4946 			switch (choice)
4947 			{
4948 			    case 1:
4949 				buf->b_p_ro = TRUE;
4950 				break;
4951 			    case 2:
4952 				break;
4953 			    case 3:
4954 				swap_exists_action = SEA_RECOVER;
4955 				break;
4956 			    case 4:
4957 				mch_remove(fname);
4958 				break;
4959 			    case 5:
4960 				swap_exists_action = SEA_QUIT;
4961 				break;
4962 			    case 6:
4963 				swap_exists_action = SEA_QUIT;
4964 				got_int = TRUE;
4965 				break;
4966 			}
4967 
4968 			// If the file was deleted this fname can be used.
4969 			if (mch_getperm(fname) < 0)
4970 			    break;
4971 		    }
4972 		    else
4973 		    {
4974 			msg_puts("\n");
4975 			if (msg_silent == 0)
4976 			    // call wait_return() later
4977 			    need_wait_return = TRUE;
4978 		    }
4979 
4980 #ifdef CREATE_DUMMY_FILE
4981 		    // Going to try another name, need the dummy file again.
4982 		    if (did_use_dummy)
4983 			dummyfd = mch_fopen((char *)buf_fname, "w");
4984 #endif
4985 		}
4986 	    }
4987 	}
4988 
4989 	/*
4990 	 * Change the ".swp" extension to find another file that can be used.
4991 	 * First decrement the last char: ".swo", ".swn", etc.
4992 	 * If that still isn't enough decrement the last but one char: ".svz"
4993 	 * Can happen when editing many "No Name" buffers.
4994 	 */
4995 	if (fname[n - 1] == 'a')	// ".s?a"
4996 	{
4997 	    if (fname[n - 2] == 'a')    // ".saa": tried enough, give up
4998 	    {
4999 		emsg(_("E326: Too many swap files found"));
5000 		VIM_CLEAR(fname);
5001 		break;
5002 	    }
5003 	    --fname[n - 2];		// ".svz", ".suz", etc.
5004 	    fname[n - 1] = 'z' + 1;
5005 	}
5006 	--fname[n - 1];			// ".swo", ".swn", etc.
5007     }
5008 
5009     vim_free(dir_name);
5010 #ifdef CREATE_DUMMY_FILE
5011     if (dummyfd != NULL)	// file has been created temporarily
5012     {
5013 	fclose(dummyfd);
5014 	mch_remove(buf_fname);
5015     }
5016 #endif
5017 #ifdef MSWIN
5018     if (buf_fname != buf->b_fname)
5019 	vim_free(buf_fname);
5020 #endif
5021     return fname;
5022 }
5023 
5024     static int
5025 b0_magic_wrong(ZERO_BL *b0p)
5026 {
5027     return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
5028 	    || b0p->b0_magic_int != (int)B0_MAGIC_INT
5029 	    || b0p->b0_magic_short != (short)B0_MAGIC_SHORT
5030 	    || b0p->b0_magic_char != B0_MAGIC_CHAR);
5031 }
5032 
5033 #ifdef CHECK_INODE
5034 /*
5035  * Compare current file name with file name from swap file.
5036  * Try to use inode numbers when possible.
5037  * Return non-zero when files are different.
5038  *
5039  * When comparing file names a few things have to be taken into consideration:
5040  * - When working over a network the full path of a file depends on the host.
5041  *   We check the inode number if possible.  It is not 100% reliable though,
5042  *   because the device number cannot be used over a network.
5043  * - When a file does not exist yet (editing a new file) there is no inode
5044  *   number.
5045  * - The file name in a swap file may not be valid on the current host.  The
5046  *   "~user" form is used whenever possible to avoid this.
5047  *
5048  * This is getting complicated, let's make a table:
5049  *
5050  *		ino_c  ino_s  fname_c  fname_s	differ =
5051  *
5052  * both files exist -> compare inode numbers:
5053  *		!= 0   != 0	X	 X	ino_c != ino_s
5054  *
5055  * inode number(s) unknown, file names available -> compare file names
5056  *		== 0	X	OK	 OK	fname_c != fname_s
5057  *		 X     == 0	OK	 OK	fname_c != fname_s
5058  *
5059  * current file doesn't exist, file for swap file exist, file name(s) not
5060  * available -> probably different
5061  *		== 0   != 0    FAIL	 X	TRUE
5062  *		== 0   != 0	X	FAIL	TRUE
5063  *
5064  * current file exists, inode for swap unknown, file name(s) not
5065  * available -> probably different
5066  *		!= 0   == 0    FAIL	 X	TRUE
5067  *		!= 0   == 0	X	FAIL	TRUE
5068  *
5069  * current file doesn't exist, inode for swap unknown, one file name not
5070  * available -> probably different
5071  *		== 0   == 0    FAIL	 OK	TRUE
5072  *		== 0   == 0	OK	FAIL	TRUE
5073  *
5074  * current file doesn't exist, inode for swap unknown, both file names not
5075  * available -> compare file names
5076  *		== 0   == 0    FAIL	FAIL	fname_c != fname_s
5077  *
5078  * Note that when the ino_t is 64 bits, only the last 32 will be used.  This
5079  * can't be changed without making the block 0 incompatible with 32 bit
5080  * versions.
5081  */
5082 
5083     static int
5084 fnamecmp_ino(
5085     char_u	*fname_c,	    // current file name
5086     char_u	*fname_s,	    // file name from swap file
5087     long	ino_block0)
5088 {
5089     stat_T	st;
5090     ino_t	ino_c = 0;	    // ino of current file
5091     ino_t	ino_s;		    // ino of file from swap file
5092     char_u	buf_c[MAXPATHL];    // full path of fname_c
5093     char_u	buf_s[MAXPATHL];    // full path of fname_s
5094     int		retval_c;	    // flag: buf_c valid
5095     int		retval_s;	    // flag: buf_s valid
5096 
5097     if (mch_stat((char *)fname_c, &st) == 0)
5098 	ino_c = (ino_t)st.st_ino;
5099 
5100     /*
5101      * First we try to get the inode from the file name, because the inode in
5102      * the swap file may be outdated.  If that fails (e.g. this path is not
5103      * valid on this machine), use the inode from block 0.
5104      */
5105     if (mch_stat((char *)fname_s, &st) == 0)
5106 	ino_s = (ino_t)st.st_ino;
5107     else
5108 	ino_s = (ino_t)ino_block0;
5109 
5110     if (ino_c && ino_s)
5111 	return (ino_c != ino_s);
5112 
5113     /*
5114      * One of the inode numbers is unknown, try a forced vim_FullName() and
5115      * compare the file names.
5116      */
5117     retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
5118     retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
5119     if (retval_c == OK && retval_s == OK)
5120 	return STRCMP(buf_c, buf_s) != 0;
5121 
5122     /*
5123      * Can't compare inodes or file names, guess that the files are different,
5124      * unless both appear not to exist at all, then compare with the file name
5125      * in the swap file.
5126      */
5127     if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
5128 	return STRCMP(fname_c, fname_s) != 0;
5129     return TRUE;
5130 }
5131 #endif // CHECK_INODE
5132 
5133 /*
5134  * Move a long integer into a four byte character array.
5135  * Used for machine independency in block zero.
5136  */
5137     static void
5138 long_to_char(long n, char_u *s)
5139 {
5140     s[0] = (char_u)(n & 0xff);
5141     n = (unsigned)n >> 8;
5142     s[1] = (char_u)(n & 0xff);
5143     n = (unsigned)n >> 8;
5144     s[2] = (char_u)(n & 0xff);
5145     n = (unsigned)n >> 8;
5146     s[3] = (char_u)(n & 0xff);
5147 }
5148 
5149     static long
5150 char_to_long(char_u *s)
5151 {
5152     long    retval;
5153 
5154     retval = s[3];
5155     retval <<= 8;
5156     retval |= s[2];
5157     retval <<= 8;
5158     retval |= s[1];
5159     retval <<= 8;
5160     retval |= s[0];
5161 
5162     return retval;
5163 }
5164 
5165 /*
5166  * Set the flags in the first block of the swap file:
5167  * - file is modified or not: buf->b_changed
5168  * - 'fileformat'
5169  * - 'fileencoding'
5170  */
5171     void
5172 ml_setflags(buf_T *buf)
5173 {
5174     bhdr_T	*hp;
5175     ZERO_BL	*b0p;
5176 
5177     if (!buf->b_ml.ml_mfp)
5178 	return;
5179     for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
5180     {
5181 	if (hp->bh_bnum == 0)
5182 	{
5183 	    b0p = (ZERO_BL *)(hp->bh_data);
5184 	    b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
5185 	    b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
5186 						  | (get_fileformat(buf) + 1);
5187 	    add_b0_fenc(b0p, buf);
5188 	    hp->bh_flags |= BH_DIRTY;
5189 	    mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
5190 	    break;
5191 	}
5192     }
5193 }
5194 
5195 #if defined(FEAT_CRYPT) || defined(PROTO)
5196 /*
5197  * If "data" points to a data block encrypt the text in it and return a copy
5198  * in allocated memory.  Return NULL when out of memory.
5199  * Otherwise return "data".
5200  */
5201     char_u *
5202 ml_encrypt_data(
5203     memfile_T	*mfp,
5204     char_u	*data,
5205     off_T	offset,
5206     unsigned	size)
5207 {
5208     DATA_BL	*dp = (DATA_BL *)data;
5209     char_u	*head_end;
5210     char_u	*text_start;
5211     char_u	*new_data;
5212     int		text_len;
5213     cryptstate_T *state;
5214 
5215     if (dp->db_id != DATA_ID)
5216 	return data;
5217 
5218     state = ml_crypt_prepare(mfp, offset, FALSE);
5219     if (state == NULL)
5220 	return data;
5221 
5222     new_data = alloc(size);
5223     if (new_data == NULL)
5224 	return NULL;
5225     head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
5226     text_start = (char_u *)dp + dp->db_txt_start;
5227     text_len = size - dp->db_txt_start;
5228 
5229     // Copy the header and the text.
5230     mch_memmove(new_data, dp, head_end - (char_u *)dp);
5231 
5232     // Encrypt the text.
5233     crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
5234     crypt_free_state(state);
5235 
5236     // Clear the gap.
5237     if (head_end < text_start)
5238 	vim_memset(new_data + (head_end - data), 0, text_start - head_end);
5239 
5240     return new_data;
5241 }
5242 
5243 /*
5244  * Decrypt the text in "data" if it points to an encrypted data block.
5245  */
5246     void
5247 ml_decrypt_data(
5248     memfile_T	*mfp,
5249     char_u	*data,
5250     off_T	offset,
5251     unsigned	size)
5252 {
5253     DATA_BL	*dp = (DATA_BL *)data;
5254     char_u	*head_end;
5255     char_u	*text_start;
5256     int		text_len;
5257     cryptstate_T *state;
5258 
5259     if (dp->db_id == DATA_ID)
5260     {
5261 	head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
5262 	text_start = (char_u *)dp + dp->db_txt_start;
5263 	text_len = dp->db_txt_end - dp->db_txt_start;
5264 
5265 	if (head_end > text_start || dp->db_txt_start > size
5266 						     || dp->db_txt_end > size)
5267 	    return;  // data was messed up
5268 
5269 	state = ml_crypt_prepare(mfp, offset, TRUE);
5270 	if (state != NULL)
5271 	{
5272 	    // Decrypt the text in place.
5273 	    crypt_decode_inplace(state, text_start, text_len);
5274 	    crypt_free_state(state);
5275 	}
5276     }
5277 }
5278 
5279 /*
5280  * Prepare for encryption/decryption, using the key, seed and offset.
5281  * Return an allocated cryptstate_T *.
5282  */
5283     static cryptstate_T *
5284 ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
5285 {
5286     buf_T	*buf = mfp->mf_buffer;
5287     char_u	salt[50];
5288     int		method_nr;
5289     char_u	*key;
5290     char_u	*seed;
5291 
5292     if (reading && mfp->mf_old_key != NULL)
5293     {
5294 	// Reading back blocks with the previous key/method/seed.
5295 	method_nr = mfp->mf_old_cm;
5296 	key = mfp->mf_old_key;
5297 	seed = mfp->mf_old_seed;
5298     }
5299     else
5300     {
5301 	method_nr = crypt_get_method_nr(buf);
5302 	key = buf->b_p_key;
5303 	seed = mfp->mf_seed;
5304     }
5305     if (*key == NUL)
5306 	return NULL;
5307 
5308     if (method_nr == CRYPT_M_ZIP)
5309     {
5310 	// For PKzip: Append the offset to the key, so that we use a different
5311 	// key for every block.
5312 	vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
5313 	return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
5314     }
5315 
5316     // Using blowfish or better: add salt and seed. We use the byte offset
5317     // of the block for the salt.
5318     vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
5319     return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
5320 							   seed, MF_SEED_LEN);
5321 }
5322 
5323 #endif
5324 
5325 
5326 #if defined(FEAT_BYTEOFF) || defined(PROTO)
5327 
5328 #define MLCS_MAXL 800	// max no of lines in chunk
5329 #define MLCS_MINL 400   // should be half of MLCS_MAXL
5330 
5331 /*
5332  * Keep information for finding byte offset of a line, updtype may be one of:
5333  * ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
5334  *	   Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
5335  * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
5336  * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
5337  */
5338     static void
5339 ml_updatechunk(
5340     buf_T	*buf,
5341     linenr_T	line,
5342     long	len,
5343     int		updtype)
5344 {
5345     static buf_T	*ml_upd_lastbuf = NULL;
5346     static linenr_T	ml_upd_lastline;
5347     static linenr_T	ml_upd_lastcurline;
5348     static int		ml_upd_lastcurix;
5349 
5350     linenr_T		curline = ml_upd_lastcurline;
5351     int			curix = ml_upd_lastcurix;
5352     long		size;
5353     chunksize_T		*curchnk;
5354     int			rest;
5355     bhdr_T		*hp;
5356     DATA_BL		*dp;
5357 
5358     if (buf->b_ml.ml_usedchunks == -1 || len == 0)
5359 	return;
5360     if (buf->b_ml.ml_chunksize == NULL)
5361     {
5362 	buf->b_ml.ml_chunksize = ALLOC_MULT(chunksize_T, 100);
5363 	if (buf->b_ml.ml_chunksize == NULL)
5364 	{
5365 	    buf->b_ml.ml_usedchunks = -1;
5366 	    return;
5367 	}
5368 	buf->b_ml.ml_numchunks = 100;
5369 	buf->b_ml.ml_usedchunks = 1;
5370 	buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
5371 	buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
5372     }
5373 
5374     if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
5375     {
5376 	/*
5377 	 * First line in empty buffer from ml_flush_line() -- reset
5378 	 */
5379 	buf->b_ml.ml_usedchunks = 1;
5380 	buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
5381 	buf->b_ml.ml_chunksize[0].mlcs_totalsize = (long)buf->b_ml.ml_line_len;
5382 	return;
5383     }
5384 
5385     /*
5386      * Find chunk that our line belongs to, curline will be at start of the
5387      * chunk.
5388      */
5389     if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
5390 	    || updtype != ML_CHNK_ADDLINE)
5391     {
5392 	for (curline = 1, curix = 0;
5393 	     curix < buf->b_ml.ml_usedchunks - 1
5394 	     && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5395 	     curix++)
5396 	    curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5397     }
5398     else if (curix < buf->b_ml.ml_usedchunks - 1
5399 	      && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
5400     {
5401 	// Adjust cached curix & curline
5402 	curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5403 	curix++;
5404     }
5405     curchnk = buf->b_ml.ml_chunksize + curix;
5406 
5407     if (updtype == ML_CHNK_DELLINE)
5408 	len = -len;
5409     curchnk->mlcs_totalsize += len;
5410     if (updtype == ML_CHNK_ADDLINE)
5411     {
5412 	curchnk->mlcs_numlines++;
5413 
5414 	// May resize here so we don't have to do it in both cases below
5415 	if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
5416 	{
5417 	    chunksize_T *t_chunksize = buf->b_ml.ml_chunksize;
5418 
5419 	    buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
5420 	    buf->b_ml.ml_chunksize = (chunksize_T *)
5421 		vim_realloc(buf->b_ml.ml_chunksize,
5422 			    sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
5423 	    if (buf->b_ml.ml_chunksize == NULL)
5424 	    {
5425 		// Hmmmm, Give up on offset for this buffer
5426 		vim_free(t_chunksize);
5427 		buf->b_ml.ml_usedchunks = -1;
5428 		return;
5429 	    }
5430 	}
5431 
5432 	if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
5433 	{
5434 	    int	    count;	    // number of entries in block
5435 	    int	    idx;
5436 	    int	    end_idx;
5437 	    int	    text_end;
5438 	    int	    linecnt;
5439 
5440 	    mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
5441 			buf->b_ml.ml_chunksize + curix,
5442 			(buf->b_ml.ml_usedchunks - curix) *
5443 			sizeof(chunksize_T));
5444 	    // Compute length of first half of lines in the split chunk
5445 	    size = 0;
5446 	    linecnt = 0;
5447 	    while (curline < buf->b_ml.ml_line_count
5448 			&& linecnt < MLCS_MINL)
5449 	    {
5450 		if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
5451 		{
5452 		    buf->b_ml.ml_usedchunks = -1;
5453 		    return;
5454 		}
5455 		dp = (DATA_BL *)(hp->bh_data);
5456 		count = (long)(buf->b_ml.ml_locked_high) -
5457 			(long)(buf->b_ml.ml_locked_low) + 1;
5458 		idx = curline - buf->b_ml.ml_locked_low;
5459 		curline = buf->b_ml.ml_locked_high + 1;
5460 
5461 		// compute index of last line to use in this MEMLINE
5462 		rest = count - idx;
5463 		if (linecnt + rest > MLCS_MINL)
5464 		{
5465 		    end_idx = idx + MLCS_MINL - linecnt - 1;
5466 		    linecnt = MLCS_MINL;
5467 		}
5468 		else
5469 		{
5470 		    end_idx = count - 1;
5471 		    linecnt += rest;
5472 		}
5473 #ifdef FEAT_PROP_POPUP
5474 		if (buf->b_has_textprop)
5475 		{
5476 		    int i;
5477 
5478 		    // We cannot use the text pointers to get the text length,
5479 		    // the text prop info would also be counted.  Go over the
5480 		    // lines.
5481 		    for (i = end_idx; i < idx; ++i)
5482 			size += (int)STRLEN((char_u *)dp + (dp->db_index[i] & DB_INDEX_MASK)) + 1;
5483 		}
5484 		else
5485 #endif
5486 		{
5487 		    if (idx == 0)// first line in block, text at the end
5488 			text_end = dp->db_txt_end;
5489 		    else
5490 			text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5491 		    size += text_end - ((dp->db_index[end_idx]) & DB_INDEX_MASK);
5492 		}
5493 	    }
5494 	    buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
5495 	    buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
5496 	    buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
5497 	    buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
5498 	    buf->b_ml.ml_usedchunks++;
5499 	    ml_upd_lastbuf = NULL;   // Force recalc of curix & curline
5500 	    return;
5501 	}
5502 	else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
5503 		     && curix == buf->b_ml.ml_usedchunks - 1
5504 		     && buf->b_ml.ml_line_count - line <= 1)
5505 	{
5506 	    /*
5507 	     * We are in the last chunk and it is cheap to crate a new one
5508 	     * after this. Do it now to avoid the loop above later on
5509 	     */
5510 	    curchnk = buf->b_ml.ml_chunksize + curix + 1;
5511 	    buf->b_ml.ml_usedchunks++;
5512 	    if (line == buf->b_ml.ml_line_count)
5513 	    {
5514 		curchnk->mlcs_numlines = 0;
5515 		curchnk->mlcs_totalsize = 0;
5516 	    }
5517 	    else
5518 	    {
5519 		/*
5520 		 * Line is just prior to last, move count for last
5521 		 * This is the common case  when loading a new file
5522 		 */
5523 		hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
5524 		if (hp == NULL)
5525 		{
5526 		    buf->b_ml.ml_usedchunks = -1;
5527 		    return;
5528 		}
5529 		dp = (DATA_BL *)(hp->bh_data);
5530 		if (dp->db_line_count == 1)
5531 		    rest = dp->db_txt_end - dp->db_txt_start;
5532 		else
5533 		    rest =
5534 			((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
5535 			- dp->db_txt_start;
5536 		curchnk->mlcs_totalsize = rest;
5537 		curchnk->mlcs_numlines = 1;
5538 		curchnk[-1].mlcs_totalsize -= rest;
5539 		curchnk[-1].mlcs_numlines -= 1;
5540 	    }
5541 	}
5542     }
5543     else if (updtype == ML_CHNK_DELLINE)
5544     {
5545 	curchnk->mlcs_numlines--;
5546 	ml_upd_lastbuf = NULL;   // Force recalc of curix & curline
5547 	if (curix < (buf->b_ml.ml_usedchunks - 1)
5548 		&& (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
5549 		   <= MLCS_MINL)
5550 	{
5551 	    curix++;
5552 	    curchnk = buf->b_ml.ml_chunksize + curix;
5553 	}
5554 	else if (curix == 0 && curchnk->mlcs_numlines <= 0)
5555 	{
5556 	    buf->b_ml.ml_usedchunks--;
5557 	    mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
5558 			buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
5559 	    return;
5560 	}
5561 	else if (curix == 0 || (curchnk->mlcs_numlines > 10
5562 		    && (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
5563 		       > MLCS_MINL))
5564 	{
5565 	    return;
5566 	}
5567 
5568 	// Collapse chunks
5569 	curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
5570 	curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
5571 	buf->b_ml.ml_usedchunks--;
5572 	if (curix < buf->b_ml.ml_usedchunks)
5573 	{
5574 	    mch_memmove(buf->b_ml.ml_chunksize + curix,
5575 			buf->b_ml.ml_chunksize + curix + 1,
5576 			(buf->b_ml.ml_usedchunks - curix) *
5577 			sizeof(chunksize_T));
5578 	}
5579 	return;
5580     }
5581     ml_upd_lastbuf = buf;
5582     ml_upd_lastline = line;
5583     ml_upd_lastcurline = curline;
5584     ml_upd_lastcurix = curix;
5585 }
5586 
5587 /*
5588  * Find offset for line or line with offset.
5589  * Find line with offset if "lnum" is 0; return remaining offset in offp
5590  * Find offset of line if "lnum" > 0
5591  * return -1 if information is not available
5592  */
5593     long
5594 ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp)
5595 {
5596     linenr_T	curline;
5597     int		curix;
5598     long	size;
5599     bhdr_T	*hp;
5600     DATA_BL	*dp;
5601     int		count;		// number of entries in block
5602     int		idx;
5603     int		start_idx;
5604     int		text_end;
5605     long	offset;
5606     int		len;
5607     int		ffdos = (get_fileformat(buf) == EOL_DOS);
5608     int		extra = 0;
5609 
5610     // take care of cached line first
5611     ml_flush_line(curbuf);
5612 
5613     if (buf->b_ml.ml_usedchunks == -1
5614 	    || buf->b_ml.ml_chunksize == NULL
5615 	    || lnum < 0)
5616 	return -1;
5617 
5618     if (offp == NULL)
5619 	offset = 0;
5620     else
5621 	offset = *offp;
5622     if (lnum == 0 && offset <= 0)
5623 	return 1;   // Not a "find offset" and offset 0 _must_ be in line 1
5624     /*
5625      * Find the last chunk before the one containing our line. Last chunk is
5626      * special because it will never qualify
5627      */
5628     curline = 1;
5629     curix = size = 0;
5630     while (curix < buf->b_ml.ml_usedchunks - 1
5631 	    && ((lnum != 0
5632 	     && lnum >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
5633 		|| (offset != 0
5634 	       && offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
5635 		      + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
5636     {
5637 	curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5638 	size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
5639 	if (offset && ffdos)
5640 	    size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5641 	curix++;
5642     }
5643 
5644     while ((lnum != 0 && curline < lnum) || (offset != 0 && size < offset))
5645     {
5646 	if (curline > buf->b_ml.ml_line_count
5647 		|| (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
5648 	    return -1;
5649 	dp = (DATA_BL *)(hp->bh_data);
5650 	count = (long)(buf->b_ml.ml_locked_high) -
5651 		(long)(buf->b_ml.ml_locked_low) + 1;
5652 	start_idx = idx = curline - buf->b_ml.ml_locked_low;
5653 	if (idx == 0)  // first line in block, text at the end
5654 	    text_end = dp->db_txt_end;
5655 	else
5656 	    text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5657 	// Compute index of last line to use in this MEMLINE
5658 	if (lnum != 0)
5659 	{
5660 	    if (curline + (count - idx) >= lnum)
5661 		idx += lnum - curline - 1;
5662 	    else
5663 		idx = count - 1;
5664 	}
5665 	else
5666 	{
5667 #ifdef FEAT_PROP_POPUP
5668 	    size_t textprop_total = 0;
5669 	    size_t textprop_size = 0;
5670 	    char_u *l1, *l2;
5671 #endif
5672 
5673 	    extra = 0;
5674 	    for (;;)
5675 	    {
5676 #ifdef FEAT_PROP_POPUP
5677 		if (buf->b_has_textprop)
5678 		{
5679 		    // compensate for the extra bytes taken by textprops
5680 		    l1 = (char_u *)dp + ((dp->db_index[idx]) & DB_INDEX_MASK);
5681 		    l2 = (char_u *)dp + (idx == 0 ? dp->db_txt_end
5682 				  : ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
5683 		    textprop_size = (l2 - l1) - (STRLEN(l1) + 1);
5684 		}
5685 #endif
5686 		if (!(offset >= size
5687 			+ text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
5688 #ifdef FEAT_PROP_POPUP
5689 			- (long)(textprop_total + textprop_size)
5690 #endif
5691 			+ ffdos))
5692 		    break;
5693 
5694 		if (ffdos)
5695 		    size++;
5696 #ifdef FEAT_PROP_POPUP
5697 		textprop_total += textprop_size;
5698 #endif
5699 		if (idx == count - 1)
5700 		{
5701 		    extra = 1;
5702 		    break;
5703 		}
5704 		idx++;
5705 	    }
5706 	}
5707 #ifdef FEAT_PROP_POPUP
5708 	if (buf->b_has_textprop)
5709 	{
5710 	    int i;
5711 
5712 	    // cannot use the db_index pointer, need to get the actual text
5713 	    // lengths.
5714 	    len = 0;
5715 	    for (i = start_idx; i <= idx; ++i)
5716 		len += (int)STRLEN((char_u *)dp
5717 				    + ((dp->db_index[i]) & DB_INDEX_MASK)) + 1;
5718 	}
5719 	else
5720 #endif
5721 	    len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
5722 	size += len;
5723 	if (offset != 0 && size >= offset)
5724 	{
5725 	    if (size + ffdos == offset)
5726 		*offp = 0;
5727 	    else if (idx == start_idx)
5728 		*offp = offset - size + len;
5729 	    else
5730 		*offp = offset - size + len
5731 		     - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
5732 	    curline += idx - start_idx + extra;
5733 	    if (curline > buf->b_ml.ml_line_count)
5734 		return -1;	// exactly one byte beyond the end
5735 	    return curline;
5736 	}
5737 	curline = buf->b_ml.ml_locked_high + 1;
5738     }
5739 
5740     if (lnum != 0)
5741     {
5742 	// Count extra CR characters.
5743 	if (ffdos)
5744 	    size += lnum - 1;
5745 
5746 	// Don't count the last line break if 'noeol' and ('bin' or
5747 	// 'nofixeol').
5748 	if ((!buf->b_p_fixeol || buf->b_p_bin) && !buf->b_p_eol
5749 					   && lnum > buf->b_ml.ml_line_count)
5750 	    size -= ffdos + 1;
5751     }
5752 
5753     return size;
5754 }
5755 
5756 /*
5757  * Goto byte in buffer with offset 'cnt'.
5758  */
5759     void
5760 goto_byte(long cnt)
5761 {
5762     long	boff = cnt;
5763     linenr_T	lnum;
5764 
5765     ml_flush_line(curbuf);	// cached line may be dirty
5766     setpcmark();
5767     if (boff)
5768 	--boff;
5769     lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
5770     if (lnum < 1)	// past the end
5771     {
5772 	curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5773 	curwin->w_curswant = MAXCOL;
5774 	coladvance((colnr_T)MAXCOL);
5775     }
5776     else
5777     {
5778 	curwin->w_cursor.lnum = lnum;
5779 	curwin->w_cursor.col = (colnr_T)boff;
5780 	curwin->w_cursor.coladd = 0;
5781 	curwin->w_set_curswant = TRUE;
5782     }
5783     check_cursor();
5784 
5785     // Make sure the cursor is on the first byte of a multi-byte char.
5786     if (has_mbyte)
5787 	mb_adjust_cursor();
5788 }
5789 #endif
5790