blob: 7ea94ab8bd76d509d3499004c836517d3d15777c [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/* for debugging */
11/* #define CHECK(c, s) if (c) EMSG(s) */
12#define CHECK(c, s)
13
14/*
15 * memline.c: Contains the functions for appending, deleting and changing the
Bram Moolenaar4770d092006-01-12 23:22:24 +000016 * 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.
Bram Moolenaar071d4272004-06-13 20:20:40 +000021 *
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
Bram Moolenaar071d4272004-06-13 20:20:40 +000045#include "vim.h"
46
Bram Moolenaar071d4272004-06-13 20:20:40 +000047#ifndef UNIX /* it's in os_unix.h for Unix */
48# include <time.h>
49#endif
50
Bram Moolenaar5a6404c2006-11-01 17:12:57 +000051#if defined(SASC) || defined(__amigaos4__)
Bram Moolenaar071d4272004-06-13 20:20:40 +000052# include <proto/dos.h> /* for Open() and Close() */
53#endif
54
55typedef struct block0 ZERO_BL; /* contents of the first block */
56typedef struct pointer_block PTR_BL; /* contents of a pointer block */
57typedef struct data_block DATA_BL; /* contents of a data block */
58typedef struct pointer_entry PTR_EN; /* block/line-count pair */
59
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +020060#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 */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020066#define BLOCK0_ID1_C2 'd' /* block 0 id 1 'cm' 2 */
67
68#if defined(FEAT_CRYPT)
69static 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
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * pointer to a block, used in a pointer block
78 */
79struct 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 */
90struct pointer_block
91{
92 short_u pb_id; /* ID for pointer block: PTR_ID */
Bram Moolenaar20a825a2010-05-31 21:27:30 +020093 short_u pb_count; /* number of pointers in this block */
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 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 */
106struct 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 upto 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
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000133#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200134#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 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000136#define B0_UNAME_SIZE 40
137#define B0_HNAME_SIZE 40
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138/*
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 *
Bram Moolenaarbae0c162007-05-10 19:30:25 +0000156 * This block is built up of single bytes, to make it portable across
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 * 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 */
160struct block0
161{
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200162 char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200163 * BLOCK0_ID1_C0, BLOCK0_ID1_C1, etc. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164 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) */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000171 char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 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};
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000177
178/*
Bram Moolenaar4770d092006-01-12 23:22:24 +0000179 * Note: b0_dirty and b0_flags are put at the end of the file name. For very
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000180 * 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
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200185#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG - 1]
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000186
187/*
188 * The b0_flags field is new in Vim 7.0.
189 */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200190#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]
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000197
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
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210
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 */
219static 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
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200230/* argument for ml_upd_block0() */
231typedef 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
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100238static void ml_set_mfp_crypt(buf_T *buf);
239static void ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200240#endif
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100241static int ml_check_b0_id(ZERO_BL *b0p);
242static void ml_upd_block0(buf_T *buf, upd_block0_T what);
243static void set_b0_fname(ZERO_BL *, buf_T *buf);
244static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000245#ifdef FEAT_MBYTE
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100246static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000247#endif
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100248static time_t swapfile_info(char_u *);
249static int recov_file_names(char_u **, char_u *, int prepend_dot);
250static int ml_append_int(buf_T *, linenr_T, char_u *, colnr_T, int, int);
251static int ml_delete_int(buf_T *, linenr_T, int);
252static char_u *findswapname(buf_T *, char_u **, char_u *);
253static void ml_flush_line(buf_T *);
254static bhdr_T *ml_new_data(memfile_T *, int, int);
255static bhdr_T *ml_new_ptr(memfile_T *);
256static bhdr_T *ml_find_line(buf_T *, linenr_T, int);
257static int ml_add_stack(buf_T *);
258static void ml_lineadd(buf_T *, int);
259static int b0_magic_wrong(ZERO_BL *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000260#ifdef CHECK_INODE
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100261static int fnamecmp_ino(char_u *, char_u *, long);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262#endif
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100263static void long_to_char(long, char_u *);
264static long char_to_long(char_u *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265#if defined(UNIX) || defined(WIN3264)
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100266static char_u *make_percent_swname(char_u *dir, char_u *name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000267#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200268#ifdef FEAT_CRYPT
Bram Moolenaar8767f522016-07-01 17:17:39 +0200269static cryptstate_T *ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200270#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000271#ifdef FEAT_BYTEOFF
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100272static void ml_updatechunk(buf_T *buf, long line, long len, int updtype);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000273#endif
274
275/*
Bram Moolenaar4770d092006-01-12 23:22:24 +0000276 * Open a new memline for "buf".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277 *
Bram Moolenaar4770d092006-01-12 23:22:24 +0000278 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279 */
280 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100281ml_open(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282{
283 memfile_T *mfp;
284 bhdr_T *hp = NULL;
285 ZERO_BL *b0p;
286 PTR_BL *pp;
287 DATA_BL *dp;
288
Bram Moolenaar4770d092006-01-12 23:22:24 +0000289 /*
290 * init fields in memline struct
291 */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200292 buf->b_ml.ml_stack_size = 0; /* no stack yet */
Bram Moolenaar4770d092006-01-12 23:22:24 +0000293 buf->b_ml.ml_stack = NULL; /* no stack yet */
294 buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
295 buf->b_ml.ml_locked = NULL; /* no cached block */
296 buf->b_ml.ml_line_lnum = 0; /* no cached line */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297#ifdef FEAT_BYTEOFF
Bram Moolenaar4770d092006-01-12 23:22:24 +0000298 buf->b_ml.ml_chunksize = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299#endif
300
Bram Moolenaar5803ae62014-03-23 16:04:02 +0100301 if (cmdmod.noswapfile)
302 buf->b_p_swf = FALSE;
303
Bram Moolenaar4770d092006-01-12 23:22:24 +0000304 /*
305 * When 'updatecount' is non-zero swap file may be opened later.
306 */
307 if (p_uc && buf->b_p_swf)
308 buf->b_may_swap = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000309 else
Bram Moolenaar4770d092006-01-12 23:22:24 +0000310 buf->b_may_swap = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000311
Bram Moolenaar4770d092006-01-12 23:22:24 +0000312 /*
313 * Open the memfile. No swap file is created yet.
314 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000315 mfp = mf_open(NULL, 0);
316 if (mfp == NULL)
317 goto error;
318
Bram Moolenaar4770d092006-01-12 23:22:24 +0000319 buf->b_ml.ml_mfp = mfp;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200320#ifdef FEAT_CRYPT
321 mfp->mf_buffer = buf;
322#endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000323 buf->b_ml.ml_flags = ML_EMPTY;
324 buf->b_ml.ml_line_count = 1;
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000325#ifdef FEAT_LINEBREAK
326 curwin->w_nrwidth_line_count = 0;
327#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000328
Bram Moolenaar071d4272004-06-13 20:20:40 +0000329/*
330 * fill block0 struct and write page 0
331 */
332 if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
333 goto error;
334 if (hp->bh_bnum != 0)
335 {
Bram Moolenaar95f09602016-11-10 20:01:45 +0100336 IEMSG(_("E298: Didn't get block nr 0?"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000337 goto error;
338 }
339 b0p = (ZERO_BL *)(hp->bh_data);
340
341 b0p->b0_id[0] = BLOCK0_ID0;
342 b0p->b0_id[1] = BLOCK0_ID1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343 b0p->b0_magic_long = (long)B0_MAGIC_LONG;
344 b0p->b0_magic_int = (int)B0_MAGIC_INT;
345 b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
346 b0p->b0_magic_char = B0_MAGIC_CHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 STRNCPY(b0p->b0_version, "VIM ", 4);
348 STRNCPY(b0p->b0_version + 4, Version, 6);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000349 long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000350
Bram Moolenaar76b92b22006-03-24 22:46:53 +0000351#ifdef FEAT_SPELL
352 if (!buf->b_spell)
353#endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000354 {
355 b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
356 b0p->b0_flags = get_fileformat(buf) + 1;
357 set_b0_fname(b0p, buf);
358 (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
359 b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
360 mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
361 b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
362 long_to_char(mch_get_pid(), b0p->b0_pid);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200363#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200364 ml_set_b0_crypt(buf, b0p);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200365#endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000366 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000367
368 /*
369 * Always sync block number 0 to disk, so we can check the file name in
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200370 * the swap file in findswapname(). Don't do this for a help files or
371 * a spell buffer though.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000372 * Only works when there's a swapfile, otherwise it's done when the file
373 * is created.
374 */
375 mf_put(mfp, hp, TRUE, FALSE);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000376 if (!buf->b_help && !B_SPELL(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 (void)mf_sync(mfp, 0);
378
Bram Moolenaar4770d092006-01-12 23:22:24 +0000379 /*
380 * Fill in root pointer block and write page 1.
381 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382 if ((hp = ml_new_ptr(mfp)) == NULL)
383 goto error;
384 if (hp->bh_bnum != 1)
385 {
Bram Moolenaar95f09602016-11-10 20:01:45 +0100386 IEMSG(_("E298: Didn't get block nr 1?"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387 goto error;
388 }
389 pp = (PTR_BL *)(hp->bh_data);
390 pp->pb_count = 1;
391 pp->pb_pointer[0].pe_bnum = 2;
392 pp->pb_pointer[0].pe_page_count = 1;
393 pp->pb_pointer[0].pe_old_lnum = 1;
394 pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */
395 mf_put(mfp, hp, TRUE, FALSE);
396
Bram Moolenaar4770d092006-01-12 23:22:24 +0000397 /*
398 * Allocate first data block and create an empty line 1.
399 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
401 goto error;
402 if (hp->bh_bnum != 2)
403 {
Bram Moolenaar95f09602016-11-10 20:01:45 +0100404 IEMSG(_("E298: Didn't get block nr 2?"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405 goto error;
406 }
407
408 dp = (DATA_BL *)(hp->bh_data);
409 dp->db_index[0] = --dp->db_txt_start; /* at end of block */
410 dp->db_free -= 1 + INDEX_SIZE;
411 dp->db_line_count = 1;
Bram Moolenaarf05da212009-11-17 16:13:15 +0000412 *((char_u *)dp + dp->db_txt_start) = NUL; /* empty line */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413
414 return OK;
415
416error:
417 if (mfp != NULL)
418 {
419 if (hp)
420 mf_put(mfp, hp, FALSE, FALSE);
421 mf_close(mfp, TRUE); /* will also free(mfp->mf_fname) */
422 }
Bram Moolenaar4770d092006-01-12 23:22:24 +0000423 buf->b_ml.ml_mfp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 return FAIL;
425}
426
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200427#if defined(FEAT_CRYPT) || defined(PROTO)
428/*
Bram Moolenaar2be79502014-08-13 21:58:28 +0200429 * Prepare encryption for "buf" for the current key and method.
430 */
431 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100432ml_set_mfp_crypt(buf_T *buf)
Bram Moolenaar2be79502014-08-13 21:58:28 +0200433{
434 if (*buf->b_p_key != NUL)
435 {
436 int method_nr = crypt_get_method_nr(buf);
437
438 if (method_nr > CRYPT_M_ZIP)
439 {
440 /* Generate a seed and store it in the memfile. */
441 sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
442 }
443 }
444}
445
446/*
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200447 * Prepare encryption for "buf" with block 0 "b0p".
448 */
449 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100450ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200451{
452 if (*buf->b_p_key == NUL)
453 b0p->b0_id[1] = BLOCK0_ID1;
454 else
455 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200456 int method_nr = crypt_get_method_nr(buf);
457
458 b0p->b0_id[1] = id1_codes[method_nr];
459 if (method_nr > CRYPT_M_ZIP)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200460 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200461 /* Generate a seed and store it in block 0 and in the memfile. */
462 sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
463 mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
464 }
465 }
466}
467
468/*
469 * Called after the crypt key or 'cryptmethod' was changed for "buf".
470 * Will apply this to the swapfile.
471 * "old_key" is the previous key. It is equal to buf->b_p_key when
472 * 'cryptmethod' is changed.
Bram Moolenaar49771f42010-07-20 17:32:38 +0200473 * "old_cm" is the previous 'cryptmethod'. It is equal to the current
474 * 'cryptmethod' when 'key' is changed.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200475 */
476 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100477ml_set_crypt_key(
478 buf_T *buf,
479 char_u *old_key,
480 char_u *old_cm)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200481{
482 memfile_T *mfp = buf->b_ml.ml_mfp;
483 bhdr_T *hp;
484 int page_count;
485 int idx;
486 long error;
487 infoptr_T *ip;
488 PTR_BL *pp;
489 DATA_BL *dp;
490 blocknr_T bnum;
491 int top;
Bram Moolenaarbc563362015-06-09 18:35:25 +0200492 int old_method;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200493
Bram Moolenaar3832c462010-08-04 15:32:46 +0200494 if (mfp == NULL)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200495 return; /* no memfile yet, nothing to do */
Bram Moolenaarbc563362015-06-09 18:35:25 +0200496 old_method = crypt_method_nr_from_name(old_cm);
497
498 /* First make sure the swapfile is in a consistent state, using the old
499 * key and method. */
500 {
501 char_u *new_key = buf->b_p_key;
502 char_u *new_buf_cm = buf->b_p_cm;
503
504 buf->b_p_key = old_key;
505 buf->b_p_cm = old_cm;
506 ml_preserve(buf, FALSE);
507 buf->b_p_key = new_key;
508 buf->b_p_cm = new_buf_cm;
509 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200510
511 /* Set the key, method and seed to be used for reading, these must be the
512 * old values. */
513 mfp->mf_old_key = old_key;
Bram Moolenaarbc563362015-06-09 18:35:25 +0200514 mfp->mf_old_cm = old_method;
515 if (old_method > 0 && *old_key != NUL)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200516 mch_memmove(mfp->mf_old_seed, mfp->mf_seed, MF_SEED_LEN);
517
518 /* Update block 0 with the crypt flag and may set a new seed. */
519 ml_upd_block0(buf, UB_CRYPT);
520
521 if (mfp->mf_infile_count > 2)
522 {
523 /*
524 * Need to read back all data blocks from disk, decrypt them with the
525 * old key/method and mark them to be written. The algorithm is
526 * similar to what happens in ml_recover(), but we skip negative block
527 * numbers.
528 */
529 ml_flush_line(buf); /* flush buffered line */
530 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
531
532 hp = NULL;
533 bnum = 1; /* start with block 1 */
534 page_count = 1; /* which is 1 page */
535 idx = 0; /* start with first index in block 1 */
536 error = 0;
537 buf->b_ml.ml_stack_top = 0;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100538 VIM_CLEAR(buf->b_ml.ml_stack);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200539 buf->b_ml.ml_stack_size = 0; /* no stack yet */
540
541 for ( ; !got_int; line_breakcheck())
542 {
543 if (hp != NULL)
544 mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
545
546 /* get the block (pointer or data) */
547 if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
548 {
549 if (bnum == 1)
550 break;
551 ++error;
552 }
553 else
554 {
555 pp = (PTR_BL *)(hp->bh_data);
556 if (pp->pb_id == PTR_ID) /* it is a pointer block */
557 {
558 if (pp->pb_count == 0)
559 {
560 /* empty block? */
561 ++error;
562 }
563 else if (idx < (int)pp->pb_count) /* go a block deeper */
564 {
565 if (pp->pb_pointer[idx].pe_bnum < 0)
566 {
Bram Moolenaarbc563362015-06-09 18:35:25 +0200567 /* Skip data block with negative block number.
568 * Should not happen, because of the ml_preserve()
569 * above. Get same block again for next index. */
570 ++idx;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200571 continue;
572 }
573
574 /* going one block deeper in the tree, new entry in
575 * stack */
576 if ((top = ml_add_stack(buf)) < 0)
577 {
578 ++error;
579 break; /* out of memory */
580 }
581 ip = &(buf->b_ml.ml_stack[top]);
582 ip->ip_bnum = bnum;
583 ip->ip_index = idx;
584
585 bnum = pp->pb_pointer[idx].pe_bnum;
586 page_count = pp->pb_pointer[idx].pe_page_count;
Bram Moolenaarbc563362015-06-09 18:35:25 +0200587 idx = 0;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200588 continue;
589 }
590 }
591 else /* not a pointer block */
592 {
593 dp = (DATA_BL *)(hp->bh_data);
594 if (dp->db_id != DATA_ID) /* block id wrong */
595 ++error;
596 else
597 {
598 /* It is a data block, need to write it back to disk. */
599 mf_put(mfp, hp, TRUE, FALSE);
600 hp = NULL;
601 }
602 }
603 }
604
605 if (buf->b_ml.ml_stack_top == 0) /* finished */
606 break;
607
608 /* go one block up in the tree */
609 ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
610 bnum = ip->ip_bnum;
611 idx = ip->ip_index + 1; /* go to next index */
612 page_count = 1;
613 }
Bram Moolenaarbc563362015-06-09 18:35:25 +0200614 if (hp != NULL)
615 mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +0100616
617 if (error > 0)
618 EMSG(_("E843: Error while updating swap file crypt"));
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200619 }
620
621 mfp->mf_old_key = NULL;
622}
623#endif
624
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625/*
626 * ml_setname() is called when the file name of "buf" has been changed.
627 * It may rename the swap file.
628 */
629 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100630ml_setname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631{
632 int success = FALSE;
633 memfile_T *mfp;
634 char_u *fname;
635 char_u *dirp;
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100636#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 char_u *p;
638#endif
639
640 mfp = buf->b_ml.ml_mfp;
641 if (mfp->mf_fd < 0) /* there is no swap file yet */
642 {
643 /*
644 * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
645 * For help files we will make a swap file now.
646 */
Bram Moolenaar5803ae62014-03-23 16:04:02 +0100647 if (p_uc != 0 && !cmdmod.noswapfile)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648 ml_open_file(buf); /* create a swap file */
649 return;
650 }
651
652 /*
653 * Try all directories in the 'directory' option.
654 */
655 dirp = p_dir;
656 for (;;)
657 {
658 if (*dirp == NUL) /* tried all directories, fail */
659 break;
Bram Moolenaar8fc061c2004-12-29 21:03:02 +0000660 fname = findswapname(buf, &dirp, mfp->mf_fname);
661 /* alloc's fname */
Bram Moolenaarf541c362011-10-26 11:44:18 +0200662 if (dirp == NULL) /* out of memory */
663 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664 if (fname == NULL) /* no file name found for this dir */
665 continue;
666
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100667#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 /*
669 * Set full pathname for swap file now, because a ":!cd dir" may
670 * change directory without us knowing it.
671 */
672 p = FullName_save(fname, FALSE);
673 vim_free(fname);
674 fname = p;
675 if (fname == NULL)
676 continue;
677#endif
678 /* if the file name is the same we don't have to do anything */
679 if (fnamecmp(fname, mfp->mf_fname) == 0)
680 {
681 vim_free(fname);
682 success = TRUE;
683 break;
684 }
685 /* need to close the swap file before renaming */
686 if (mfp->mf_fd >= 0)
687 {
688 close(mfp->mf_fd);
689 mfp->mf_fd = -1;
690 }
691
692 /* try to rename the swap file */
693 if (vim_rename(mfp->mf_fname, fname) == 0)
694 {
695 success = TRUE;
696 vim_free(mfp->mf_fname);
697 mfp->mf_fname = fname;
698 vim_free(mfp->mf_ffname);
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100699#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700 mfp->mf_ffname = NULL; /* mf_fname is full pathname already */
701#else
702 mf_set_ffname(mfp);
703#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200704 ml_upd_block0(buf, UB_SAME_DIR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705 break;
706 }
707 vim_free(fname); /* this fname didn't work, try another */
708 }
709
710 if (mfp->mf_fd == -1) /* need to (re)open the swap file */
711 {
712 mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
713 if (mfp->mf_fd < 0)
714 {
715 /* could not (re)open the swap file, what can we do???? */
716 EMSG(_("E301: Oops, lost the swap file!!!"));
717 return;
718 }
Bram Moolenaarf05da212009-11-17 16:13:15 +0000719#ifdef HAVE_FD_CLOEXEC
720 {
721 int fdflags = fcntl(mfp->mf_fd, F_GETFD);
722 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +0100723 (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaarf05da212009-11-17 16:13:15 +0000724 }
725#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 }
727 if (!success)
728 EMSG(_("E302: Could not rename swap file"));
729}
730
731/*
732 * Open a file for the memfile for all buffers that are not readonly or have
733 * been modified.
734 * Used when 'updatecount' changes from zero to non-zero.
735 */
736 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100737ml_open_files(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738{
739 buf_T *buf;
740
Bram Moolenaar29323592016-07-24 22:04:11 +0200741 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 if (!buf->b_p_ro || buf->b_changed)
743 ml_open_file(buf);
744}
745
746/*
747 * Open a swap file for an existing memfile, if there is no swap file yet.
748 * If we are unable to find a file name, mf_fname will be NULL
749 * and the memfile will be in memory only (no recovery possible).
750 */
751 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100752ml_open_file(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753{
754 memfile_T *mfp;
755 char_u *fname;
756 char_u *dirp;
757
758 mfp = buf->b_ml.ml_mfp;
Bram Moolenaar5803ae62014-03-23 16:04:02 +0100759 if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || cmdmod.noswapfile)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 return; /* nothing to do */
761
Bram Moolenaara1956f62006-03-12 22:18:00 +0000762#ifdef FEAT_SPELL
Bram Moolenaar4770d092006-01-12 23:22:24 +0000763 /* For a spell buffer use a temp file name. */
764 if (buf->b_spell)
765 {
Bram Moolenaare5c421c2015-03-31 13:33:08 +0200766 fname = vim_tempname('s', FALSE);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000767 if (fname != NULL)
768 (void)mf_open_file(mfp, fname); /* consumes fname! */
769 buf->b_may_swap = FALSE;
770 return;
771 }
772#endif
773
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 /*
775 * Try all directories in 'directory' option.
776 */
777 dirp = p_dir;
778 for (;;)
779 {
780 if (*dirp == NUL)
781 break;
Bram Moolenaare242b832010-06-24 05:39:03 +0200782 /* There is a small chance that between choosing the swap file name
783 * and creating it, another Vim creates the file. In that case the
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 * creation will fail and we will use another directory. */
Bram Moolenaar8fc061c2004-12-29 21:03:02 +0000785 fname = findswapname(buf, &dirp, NULL); /* allocates fname */
Bram Moolenaarf541c362011-10-26 11:44:18 +0200786 if (dirp == NULL)
787 break; /* out of memory */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000788 if (fname == NULL)
789 continue;
790 if (mf_open_file(mfp, fname) == OK) /* consumes fname! */
791 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100792#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 /*
794 * set full pathname for swap file now, because a ":!cd dir" may
795 * change directory without us knowing it.
796 */
797 mf_fullname(mfp);
798#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200799 ml_upd_block0(buf, UB_SAME_DIR);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000800
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 /* Flush block zero, so others can read it */
802 if (mf_sync(mfp, MFS_ZERO) == OK)
Bram Moolenaarc32840f2006-01-14 21:23:38 +0000803 {
804 /* Mark all blocks that should be in the swapfile as dirty.
805 * Needed for when the 'swapfile' option was reset, so that
806 * the swap file was deleted, and then on again. */
807 mf_set_dirty(mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 break;
Bram Moolenaarc32840f2006-01-14 21:23:38 +0000809 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 /* Writing block 0 failed: close the file and try another dir */
811 mf_close_file(buf, FALSE);
812 }
813 }
814
815 if (mfp->mf_fname == NULL) /* Failed! */
816 {
817 need_wait_return = TRUE; /* call wait_return later */
818 ++no_wait_return;
819 (void)EMSG2(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200820 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 --no_wait_return;
822 }
823
824 /* don't try to open a swap file again */
825 buf->b_may_swap = FALSE;
826}
827
828/*
829 * If still need to create a swap file, and starting to edit a not-readonly
830 * file, or reading into an existing buffer, create a swap file now.
831 */
832 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100833check_need_swap(
834 int newfile) /* reading file into new buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835{
836 if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
837 ml_open_file(curbuf);
838}
839
840/*
841 * Close memline for buffer 'buf'.
842 * If 'del_file' is TRUE, delete the swap file
843 */
844 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100845ml_close(buf_T *buf, int del_file)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846{
847 if (buf->b_ml.ml_mfp == NULL) /* not open */
848 return;
849 mf_close(buf->b_ml.ml_mfp, del_file); /* close the .swp file */
850 if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
851 vim_free(buf->b_ml.ml_line_ptr);
852 vim_free(buf->b_ml.ml_stack);
853#ifdef FEAT_BYTEOFF
Bram Moolenaard23a8232018-02-10 18:45:26 +0100854 VIM_CLEAR(buf->b_ml.ml_chunksize);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855#endif
856 buf->b_ml.ml_mfp = NULL;
857
858 /* Reset the "recovered" flag, give the ATTENTION prompt the next time
859 * this buffer is loaded. */
860 buf->b_flags &= ~BF_RECOVERED;
861}
862
863/*
864 * Close all existing memlines and memfiles.
865 * Only used when exiting.
866 * When 'del_file' is TRUE, delete the memfiles.
Bram Moolenaar81bf7082005-02-12 14:31:42 +0000867 * But don't delete files that were ":preserve"d when we are POSIX compatible.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868 */
869 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100870ml_close_all(int del_file)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871{
872 buf_T *buf;
873
Bram Moolenaar29323592016-07-24 22:04:11 +0200874 FOR_ALL_BUFFERS(buf)
Bram Moolenaar81bf7082005-02-12 14:31:42 +0000875 ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0
876 || vim_strchr(p_cpo, CPO_PRESERVE) == NULL));
Bram Moolenaar34b466e2013-11-28 17:41:46 +0100877#ifdef FEAT_SPELL
878 spell_delete_wordlist(); /* delete the internal wordlist */
879#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880#ifdef TEMPDIRNAMES
Bram Moolenaar34b466e2013-11-28 17:41:46 +0100881 vim_deltempdir(); /* delete created temp directory */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882#endif
883}
884
885/*
886 * Close all memfiles for not modified buffers.
887 * Only use just before exiting!
888 */
889 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100890ml_close_notmod(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000891{
892 buf_T *buf;
893
Bram Moolenaar29323592016-07-24 22:04:11 +0200894 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 if (!bufIsChanged(buf))
896 ml_close(buf, TRUE); /* close all not-modified buffers */
897}
898
899/*
900 * Update the timestamp in the .swp file.
901 * Used when the file has been written.
902 */
903 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100904ml_timestamp(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905{
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200906 ml_upd_block0(buf, UB_FNAME);
907}
908
909/*
910 * Return FAIL when the ID of "b0p" is wrong.
911 */
912 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100913ml_check_b0_id(ZERO_BL *b0p)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200914{
915 if (b0p->b0_id[0] != BLOCK0_ID0
916 || (b0p->b0_id[1] != BLOCK0_ID1
917 && b0p->b0_id[1] != BLOCK0_ID1_C0
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200918 && b0p->b0_id[1] != BLOCK0_ID1_C1
919 && b0p->b0_id[1] != BLOCK0_ID1_C2)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200920 )
921 return FAIL;
922 return OK;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000923}
924
925/*
926 * Update the timestamp or the B0_SAME_DIR flag of the .swp file.
927 */
928 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100929ml_upd_block0(buf_T *buf, upd_block0_T what)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000930{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931 memfile_T *mfp;
932 bhdr_T *hp;
933 ZERO_BL *b0p;
934
935 mfp = buf->b_ml.ml_mfp;
Bram Moolenaar2be79502014-08-13 21:58:28 +0200936 if (mfp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 return;
Bram Moolenaar2be79502014-08-13 21:58:28 +0200938 hp = mf_get(mfp, (blocknr_T)0, 1);
939 if (hp == NULL)
940 {
941#ifdef FEAT_CRYPT
942 /* Possibly update the seed in the memfile before there is a block0. */
943 if (what == UB_CRYPT)
944 ml_set_mfp_crypt(buf);
945#endif
946 return;
947 }
948
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200950 if (ml_check_b0_id(b0p) == FAIL)
Bram Moolenaar95f09602016-11-10 20:01:45 +0100951 IEMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 else
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000953 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200954 if (what == UB_FNAME)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000955 set_b0_fname(b0p, buf);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200956#ifdef FEAT_CRYPT
957 else if (what == UB_CRYPT)
958 ml_set_b0_crypt(buf, b0p);
959#endif
960 else /* what == UB_SAME_DIR */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000961 set_b0_dir_flag(b0p, buf);
962 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963 mf_put(mfp, hp, TRUE, FALSE);
964}
965
966/*
967 * Write file name and timestamp into block 0 of a swap file.
968 * Also set buf->b_mtime.
969 * Don't use NameBuff[]!!!
970 */
971 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100972set_b0_fname(ZERO_BL *b0p, buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000973{
Bram Moolenaar8767f522016-07-01 17:17:39 +0200974 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975
976 if (buf->b_ffname == NULL)
977 b0p->b0_fname[0] = NUL;
978 else
979 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100980#if defined(MSWIN) || defined(AMIGA)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000981 /* Systems that cannot translate "~user" back into a path: copy the
982 * file name unmodified. Do use slashes instead of backslashes for
983 * portability. */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200984 vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT - 1);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000985# ifdef BACKSLASH_IN_FILENAME
986 forward_slash(b0p->b0_fname);
987# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988#else
989 size_t flen, ulen;
990 char_u uname[B0_UNAME_SIZE];
991
992 /*
993 * For a file under the home directory of the current user, we try to
994 * replace the home directory path with "~user". This helps when
995 * editing the same file on different machines over a network.
996 * First replace home dir path with "~/" with home_replace().
997 * Then insert the user name to get "~user/".
998 */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200999 home_replace(NULL, buf->b_ffname, b0p->b0_fname,
1000 B0_FNAME_SIZE_CRYPT, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001 if (b0p->b0_fname[0] == '~')
1002 {
1003 flen = STRLEN(b0p->b0_fname);
1004 /* If there is no user name or it is too long, don't use "~/" */
1005 if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001006 || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE_CRYPT - 1)
1007 vim_strncpy(b0p->b0_fname, buf->b_ffname,
1008 B0_FNAME_SIZE_CRYPT - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 else
1010 {
1011 mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
1012 mch_memmove(b0p->b0_fname + 1, uname, ulen);
1013 }
1014 }
1015#endif
1016 if (mch_stat((char *)buf->b_ffname, &st) >= 0)
1017 {
1018 long_to_char((long)st.st_mtime, b0p->b0_mtime);
1019#ifdef CHECK_INODE
1020 long_to_char((long)st.st_ino, b0p->b0_ino);
1021#endif
1022 buf_store_time(buf, &st, buf->b_ffname);
1023 buf->b_mtime_read = buf->b_mtime;
1024 }
1025 else
1026 {
1027 long_to_char(0L, b0p->b0_mtime);
1028#ifdef CHECK_INODE
1029 long_to_char(0L, b0p->b0_ino);
1030#endif
1031 buf->b_mtime = 0;
1032 buf->b_mtime_read = 0;
1033 buf->b_orig_size = 0;
1034 buf->b_orig_mode = 0;
1035 }
1036 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001037
1038#ifdef FEAT_MBYTE
1039 /* Also add the 'fileencoding' if there is room. */
1040 add_b0_fenc(b0p, curbuf);
1041#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001042}
1043
1044/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001045 * Update the B0_SAME_DIR flag of the swap file. It's set if the file and the
1046 * swapfile for "buf" are in the same directory.
1047 * This is fail safe: if we are not sure the directories are equal the flag is
1048 * not set.
1049 */
1050 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001051set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001052{
1053 if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
1054 b0p->b0_flags |= B0_SAME_DIR;
1055 else
1056 b0p->b0_flags &= ~B0_SAME_DIR;
1057}
1058
1059#ifdef FEAT_MBYTE
1060/*
1061 * When there is room, add the 'fileencoding' to block zero.
1062 */
1063 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001064add_b0_fenc(
1065 ZERO_BL *b0p,
1066 buf_T *buf)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001067{
1068 int n;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001069 int size = B0_FNAME_SIZE_NOCRYPT;
1070
1071# ifdef FEAT_CRYPT
1072 /* Without encryption use the same offset as in Vim 7.2 to be compatible.
1073 * With encryption it's OK to move elsewhere, the swap file is not
1074 * compatible anyway. */
1075 if (*buf->b_p_key != NUL)
1076 size = B0_FNAME_SIZE_CRYPT;
1077# endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001078
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001079 n = (int)STRLEN(buf->b_p_fenc);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001080 if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001081 b0p->b0_flags &= ~B0_HAS_FENC;
1082 else
1083 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001084 mch_memmove((char *)b0p->b0_fname + size - n,
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001085 (char *)buf->b_p_fenc, (size_t)n);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001086 *(b0p->b0_fname + size - n - 1) = NUL;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001087 b0p->b0_flags |= B0_HAS_FENC;
1088 }
1089}
1090#endif
1091
1092
1093/*
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001094 * Try to recover curbuf from the .swp file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095 */
1096 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001097ml_recover(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098{
1099 buf_T *buf = NULL;
1100 memfile_T *mfp = NULL;
1101 char_u *fname;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001102 char_u *fname_used = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001103 bhdr_T *hp = NULL;
1104 ZERO_BL *b0p;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001105 int b0_ff;
1106 char_u *b0_fenc = NULL;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001107#ifdef FEAT_CRYPT
1108 int b0_cm = -1;
1109#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 PTR_BL *pp;
1111 DATA_BL *dp;
1112 infoptr_T *ip;
1113 blocknr_T bnum;
1114 int page_count;
Bram Moolenaar8767f522016-07-01 17:17:39 +02001115 stat_T org_stat, swp_stat;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116 int len;
1117 int directly;
1118 linenr_T lnum;
1119 char_u *p;
1120 int i;
1121 long error;
1122 int cannot_open;
1123 linenr_T line_count;
1124 int has_error;
1125 int idx;
1126 int top;
1127 int txt_start;
Bram Moolenaar8767f522016-07-01 17:17:39 +02001128 off_T size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 int called_from_main;
1130 int serious_error = TRUE;
1131 long mtime;
1132 int attr;
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001133 int orig_file_status = NOTDONE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134
1135 recoverymode = TRUE;
1136 called_from_main = (curbuf->b_ml.ml_mfp == NULL);
Bram Moolenaar8820b482017-03-16 17:23:31 +01001137 attr = HL_ATTR(HLF_E);
Bram Moolenaard0ba34a2009-11-03 12:06:23 +00001138
1139 /*
Bram Moolenaaraf903e52017-12-02 15:11:22 +01001140 * If the file name ends in ".s[a-w][a-z]" we assume this is the swap file.
Bram Moolenaard0ba34a2009-11-03 12:06:23 +00001141 * Otherwise a search is done to find the swap file(s).
1142 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143 fname = curbuf->b_fname;
1144 if (fname == NULL) /* When there is no file name */
1145 fname = (char_u *)"";
1146 len = (int)STRLEN(fname);
1147 if (len >= 4 &&
Bram Moolenaare60acc12011-05-10 16:41:25 +02001148#if defined(VMS)
Bram Moolenaar79518e22017-02-17 16:31:35 +01001149 STRNICMP(fname + len - 4, "_s", 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150#else
Bram Moolenaar79518e22017-02-17 16:31:35 +01001151 STRNICMP(fname + len - 4, ".s", 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152#endif
Bram Moolenaar79518e22017-02-17 16:31:35 +01001153 == 0
Bram Moolenaaraf903e52017-12-02 15:11:22 +01001154 && vim_strchr((char_u *)"abcdefghijklmnopqrstuvw",
1155 TOLOWER_ASC(fname[len - 2])) != NULL
Bram Moolenaard0ba34a2009-11-03 12:06:23 +00001156 && ASCII_ISALPHA(fname[len - 1]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 {
1158 directly = TRUE;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001159 fname_used = vim_strsave(fname); /* make a copy for mf_open() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 }
1161 else
1162 {
1163 directly = FALSE;
1164
1165 /* count the number of matching swap files */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001166 len = recover_names(fname, FALSE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 if (len == 0) /* no swap files found */
1168 {
1169 EMSG2(_("E305: No swap file found for %s"), fname);
1170 goto theend;
1171 }
1172 if (len == 1) /* one swap file found, use it */
1173 i = 1;
1174 else /* several swap files found, choose */
1175 {
1176 /* list the names of the swap files */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001177 (void)recover_names(fname, TRUE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 msg_putchar('\n');
1179 MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00001180 i = get_number(FALSE, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 if (i < 1 || i > len)
1182 goto theend;
1183 }
1184 /* get the swap file name that will be used */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001185 (void)recover_names(fname, FALSE, i, &fname_used);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001187 if (fname_used == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188 goto theend; /* out of memory */
1189
1190 /* When called from main() still need to initialize storage structure */
Bram Moolenaar4770d092006-01-12 23:22:24 +00001191 if (called_from_main && ml_open(curbuf) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192 getout(1);
1193
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001194 /*
1195 * Allocate a buffer structure for the swap file that is used for recovery.
Bram Moolenaar0ad014c2010-07-25 14:00:46 +02001196 * Only the memline and crypt information in it are really used.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001197 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198 buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
1199 if (buf == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001202 /*
1203 * init fields in memline struct
1204 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205 buf->b_ml.ml_stack_size = 0; /* no stack yet */
1206 buf->b_ml.ml_stack = NULL; /* no stack yet */
1207 buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
1208 buf->b_ml.ml_line_lnum = 0; /* no cached line */
1209 buf->b_ml.ml_locked = NULL; /* no locked block */
1210 buf->b_ml.ml_flags = 0;
Bram Moolenaar0fe849a2010-07-25 15:11:11 +02001211#ifdef FEAT_CRYPT
1212 buf->b_p_key = empty_option;
1213 buf->b_p_cm = empty_option;
1214#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001215
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001216 /*
1217 * open the memfile from the old swap file
1218 */
1219 p = vim_strsave(fname_used); /* save "fname_used" for the message:
1220 mf_open() will consume "fname_used"! */
1221 mfp = mf_open(fname_used, O_RDONLY);
1222 fname_used = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223 if (mfp == NULL || mfp->mf_fd < 0)
1224 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001225 if (fname_used != NULL)
1226 EMSG2(_("E306: Cannot open %s"), fname_used);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227 goto theend;
1228 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 buf->b_ml.ml_mfp = mfp;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001230#ifdef FEAT_CRYPT
1231 mfp->mf_buffer = buf;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001232#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233
1234 /*
1235 * The page size set in mf_open() might be different from the page size
1236 * used in the swap file, we must get it from block 0. But to read block
1237 * 0 we need a page size. Use the minimal size for block 0 here, it will
1238 * be set to the real value below.
1239 */
1240 mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
1241
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001242 /*
1243 * try to read block 0
1244 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245 if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
1246 {
1247 msg_start();
1248 MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
1249 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001250 MSG_PUTS_ATTR(_("\nMaybe no changes were made or Vim did not update the swap file."),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251 attr | MSG_HIST);
1252 msg_end();
1253 goto theend;
1254 }
1255 b0p = (ZERO_BL *)(hp->bh_data);
1256 if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
1257 {
1258 msg_start();
1259 msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
1260 MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
1261 MSG_HIST);
1262 MSG_PUTS_ATTR(_("Use Vim version 3.0.\n"), MSG_HIST);
1263 msg_end();
1264 goto theend;
1265 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001266 if (ml_check_b0_id(b0p) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267 {
1268 EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
1269 goto theend;
1270 }
1271 if (b0_magic_wrong(b0p))
1272 {
1273 msg_start();
1274 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
Bram Moolenaar48e330a2016-02-23 14:53:34 +01001275#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276 if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
1277 MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
1278 attr | MSG_HIST);
1279 else
1280#endif
1281 MSG_PUTS_ATTR(_(" cannot be used on this computer.\n"),
1282 attr | MSG_HIST);
1283 MSG_PUTS_ATTR(_("The file was created on "), attr | MSG_HIST);
Bram Moolenaare242b832010-06-24 05:39:03 +02001284 /* avoid going past the end of a corrupted hostname */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285 b0p->b0_fname[0] = NUL;
1286 MSG_PUTS_ATTR(b0p->b0_hname, attr | MSG_HIST);
1287 MSG_PUTS_ATTR(_(",\nor the file has been damaged."), attr | MSG_HIST);
1288 msg_end();
1289 goto theend;
1290 }
Bram Moolenaar1c536282007-04-26 15:21:56 +00001291
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001292#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001293 for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
1294 if (id1_codes[i] == b0p->b0_id[1])
1295 b0_cm = i;
1296 if (b0_cm > 0)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001297 mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001298 crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001299#else
1300 if (b0p->b0_id[1] != BLOCK0_ID1)
1301 {
Bram Moolenaar996343d2010-07-04 22:20:21 +02001302 EMSG2(_("E833: %s is encrypted and this version of Vim does not support encryption"), mfp->mf_fname);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001303 goto theend;
1304 }
1305#endif
1306
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307 /*
1308 * If we guessed the wrong page size, we have to recalculate the
1309 * highest block number in the file.
1310 */
1311 if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
1312 {
Bram Moolenaar1c536282007-04-26 15:21:56 +00001313 unsigned previous_page_size = mfp->mf_page_size;
1314
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
Bram Moolenaar1c536282007-04-26 15:21:56 +00001316 if (mfp->mf_page_size < previous_page_size)
1317 {
1318 msg_start();
1319 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1320 MSG_PUTS_ATTR(_(" has been damaged (page size is smaller than minimum value).\n"),
1321 attr | MSG_HIST);
1322 msg_end();
1323 goto theend;
1324 }
Bram Moolenaar8767f522016-07-01 17:17:39 +02001325 if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001326 mfp->mf_blocknr_max = 0; /* no file or empty file */
1327 else
1328 mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
1329 mfp->mf_infile_count = mfp->mf_blocknr_max;
Bram Moolenaar1c536282007-04-26 15:21:56 +00001330
1331 /* need to reallocate the memory used to store the data */
1332 p = alloc(mfp->mf_page_size);
1333 if (p == NULL)
1334 goto theend;
1335 mch_memmove(p, hp->bh_data, previous_page_size);
1336 vim_free(hp->bh_data);
1337 hp->bh_data = p;
1338 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339 }
1340
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001341 /*
1342 * If .swp file name given directly, use name from swap file for buffer.
1343 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001344 if (directly)
1345 {
1346 expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
1347 if (setfname(curbuf, NameBuff, NULL, TRUE) == FAIL)
1348 goto theend;
1349 }
1350
1351 home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar555b2802005-05-19 21:08:39 +00001352 smsg((char_u *)_("Using swap file \"%s\""), NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353
1354 if (buf_spname(curbuf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001355 vim_strncpy(NameBuff, buf_spname(curbuf), MAXPATHL - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356 else
1357 home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar555b2802005-05-19 21:08:39 +00001358 smsg((char_u *)_("Original file \"%s\""), NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 msg_putchar('\n');
1360
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001361 /*
1362 * check date of swap file and original file
1363 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001364 mtime = char_to_long(b0p->b0_mtime);
1365 if (curbuf->b_ffname != NULL
1366 && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
1367 && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
1368 && org_stat.st_mtime > swp_stat.st_mtime)
1369 || org_stat.st_mtime != mtime))
1370 {
1371 EMSG(_("E308: Warning: Original file may have been changed"));
1372 }
1373 out_flush();
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001374
1375 /* Get the 'fileformat' and 'fileencoding' from block zero. */
1376 b0_ff = (b0p->b0_flags & B0_FF_MASK);
1377 if (b0p->b0_flags & B0_HAS_FENC)
1378 {
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001379 int fnsize = B0_FNAME_SIZE_NOCRYPT;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001380
1381#ifdef FEAT_CRYPT
1382 /* Use the same size as in add_b0_fenc(). */
1383 if (b0p->b0_id[1] != BLOCK0_ID1)
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001384 fnsize = B0_FNAME_SIZE_CRYPT;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001385#endif
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001386 for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; --p)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001387 ;
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001388 b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + fnsize - p));
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001389 }
1390
Bram Moolenaar071d4272004-06-13 20:20:40 +00001391 mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
1392 hp = NULL;
1393
1394 /*
1395 * Now that we are sure that the file is going to be recovered, clear the
1396 * contents of the current buffer.
1397 */
1398 while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
1399 ml_delete((linenr_T)1, FALSE);
1400
1401 /*
1402 * Try reading the original file to obtain the values of 'fileformat',
1403 * 'fileencoding', etc. Ignore errors. The text itself is not used.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001404 * When the file is encrypted the user is asked to enter the key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001405 */
1406 if (curbuf->b_ffname != NULL)
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001407 orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001408 (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001409
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001410#ifdef FEAT_CRYPT
1411 if (b0_cm >= 0)
1412 {
1413 /* Need to ask the user for the crypt key. If this fails we continue
1414 * without a key, will probably get garbage text. */
1415 if (*curbuf->b_p_key != NUL)
1416 {
1417 smsg((char_u *)_("Swap file is encrypted: \"%s\""), fname_used);
1418 MSG_PUTS(_("\nIf you entered a new crypt key but did not write the text file,"));
1419 MSG_PUTS(_("\nenter the new crypt key."));
1420 MSG_PUTS(_("\nIf you wrote the text file after changing the crypt key press enter"));
1421 MSG_PUTS(_("\nto use the same key for text file and swap file"));
1422 }
1423 else
1424 smsg((char_u *)_(need_key_msg), fname_used);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001425 buf->b_p_key = crypt_get_key(FALSE, FALSE);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001426 if (buf->b_p_key == NULL)
1427 buf->b_p_key = curbuf->b_p_key;
1428 else if (*buf->b_p_key == NUL)
1429 {
1430 vim_free(buf->b_p_key);
1431 buf->b_p_key = curbuf->b_p_key;
1432 }
1433 if (buf->b_p_key == NULL)
1434 buf->b_p_key = empty_option;
1435 }
1436#endif
1437
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001438 /* Use the 'fileformat' and 'fileencoding' as stored in the swap file. */
1439 if (b0_ff != 0)
1440 set_fileformat(b0_ff - 1, OPT_LOCAL);
1441 if (b0_fenc != NULL)
1442 {
1443 set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
1444 vim_free(b0_fenc);
1445 }
1446 unchanged(curbuf, TRUE);
1447
Bram Moolenaar071d4272004-06-13 20:20:40 +00001448 bnum = 1; /* start with block 1 */
1449 page_count = 1; /* which is 1 page */
1450 lnum = 0; /* append after line 0 in curbuf */
1451 line_count = 0;
1452 idx = 0; /* start with first index in block 1 */
1453 error = 0;
1454 buf->b_ml.ml_stack_top = 0;
1455 buf->b_ml.ml_stack = NULL;
1456 buf->b_ml.ml_stack_size = 0; /* no stack yet */
1457
1458 if (curbuf->b_ffname == NULL)
1459 cannot_open = TRUE;
1460 else
1461 cannot_open = FALSE;
1462
1463 serious_error = FALSE;
1464 for ( ; !got_int; line_breakcheck())
1465 {
1466 if (hp != NULL)
1467 mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
1468
1469 /*
1470 * get block
1471 */
1472 if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
1473 {
1474 if (bnum == 1)
1475 {
1476 EMSG2(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
1477 goto theend;
1478 }
1479 ++error;
1480 ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
1481 (colnr_T)0, TRUE);
1482 }
1483 else /* there is a block */
1484 {
1485 pp = (PTR_BL *)(hp->bh_data);
1486 if (pp->pb_id == PTR_ID) /* it is a pointer block */
1487 {
1488 /* check line count when using pointer block first time */
1489 if (idx == 0 && line_count != 0)
1490 {
1491 for (i = 0; i < (int)pp->pb_count; ++i)
1492 line_count -= pp->pb_pointer[i].pe_line_count;
1493 if (line_count != 0)
1494 {
1495 ++error;
1496 ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
1497 (colnr_T)0, TRUE);
1498 }
1499 }
1500
1501 if (pp->pb_count == 0)
1502 {
1503 ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
1504 (colnr_T)0, TRUE);
1505 ++error;
1506 }
1507 else if (idx < (int)pp->pb_count) /* go a block deeper */
1508 {
1509 if (pp->pb_pointer[idx].pe_bnum < 0)
1510 {
1511 /*
1512 * Data block with negative block number.
1513 * Try to read lines from the original file.
1514 * This is slow, but it works.
1515 */
1516 if (!cannot_open)
1517 {
1518 line_count = pp->pb_pointer[idx].pe_line_count;
1519 if (readfile(curbuf->b_ffname, NULL, lnum,
1520 pp->pb_pointer[idx].pe_old_lnum - 1,
Bram Moolenaare13b9af2017-01-13 22:01:02 +01001521 line_count, NULL, 0) != OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001522 cannot_open = TRUE;
1523 else
1524 lnum += line_count;
1525 }
1526 if (cannot_open)
1527 {
1528 ++error;
1529 ml_append(lnum++, (char_u *)_("???LINES MISSING"),
1530 (colnr_T)0, TRUE);
1531 }
1532 ++idx; /* get same block again for next index */
1533 continue;
1534 }
1535
1536 /*
1537 * going one block deeper in the tree
1538 */
1539 if ((top = ml_add_stack(buf)) < 0) /* new entry in stack */
1540 {
1541 ++error;
1542 break; /* out of memory */
1543 }
1544 ip = &(buf->b_ml.ml_stack[top]);
1545 ip->ip_bnum = bnum;
1546 ip->ip_index = idx;
1547
1548 bnum = pp->pb_pointer[idx].pe_bnum;
1549 line_count = pp->pb_pointer[idx].pe_line_count;
1550 page_count = pp->pb_pointer[idx].pe_page_count;
Bram Moolenaar986a0032011-06-13 01:07:27 +02001551 idx = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001552 continue;
1553 }
1554 }
1555 else /* not a pointer block */
1556 {
1557 dp = (DATA_BL *)(hp->bh_data);
1558 if (dp->db_id != DATA_ID) /* block id wrong */
1559 {
1560 if (bnum == 1)
1561 {
1562 EMSG2(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
1563 mfp->mf_fname);
1564 goto theend;
1565 }
1566 ++error;
1567 ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
1568 (colnr_T)0, TRUE);
1569 }
1570 else
1571 {
1572 /*
1573 * it is a data block
1574 * Append all the lines in this block
1575 */
1576 has_error = FALSE;
1577 /*
1578 * check length of block
1579 * if wrong, use length in pointer block
1580 */
1581 if (page_count * mfp->mf_page_size != dp->db_txt_end)
1582 {
1583 ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
1584 (colnr_T)0, TRUE);
1585 ++error;
1586 has_error = TRUE;
1587 dp->db_txt_end = page_count * mfp->mf_page_size;
1588 }
1589
1590 /* make sure there is a NUL at the end of the block */
1591 *((char_u *)dp + dp->db_txt_end - 1) = NUL;
1592
1593 /*
1594 * check number of lines in block
1595 * if wrong, use count in data block
1596 */
1597 if (line_count != dp->db_line_count)
1598 {
1599 ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
1600 (colnr_T)0, TRUE);
1601 ++error;
1602 has_error = TRUE;
1603 }
1604
1605 for (i = 0; i < dp->db_line_count; ++i)
1606 {
1607 txt_start = (dp->db_index[i] & DB_INDEX_MASK);
Bram Moolenaar740885b2009-11-03 14:33:17 +00001608 if (txt_start <= (int)HEADER_SIZE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001609 || txt_start >= (int)dp->db_txt_end)
1610 {
1611 p = (char_u *)"???";
1612 ++error;
1613 }
1614 else
1615 p = (char_u *)dp + txt_start;
1616 ml_append(lnum++, p, (colnr_T)0, TRUE);
1617 }
1618 if (has_error)
Bram Moolenaar740885b2009-11-03 14:33:17 +00001619 ml_append(lnum++, (char_u *)_("???END"),
1620 (colnr_T)0, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 }
1622 }
1623 }
1624
1625 if (buf->b_ml.ml_stack_top == 0) /* finished */
1626 break;
1627
1628 /*
1629 * go one block up in the tree
1630 */
1631 ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
1632 bnum = ip->ip_bnum;
1633 idx = ip->ip_index + 1; /* go to next index */
1634 page_count = 1;
1635 }
1636
1637 /*
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001638 * Compare the buffer contents with the original file. When they differ
1639 * set the 'modified' flag.
1640 * Lines 1 - lnum are the new contents.
1641 * Lines lnum + 1 to ml_line_count are the original contents.
1642 * Line ml_line_count + 1 in the dummy empty line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001643 */
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001644 if (orig_file_status != OK || curbuf->b_ml.ml_line_count != lnum * 2 + 1)
1645 {
1646 /* Recovering an empty file results in two lines and the first line is
1647 * empty. Don't set the modified flag then. */
1648 if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL))
1649 {
1650 changed_int();
Bram Moolenaar95c526e2017-02-25 14:59:34 +01001651 ++CHANGEDTICK(curbuf);
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001652 }
1653 }
1654 else
1655 {
1656 for (idx = 1; idx <= lnum; ++idx)
1657 {
1658 /* Need to copy one line, fetching the other one may flush it. */
1659 p = vim_strsave(ml_get(idx));
1660 i = STRCMP(p, ml_get(idx + lnum));
1661 vim_free(p);
1662 if (i != 0)
1663 {
1664 changed_int();
Bram Moolenaar95c526e2017-02-25 14:59:34 +01001665 ++CHANGEDTICK(curbuf);
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001666 break;
1667 }
1668 }
1669 }
1670
1671 /*
1672 * Delete the lines from the original file and the dummy line from the
1673 * empty buffer. These will now be after the last line in the buffer.
1674 */
1675 while (curbuf->b_ml.ml_line_count > lnum
1676 && !(curbuf->b_ml.ml_flags & ML_EMPTY))
1677 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678 curbuf->b_flags |= BF_RECOVERED;
1679
1680 recoverymode = FALSE;
1681 if (got_int)
1682 EMSG(_("E311: Recovery Interrupted"));
1683 else if (error)
1684 {
1685 ++no_wait_return;
1686 MSG(">>>>>>>>>>>>>");
1687 EMSG(_("E312: Errors detected while recovering; look for lines starting with ???"));
1688 --no_wait_return;
1689 MSG(_("See \":help E312\" for more information."));
1690 MSG(">>>>>>>>>>>>>");
1691 }
1692 else
1693 {
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001694 if (curbuf->b_changed)
1695 {
1696 MSG(_("Recovery completed. You should check if everything is OK."));
1697 MSG_PUTS(_("\n(You might want to write out this file under another name\n"));
1698 MSG_PUTS(_("and run diff with the original file to check for changes)"));
1699 }
1700 else
1701 MSG(_("Recovery completed. Buffer contents equals file contents."));
1702 MSG_PUTS(_("\nYou may want to delete the .swp file now.\n\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 cmdline_row = msg_row;
1704 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001705#ifdef FEAT_CRYPT
1706 if (*buf->b_p_key != NUL && STRCMP(curbuf->b_p_key, buf->b_p_key) != 0)
1707 {
1708 MSG_PUTS(_("Using crypt key from swap file for the text file.\n"));
1709 set_option_value((char_u *)"key", 0L, buf->b_p_key, OPT_LOCAL);
1710 }
1711#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712 redraw_curbuf_later(NOT_VALID);
1713
1714theend:
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001715 vim_free(fname_used);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716 recoverymode = FALSE;
1717 if (mfp != NULL)
1718 {
1719 if (hp != NULL)
1720 mf_put(mfp, hp, FALSE, FALSE);
1721 mf_close(mfp, FALSE); /* will also vim_free(mfp->mf_fname) */
1722 }
Bram Moolenaardf88dda2007-01-09 13:34:50 +00001723 if (buf != NULL)
1724 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001725#ifdef FEAT_CRYPT
1726 if (buf->b_p_key != curbuf->b_p_key)
1727 free_string_option(buf->b_p_key);
Bram Moolenaar0ad014c2010-07-25 14:00:46 +02001728 free_string_option(buf->b_p_cm);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001729#endif
Bram Moolenaardf88dda2007-01-09 13:34:50 +00001730 vim_free(buf->b_ml.ml_stack);
1731 vim_free(buf);
1732 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733 if (serious_error && called_from_main)
1734 ml_close(curbuf, TRUE);
1735#ifdef FEAT_AUTOCMD
1736 else
1737 {
1738 apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
1739 apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
1740 }
1741#endif
1742 return;
1743}
1744
1745/*
1746 * Find the names of swap files in current directory and the directory given
1747 * with the 'directory' option.
1748 *
1749 * Used to:
1750 * - list the swap files for "vim -r"
1751 * - count the number of swap files when recovering
1752 * - list the swap files when recovering
1753 * - find the name of the n'th swap file when recovering
1754 */
1755 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001756recover_names(
1757 char_u *fname, /* base for swap file name */
1758 int list, /* when TRUE, list the swap file names */
1759 int nr, /* when non-zero, return nr'th swap file name */
1760 char_u **fname_out) /* result when "nr" > 0 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761{
1762 int num_names;
1763 char_u *(names[6]);
1764 char_u *tail;
1765 char_u *p;
1766 int num_files;
1767 int file_count = 0;
1768 char_u **files;
1769 int i;
1770 char_u *dirp;
1771 char_u *dir_name;
Bram Moolenaar64354da2010-05-25 21:37:17 +02001772 char_u *fname_res = NULL;
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001773#ifdef HAVE_READLINK
1774 char_u fname_buf[MAXPATHL];
Bram Moolenaar64354da2010-05-25 21:37:17 +02001775#endif
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001776
Bram Moolenaar64354da2010-05-25 21:37:17 +02001777 if (fname != NULL)
1778 {
1779#ifdef HAVE_READLINK
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001780 /* Expand symlink in the file name, because the swap file is created
1781 * with the actual file instead of with the symlink. */
1782 if (resolve_symlink(fname, fname_buf) == OK)
1783 fname_res = fname_buf;
1784 else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001785#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001786 fname_res = fname;
Bram Moolenaar64354da2010-05-25 21:37:17 +02001787 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788
1789 if (list)
1790 {
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001791 /* use msg() to start the scrolling properly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001792 msg((char_u *)_("Swap files found:"));
1793 msg_putchar('\n');
1794 }
1795
1796 /*
1797 * Do the loop for every directory in 'directory'.
1798 * First allocate some memory to put the directory name in.
1799 */
1800 dir_name = alloc((unsigned)STRLEN(p_dir) + 1);
1801 dirp = p_dir;
1802 while (dir_name != NULL && *dirp)
1803 {
1804 /*
1805 * Isolate a directory name from *dirp and put it in dir_name (we know
1806 * it is large enough, so use 31000 for length).
1807 * Advance dirp to next directory name.
1808 */
1809 (void)copy_option_part(&dirp, dir_name, 31000, ",");
1810
1811 if (dir_name[0] == '.' && dir_name[1] == NUL) /* check current dir */
1812 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001813 if (fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 {
1815#ifdef VMS
1816 names[0] = vim_strsave((char_u *)"*_sw%");
1817#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 names[0] = vim_strsave((char_u *)"*.sw?");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819#endif
Bram Moolenaar2cc93182006-10-10 19:56:03 +00001820#if defined(UNIX) || defined(WIN3264)
1821 /* For Unix names starting with a dot are special. MS-Windows
1822 * supports this too, on some file systems. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 names[1] = vim_strsave((char_u *)".*.sw?");
1824 names[2] = vim_strsave((char_u *)".sw?");
1825 num_names = 3;
1826#else
1827# ifdef VMS
1828 names[1] = vim_strsave((char_u *)".*_sw%");
1829 num_names = 2;
1830# else
1831 num_names = 1;
1832# endif
1833#endif
1834 }
1835 else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001836 num_names = recov_file_names(names, fname_res, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837 }
1838 else /* check directory dir_name */
1839 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001840 if (fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001841 {
1842#ifdef VMS
1843 names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
1844#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846#endif
Bram Moolenaar2cc93182006-10-10 19:56:03 +00001847#if defined(UNIX) || defined(WIN3264)
1848 /* For Unix names starting with a dot are special. MS-Windows
1849 * supports this too, on some file systems. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
1851 names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
1852 num_names = 3;
1853#else
1854# ifdef VMS
1855 names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
1856 num_names = 2;
1857# else
1858 num_names = 1;
1859# endif
1860#endif
1861 }
1862 else
1863 {
1864#if defined(UNIX) || defined(WIN3264)
Bram Moolenaarb113c3a2017-02-28 21:26:17 +01001865 int len = (int)STRLEN(dir_name);
Bram Moolenaarc525e3a2017-02-18 16:59:02 +01001866
1867 p = dir_name + len;
1868 if (after_pathsep(dir_name, p) && len > 1 && p[-1] == p[-2])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001869 {
1870 /* Ends with '//', Use Full path for swap name */
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001871 tail = make_percent_swname(dir_name, fname_res);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 }
1873 else
1874#endif
1875 {
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001876 tail = gettail(fname_res);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 tail = concat_fnames(dir_name, tail, TRUE);
1878 }
1879 if (tail == NULL)
1880 num_names = 0;
1881 else
1882 {
1883 num_names = recov_file_names(names, tail, FALSE);
1884 vim_free(tail);
1885 }
1886 }
1887 }
1888
1889 /* check for out-of-memory */
1890 for (i = 0; i < num_names; ++i)
1891 {
1892 if (names[i] == NULL)
1893 {
1894 for (i = 0; i < num_names; ++i)
1895 vim_free(names[i]);
1896 num_names = 0;
1897 }
1898 }
1899 if (num_names == 0)
1900 num_files = 0;
1901 else if (expand_wildcards(num_names, names, &num_files, &files,
1902 EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
1903 num_files = 0;
1904
1905 /*
1906 * When no swap file found, wildcard expansion might have failed (e.g.
1907 * not able to execute the shell).
1908 * Try finding a swap file by simply adding ".swp" to the file name.
1909 */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001910 if (*dirp == NUL && file_count + num_files == 0 && fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911 {
Bram Moolenaar8767f522016-07-01 17:17:39 +02001912 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913 char_u *swapname;
1914
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001915 swapname = modname(fname_res,
Bram Moolenaare60acc12011-05-10 16:41:25 +02001916#if defined(VMS)
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001917 (char_u *)"_swp", FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918#else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001919 (char_u *)".swp", TRUE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920#endif
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001921 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922 if (swapname != NULL)
1923 {
1924 if (mch_stat((char *)swapname, &st) != -1) /* It exists! */
1925 {
1926 files = (char_u **)alloc((unsigned)sizeof(char_u *));
1927 if (files != NULL)
1928 {
1929 files[0] = swapname;
1930 swapname = NULL;
1931 num_files = 1;
1932 }
1933 }
1934 vim_free(swapname);
1935 }
1936 }
1937
1938 /*
1939 * remove swapfile name of the current buffer, it must be ignored
1940 */
1941 if (curbuf->b_ml.ml_mfp != NULL
1942 && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
1943 {
1944 for (i = 0; i < num_files; ++i)
1945 if (fullpathcmp(p, files[i], TRUE) & FPC_SAME)
1946 {
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00001947 /* Remove the name from files[i]. Move further entries
1948 * down. When the array becomes empty free it here, since
1949 * FreeWild() won't be called below. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950 vim_free(files[i]);
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00001951 if (--num_files == 0)
1952 vim_free(files);
1953 else
1954 for ( ; i < num_files; ++i)
1955 files[i] = files[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 }
1957 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001958 if (nr > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 {
1960 file_count += num_files;
1961 if (nr <= file_count)
1962 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001963 *fname_out = vim_strsave(
1964 files[nr - 1 + num_files - file_count]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 dirp = (char_u *)""; /* stop searching */
1966 }
1967 }
1968 else if (list)
1969 {
1970 if (dir_name[0] == '.' && dir_name[1] == NUL)
1971 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001972 if (fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973 MSG_PUTS(_(" In current directory:\n"));
1974 else
1975 MSG_PUTS(_(" Using specified name:\n"));
1976 }
1977 else
1978 {
1979 MSG_PUTS(_(" In directory "));
1980 msg_home_replace(dir_name);
1981 MSG_PUTS(":\n");
1982 }
1983
1984 if (num_files)
1985 {
1986 for (i = 0; i < num_files; ++i)
1987 {
1988 /* print the swap file name */
1989 msg_outnum((long)++file_count);
1990 MSG_PUTS(". ");
1991 msg_puts(gettail(files[i]));
1992 msg_putchar('\n');
1993 (void)swapfile_info(files[i]);
1994 }
1995 }
1996 else
1997 MSG_PUTS(_(" -- none --\n"));
1998 out_flush();
1999 }
2000 else
2001 file_count += num_files;
2002
2003 for (i = 0; i < num_names; ++i)
2004 vim_free(names[i]);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00002005 if (num_files > 0)
2006 FreeWild(num_files, files);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002007 }
2008 vim_free(dir_name);
2009 return file_count;
2010}
2011
2012#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
2013/*
2014 * Append the full path to name with path separators made into percent
2015 * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
2016 */
2017 static char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002018make_percent_swname(char_u *dir, char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002019{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002020 char_u *d, *s, *f;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002021
2022 f = fix_fname(name != NULL ? name : (char_u *) "");
2023 d = NULL;
2024 if (f != NULL)
2025 {
2026 s = alloc((unsigned)(STRLEN(f) + 1));
2027 if (s != NULL)
2028 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002029 STRCPY(s, f);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01002030 for (d = s; *d != NUL; MB_PTR_ADV(d))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002031 if (vim_ispathsep(*d))
2032 *d = '%';
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033 d = concat_fnames(dir, s, TRUE);
2034 vim_free(s);
2035 }
2036 vim_free(f);
2037 }
2038 return d;
2039}
2040#endif
2041
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002042#if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043static int process_still_running;
2044#endif
2045
2046/*
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00002047 * Give information about an existing swap file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048 * Returns timestamp (0 when unknown).
2049 */
2050 static time_t
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002051swapfile_info(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002052{
Bram Moolenaar8767f522016-07-01 17:17:39 +02002053 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002054 int fd;
2055 struct block0 b0;
2056 time_t x = (time_t)0;
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00002057 char *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058#ifdef UNIX
2059 char_u uname[B0_UNAME_SIZE];
2060#endif
2061
2062 /* print the swap file date */
2063 if (mch_stat((char *)fname, &st) != -1)
2064 {
2065#ifdef UNIX
2066 /* print name of owner of the file */
2067 if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
2068 {
2069 MSG_PUTS(_(" owned by: "));
2070 msg_outtrans(uname);
2071 MSG_PUTS(_(" dated: "));
2072 }
2073 else
2074#endif
2075 MSG_PUTS(_(" dated: "));
2076 x = st.st_mtime; /* Manx C can't do &st.st_mtime */
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00002077 p = ctime(&x); /* includes '\n' */
2078 if (p == NULL)
2079 MSG_PUTS("(invalid)\n");
2080 else
2081 MSG_PUTS(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082 }
2083
2084 /*
2085 * print the original file name
2086 */
2087 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2088 if (fd >= 0)
2089 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01002090 if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 {
2092 if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
2093 {
2094 MSG_PUTS(_(" [from Vim version 3.0]"));
2095 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002096 else if (ml_check_b0_id(&b0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097 {
2098 MSG_PUTS(_(" [does not look like a Vim swap file]"));
2099 }
2100 else
2101 {
2102 MSG_PUTS(_(" file name: "));
2103 if (b0.b0_fname[0] == NUL)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002104 MSG_PUTS(_("[No Name]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002105 else
2106 msg_outtrans(b0.b0_fname);
2107
2108 MSG_PUTS(_("\n modified: "));
2109 MSG_PUTS(b0.b0_dirty ? _("YES") : _("no"));
2110
2111 if (*(b0.b0_uname) != NUL)
2112 {
2113 MSG_PUTS(_("\n user name: "));
2114 msg_outtrans(b0.b0_uname);
2115 }
2116
2117 if (*(b0.b0_hname) != NUL)
2118 {
2119 if (*(b0.b0_uname) != NUL)
2120 MSG_PUTS(_(" host name: "));
2121 else
2122 MSG_PUTS(_("\n host name: "));
2123 msg_outtrans(b0.b0_hname);
2124 }
2125
2126 if (char_to_long(b0.b0_pid) != 0L)
2127 {
2128 MSG_PUTS(_("\n process ID: "));
2129 msg_outnum(char_to_long(b0.b0_pid));
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002130#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 /* EMX kill() not working correctly, it seems */
2132 if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
2133 {
2134 MSG_PUTS(_(" (still running)"));
2135# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2136 process_still_running = TRUE;
2137# endif
2138 }
2139#endif
2140 }
2141
2142 if (b0_magic_wrong(&b0))
2143 {
Bram Moolenaar48e330a2016-02-23 14:53:34 +01002144#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
2146 MSG_PUTS(_("\n [not usable with this version of Vim]"));
2147 else
2148#endif
2149 MSG_PUTS(_("\n [not usable on this computer]"));
2150 }
2151 }
2152 }
2153 else
2154 MSG_PUTS(_(" [cannot be read]"));
2155 close(fd);
2156 }
2157 else
2158 MSG_PUTS(_(" [cannot be opened]"));
2159 msg_putchar('\n');
2160
2161 return x;
2162}
2163
2164 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002165recov_file_names(char_u **names, char_u *path, int prepend_dot)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166{
2167 int num_names;
2168
Bram Moolenaar071d4272004-06-13 20:20:40 +00002169 /*
2170 * (Win32 and Win64) never short names, but do prepend a dot.
2171 * (Not MS-DOS or Win32 or Win64) maybe short name, maybe not: Try both.
2172 * Only use the short name if it is different.
2173 */
2174 char_u *p;
2175 int i;
2176# ifndef WIN3264
2177 int shortname = curbuf->b_shortname;
2178
2179 curbuf->b_shortname = FALSE;
2180# endif
2181
2182 num_names = 0;
2183
2184 /*
2185 * May also add the file name with a dot prepended, for swap file in same
2186 * dir as original file.
2187 */
2188 if (prepend_dot)
2189 {
2190 names[num_names] = modname(path, (char_u *)".sw?", TRUE);
2191 if (names[num_names] == NULL)
2192 goto end;
2193 ++num_names;
2194 }
2195
2196 /*
2197 * Form the normal swap file name pattern by appending ".sw?".
2198 */
2199#ifdef VMS
2200 names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
2201#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202 names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203#endif
2204 if (names[num_names] == NULL)
2205 goto end;
2206 if (num_names >= 1) /* check if we have the same name twice */
2207 {
2208 p = names[num_names - 1];
2209 i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
2210 if (i > 0)
2211 p += i; /* file name has been expanded to full path */
2212
2213 if (STRCMP(p, names[num_names]) != 0)
2214 ++num_names;
2215 else
2216 vim_free(names[num_names]);
2217 }
2218 else
2219 ++num_names;
2220
2221# ifndef WIN3264
2222 /*
2223 * Also try with 'shortname' set, in case the file is on a DOS filesystem.
2224 */
2225 curbuf->b_shortname = TRUE;
2226#ifdef VMS
2227 names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
2228#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229 names[num_names] = modname(path, (char_u *)".sw?", FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230#endif
2231 if (names[num_names] == NULL)
2232 goto end;
2233
2234 /*
2235 * Remove the one from 'shortname', if it's the same as with 'noshortname'.
2236 */
2237 p = names[num_names];
2238 i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
2239 if (i > 0)
2240 p += i; /* file name has been expanded to full path */
2241 if (STRCMP(names[num_names - 1], p) == 0)
2242 vim_free(names[num_names]);
2243 else
2244 ++num_names;
2245# endif
2246
2247end:
2248# ifndef WIN3264
2249 curbuf->b_shortname = shortname;
2250# endif
2251
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 return num_names;
2253}
2254
2255/*
2256 * sync all memlines
2257 *
2258 * If 'check_file' is TRUE, check if original file exists and was not changed.
2259 * If 'check_char' is TRUE, stop syncing when character becomes available, but
2260 * always sync at least one block.
2261 */
2262 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002263ml_sync_all(int check_file, int check_char)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002264{
2265 buf_T *buf;
Bram Moolenaar8767f522016-07-01 17:17:39 +02002266 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267
Bram Moolenaar29323592016-07-24 22:04:11 +02002268 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 {
2270 if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
2271 continue; /* no file */
2272
2273 ml_flush_line(buf); /* flush buffered line */
2274 /* flush locked block */
2275 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
2276 if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
2277 && buf->b_ffname != NULL)
2278 {
2279 /*
2280 * If the original file does not exist anymore or has been changed
2281 * call ml_preserve() to get rid of all negative numbered blocks.
2282 */
2283 if (mch_stat((char *)buf->b_ffname, &st) == -1
2284 || st.st_mtime != buf->b_mtime_read
Bram Moolenaar914703b2010-05-31 21:59:46 +02002285 || st.st_size != buf->b_orig_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 {
2287 ml_preserve(buf, FALSE);
2288 did_check_timestamps = FALSE;
2289 need_check_timestamps = TRUE; /* give message later */
2290 }
2291 }
2292 if (buf->b_ml.ml_mfp->mf_dirty)
2293 {
2294 (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
2295 | (bufIsChanged(buf) ? MFS_FLUSH : 0));
2296 if (check_char && ui_char_avail()) /* character available now */
2297 break;
2298 }
2299 }
2300}
2301
2302/*
2303 * sync one buffer, including negative blocks
2304 *
2305 * after this all the blocks are in the swap file
2306 *
2307 * Used for the :preserve command and when the original file has been
2308 * changed or deleted.
2309 *
2310 * when message is TRUE the success of preserving is reported
2311 */
2312 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002313ml_preserve(buf_T *buf, int message)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314{
2315 bhdr_T *hp;
2316 linenr_T lnum;
2317 memfile_T *mfp = buf->b_ml.ml_mfp;
2318 int status;
2319 int got_int_save = got_int;
2320
2321 if (mfp == NULL || mfp->mf_fname == NULL)
2322 {
2323 if (message)
2324 EMSG(_("E313: Cannot preserve, there is no swap file"));
2325 return;
2326 }
2327
2328 /* We only want to stop when interrupted here, not when interrupted
2329 * before. */
2330 got_int = FALSE;
2331
2332 ml_flush_line(buf); /* flush buffered line */
2333 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
2334 status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
2335
2336 /* stack is invalid after mf_sync(.., MFS_ALL) */
2337 buf->b_ml.ml_stack_top = 0;
2338
2339 /*
2340 * Some of the data blocks may have been changed from negative to
2341 * positive block number. In that case the pointer blocks need to be
2342 * updated.
2343 *
2344 * We don't know in which pointer block the references are, so we visit
2345 * all data blocks until there are no more translations to be done (or
2346 * we hit the end of the file, which can only happen in case a write fails,
2347 * e.g. when file system if full).
2348 * ml_find_line() does the work by translating the negative block numbers
2349 * when getting the first line of each data block.
2350 */
2351 if (mf_need_trans(mfp) && !got_int)
2352 {
2353 lnum = 1;
2354 while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
2355 {
2356 hp = ml_find_line(buf, lnum, ML_FIND);
2357 if (hp == NULL)
2358 {
2359 status = FAIL;
2360 goto theend;
2361 }
2362 CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
2363 lnum = buf->b_ml.ml_locked_high + 1;
2364 }
2365 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
2366 /* sync the updated pointer blocks */
2367 if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
2368 status = FAIL;
2369 buf->b_ml.ml_stack_top = 0; /* stack is invalid now */
2370 }
2371theend:
2372 got_int |= got_int_save;
2373
2374 if (message)
2375 {
2376 if (status == OK)
2377 MSG(_("File preserved"));
2378 else
2379 EMSG(_("E314: Preserve failed"));
2380 }
2381}
2382
2383/*
2384 * NOTE: The pointer returned by the ml_get_*() functions only remains valid
2385 * until the next call!
2386 * line1 = ml_get(1);
2387 * line2 = ml_get(2); // line1 is now invalid!
2388 * Make a copy of the line if necessary.
2389 */
2390/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002391 * Return a pointer to a (read-only copy of a) line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 *
2393 * On failure an error message is given and IObuff is returned (to avoid
2394 * having to check for error everywhere).
2395 */
2396 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002397ml_get(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398{
2399 return ml_get_buf(curbuf, lnum, FALSE);
2400}
2401
2402/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002403 * Return pointer to position "pos".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 */
2405 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002406ml_get_pos(pos_T *pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407{
2408 return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
2409}
2410
2411/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002412 * Return pointer to cursor line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413 */
2414 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002415ml_get_curline(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416{
2417 return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
2418}
2419
2420/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002421 * Return pointer to cursor position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422 */
2423 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002424ml_get_cursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425{
2426 return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
2427 curwin->w_cursor.col);
2428}
2429
2430/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002431 * Return a pointer to a line in a specific buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 *
2433 * "will_change": if TRUE mark the buffer dirty (chars in the line will be
2434 * changed)
2435 */
2436 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002437ml_get_buf(
2438 buf_T *buf,
2439 linenr_T lnum,
2440 int will_change) /* line will be changed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441{
Bram Moolenaarad40f022007-02-13 03:01:39 +00002442 bhdr_T *hp;
2443 DATA_BL *dp;
2444 char_u *ptr;
2445 static int recursive = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446
2447 if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
2448 {
Bram Moolenaarad40f022007-02-13 03:01:39 +00002449 if (recursive == 0)
2450 {
2451 /* Avoid giving this message for a recursive call, may happen when
2452 * the GUI redraws part of the text. */
2453 ++recursive;
Bram Moolenaar95f09602016-11-10 20:01:45 +01002454 IEMSGN(_("E315: ml_get: invalid lnum: %ld"), lnum);
Bram Moolenaarad40f022007-02-13 03:01:39 +00002455 --recursive;
2456 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457errorret:
2458 STRCPY(IObuff, "???");
2459 return IObuff;
2460 }
2461 if (lnum <= 0) /* pretend line 0 is line 1 */
2462 lnum = 1;
2463
2464 if (buf->b_ml.ml_mfp == NULL) /* there are no lines */
2465 return (char_u *)"";
2466
Bram Moolenaar37d619f2010-03-10 14:46:26 +01002467 /*
2468 * See if it is the same line as requested last time.
2469 * Otherwise may need to flush last used line.
2470 * Don't use the last used line when 'swapfile' is reset, need to load all
2471 * blocks.
2472 */
Bram Moolenaar47b8b152007-02-07 02:41:57 +00002473 if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 {
2475 ml_flush_line(buf);
2476
2477 /*
2478 * Find the data block containing the line.
2479 * This also fills the stack with the blocks from the root to the data
2480 * block and releases any locked block.
2481 */
2482 if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
2483 {
Bram Moolenaarad40f022007-02-13 03:01:39 +00002484 if (recursive == 0)
2485 {
2486 /* Avoid giving this message for a recursive call, may happen
2487 * when the GUI redraws part of the text. */
2488 ++recursive;
Bram Moolenaar95f09602016-11-10 20:01:45 +01002489 IEMSGN(_("E316: ml_get: cannot find line %ld"), lnum);
Bram Moolenaarad40f022007-02-13 03:01:39 +00002490 --recursive;
2491 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 goto errorret;
2493 }
2494
2495 dp = (DATA_BL *)(hp->bh_data);
2496
2497 ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
2498 buf->b_ml.ml_line_ptr = ptr;
2499 buf->b_ml.ml_line_lnum = lnum;
2500 buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
2501 }
2502 if (will_change)
2503 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
2504
2505 return buf->b_ml.ml_line_ptr;
2506}
2507
2508/*
2509 * Check if a line that was just obtained by a call to ml_get
2510 * is in allocated memory.
2511 */
2512 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002513ml_line_alloced(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514{
2515 return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
2516}
2517
2518/*
2519 * Append a line after lnum (may be 0 to insert a line in front of the file).
2520 * "line" does not need to be allocated, but can't be another line in a
2521 * buffer, unlocking may make it invalid.
2522 *
2523 * newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
2524 * will be set for recovery
2525 * Check: The caller of this function should probably also call
2526 * appended_lines().
2527 *
2528 * return FAIL for failure, OK otherwise
2529 */
2530 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002531ml_append(
2532 linenr_T lnum, /* append after this line (can be 0) */
2533 char_u *line, /* text of the new line */
2534 colnr_T len, /* length of new line, including NUL, or 0 */
2535 int newfile) /* flag, see above */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536{
2537 /* When starting up, we might still need to create the memfile */
Bram Moolenaar59f931e2010-07-24 20:27:03 +02002538 if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 return FAIL;
2540
2541 if (curbuf->b_ml.ml_line_lnum != 0)
2542 ml_flush_line(curbuf);
2543 return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
2544}
2545
Bram Moolenaar4033c552017-09-16 20:54:51 +02002546#if defined(FEAT_SPELL) || defined(FEAT_QUICKFIX) || defined(PROTO)
Bram Moolenaar4770d092006-01-12 23:22:24 +00002547/*
2548 * Like ml_append() but for an arbitrary buffer. The buffer must already have
2549 * a memline.
2550 */
2551 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002552ml_append_buf(
2553 buf_T *buf,
2554 linenr_T lnum, /* append after this line (can be 0) */
2555 char_u *line, /* text of the new line */
2556 colnr_T len, /* length of new line, including NUL, or 0 */
2557 int newfile) /* flag, see above */
Bram Moolenaar4770d092006-01-12 23:22:24 +00002558{
2559 if (buf->b_ml.ml_mfp == NULL)
2560 return FAIL;
2561
2562 if (buf->b_ml.ml_line_lnum != 0)
2563 ml_flush_line(buf);
2564 return ml_append_int(buf, lnum, line, len, newfile, FALSE);
2565}
2566#endif
2567
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002569ml_append_int(
2570 buf_T *buf,
2571 linenr_T lnum, /* append after this line (can be 0) */
2572 char_u *line, /* text of the new line */
2573 colnr_T len, /* length of line, including NUL, or 0 */
2574 int newfile, /* flag, see above */
2575 int mark) /* mark the new line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576{
2577 int i;
2578 int line_count; /* number of indexes in current block */
2579 int offset;
2580 int from, to;
2581 int space_needed; /* space needed for new line */
2582 int page_size;
2583 int page_count;
2584 int db_idx; /* index for lnum in data block */
2585 bhdr_T *hp;
2586 memfile_T *mfp;
2587 DATA_BL *dp;
2588 PTR_BL *pp;
2589 infoptr_T *ip;
2590
2591 /* lnum out of range */
2592 if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
2593 return FAIL;
2594
2595 if (lowest_marked && lowest_marked > lnum)
2596 lowest_marked = lnum + 1;
2597
2598 if (len == 0)
2599 len = (colnr_T)STRLEN(line) + 1; /* space needed for the text */
2600 space_needed = len + INDEX_SIZE; /* space needed for text + index */
2601
2602 mfp = buf->b_ml.ml_mfp;
2603 page_size = mfp->mf_page_size;
2604
2605/*
2606 * find the data block containing the previous line
2607 * This also fills the stack with the blocks from the root to the data block
2608 * This also releases any locked block.
2609 */
2610 if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
2611 ML_INSERT)) == NULL)
2612 return FAIL;
2613
2614 buf->b_ml.ml_flags &= ~ML_EMPTY;
2615
2616 if (lnum == 0) /* got line one instead, correct db_idx */
2617 db_idx = -1; /* careful, it is negative! */
2618 else
2619 db_idx = lnum - buf->b_ml.ml_locked_low;
2620 /* get line count before the insertion */
2621 line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2622
2623 dp = (DATA_BL *)(hp->bh_data);
2624
2625/*
2626 * If
2627 * - there is not enough room in the current block
2628 * - appending to the last line in the block
2629 * - not appending to the last line in the file
2630 * insert in front of the next block.
2631 */
2632 if ((int)dp->db_free < space_needed && db_idx == line_count - 1
2633 && lnum < buf->b_ml.ml_line_count)
2634 {
2635 /*
2636 * Now that the line is not going to be inserted in the block that we
2637 * expected, the line count has to be adjusted in the pointer blocks
2638 * by using ml_locked_lineadd.
2639 */
2640 --(buf->b_ml.ml_locked_lineadd);
2641 --(buf->b_ml.ml_locked_high);
2642 if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
2643 return FAIL;
2644
2645 db_idx = -1; /* careful, it is negative! */
2646 /* get line count before the insertion */
2647 line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2648 CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
2649
2650 dp = (DATA_BL *)(hp->bh_data);
2651 }
2652
2653 ++buf->b_ml.ml_line_count;
2654
2655 if ((int)dp->db_free >= space_needed) /* enough room in data block */
2656 {
2657/*
2658 * Insert new line in existing data block, or in data block allocated above.
2659 */
2660 dp->db_txt_start -= len;
2661 dp->db_free -= space_needed;
2662 ++(dp->db_line_count);
2663
2664 /*
2665 * move the text of the lines that follow to the front
2666 * adjust the indexes of the lines that follow
2667 */
2668 if (line_count > db_idx + 1) /* if there are following lines */
2669 {
2670 /*
2671 * Offset is the start of the previous line.
2672 * This will become the character just after the new line.
2673 */
2674 if (db_idx < 0)
2675 offset = dp->db_txt_end;
2676 else
2677 offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
2678 mch_memmove((char *)dp + dp->db_txt_start,
2679 (char *)dp + dp->db_txt_start + len,
2680 (size_t)(offset - (dp->db_txt_start + len)));
2681 for (i = line_count - 1; i > db_idx; --i)
2682 dp->db_index[i + 1] = dp->db_index[i] - len;
2683 dp->db_index[db_idx + 1] = offset - len;
2684 }
2685 else /* add line at the end */
2686 dp->db_index[db_idx + 1] = dp->db_txt_start;
2687
2688 /*
2689 * copy the text into the block
2690 */
2691 mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
2692 if (mark)
2693 dp->db_index[db_idx + 1] |= DB_MARKED;
2694
2695 /*
2696 * Mark the block dirty.
2697 */
2698 buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2699 if (!newfile)
2700 buf->b_ml.ml_flags |= ML_LOCKED_POS;
2701 }
2702 else /* not enough space in data block */
2703 {
2704/*
2705 * If there is not enough room we have to create a new data block and copy some
2706 * lines into it.
2707 * Then we have to insert an entry in the pointer block.
2708 * If this pointer block also is full, we go up another block, and so on, up
2709 * to the root if necessary.
2710 * The line counts in the pointer blocks have already been adjusted by
2711 * ml_find_line().
2712 */
2713 long line_count_left, line_count_right;
2714 int page_count_left, page_count_right;
2715 bhdr_T *hp_left;
2716 bhdr_T *hp_right;
2717 bhdr_T *hp_new;
2718 int lines_moved;
2719 int data_moved = 0; /* init to shut up gcc */
2720 int total_moved = 0; /* init to shut up gcc */
2721 DATA_BL *dp_right, *dp_left;
2722 int stack_idx;
2723 int in_left;
2724 int lineadd;
2725 blocknr_T bnum_left, bnum_right;
2726 linenr_T lnum_left, lnum_right;
2727 int pb_idx;
2728 PTR_BL *pp_new;
2729
2730 /*
2731 * We are going to allocate a new data block. Depending on the
2732 * situation it will be put to the left or right of the existing
2733 * block. If possible we put the new line in the left block and move
2734 * the lines after it to the right block. Otherwise the new line is
2735 * also put in the right block. This method is more efficient when
2736 * inserting a lot of lines at one place.
2737 */
2738 if (db_idx < 0) /* left block is new, right block is existing */
2739 {
2740 lines_moved = 0;
2741 in_left = TRUE;
2742 /* space_needed does not change */
2743 }
2744 else /* left block is existing, right block is new */
2745 {
2746 lines_moved = line_count - db_idx - 1;
2747 if (lines_moved == 0)
2748 in_left = FALSE; /* put new line in right block */
2749 /* space_needed does not change */
2750 else
2751 {
2752 data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
2753 dp->db_txt_start;
2754 total_moved = data_moved + lines_moved * INDEX_SIZE;
2755 if ((int)dp->db_free + total_moved >= space_needed)
2756 {
2757 in_left = TRUE; /* put new line in left block */
2758 space_needed = total_moved;
2759 }
2760 else
2761 {
2762 in_left = FALSE; /* put new line in right block */
2763 space_needed += total_moved;
2764 }
2765 }
2766 }
2767
2768 page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
2769 if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
2770 {
2771 /* correct line counts in pointer blocks */
2772 --(buf->b_ml.ml_locked_lineadd);
2773 --(buf->b_ml.ml_locked_high);
2774 return FAIL;
2775 }
2776 if (db_idx < 0) /* left block is new */
2777 {
2778 hp_left = hp_new;
2779 hp_right = hp;
2780 line_count_left = 0;
2781 line_count_right = line_count;
2782 }
2783 else /* right block is new */
2784 {
2785 hp_left = hp;
2786 hp_right = hp_new;
2787 line_count_left = line_count;
2788 line_count_right = 0;
2789 }
2790 dp_right = (DATA_BL *)(hp_right->bh_data);
2791 dp_left = (DATA_BL *)(hp_left->bh_data);
2792 bnum_left = hp_left->bh_bnum;
2793 bnum_right = hp_right->bh_bnum;
2794 page_count_left = hp_left->bh_page_count;
2795 page_count_right = hp_right->bh_page_count;
2796
2797 /*
2798 * May move the new line into the right/new block.
2799 */
2800 if (!in_left)
2801 {
2802 dp_right->db_txt_start -= len;
2803 dp_right->db_free -= len + INDEX_SIZE;
2804 dp_right->db_index[0] = dp_right->db_txt_start;
2805 if (mark)
2806 dp_right->db_index[0] |= DB_MARKED;
2807
2808 mch_memmove((char *)dp_right + dp_right->db_txt_start,
2809 line, (size_t)len);
2810 ++line_count_right;
2811 }
2812 /*
2813 * may move lines from the left/old block to the right/new one.
2814 */
2815 if (lines_moved)
2816 {
2817 /*
2818 */
2819 dp_right->db_txt_start -= data_moved;
2820 dp_right->db_free -= total_moved;
2821 mch_memmove((char *)dp_right + dp_right->db_txt_start,
2822 (char *)dp_left + dp_left->db_txt_start,
2823 (size_t)data_moved);
2824 offset = dp_right->db_txt_start - dp_left->db_txt_start;
2825 dp_left->db_txt_start += data_moved;
2826 dp_left->db_free += total_moved;
2827
2828 /*
2829 * update indexes in the new block
2830 */
2831 for (to = line_count_right, from = db_idx + 1;
2832 from < line_count_left; ++from, ++to)
2833 dp_right->db_index[to] = dp->db_index[from] + offset;
2834 line_count_right += lines_moved;
2835 line_count_left -= lines_moved;
2836 }
2837
2838 /*
2839 * May move the new line into the left (old or new) block.
2840 */
2841 if (in_left)
2842 {
2843 dp_left->db_txt_start -= len;
2844 dp_left->db_free -= len + INDEX_SIZE;
2845 dp_left->db_index[line_count_left] = dp_left->db_txt_start;
2846 if (mark)
2847 dp_left->db_index[line_count_left] |= DB_MARKED;
2848 mch_memmove((char *)dp_left + dp_left->db_txt_start,
2849 line, (size_t)len);
2850 ++line_count_left;
2851 }
2852
2853 if (db_idx < 0) /* left block is new */
2854 {
2855 lnum_left = lnum + 1;
2856 lnum_right = 0;
2857 }
2858 else /* right block is new */
2859 {
2860 lnum_left = 0;
2861 if (in_left)
2862 lnum_right = lnum + 2;
2863 else
2864 lnum_right = lnum + 1;
2865 }
2866 dp_left->db_line_count = line_count_left;
2867 dp_right->db_line_count = line_count_right;
2868
2869 /*
2870 * release the two data blocks
2871 * The new one (hp_new) already has a correct blocknumber.
2872 * The old one (hp, in ml_locked) gets a positive blocknumber if
2873 * we changed it and we are not editing a new file.
2874 */
2875 if (lines_moved || in_left)
2876 buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2877 if (!newfile && db_idx >= 0 && in_left)
2878 buf->b_ml.ml_flags |= ML_LOCKED_POS;
2879 mf_put(mfp, hp_new, TRUE, FALSE);
2880
2881 /*
2882 * flush the old data block
2883 * set ml_locked_lineadd to 0, because the updating of the
2884 * pointer blocks is done below
2885 */
2886 lineadd = buf->b_ml.ml_locked_lineadd;
2887 buf->b_ml.ml_locked_lineadd = 0;
2888 ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush data block */
2889
2890 /*
2891 * update pointer blocks for the new data block
2892 */
2893 for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
2894 --stack_idx)
2895 {
2896 ip = &(buf->b_ml.ml_stack[stack_idx]);
2897 pb_idx = ip->ip_index;
2898 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
2899 return FAIL;
2900 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
2901 if (pp->pb_id != PTR_ID)
2902 {
Bram Moolenaar95f09602016-11-10 20:01:45 +01002903 IEMSG(_("E317: pointer block id wrong 3"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904 mf_put(mfp, hp, FALSE, FALSE);
2905 return FAIL;
2906 }
2907 /*
2908 * TODO: If the pointer block is full and we are adding at the end
2909 * try to insert in front of the next block
2910 */
2911 /* block not full, add one entry */
2912 if (pp->pb_count < pp->pb_count_max)
2913 {
2914 if (pb_idx + 1 < (int)pp->pb_count)
2915 mch_memmove(&pp->pb_pointer[pb_idx + 2],
2916 &pp->pb_pointer[pb_idx + 1],
2917 (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
2918 ++pp->pb_count;
2919 pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
2920 pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
2921 pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
2922 pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
2923 pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
2924 pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
2925
2926 if (lnum_left != 0)
2927 pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
2928 if (lnum_right != 0)
2929 pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
2930
2931 mf_put(mfp, hp, TRUE, FALSE);
2932 buf->b_ml.ml_stack_top = stack_idx + 1; /* truncate stack */
2933
2934 if (lineadd)
2935 {
2936 --(buf->b_ml.ml_stack_top);
Bram Moolenaar6b803a72007-05-06 14:25:46 +00002937 /* fix line count for rest of blocks in the stack */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 ml_lineadd(buf, lineadd);
2939 /* fix stack itself */
2940 buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
2941 lineadd;
2942 ++(buf->b_ml.ml_stack_top);
2943 }
2944
2945 /*
2946 * We are finished, break the loop here.
2947 */
2948 break;
2949 }
2950 else /* pointer block full */
2951 {
2952 /*
2953 * split the pointer block
2954 * allocate a new pointer block
2955 * move some of the pointer into the new block
2956 * prepare for updating the parent block
2957 */
2958 for (;;) /* do this twice when splitting block 1 */
2959 {
2960 hp_new = ml_new_ptr(mfp);
2961 if (hp_new == NULL) /* TODO: try to fix tree */
2962 return FAIL;
2963 pp_new = (PTR_BL *)(hp_new->bh_data);
2964
2965 if (hp->bh_bnum != 1)
2966 break;
2967
2968 /*
2969 * if block 1 becomes full the tree is given an extra level
2970 * The pointers from block 1 are moved into the new block.
2971 * block 1 is updated to point to the new block
2972 * then continue to split the new block
2973 */
2974 mch_memmove(pp_new, pp, (size_t)page_size);
2975 pp->pb_count = 1;
2976 pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
2977 pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
2978 pp->pb_pointer[0].pe_old_lnum = 1;
2979 pp->pb_pointer[0].pe_page_count = 1;
2980 mf_put(mfp, hp, TRUE, FALSE); /* release block 1 */
2981 hp = hp_new; /* new block is to be split */
2982 pp = pp_new;
2983 CHECK(stack_idx != 0, _("stack_idx should be 0"));
2984 ip->ip_index = 0;
2985 ++stack_idx; /* do block 1 again later */
2986 }
2987 /*
2988 * move the pointers after the current one to the new block
2989 * If there are none, the new entry will be in the new block.
2990 */
2991 total_moved = pp->pb_count - pb_idx - 1;
2992 if (total_moved)
2993 {
2994 mch_memmove(&pp_new->pb_pointer[0],
2995 &pp->pb_pointer[pb_idx + 1],
2996 (size_t)(total_moved) * sizeof(PTR_EN));
2997 pp_new->pb_count = total_moved;
2998 pp->pb_count -= total_moved - 1;
2999 pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
3000 pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
3001 pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
3002 if (lnum_right)
3003 pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
3004 }
3005 else
3006 {
3007 pp_new->pb_count = 1;
3008 pp_new->pb_pointer[0].pe_bnum = bnum_right;
3009 pp_new->pb_pointer[0].pe_line_count = line_count_right;
3010 pp_new->pb_pointer[0].pe_page_count = page_count_right;
3011 pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
3012 }
3013 pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
3014 pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
3015 pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
3016 if (lnum_left)
3017 pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
3018 lnum_left = 0;
3019 lnum_right = 0;
3020
3021 /*
3022 * recompute line counts
3023 */
3024 line_count_right = 0;
3025 for (i = 0; i < (int)pp_new->pb_count; ++i)
3026 line_count_right += pp_new->pb_pointer[i].pe_line_count;
3027 line_count_left = 0;
3028 for (i = 0; i < (int)pp->pb_count; ++i)
3029 line_count_left += pp->pb_pointer[i].pe_line_count;
3030
3031 bnum_left = hp->bh_bnum;
3032 bnum_right = hp_new->bh_bnum;
3033 page_count_left = 1;
3034 page_count_right = 1;
3035 mf_put(mfp, hp, TRUE, FALSE);
3036 mf_put(mfp, hp_new, TRUE, FALSE);
3037 }
3038 }
3039
3040 /*
3041 * Safety check: fallen out of for loop?
3042 */
3043 if (stack_idx < 0)
3044 {
Bram Moolenaar95f09602016-11-10 20:01:45 +01003045 IEMSG(_("E318: Updated too many blocks?"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046 buf->b_ml.ml_stack_top = 0; /* invalidate stack */
3047 }
3048 }
3049
3050#ifdef FEAT_BYTEOFF
3051 /* The line was inserted below 'lnum' */
3052 ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
3053#endif
3054#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003055 if (netbeans_active())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 {
3057 if (STRLEN(line) > 0)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003058 netbeans_inserted(buf, lnum+1, (colnr_T)0, line, (int)STRLEN(line));
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00003059 netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060 (char_u *)"\n", 1);
3061 }
3062#endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01003063#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar99ef0622016-03-06 20:22:25 +01003064 if (buf->b_write_to_channel)
3065 channel_write_new_lines(buf);
3066#endif
3067
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 return OK;
3069}
3070
3071/*
Bram Moolenaar4770d092006-01-12 23:22:24 +00003072 * Replace line lnum, with buffering, in current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003073 *
Bram Moolenaar1056d982006-03-09 22:37:52 +00003074 * If "copy" is TRUE, make a copy of the line, otherwise the line has been
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 * copied to allocated memory already.
3076 *
3077 * Check: The caller of this function should probably also call
3078 * changed_lines(), unless update_screen(NOT_VALID) is used.
3079 *
3080 * return FAIL for failure, OK otherwise
3081 */
3082 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003083ml_replace(linenr_T lnum, char_u *line, int copy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084{
3085 if (line == NULL) /* just checking... */
3086 return FAIL;
3087
3088 /* When starting up, we might still need to create the memfile */
Bram Moolenaar59f931e2010-07-24 20:27:03 +02003089 if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090 return FAIL;
3091
3092 if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */
3093 return FAIL;
3094#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003095 if (netbeans_active())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096 {
3097 netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003098 netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 }
3100#endif
3101 if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
3102 ml_flush_line(curbuf); /* flush it */
3103 else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
3104 vim_free(curbuf->b_ml.ml_line_ptr); /* free it */
3105 curbuf->b_ml.ml_line_ptr = line;
3106 curbuf->b_ml.ml_line_lnum = lnum;
3107 curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
3108
3109 return OK;
3110}
3111
3112/*
Bram Moolenaar4033c552017-09-16 20:54:51 +02003113 * Delete line "lnum" in the current buffer.
3114 * When "message" is TRUE may give a "No lines in buffer" message.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115 *
3116 * Check: The caller of this function should probably also call
3117 * deleted_lines() after this.
3118 *
3119 * return FAIL for failure, OK otherwise
3120 */
3121 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003122ml_delete(linenr_T lnum, int message)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003123{
3124 ml_flush_line(curbuf);
3125 return ml_delete_int(curbuf, lnum, message);
3126}
3127
3128 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003129ml_delete_int(buf_T *buf, linenr_T lnum, int message)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130{
3131 bhdr_T *hp;
3132 memfile_T *mfp;
3133 DATA_BL *dp;
3134 PTR_BL *pp;
3135 infoptr_T *ip;
3136 int count; /* number of entries in block */
3137 int idx;
3138 int stack_idx;
3139 int text_start;
3140 int line_start;
3141 long line_size;
3142 int i;
3143
3144 if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
3145 return FAIL;
3146
3147 if (lowest_marked && lowest_marked > lnum)
3148 lowest_marked--;
3149
3150/*
3151 * If the file becomes empty the last line is replaced by an empty line.
3152 */
3153 if (buf->b_ml.ml_line_count == 1) /* file becomes empty */
3154 {
3155 if (message
3156#ifdef FEAT_NETBEANS_INTG
3157 && !netbeansSuppressNoLines
3158#endif
3159 )
Bram Moolenaar238a5642006-02-21 22:12:05 +00003160 set_keep_msg((char_u *)_(no_lines_msg), 0);
3161
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003162 /* FEAT_BYTEOFF already handled in there, don't worry 'bout it below */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163 i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
3164 buf->b_ml.ml_flags |= ML_EMPTY;
3165
3166 return i;
3167 }
3168
3169/*
3170 * find the data block containing the line
3171 * This also fills the stack with the blocks from the root to the data block
3172 * This also releases any locked block.
3173 */
3174 mfp = buf->b_ml.ml_mfp;
3175 if (mfp == NULL)
3176 return FAIL;
3177
3178 if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
3179 return FAIL;
3180
3181 dp = (DATA_BL *)(hp->bh_data);
3182 /* compute line count before the delete */
3183 count = (long)(buf->b_ml.ml_locked_high)
3184 - (long)(buf->b_ml.ml_locked_low) + 2;
3185 idx = lnum - buf->b_ml.ml_locked_low;
3186
3187 --buf->b_ml.ml_line_count;
3188
3189 line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3190 if (idx == 0) /* first line in block, text at the end */
3191 line_size = dp->db_txt_end - line_start;
3192 else
3193 line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
3194
3195#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003196 if (netbeans_active())
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00003197 netbeans_removed(buf, lnum, 0, (long)line_size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198#endif
3199
3200/*
3201 * special case: If there is only one line in the data block it becomes empty.
3202 * Then we have to remove the entry, pointing to this data block, from the
3203 * pointer block. If this pointer block also becomes empty, we go up another
3204 * block, and so on, up to the root if necessary.
3205 * The line counts in the pointer blocks have already been adjusted by
3206 * ml_find_line().
3207 */
3208 if (count == 1)
3209 {
3210 mf_free(mfp, hp); /* free the data block */
3211 buf->b_ml.ml_locked = NULL;
3212
Bram Moolenaare60acc12011-05-10 16:41:25 +02003213 for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
3214 --stack_idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215 {
3216 buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */
3217 ip = &(buf->b_ml.ml_stack[stack_idx]);
3218 idx = ip->ip_index;
3219 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3220 return FAIL;
3221 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
3222 if (pp->pb_id != PTR_ID)
3223 {
Bram Moolenaar95f09602016-11-10 20:01:45 +01003224 IEMSG(_("E317: pointer block id wrong 4"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 mf_put(mfp, hp, FALSE, FALSE);
3226 return FAIL;
3227 }
3228 count = --(pp->pb_count);
3229 if (count == 0) /* the pointer block becomes empty! */
3230 mf_free(mfp, hp);
3231 else
3232 {
3233 if (count != idx) /* move entries after the deleted one */
3234 mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
3235 (size_t)(count - idx) * sizeof(PTR_EN));
3236 mf_put(mfp, hp, TRUE, FALSE);
3237
3238 buf->b_ml.ml_stack_top = stack_idx; /* truncate stack */
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003239 /* fix line count for rest of blocks in the stack */
3240 if (buf->b_ml.ml_locked_lineadd != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 {
3242 ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
3243 buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003244 buf->b_ml.ml_locked_lineadd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245 }
3246 ++(buf->b_ml.ml_stack_top);
3247
3248 break;
3249 }
3250 }
3251 CHECK(stack_idx < 0, _("deleted block 1?"));
3252 }
3253 else
3254 {
3255 /*
3256 * delete the text by moving the next lines forwards
3257 */
3258 text_start = dp->db_txt_start;
3259 mch_memmove((char *)dp + text_start + line_size,
3260 (char *)dp + text_start, (size_t)(line_start - text_start));
3261
3262 /*
3263 * delete the index by moving the next indexes backwards
3264 * Adjust the indexes for the text movement.
3265 */
3266 for (i = idx; i < count - 1; ++i)
3267 dp->db_index[i] = dp->db_index[i + 1] + line_size;
3268
3269 dp->db_free += line_size + INDEX_SIZE;
3270 dp->db_txt_start += line_size;
3271 --(dp->db_line_count);
3272
3273 /*
3274 * mark the block dirty and make sure it is in the file (for recovery)
3275 */
3276 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3277 }
3278
3279#ifdef FEAT_BYTEOFF
3280 ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
3281#endif
3282 return OK;
3283}
3284
3285/*
3286 * set the B_MARKED flag for line 'lnum'
3287 */
3288 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003289ml_setmarked(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290{
3291 bhdr_T *hp;
3292 DATA_BL *dp;
3293 /* invalid line number */
3294 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
3295 || curbuf->b_ml.ml_mfp == NULL)
3296 return; /* give error message? */
3297
3298 if (lowest_marked == 0 || lowest_marked > lnum)
3299 lowest_marked = lnum;
3300
3301 /*
3302 * find the data block containing the line
3303 * This also fills the stack with the blocks from the root to the data block
3304 * This also releases any locked block.
3305 */
3306 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3307 return; /* give error message? */
3308
3309 dp = (DATA_BL *)(hp->bh_data);
3310 dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
3311 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3312}
3313
3314/*
3315 * find the first line with its B_MARKED flag set
3316 */
3317 linenr_T
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003318ml_firstmarked(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319{
3320 bhdr_T *hp;
3321 DATA_BL *dp;
3322 linenr_T lnum;
3323 int i;
3324
3325 if (curbuf->b_ml.ml_mfp == NULL)
3326 return (linenr_T) 0;
3327
3328 /*
3329 * The search starts with lowest_marked line. This is the last line where
3330 * a mark was found, adjusted by inserting/deleting lines.
3331 */
3332 for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3333 {
3334 /*
3335 * Find the data block containing the line.
3336 * This also fills the stack with the blocks from the root to the data
3337 * block This also releases any locked block.
3338 */
3339 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3340 return (linenr_T)0; /* give error message? */
3341
3342 dp = (DATA_BL *)(hp->bh_data);
3343
3344 for (i = lnum - curbuf->b_ml.ml_locked_low;
3345 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3346 if ((dp->db_index[i]) & DB_MARKED)
3347 {
3348 (dp->db_index[i]) &= DB_INDEX_MASK;
3349 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3350 lowest_marked = lnum + 1;
3351 return lnum;
3352 }
3353 }
3354
3355 return (linenr_T) 0;
3356}
3357
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358/*
3359 * clear all DB_MARKED flags
3360 */
3361 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003362ml_clearmarked(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363{
3364 bhdr_T *hp;
3365 DATA_BL *dp;
3366 linenr_T lnum;
3367 int i;
3368
3369 if (curbuf->b_ml.ml_mfp == NULL) /* nothing to do */
3370 return;
3371
3372 /*
3373 * The search starts with line lowest_marked.
3374 */
3375 for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3376 {
3377 /*
3378 * Find the data block containing the line.
3379 * This also fills the stack with the blocks from the root to the data
3380 * block and releases any locked block.
3381 */
3382 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3383 return; /* give error message? */
3384
3385 dp = (DATA_BL *)(hp->bh_data);
3386
3387 for (i = lnum - curbuf->b_ml.ml_locked_low;
3388 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3389 if ((dp->db_index[i]) & DB_MARKED)
3390 {
3391 (dp->db_index[i]) &= DB_INDEX_MASK;
3392 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3393 }
3394 }
3395
3396 lowest_marked = 0;
3397 return;
3398}
3399
3400/*
3401 * flush ml_line if necessary
3402 */
3403 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003404ml_flush_line(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405{
3406 bhdr_T *hp;
3407 DATA_BL *dp;
3408 linenr_T lnum;
3409 char_u *new_line;
3410 char_u *old_line;
3411 colnr_T new_len;
3412 int old_len;
3413 int extra;
3414 int idx;
3415 int start;
3416 int count;
3417 int i;
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003418 static int entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419
3420 if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
3421 return; /* nothing to do */
3422
3423 if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
3424 {
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003425 /* This code doesn't work recursively, but Netbeans may call back here
3426 * when obtaining the cursor position. */
3427 if (entered)
3428 return;
3429 entered = TRUE;
3430
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431 lnum = buf->b_ml.ml_line_lnum;
3432 new_line = buf->b_ml.ml_line_ptr;
3433
3434 hp = ml_find_line(buf, lnum, ML_FIND);
3435 if (hp == NULL)
Bram Moolenaar95f09602016-11-10 20:01:45 +01003436 IEMSGN(_("E320: Cannot find line %ld"), lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003437 else
3438 {
3439 dp = (DATA_BL *)(hp->bh_data);
3440 idx = lnum - buf->b_ml.ml_locked_low;
3441 start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3442 old_line = (char_u *)dp + start;
3443 if (idx == 0) /* line is last in block */
3444 old_len = dp->db_txt_end - start;
3445 else /* text of previous line follows */
3446 old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
3447 new_len = (colnr_T)STRLEN(new_line) + 1;
3448 extra = new_len - old_len; /* negative if lines gets smaller */
3449
3450 /*
3451 * if new line fits in data block, replace directly
3452 */
3453 if ((int)dp->db_free >= extra)
3454 {
3455 /* if the length changes and there are following lines */
3456 count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
3457 if (extra != 0 && idx < count - 1)
3458 {
3459 /* move text of following lines */
3460 mch_memmove((char *)dp + dp->db_txt_start - extra,
3461 (char *)dp + dp->db_txt_start,
3462 (size_t)(start - dp->db_txt_start));
3463
3464 /* adjust pointers of this and following lines */
3465 for (i = idx + 1; i < count; ++i)
3466 dp->db_index[i] -= extra;
3467 }
3468 dp->db_index[idx] -= extra;
3469
3470 /* adjust free space */
3471 dp->db_free -= extra;
3472 dp->db_txt_start -= extra;
3473
3474 /* copy new line into the data block */
3475 mch_memmove(old_line - extra, new_line, (size_t)new_len);
3476 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3477#ifdef FEAT_BYTEOFF
3478 /* The else case is already covered by the insert and delete */
3479 ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
3480#endif
3481 }
3482 else
3483 {
3484 /*
3485 * Cannot do it in one data block: Delete and append.
3486 * Append first, because ml_delete_int() cannot delete the
3487 * last line in a buffer, which causes trouble for a buffer
3488 * that has only one line.
3489 * Don't forget to copy the mark!
3490 */
3491 /* How about handling errors??? */
3492 (void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
3493 (dp->db_index[idx] & DB_MARKED));
3494 (void)ml_delete_int(buf, lnum, FALSE);
3495 }
3496 }
3497 vim_free(new_line);
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003498
3499 entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500 }
3501
3502 buf->b_ml.ml_line_lnum = 0;
3503}
3504
3505/*
3506 * create a new, empty, data block
3507 */
3508 static bhdr_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003509ml_new_data(memfile_T *mfp, int negative, int page_count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510{
3511 bhdr_T *hp;
3512 DATA_BL *dp;
3513
3514 if ((hp = mf_new(mfp, negative, page_count)) == NULL)
3515 return NULL;
3516
3517 dp = (DATA_BL *)(hp->bh_data);
3518 dp->db_id = DATA_ID;
3519 dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
3520 dp->db_free = dp->db_txt_start - HEADER_SIZE;
3521 dp->db_line_count = 0;
3522
3523 return hp;
3524}
3525
3526/*
3527 * create a new, empty, pointer block
3528 */
3529 static bhdr_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003530ml_new_ptr(memfile_T *mfp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531{
3532 bhdr_T *hp;
3533 PTR_BL *pp;
3534
3535 if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
3536 return NULL;
3537
3538 pp = (PTR_BL *)(hp->bh_data);
3539 pp->pb_id = PTR_ID;
3540 pp->pb_count = 0;
Bram Moolenaar20a825a2010-05-31 21:27:30 +02003541 pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL))
3542 / sizeof(PTR_EN) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543
3544 return hp;
3545}
3546
3547/*
3548 * lookup line 'lnum' in a memline
3549 *
3550 * action: if ML_DELETE or ML_INSERT the line count is updated while searching
3551 * if ML_FLUSH only flush a locked block
3552 * if ML_FIND just find the line
3553 *
3554 * If the block was found it is locked and put in ml_locked.
3555 * The stack is updated to lead to the locked block. The ip_high field in
3556 * the stack is updated to reflect the last line in the block AFTER the
3557 * insert or delete, also if the pointer block has not been updated yet. But
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003558 * if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003559 *
3560 * return: NULL for failure, pointer to block header otherwise
3561 */
3562 static bhdr_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003563ml_find_line(buf_T *buf, linenr_T lnum, int action)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003564{
3565 DATA_BL *dp;
3566 PTR_BL *pp;
3567 infoptr_T *ip;
3568 bhdr_T *hp;
3569 memfile_T *mfp;
3570 linenr_T t;
3571 blocknr_T bnum, bnum2;
3572 int dirty;
3573 linenr_T low, high;
3574 int top;
3575 int page_count;
3576 int idx;
3577
3578 mfp = buf->b_ml.ml_mfp;
3579
3580 /*
3581 * If there is a locked block check if the wanted line is in it.
3582 * If not, flush and release the locked block.
3583 * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
3584 * Don't do this for ML_FLUSH, because we want to flush the locked block.
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003585 * Don't do this when 'swapfile' is reset, we want to load all the blocks.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 */
3587 if (buf->b_ml.ml_locked)
3588 {
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003589 if (ML_SIMPLE(action)
3590 && buf->b_ml.ml_locked_low <= lnum
3591 && buf->b_ml.ml_locked_high >= lnum
3592 && !mf_dont_release)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593 {
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003594 /* remember to update pointer blocks and stack later */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595 if (action == ML_INSERT)
3596 {
3597 ++(buf->b_ml.ml_locked_lineadd);
3598 ++(buf->b_ml.ml_locked_high);
3599 }
3600 else if (action == ML_DELETE)
3601 {
3602 --(buf->b_ml.ml_locked_lineadd);
3603 --(buf->b_ml.ml_locked_high);
3604 }
3605 return (buf->b_ml.ml_locked);
3606 }
3607
3608 mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
3609 buf->b_ml.ml_flags & ML_LOCKED_POS);
3610 buf->b_ml.ml_locked = NULL;
3611
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003612 /*
3613 * If lines have been added or deleted in the locked block, need to
3614 * update the line count in pointer blocks.
3615 */
3616 if (buf->b_ml.ml_locked_lineadd != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
3618 }
3619
3620 if (action == ML_FLUSH) /* nothing else to do */
3621 return NULL;
3622
3623 bnum = 1; /* start at the root of the tree */
3624 page_count = 1;
3625 low = 1;
3626 high = buf->b_ml.ml_line_count;
3627
3628 if (action == ML_FIND) /* first try stack entries */
3629 {
3630 for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
3631 {
3632 ip = &(buf->b_ml.ml_stack[top]);
3633 if (ip->ip_low <= lnum && ip->ip_high >= lnum)
3634 {
3635 bnum = ip->ip_bnum;
3636 low = ip->ip_low;
3637 high = ip->ip_high;
3638 buf->b_ml.ml_stack_top = top; /* truncate stack at prev entry */
3639 break;
3640 }
3641 }
3642 if (top < 0)
3643 buf->b_ml.ml_stack_top = 0; /* not found, start at the root */
3644 }
3645 else /* ML_DELETE or ML_INSERT */
3646 buf->b_ml.ml_stack_top = 0; /* start at the root */
3647
3648/*
3649 * search downwards in the tree until a data block is found
3650 */
3651 for (;;)
3652 {
3653 if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
3654 goto error_noblock;
3655
3656 /*
3657 * update high for insert/delete
3658 */
3659 if (action == ML_INSERT)
3660 ++high;
3661 else if (action == ML_DELETE)
3662 --high;
3663
3664 dp = (DATA_BL *)(hp->bh_data);
3665 if (dp->db_id == DATA_ID) /* data block */
3666 {
3667 buf->b_ml.ml_locked = hp;
3668 buf->b_ml.ml_locked_low = low;
3669 buf->b_ml.ml_locked_high = high;
3670 buf->b_ml.ml_locked_lineadd = 0;
3671 buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
3672 return hp;
3673 }
3674
3675 pp = (PTR_BL *)(dp); /* must be pointer block */
3676 if (pp->pb_id != PTR_ID)
3677 {
Bram Moolenaar95f09602016-11-10 20:01:45 +01003678 IEMSG(_("E317: pointer block id wrong"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679 goto error_block;
3680 }
3681
3682 if ((top = ml_add_stack(buf)) < 0) /* add new entry to stack */
3683 goto error_block;
3684 ip = &(buf->b_ml.ml_stack[top]);
3685 ip->ip_bnum = bnum;
3686 ip->ip_low = low;
3687 ip->ip_high = high;
3688 ip->ip_index = -1; /* index not known yet */
3689
3690 dirty = FALSE;
3691 for (idx = 0; idx < (int)pp->pb_count; ++idx)
3692 {
3693 t = pp->pb_pointer[idx].pe_line_count;
3694 CHECK(t == 0, _("pe_line_count is zero"));
3695 if ((low += t) > lnum)
3696 {
3697 ip->ip_index = idx;
3698 bnum = pp->pb_pointer[idx].pe_bnum;
3699 page_count = pp->pb_pointer[idx].pe_page_count;
3700 high = low - 1;
3701 low -= t;
3702
3703 /*
3704 * a negative block number may have been changed
3705 */
3706 if (bnum < 0)
3707 {
3708 bnum2 = mf_trans_del(mfp, bnum);
3709 if (bnum != bnum2)
3710 {
3711 bnum = bnum2;
3712 pp->pb_pointer[idx].pe_bnum = bnum;
3713 dirty = TRUE;
3714 }
3715 }
3716
3717 break;
3718 }
3719 }
3720 if (idx >= (int)pp->pb_count) /* past the end: something wrong! */
3721 {
3722 if (lnum > buf->b_ml.ml_line_count)
Bram Moolenaar95f09602016-11-10 20:01:45 +01003723 IEMSGN(_("E322: line number out of range: %ld past the end"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 lnum - buf->b_ml.ml_line_count);
3725
3726 else
Bram Moolenaar95f09602016-11-10 20:01:45 +01003727 IEMSGN(_("E323: line count wrong in block %ld"), bnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728 goto error_block;
3729 }
3730 if (action == ML_DELETE)
3731 {
3732 pp->pb_pointer[idx].pe_line_count--;
3733 dirty = TRUE;
3734 }
3735 else if (action == ML_INSERT)
3736 {
3737 pp->pb_pointer[idx].pe_line_count++;
3738 dirty = TRUE;
3739 }
3740 mf_put(mfp, hp, dirty, FALSE);
3741 }
3742
3743error_block:
3744 mf_put(mfp, hp, FALSE, FALSE);
3745error_noblock:
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003746 /*
3747 * If action is ML_DELETE or ML_INSERT we have to correct the tree for
3748 * the incremented/decremented line counts, because there won't be a line
3749 * inserted/deleted after all.
3750 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 if (action == ML_DELETE)
3752 ml_lineadd(buf, 1);
3753 else if (action == ML_INSERT)
3754 ml_lineadd(buf, -1);
3755 buf->b_ml.ml_stack_top = 0;
3756 return NULL;
3757}
3758
3759/*
3760 * add an entry to the info pointer stack
3761 *
3762 * return -1 for failure, number of the new entry otherwise
3763 */
3764 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003765ml_add_stack(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003766{
3767 int top;
3768 infoptr_T *newstack;
3769
3770 top = buf->b_ml.ml_stack_top;
3771
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003772 /* may have to increase the stack size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003773 if (top == buf->b_ml.ml_stack_size)
3774 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003775 CHECK(top > 0, _("Stack size increases")); /* more than 5 levels??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003776
3777 newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
3778 (buf->b_ml.ml_stack_size + STACK_INCR));
3779 if (newstack == NULL)
3780 return -1;
Bram Moolenaarfbd302f2015-08-08 18:23:46 +02003781 if (top > 0)
3782 mch_memmove(newstack, buf->b_ml.ml_stack,
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003783 (size_t)top * sizeof(infoptr_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003784 vim_free(buf->b_ml.ml_stack);
3785 buf->b_ml.ml_stack = newstack;
3786 buf->b_ml.ml_stack_size += STACK_INCR;
3787 }
3788
3789 buf->b_ml.ml_stack_top++;
3790 return top;
3791}
3792
3793/*
3794 * Update the pointer blocks on the stack for inserted/deleted lines.
3795 * The stack itself is also updated.
3796 *
3797 * When a insert/delete line action fails, the line is not inserted/deleted,
3798 * but the pointer blocks have already been updated. That is fixed here by
3799 * walking through the stack.
3800 *
3801 * Count is the number of lines added, negative if lines have been deleted.
3802 */
3803 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003804ml_lineadd(buf_T *buf, int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003805{
3806 int idx;
3807 infoptr_T *ip;
3808 PTR_BL *pp;
3809 memfile_T *mfp = buf->b_ml.ml_mfp;
3810 bhdr_T *hp;
3811
3812 for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
3813 {
3814 ip = &(buf->b_ml.ml_stack[idx]);
3815 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3816 break;
3817 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
3818 if (pp->pb_id != PTR_ID)
3819 {
3820 mf_put(mfp, hp, FALSE, FALSE);
Bram Moolenaar95f09602016-11-10 20:01:45 +01003821 IEMSG(_("E317: pointer block id wrong 2"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 break;
3823 }
3824 pp->pb_pointer[ip->ip_index].pe_line_count += count;
3825 ip->ip_high += count;
3826 mf_put(mfp, hp, TRUE, FALSE);
3827 }
3828}
3829
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003830#if defined(HAVE_READLINK) || defined(PROTO)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003831/*
3832 * Resolve a symlink in the last component of a file name.
3833 * Note that f_resolve() does it for every part of the path, we don't do that
3834 * here.
3835 * If it worked returns OK and the resolved link in "buf[MAXPATHL]".
3836 * Otherwise returns FAIL.
3837 */
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003838 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003839resolve_symlink(char_u *fname, char_u *buf)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003840{
3841 char_u tmp[MAXPATHL];
3842 int ret;
3843 int depth = 0;
3844
3845 if (fname == NULL)
3846 return FAIL;
3847
3848 /* Put the result so far in tmp[], starting with the original name. */
3849 vim_strncpy(tmp, fname, MAXPATHL - 1);
3850
3851 for (;;)
3852 {
3853 /* Limit symlink depth to 100, catch recursive loops. */
3854 if (++depth == 100)
3855 {
3856 EMSG2(_("E773: Symlink loop for \"%s\""), fname);
3857 return FAIL;
3858 }
3859
3860 ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
3861 if (ret <= 0)
3862 {
Bram Moolenaarcc984262005-12-23 22:19:46 +00003863 if (errno == EINVAL || errno == ENOENT)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003864 {
Bram Moolenaarcc984262005-12-23 22:19:46 +00003865 /* Found non-symlink or not existing file, stop here.
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00003866 * When at the first level use the unmodified name, skip the
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003867 * call to vim_FullName(). */
3868 if (depth == 1)
3869 return FAIL;
3870
3871 /* Use the resolved name in tmp[]. */
3872 break;
3873 }
3874
3875 /* There must be some error reading links, use original name. */
3876 return FAIL;
3877 }
3878 buf[ret] = NUL;
3879
3880 /*
3881 * Check whether the symlink is relative or absolute.
3882 * If it's relative, build a new path based on the directory
3883 * portion of the filename (if any) and the path the symlink
3884 * points to.
3885 */
3886 if (mch_isFullName(buf))
3887 STRCPY(tmp, buf);
3888 else
3889 {
3890 char_u *tail;
3891
3892 tail = gettail(tmp);
3893 if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
3894 return FAIL;
3895 STRCPY(tail, buf);
3896 }
3897 }
3898
3899 /*
3900 * Try to resolve the full name of the file so that the swapfile name will
3901 * be consistent even when opening a relative symlink from different
3902 * working directories.
3903 */
3904 return vim_FullName(tmp, buf, MAXPATHL, TRUE);
3905}
3906#endif
3907
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908/*
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003909 * Make swap file name out of the file name and a directory name.
3910 * Returns pointer to allocated memory or NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 */
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003912 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003913makeswapname(
3914 char_u *fname,
3915 char_u *ffname UNUSED,
3916 buf_T *buf,
3917 char_u *dir_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003918{
3919 char_u *r, *s;
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02003920 char_u *fname_res = fname;
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003921#ifdef HAVE_READLINK
3922 char_u fname_buf[MAXPATHL];
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003923#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003924
3925#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
Bram Moolenaarb113c3a2017-02-28 21:26:17 +01003926 int len = (int)STRLEN(dir_name);
Bram Moolenaarc525e3a2017-02-18 16:59:02 +01003927
3928 s = dir_name + len;
3929 if (after_pathsep(dir_name, s) && len > 1 && s[-1] == s[-2])
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930 { /* Ends with '//', Use Full path */
3931 r = NULL;
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003932 if ((s = make_percent_swname(dir_name, fname)) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 {
3934 r = modname(s, (char_u *)".swp", FALSE);
3935 vim_free(s);
3936 }
3937 return r;
3938 }
3939#endif
3940
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003941#ifdef HAVE_READLINK
3942 /* Expand symlink in the file name, so that we put the swap file with the
3943 * actual file instead of with the symlink. */
3944 if (resolve_symlink(fname, fname_buf) == OK)
3945 fname_res = fname_buf;
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003946#endif
3947
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948 r = buf_modname(
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949 (buf->b_p_sn || buf->b_shortname),
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003950 fname_res,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951 (char_u *)
Bram Moolenaare60acc12011-05-10 16:41:25 +02003952#if defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003953 "_swp",
3954#else
3955 ".swp",
3956#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003957 /* Prepend a '.' to the swap file name for the current directory. */
Bram Moolenaar48e330a2016-02-23 14:53:34 +01003958 dir_name[0] == '.' && dir_name[1] == NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003959 if (r == NULL) /* out of memory */
3960 return NULL;
3961
3962 s = get_file_in_dir(r, dir_name);
3963 vim_free(r);
3964 return s;
3965}
3966
3967/*
3968 * Get file name to use for swap file or backup file.
3969 * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
3970 * option "dname".
3971 * - If "dname" is ".", return "fname" (swap file in dir of file).
3972 * - If "dname" starts with "./", insert "dname" in "fname" (swap file
3973 * relative to dir of file).
3974 * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
3975 * dir).
3976 *
3977 * The return value is an allocated string and can be NULL.
3978 */
3979 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003980get_file_in_dir(
3981 char_u *fname,
3982 char_u *dname) /* don't use "dirname", it is a global for Alpha */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003983{
3984 char_u *t;
3985 char_u *tail;
3986 char_u *retval;
3987 int save_char;
3988
3989 tail = gettail(fname);
3990
3991 if (dname[0] == '.' && dname[1] == NUL)
3992 retval = vim_strsave(fname);
3993 else if (dname[0] == '.' && vim_ispathsep(dname[1]))
3994 {
3995 if (tail == fname) /* no path before file name */
3996 retval = concat_fnames(dname + 2, tail, TRUE);
3997 else
3998 {
3999 save_char = *tail;
4000 *tail = NUL;
4001 t = concat_fnames(fname, dname + 2, TRUE);
4002 *tail = save_char;
4003 if (t == NULL) /* out of memory */
4004 retval = NULL;
4005 else
4006 {
4007 retval = concat_fnames(t, tail, TRUE);
4008 vim_free(t);
4009 }
4010 }
4011 }
4012 else
4013 retval = concat_fnames(dname, tail, TRUE);
4014
Bram Moolenaar69c35002013-11-04 02:54:12 +01004015#ifdef WIN3264
4016 if (retval != NULL)
Bram Moolenaar91acfff2017-03-12 19:22:36 +01004017 for (t = gettail(retval); *t != NUL; MB_PTR_ADV(t))
Bram Moolenaar69c35002013-11-04 02:54:12 +01004018 if (*t == ':')
4019 *t = '%';
4020#endif
4021
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 return retval;
4023}
4024
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01004025static void attention_message(buf_T *buf, char_u *fname);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004026
4027/*
4028 * Print the ATTENTION message: info about an existing swap file.
4029 */
4030 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004031attention_message(
4032 buf_T *buf, /* buffer being edited */
4033 char_u *fname) /* swap file name */
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004034{
Bram Moolenaar8767f522016-07-01 17:17:39 +02004035 stat_T st;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004036 time_t x, sx;
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00004037 char *p;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004038
4039 ++no_wait_return;
4040 (void)EMSG(_("E325: ATTENTION"));
4041 MSG_PUTS(_("\nFound a swap file by the name \""));
4042 msg_home_replace(fname);
4043 MSG_PUTS("\"\n");
4044 sx = swapfile_info(fname);
4045 MSG_PUTS(_("While opening file \""));
4046 msg_outtrans(buf->b_fname);
4047 MSG_PUTS("\"\n");
4048 if (mch_stat((char *)buf->b_fname, &st) != -1)
4049 {
4050 MSG_PUTS(_(" dated: "));
4051 x = st.st_mtime; /* Manx C can't do &st.st_mtime */
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00004052 p = ctime(&x); /* includes '\n' */
4053 if (p == NULL)
4054 MSG_PUTS("(invalid)\n");
4055 else
4056 MSG_PUTS(p);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004057 if (sx != 0 && x > sx)
4058 MSG_PUTS(_(" NEWER than swap file!\n"));
4059 }
4060 /* Some of these messages are long to allow translation to
4061 * other languages. */
Bram Moolenaard9ea9062016-02-02 12:38:02 +01004062 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"));
Bram Moolenaarc41fc712011-02-15 11:57:04 +01004063 MSG_PUTS(_("(2) An edit session for this file crashed.\n"));
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004064 MSG_PUTS(_(" If this is the case, use \":recover\" or \"vim -r "));
4065 msg_outtrans(buf->b_fname);
4066 MSG_PUTS(_("\"\n to recover the changes (see \":help recovery\").\n"));
4067 MSG_PUTS(_(" If you did this already, delete the swap file \""));
4068 msg_outtrans(fname);
4069 MSG_PUTS(_("\"\n to avoid this message.\n"));
4070 cmdline_row = msg_row;
4071 --no_wait_return;
4072}
4073
4074#ifdef FEAT_AUTOCMD
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01004075static int do_swapexists(buf_T *buf, char_u *fname);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004076
4077/*
4078 * Trigger the SwapExists autocommands.
4079 * Returns a value for equivalent to do_dialog() (see below):
4080 * 0: still need to ask for a choice
4081 * 1: open read-only
4082 * 2: edit anyway
4083 * 3: recover
4084 * 4: delete it
4085 * 5: quit
4086 * 6: abort
4087 */
4088 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004089do_swapexists(buf_T *buf, char_u *fname)
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004090{
4091 set_vim_var_string(VV_SWAPNAME, fname, -1);
4092 set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
4093
4094 /* Trigger SwapExists autocommands with <afile> set to the file being
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00004095 * edited. Disallow changing directory here. */
4096 ++allbuf_lock;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004097 apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, FALSE, NULL);
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00004098 --allbuf_lock;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004099
4100 set_vim_var_string(VV_SWAPNAME, NULL, -1);
4101
4102 switch (*get_vim_var_str(VV_SWAPCHOICE))
4103 {
4104 case 'o': return 1;
4105 case 'e': return 2;
4106 case 'r': return 3;
4107 case 'd': return 4;
4108 case 'q': return 5;
4109 case 'a': return 6;
4110 }
4111
4112 return 0;
4113}
4114#endif
4115
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116/*
4117 * Find out what name to use for the swap file for buffer 'buf'.
4118 *
4119 * Several names are tried to find one that does not exist
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004120 * Returns the name in allocated memory or NULL.
Bram Moolenaarf541c362011-10-26 11:44:18 +02004121 * When out of memory "dirp" is set to NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 *
4123 * Note: If BASENAMELEN is not correct, you will get error messages for
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004124 * not being able to open the swap or undo file
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00004125 * Note: May trigger SwapExists autocmd, pointers may change!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126 */
4127 static char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004128findswapname(
4129 buf_T *buf,
4130 char_u **dirp, /* pointer to list of directories */
4131 char_u *old_fname) /* don't give warning for this file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132{
4133 char_u *fname;
4134 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 char_u *dir_name;
4136#ifdef AMIGA
4137 BPTR fh;
4138#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004139 int r;
Bram Moolenaar69c35002013-11-04 02:54:12 +01004140 char_u *buf_fname = buf->b_fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004141
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004142#if !defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004143# define CREATE_DUMMY_FILE
4144 FILE *dummyfd = NULL;
4145
Bram Moolenaar69c35002013-11-04 02:54:12 +01004146# ifdef WIN3264
4147 if (buf_fname != NULL && !mch_isFullName(buf_fname)
4148 && vim_strchr(gettail(buf_fname), ':'))
4149 {
4150 char_u *t;
4151
4152 buf_fname = vim_strsave(buf_fname);
4153 if (buf_fname == NULL)
4154 buf_fname = buf->b_fname;
4155 else
Bram Moolenaar91acfff2017-03-12 19:22:36 +01004156 for (t = gettail(buf_fname); *t != NUL; MB_PTR_ADV(t))
Bram Moolenaar69c35002013-11-04 02:54:12 +01004157 if (*t == ':')
4158 *t = '%';
4159 }
4160# endif
4161
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004162 /*
4163 * If we start editing a new file, e.g. "test.doc", which resides on an
4164 * MSDOS compatible filesystem, it is possible that the file
4165 * "test.doc.swp" which we create will be exactly the same file. To avoid
4166 * this problem we temporarily create "test.doc". Don't do this when the
4167 * check below for a 8.3 file name is used.
4168 */
Bram Moolenaar69c35002013-11-04 02:54:12 +01004169 if (!(buf->b_p_sn || buf->b_shortname) && buf_fname != NULL
4170 && mch_getperm(buf_fname) < 0)
4171 dummyfd = mch_fopen((char *)buf_fname, "w");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172#endif
4173
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004174 /*
4175 * Isolate a directory name from *dirp and put it in dir_name.
4176 * First allocate some memory to put the directory name in.
4177 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178 dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
Bram Moolenaarf541c362011-10-26 11:44:18 +02004179 if (dir_name == NULL)
4180 *dirp = NULL;
4181 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182 (void)copy_option_part(dirp, dir_name, 31000, ",");
4183
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004184 /*
4185 * we try different names until we find one that does not exist yet
4186 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187 if (dir_name == NULL) /* out of memory */
4188 fname = NULL;
4189 else
Bram Moolenaar69c35002013-11-04 02:54:12 +01004190 fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191
4192 for (;;)
4193 {
4194 if (fname == NULL) /* must be out of memory */
4195 break;
4196 if ((n = (int)STRLEN(fname)) == 0) /* safety check */
4197 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01004198 VIM_CLEAR(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199 break;
4200 }
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004201#if defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004202/*
4203 * Some systems have a MS-DOS compatible filesystem that use 8.3 character
4204 * file names. If this is the first try and the swap file name does not fit in
4205 * 8.3, detect if this is the case, set shortname and try again.
4206 */
4207 if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
4208 && !(buf->b_p_sn || buf->b_shortname))
4209 {
4210 char_u *tail;
4211 char_u *fname2;
Bram Moolenaar8767f522016-07-01 17:17:39 +02004212 stat_T s1, s2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213 int f1, f2;
4214 int created1 = FALSE, created2 = FALSE;
4215 int same = FALSE;
4216
4217 /*
4218 * Check if swapfile name does not fit in 8.3:
4219 * It either contains two dots, is longer than 8 chars, or starts
4220 * with a dot.
4221 */
Bram Moolenaar69c35002013-11-04 02:54:12 +01004222 tail = gettail(buf_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 if ( vim_strchr(tail, '.') != NULL
4224 || STRLEN(tail) > (size_t)8
4225 || *gettail(fname) == '.')
4226 {
4227 fname2 = alloc(n + 2);
4228 if (fname2 != NULL)
4229 {
4230 STRCPY(fname2, fname);
4231 /* if fname == "xx.xx.swp", fname2 = "xx.xx.swx"
4232 * if fname == ".xx.swp", fname2 = ".xx.swpx"
4233 * if fname == "123456789.swp", fname2 = "12345678x.swp"
4234 */
4235 if (vim_strchr(tail, '.') != NULL)
4236 fname2[n - 1] = 'x';
4237 else if (*gettail(fname) == '.')
4238 {
4239 fname2[n] = 'x';
4240 fname2[n + 1] = NUL;
4241 }
4242 else
4243 fname2[n - 5] += 1;
4244 /*
4245 * may need to create the files to be able to use mch_stat()
4246 */
4247 f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
4248 if (f1 < 0)
4249 {
4250 f1 = mch_open_rw((char *)fname,
4251 O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252 created1 = TRUE;
4253 }
4254 if (f1 >= 0)
4255 {
4256 f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
4257 if (f2 < 0)
4258 {
4259 f2 = mch_open_rw((char *)fname2,
4260 O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
4261 created2 = TRUE;
4262 }
4263 if (f2 >= 0)
4264 {
4265 /*
4266 * Both files exist now. If mch_stat() returns the
4267 * same device and inode they are the same file.
4268 */
4269 if (mch_fstat(f1, &s1) != -1
4270 && mch_fstat(f2, &s2) != -1
4271 && s1.st_dev == s2.st_dev
4272 && s1.st_ino == s2.st_ino)
4273 same = TRUE;
4274 close(f2);
4275 if (created2)
4276 mch_remove(fname2);
4277 }
4278 close(f1);
4279 if (created1)
4280 mch_remove(fname);
4281 }
4282 vim_free(fname2);
4283 if (same)
4284 {
4285 buf->b_shortname = TRUE;
4286 vim_free(fname);
Bram Moolenaar69c35002013-11-04 02:54:12 +01004287 fname = makeswapname(buf_fname, buf->b_ffname,
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004288 buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289 continue; /* try again with b_shortname set */
4290 }
4291 }
4292 }
4293 }
4294#endif
4295 /*
4296 * check if the swapfile already exists
4297 */
4298 if (mch_getperm(fname) < 0) /* it does not exist */
4299 {
4300#ifdef HAVE_LSTAT
Bram Moolenaar8767f522016-07-01 17:17:39 +02004301 stat_T sb;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302
4303 /*
4304 * Extra security check: When a swap file is a symbolic link, this
4305 * is most likely a symlink attack.
4306 */
4307 if (mch_lstat((char *)fname, &sb) < 0)
4308#else
4309# ifdef AMIGA
4310 fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
4311 /*
4312 * on the Amiga mch_getperm() will return -1 when the file exists
4313 * but is being used by another program. This happens if you edit
4314 * a file twice.
4315 */
4316 if (fh != (BPTR)NULL) /* can open file, OK */
4317 {
4318 Close(fh);
4319 mch_remove(fname);
4320 break;
4321 }
4322 if (IoErr() != ERROR_OBJECT_IN_USE
4323 && IoErr() != ERROR_OBJECT_EXISTS)
4324# endif
4325#endif
4326 break;
4327 }
4328
4329 /*
4330 * A file name equal to old_fname is OK to use.
4331 */
4332 if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
4333 break;
4334
4335 /*
4336 * get here when file already exists
4337 */
4338 if (fname[n - 2] == 'w' && fname[n - 1] == 'p') /* first try */
4339 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340 /*
4341 * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
4342 * and file.doc are the same file. To guess if this problem is
4343 * present try if file.doc.swx exists. If it does, we set
4344 * buf->b_shortname and try file_doc.swp (dots replaced by
4345 * underscores for this file), and try again. If it doesn't we
4346 * assume that "file.doc.swp" already exists.
4347 */
4348 if (!(buf->b_p_sn || buf->b_shortname)) /* not tried yet */
4349 {
4350 fname[n - 1] = 'x';
4351 r = mch_getperm(fname); /* try "file.swx" */
4352 fname[n - 1] = 'p';
4353 if (r >= 0) /* "file.swx" seems to exist */
4354 {
4355 buf->b_shortname = TRUE;
4356 vim_free(fname);
Bram Moolenaar69c35002013-11-04 02:54:12 +01004357 fname = makeswapname(buf_fname, buf->b_ffname,
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004358 buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 continue; /* try again with '.' replaced with '_' */
4360 }
4361 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 /*
4363 * If we get here the ".swp" file really exists.
4364 * Give an error message, unless recovering, no file name, we are
4365 * viewing a help file or when the path of the file is different
4366 * (happens when all .swp files are in one directory).
4367 */
Bram Moolenaar69c35002013-11-04 02:54:12 +01004368 if (!recoverymode && buf_fname != NULL
Bram Moolenaar8fc061c2004-12-29 21:03:02 +00004369 && !buf->b_help && !(buf->b_flags & BF_DUMMY))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 {
4371 int fd;
4372 struct block0 b0;
4373 int differ = FALSE;
4374
4375 /*
4376 * Try to read block 0 from the swap file to get the original
4377 * file name (and inode number).
4378 */
4379 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
4380 if (fd >= 0)
4381 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004382 if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004383 {
4384 /*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004385 * If the swapfile has the same directory as the
4386 * buffer don't compare the directory names, they can
4387 * have a different mountpoint.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004388 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004389 if (b0.b0_flags & B0_SAME_DIR)
4390 {
4391 if (fnamecmp(gettail(buf->b_ffname),
4392 gettail(b0.b0_fname)) != 0
4393 || !same_directory(fname, buf->b_ffname))
Bram Moolenaar900b4d72005-12-12 22:05:50 +00004394 {
4395#ifdef CHECK_INODE
4396 /* Symlinks may point to the same file even
4397 * when the name differs, need to check the
4398 * inode too. */
4399 expand_env(b0.b0_fname, NameBuff, MAXPATHL);
4400 if (fnamecmp_ino(buf->b_ffname, NameBuff,
4401 char_to_long(b0.b0_ino)))
4402#endif
4403 differ = TRUE;
4404 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004405 }
4406 else
4407 {
4408 /*
4409 * The name in the swap file may be
4410 * "~user/path/file". Expand it first.
4411 */
4412 expand_env(b0.b0_fname, NameBuff, MAXPATHL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413#ifdef CHECK_INODE
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004414 if (fnamecmp_ino(buf->b_ffname, NameBuff,
Bram Moolenaar900b4d72005-12-12 22:05:50 +00004415 char_to_long(b0.b0_ino)))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004416 differ = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417#else
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004418 if (fnamecmp(NameBuff, buf->b_ffname) != 0)
4419 differ = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004421 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422 }
4423 close(fd);
4424 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425
4426 /* give the ATTENTION message when there is an old swap file
4427 * for the current file, and the buffer was not recovered. */
4428 if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
4429 && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
4430 {
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004431#if defined(HAS_SWAP_EXISTS_ACTION)
4432 int choice = 0;
4433#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434#ifdef CREATE_DUMMY_FILE
4435 int did_use_dummy = FALSE;
4436
4437 /* Avoid getting a warning for the file being created
4438 * outside of Vim, it was created at the start of this
4439 * function. Delete the file now, because Vim might exit
4440 * here if the window is closed. */
4441 if (dummyfd != NULL)
4442 {
4443 fclose(dummyfd);
4444 dummyfd = NULL;
Bram Moolenaar69c35002013-11-04 02:54:12 +01004445 mch_remove(buf_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446 did_use_dummy = TRUE;
4447 }
4448#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004450#if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004451 process_still_running = FALSE;
4452#endif
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004453#ifdef FEAT_AUTOCMD
4454 /*
4455 * If there is an SwapExists autocommand and we can handle
4456 * the response, trigger it. It may return 0 to ask the
4457 * user anyway.
4458 */
4459 if (swap_exists_action != SEA_NONE
Bram Moolenaar69c35002013-11-04 02:54:12 +01004460 && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004461 choice = do_swapexists(buf, fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004462
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004463 if (choice == 0)
4464#endif
4465 {
4466#ifdef FEAT_GUI
4467 /* If we are supposed to start the GUI but it wasn't
4468 * completely started yet, start it now. This makes
4469 * the messages displayed in the Vim window when
4470 * loading a session from the .gvimrc file. */
4471 if (gui.starting && !gui.in_use)
4472 gui_start();
4473#endif
4474 /* Show info about the existing swap file. */
4475 attention_message(buf, fname);
4476
4477 /* We don't want a 'q' typed at the more-prompt
4478 * interrupt loading a file. */
4479 got_int = FALSE;
4480 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481
4482#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004483 if (swap_exists_action != SEA_NONE && choice == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484 {
4485 char_u *name;
4486
4487 name = alloc((unsigned)(STRLEN(fname)
4488 + STRLEN(_("Swap file \""))
4489 + STRLEN(_("\" already exists!")) + 5));
4490 if (name != NULL)
4491 {
4492 STRCPY(name, _("Swap file \""));
4493 home_replace(NULL, fname, name + STRLEN(name),
4494 1000, TRUE);
4495 STRCAT(name, _("\" already exists!"));
4496 }
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004497 choice = do_dialog(VIM_WARNING,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498 (char_u *)_("VIM - ATTENTION"),
4499 name == NULL
4500 ? (char_u *)_("Swap file already exists!")
4501 : name,
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004502# if defined(UNIX) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 process_still_running
4504 ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") :
4505# endif
Bram Moolenaard2c340a2011-01-17 20:08:11 +01004506 (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, FALSE);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004507
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004508# if defined(UNIX) || defined(VMS)
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004509 if (process_still_running && choice >= 4)
4510 choice++; /* Skip missing "Delete it" button */
4511# endif
4512 vim_free(name);
4513
4514 /* pretend screen didn't scroll, need redraw anyway */
4515 msg_scrolled = 0;
4516 redraw_all_later(NOT_VALID);
4517 }
4518#endif
4519
4520#if defined(HAS_SWAP_EXISTS_ACTION)
4521 if (choice > 0)
4522 {
4523 switch (choice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004524 {
4525 case 1:
4526 buf->b_p_ro = TRUE;
4527 break;
4528 case 2:
4529 break;
4530 case 3:
4531 swap_exists_action = SEA_RECOVER;
4532 break;
4533 case 4:
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004534 mch_remove(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535 break;
4536 case 5:
4537 swap_exists_action = SEA_QUIT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 break;
4539 case 6:
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004540 swap_exists_action = SEA_QUIT;
4541 got_int = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542 break;
4543 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544
4545 /* If the file was deleted this fname can be used. */
4546 if (mch_getperm(fname) < 0)
4547 break;
4548 }
4549 else
4550#endif
4551 {
4552 MSG_PUTS("\n");
Bram Moolenaar4770d092006-01-12 23:22:24 +00004553 if (msg_silent == 0)
4554 /* call wait_return() later */
4555 need_wait_return = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 }
4557
4558#ifdef CREATE_DUMMY_FILE
4559 /* Going to try another name, need the dummy file again. */
4560 if (did_use_dummy)
Bram Moolenaar69c35002013-11-04 02:54:12 +01004561 dummyfd = mch_fopen((char *)buf_fname, "w");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562#endif
4563 }
4564 }
4565 }
4566
4567 /*
4568 * Change the ".swp" extension to find another file that can be used.
4569 * First decrement the last char: ".swo", ".swn", etc.
4570 * If that still isn't enough decrement the last but one char: ".svz"
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004571 * Can happen when editing many "No Name" buffers.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 */
4573 if (fname[n - 1] == 'a') /* ".s?a" */
4574 {
4575 if (fname[n - 2] == 'a') /* ".saa": tried enough, give up */
4576 {
4577 EMSG(_("E326: Too many swap files found"));
Bram Moolenaard23a8232018-02-10 18:45:26 +01004578 VIM_CLEAR(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579 break;
4580 }
4581 --fname[n - 2]; /* ".svz", ".suz", etc. */
4582 fname[n - 1] = 'z' + 1;
4583 }
4584 --fname[n - 1]; /* ".swo", ".swn", etc. */
4585 }
4586
4587 vim_free(dir_name);
4588#ifdef CREATE_DUMMY_FILE
4589 if (dummyfd != NULL) /* file has been created temporarily */
4590 {
4591 fclose(dummyfd);
Bram Moolenaar69c35002013-11-04 02:54:12 +01004592 mch_remove(buf_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593 }
4594#endif
Bram Moolenaar69c35002013-11-04 02:54:12 +01004595#ifdef WIN3264
4596 if (buf_fname != buf->b_fname)
4597 vim_free(buf_fname);
4598#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004599 return fname;
4600}
4601
4602 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004603b0_magic_wrong(ZERO_BL *b0p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604{
4605 return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
4606 || b0p->b0_magic_int != (int)B0_MAGIC_INT
4607 || b0p->b0_magic_short != (short)B0_MAGIC_SHORT
4608 || b0p->b0_magic_char != B0_MAGIC_CHAR);
4609}
4610
4611#ifdef CHECK_INODE
4612/*
4613 * Compare current file name with file name from swap file.
4614 * Try to use inode numbers when possible.
4615 * Return non-zero when files are different.
4616 *
4617 * When comparing file names a few things have to be taken into consideration:
4618 * - When working over a network the full path of a file depends on the host.
4619 * We check the inode number if possible. It is not 100% reliable though,
4620 * because the device number cannot be used over a network.
4621 * - When a file does not exist yet (editing a new file) there is no inode
4622 * number.
4623 * - The file name in a swap file may not be valid on the current host. The
4624 * "~user" form is used whenever possible to avoid this.
4625 *
4626 * This is getting complicated, let's make a table:
4627 *
4628 * ino_c ino_s fname_c fname_s differ =
4629 *
4630 * both files exist -> compare inode numbers:
4631 * != 0 != 0 X X ino_c != ino_s
4632 *
4633 * inode number(s) unknown, file names available -> compare file names
4634 * == 0 X OK OK fname_c != fname_s
4635 * X == 0 OK OK fname_c != fname_s
4636 *
4637 * current file doesn't exist, file for swap file exist, file name(s) not
4638 * available -> probably different
4639 * == 0 != 0 FAIL X TRUE
4640 * == 0 != 0 X FAIL TRUE
4641 *
4642 * current file exists, inode for swap unknown, file name(s) not
4643 * available -> probably different
4644 * != 0 == 0 FAIL X TRUE
4645 * != 0 == 0 X FAIL TRUE
4646 *
4647 * current file doesn't exist, inode for swap unknown, one file name not
4648 * available -> probably different
4649 * == 0 == 0 FAIL OK TRUE
4650 * == 0 == 0 OK FAIL TRUE
4651 *
4652 * current file doesn't exist, inode for swap unknown, both file names not
4653 * available -> probably same file
4654 * == 0 == 0 FAIL FAIL FALSE
4655 *
4656 * Note that when the ino_t is 64 bits, only the last 32 will be used. This
4657 * can't be changed without making the block 0 incompatible with 32 bit
4658 * versions.
4659 */
4660
4661 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004662fnamecmp_ino(
4663 char_u *fname_c, /* current file name */
4664 char_u *fname_s, /* file name from swap file */
4665 long ino_block0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004666{
Bram Moolenaar8767f522016-07-01 17:17:39 +02004667 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668 ino_t ino_c = 0; /* ino of current file */
4669 ino_t ino_s; /* ino of file from swap file */
4670 char_u buf_c[MAXPATHL]; /* full path of fname_c */
4671 char_u buf_s[MAXPATHL]; /* full path of fname_s */
4672 int retval_c; /* flag: buf_c valid */
4673 int retval_s; /* flag: buf_s valid */
4674
4675 if (mch_stat((char *)fname_c, &st) == 0)
4676 ino_c = (ino_t)st.st_ino;
4677
4678 /*
4679 * First we try to get the inode from the file name, because the inode in
4680 * the swap file may be outdated. If that fails (e.g. this path is not
4681 * valid on this machine), use the inode from block 0.
4682 */
4683 if (mch_stat((char *)fname_s, &st) == 0)
4684 ino_s = (ino_t)st.st_ino;
4685 else
4686 ino_s = (ino_t)ino_block0;
4687
4688 if (ino_c && ino_s)
4689 return (ino_c != ino_s);
4690
4691 /*
4692 * One of the inode numbers is unknown, try a forced vim_FullName() and
4693 * compare the file names.
4694 */
4695 retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
4696 retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
4697 if (retval_c == OK && retval_s == OK)
4698 return (STRCMP(buf_c, buf_s) != 0);
4699
4700 /*
4701 * Can't compare inodes or file names, guess that the files are different,
4702 * unless both appear not to exist at all.
4703 */
4704 if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
4705 return FALSE;
4706 return TRUE;
4707}
4708#endif /* CHECK_INODE */
4709
4710/*
4711 * Move a long integer into a four byte character array.
4712 * Used for machine independency in block zero.
4713 */
4714 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004715long_to_char(long n, char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716{
4717 s[0] = (char_u)(n & 0xff);
4718 n = (unsigned)n >> 8;
4719 s[1] = (char_u)(n & 0xff);
4720 n = (unsigned)n >> 8;
4721 s[2] = (char_u)(n & 0xff);
4722 n = (unsigned)n >> 8;
4723 s[3] = (char_u)(n & 0xff);
4724}
4725
4726 static long
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004727char_to_long(char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728{
4729 long retval;
4730
4731 retval = s[3];
4732 retval <<= 8;
4733 retval |= s[2];
4734 retval <<= 8;
4735 retval |= s[1];
4736 retval <<= 8;
4737 retval |= s[0];
4738
4739 return retval;
4740}
4741
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004742/*
4743 * Set the flags in the first block of the swap file:
4744 * - file is modified or not: buf->b_changed
4745 * - 'fileformat'
4746 * - 'fileencoding'
4747 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004749ml_setflags(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750{
4751 bhdr_T *hp;
4752 ZERO_BL *b0p;
4753
4754 if (!buf->b_ml.ml_mfp)
4755 return;
4756 for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
4757 {
4758 if (hp->bh_bnum == 0)
4759 {
4760 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004761 b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
4762 b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
4763 | (get_fileformat(buf) + 1);
4764#ifdef FEAT_MBYTE
4765 add_b0_fenc(b0p, buf);
4766#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004767 hp->bh_flags |= BH_DIRTY;
4768 mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
4769 break;
4770 }
4771 }
4772}
4773
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004774#if defined(FEAT_CRYPT) || defined(PROTO)
4775/*
4776 * If "data" points to a data block encrypt the text in it and return a copy
4777 * in allocated memory. Return NULL when out of memory.
4778 * Otherwise return "data".
4779 */
4780 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004781ml_encrypt_data(
4782 memfile_T *mfp,
4783 char_u *data,
Bram Moolenaar8767f522016-07-01 17:17:39 +02004784 off_T offset,
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004785 unsigned size)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004786{
4787 DATA_BL *dp = (DATA_BL *)data;
4788 char_u *head_end;
4789 char_u *text_start;
4790 char_u *new_data;
4791 int text_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004792 cryptstate_T *state;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004793
4794 if (dp->db_id != DATA_ID)
4795 return data;
4796
Bram Moolenaarbc563362015-06-09 18:35:25 +02004797 state = ml_crypt_prepare(mfp, offset, FALSE);
4798 if (state == NULL)
4799 return data;
4800
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004801 new_data = (char_u *)alloc(size);
4802 if (new_data == NULL)
4803 return NULL;
4804 head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
4805 text_start = (char_u *)dp + dp->db_txt_start;
4806 text_len = size - dp->db_txt_start;
4807
4808 /* Copy the header and the text. */
4809 mch_memmove(new_data, dp, head_end - (char_u *)dp);
4810
4811 /* Encrypt the text. */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004812 crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
4813 crypt_free_state(state);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004814
4815 /* Clear the gap. */
4816 if (head_end < text_start)
4817 vim_memset(new_data + (head_end - data), 0, text_start - head_end);
4818
4819 return new_data;
4820}
4821
4822/*
Bram Moolenaarbc563362015-06-09 18:35:25 +02004823 * Decrypt the text in "data" if it points to an encrypted data block.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004824 */
4825 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004826ml_decrypt_data(
4827 memfile_T *mfp,
4828 char_u *data,
Bram Moolenaar8767f522016-07-01 17:17:39 +02004829 off_T offset,
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004830 unsigned size)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004831{
4832 DATA_BL *dp = (DATA_BL *)data;
4833 char_u *head_end;
4834 char_u *text_start;
4835 int text_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004836 cryptstate_T *state;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004837
4838 if (dp->db_id == DATA_ID)
4839 {
4840 head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
4841 text_start = (char_u *)dp + dp->db_txt_start;
4842 text_len = dp->db_txt_end - dp->db_txt_start;
4843
4844 if (head_end > text_start || dp->db_txt_start > size
4845 || dp->db_txt_end > size)
4846 return; /* data was messed up */
4847
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004848 state = ml_crypt_prepare(mfp, offset, TRUE);
Bram Moolenaarbc563362015-06-09 18:35:25 +02004849 if (state != NULL)
4850 {
4851 /* Decrypt the text in place. */
4852 crypt_decode_inplace(state, text_start, text_len);
4853 crypt_free_state(state);
4854 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004855 }
4856}
4857
4858/*
4859 * Prepare for encryption/decryption, using the key, seed and offset.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004860 * Return an allocated cryptstate_T *.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004861 */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004862 static cryptstate_T *
Bram Moolenaar8767f522016-07-01 17:17:39 +02004863ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004864{
4865 buf_T *buf = mfp->mf_buffer;
4866 char_u salt[50];
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004867 int method_nr;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004868 char_u *key;
4869 char_u *seed;
4870
4871 if (reading && mfp->mf_old_key != NULL)
4872 {
4873 /* Reading back blocks with the previous key/method/seed. */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004874 method_nr = mfp->mf_old_cm;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004875 key = mfp->mf_old_key;
4876 seed = mfp->mf_old_seed;
4877 }
4878 else
4879 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004880 method_nr = crypt_get_method_nr(buf);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004881 key = buf->b_p_key;
4882 seed = mfp->mf_seed;
4883 }
Bram Moolenaarbc563362015-06-09 18:35:25 +02004884 if (*key == NUL)
4885 return NULL;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004886
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004887 if (method_nr == CRYPT_M_ZIP)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004888 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004889 /* For PKzip: Append the offset to the key, so that we use a different
4890 * key for every block. */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004891 vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004892 return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004893 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004894
4895 /* Using blowfish or better: add salt and seed. We use the byte offset
4896 * of the block for the salt. */
4897 vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
4898 return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
4899 seed, MF_SEED_LEN);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004900}
4901
4902#endif
4903
4904
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905#if defined(FEAT_BYTEOFF) || defined(PROTO)
4906
4907#define MLCS_MAXL 800 /* max no of lines in chunk */
4908#define MLCS_MINL 400 /* should be half of MLCS_MAXL */
4909
4910/*
Bram Moolenaar0ad014c2010-07-25 14:00:46 +02004911 * Keep information for finding byte offset of a line, updtype may be one of:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004912 * ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
4913 * Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
4914 * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
4915 * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
4916 */
4917 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004918ml_updatechunk(
4919 buf_T *buf,
4920 linenr_T line,
4921 long len,
4922 int updtype)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923{
4924 static buf_T *ml_upd_lastbuf = NULL;
4925 static linenr_T ml_upd_lastline;
4926 static linenr_T ml_upd_lastcurline;
4927 static int ml_upd_lastcurix;
4928
4929 linenr_T curline = ml_upd_lastcurline;
4930 int curix = ml_upd_lastcurix;
4931 long size;
4932 chunksize_T *curchnk;
4933 int rest;
4934 bhdr_T *hp;
4935 DATA_BL *dp;
4936
4937 if (buf->b_ml.ml_usedchunks == -1 || len == 0)
4938 return;
4939 if (buf->b_ml.ml_chunksize == NULL)
4940 {
4941 buf->b_ml.ml_chunksize = (chunksize_T *)
4942 alloc((unsigned)sizeof(chunksize_T) * 100);
4943 if (buf->b_ml.ml_chunksize == NULL)
4944 {
4945 buf->b_ml.ml_usedchunks = -1;
4946 return;
4947 }
4948 buf->b_ml.ml_numchunks = 100;
4949 buf->b_ml.ml_usedchunks = 1;
4950 buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
4951 buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
4952 }
4953
4954 if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
4955 {
4956 /*
4957 * First line in empty buffer from ml_flush_line() -- reset
4958 */
4959 buf->b_ml.ml_usedchunks = 1;
4960 buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
4961 buf->b_ml.ml_chunksize[0].mlcs_totalsize =
4962 (long)STRLEN(buf->b_ml.ml_line_ptr) + 1;
4963 return;
4964 }
4965
4966 /*
4967 * Find chunk that our line belongs to, curline will be at start of the
4968 * chunk.
4969 */
4970 if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
4971 || updtype != ML_CHNK_ADDLINE)
4972 {
4973 for (curline = 1, curix = 0;
4974 curix < buf->b_ml.ml_usedchunks - 1
4975 && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4976 curix++)
4977 {
4978 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4979 }
4980 }
4981 else if (line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines
4982 && curix < buf->b_ml.ml_usedchunks - 1)
4983 {
4984 /* Adjust cached curix & curline */
4985 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4986 curix++;
4987 }
4988 curchnk = buf->b_ml.ml_chunksize + curix;
4989
4990 if (updtype == ML_CHNK_DELLINE)
Bram Moolenaar5a6404c2006-11-01 17:12:57 +00004991 len = -len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004992 curchnk->mlcs_totalsize += len;
4993 if (updtype == ML_CHNK_ADDLINE)
4994 {
4995 curchnk->mlcs_numlines++;
4996
4997 /* May resize here so we don't have to do it in both cases below */
4998 if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
4999 {
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01005000 chunksize_T *t_chunksize = buf->b_ml.ml_chunksize;
5001
Bram Moolenaar071d4272004-06-13 20:20:40 +00005002 buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
5003 buf->b_ml.ml_chunksize = (chunksize_T *)
5004 vim_realloc(buf->b_ml.ml_chunksize,
5005 sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
5006 if (buf->b_ml.ml_chunksize == NULL)
5007 {
5008 /* Hmmmm, Give up on offset for this buffer */
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01005009 vim_free(t_chunksize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005010 buf->b_ml.ml_usedchunks = -1;
5011 return;
5012 }
5013 }
5014
5015 if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
5016 {
5017 int count; /* number of entries in block */
5018 int idx;
5019 int text_end;
5020 int linecnt;
5021
5022 mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
5023 buf->b_ml.ml_chunksize + curix,
5024 (buf->b_ml.ml_usedchunks - curix) *
5025 sizeof(chunksize_T));
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00005026 /* Compute length of first half of lines in the split chunk */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027 size = 0;
5028 linecnt = 0;
5029 while (curline < buf->b_ml.ml_line_count
5030 && linecnt < MLCS_MINL)
5031 {
5032 if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
5033 {
5034 buf->b_ml.ml_usedchunks = -1;
5035 return;
5036 }
5037 dp = (DATA_BL *)(hp->bh_data);
5038 count = (long)(buf->b_ml.ml_locked_high) -
5039 (long)(buf->b_ml.ml_locked_low) + 1;
5040 idx = curline - buf->b_ml.ml_locked_low;
5041 curline = buf->b_ml.ml_locked_high + 1;
5042 if (idx == 0)/* first line in block, text at the end */
5043 text_end = dp->db_txt_end;
5044 else
5045 text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5046 /* Compute index of last line to use in this MEMLINE */
5047 rest = count - idx;
5048 if (linecnt + rest > MLCS_MINL)
5049 {
5050 idx += MLCS_MINL - linecnt - 1;
5051 linecnt = MLCS_MINL;
5052 }
5053 else
5054 {
5055 idx = count - 1;
5056 linecnt += rest;
5057 }
5058 size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
5059 }
5060 buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
5061 buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
5062 buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
5063 buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
5064 buf->b_ml.ml_usedchunks++;
5065 ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
5066 return;
5067 }
5068 else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
5069 && curix == buf->b_ml.ml_usedchunks - 1
5070 && buf->b_ml.ml_line_count - line <= 1)
5071 {
5072 /*
5073 * We are in the last chunk and it is cheap to crate a new one
5074 * after this. Do it now to avoid the loop above later on
5075 */
5076 curchnk = buf->b_ml.ml_chunksize + curix + 1;
5077 buf->b_ml.ml_usedchunks++;
5078 if (line == buf->b_ml.ml_line_count)
5079 {
5080 curchnk->mlcs_numlines = 0;
5081 curchnk->mlcs_totalsize = 0;
5082 }
5083 else
5084 {
5085 /*
5086 * Line is just prior to last, move count for last
5087 * This is the common case when loading a new file
5088 */
5089 hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
5090 if (hp == NULL)
5091 {
5092 buf->b_ml.ml_usedchunks = -1;
5093 return;
5094 }
5095 dp = (DATA_BL *)(hp->bh_data);
5096 if (dp->db_line_count == 1)
5097 rest = dp->db_txt_end - dp->db_txt_start;
5098 else
5099 rest =
5100 ((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
5101 - dp->db_txt_start;
5102 curchnk->mlcs_totalsize = rest;
5103 curchnk->mlcs_numlines = 1;
5104 curchnk[-1].mlcs_totalsize -= rest;
5105 curchnk[-1].mlcs_numlines -= 1;
5106 }
5107 }
5108 }
5109 else if (updtype == ML_CHNK_DELLINE)
5110 {
5111 curchnk->mlcs_numlines--;
5112 ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
5113 if (curix < (buf->b_ml.ml_usedchunks - 1)
5114 && (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
5115 <= MLCS_MINL)
5116 {
5117 curix++;
5118 curchnk = buf->b_ml.ml_chunksize + curix;
5119 }
5120 else if (curix == 0 && curchnk->mlcs_numlines <= 0)
5121 {
5122 buf->b_ml.ml_usedchunks--;
5123 mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
5124 buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
5125 return;
5126 }
5127 else if (curix == 0 || (curchnk->mlcs_numlines > 10
5128 && (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
5129 > MLCS_MINL))
5130 {
5131 return;
5132 }
5133
5134 /* Collapse chunks */
5135 curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
5136 curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
5137 buf->b_ml.ml_usedchunks--;
5138 if (curix < buf->b_ml.ml_usedchunks)
5139 {
5140 mch_memmove(buf->b_ml.ml_chunksize + curix,
5141 buf->b_ml.ml_chunksize + curix + 1,
5142 (buf->b_ml.ml_usedchunks - curix) *
5143 sizeof(chunksize_T));
5144 }
5145 return;
5146 }
5147 ml_upd_lastbuf = buf;
5148 ml_upd_lastline = line;
5149 ml_upd_lastcurline = curline;
5150 ml_upd_lastcurix = curix;
5151}
5152
5153/*
5154 * Find offset for line or line with offset.
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005155 * Find line with offset if "lnum" is 0; return remaining offset in offp
5156 * Find offset of line if "lnum" > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157 * return -1 if information is not available
5158 */
5159 long
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01005160ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161{
5162 linenr_T curline;
5163 int curix;
5164 long size;
5165 bhdr_T *hp;
5166 DATA_BL *dp;
5167 int count; /* number of entries in block */
5168 int idx;
5169 int start_idx;
5170 int text_end;
5171 long offset;
5172 int len;
5173 int ffdos = (get_fileformat(buf) == EOL_DOS);
5174 int extra = 0;
5175
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005176 /* take care of cached line first */
5177 ml_flush_line(curbuf);
5178
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 if (buf->b_ml.ml_usedchunks == -1
5180 || buf->b_ml.ml_chunksize == NULL
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005181 || lnum < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182 return -1;
5183
5184 if (offp == NULL)
5185 offset = 0;
5186 else
5187 offset = *offp;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005188 if (lnum == 0 && offset <= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189 return 1; /* Not a "find offset" and offset 0 _must_ be in line 1 */
5190 /*
5191 * Find the last chunk before the one containing our line. Last chunk is
5192 * special because it will never qualify
5193 */
5194 curline = 1;
5195 curix = size = 0;
5196 while (curix < buf->b_ml.ml_usedchunks - 1
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005197 && ((lnum != 0
5198 && lnum >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199 || (offset != 0
5200 && offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
5201 + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
5202 {
5203 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5204 size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
5205 if (offset && ffdos)
5206 size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5207 curix++;
5208 }
5209
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005210 while ((lnum != 0 && curline < lnum) || (offset != 0 && size < offset))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 {
5212 if (curline > buf->b_ml.ml_line_count
5213 || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
5214 return -1;
5215 dp = (DATA_BL *)(hp->bh_data);
5216 count = (long)(buf->b_ml.ml_locked_high) -
5217 (long)(buf->b_ml.ml_locked_low) + 1;
5218 start_idx = idx = curline - buf->b_ml.ml_locked_low;
5219 if (idx == 0)/* first line in block, text at the end */
5220 text_end = dp->db_txt_end;
5221 else
5222 text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5223 /* Compute index of last line to use in this MEMLINE */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005224 if (lnum != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005225 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005226 if (curline + (count - idx) >= lnum)
5227 idx += lnum - curline - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005228 else
5229 idx = count - 1;
5230 }
5231 else
5232 {
5233 extra = 0;
5234 while (offset >= size
5235 + text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
5236 + ffdos)
5237 {
5238 if (ffdos)
5239 size++;
5240 if (idx == count - 1)
5241 {
5242 extra = 1;
5243 break;
5244 }
5245 idx++;
5246 }
5247 }
5248 len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
5249 size += len;
5250 if (offset != 0 && size >= offset)
5251 {
5252 if (size + ffdos == offset)
5253 *offp = 0;
5254 else if (idx == start_idx)
5255 *offp = offset - size + len;
5256 else
5257 *offp = offset - size + len
5258 - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
5259 curline += idx - start_idx + extra;
5260 if (curline > buf->b_ml.ml_line_count)
5261 return -1; /* exactly one byte beyond the end */
5262 return curline;
5263 }
5264 curline = buf->b_ml.ml_locked_high + 1;
5265 }
5266
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005267 if (lnum != 0)
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005268 {
5269 /* Count extra CR characters. */
5270 if (ffdos)
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005271 size += lnum - 1;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005272
Bram Moolenaar34d72d42015-07-17 14:18:08 +02005273 /* Don't count the last line break if 'noeol' and ('bin' or
5274 * 'nofixeol'). */
5275 if ((!buf->b_p_fixeol || buf->b_p_bin) && !buf->b_p_eol
5276 && buf->b_ml.ml_line_count == lnum)
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005277 size -= ffdos + 1;
5278 }
5279
Bram Moolenaar071d4272004-06-13 20:20:40 +00005280 return size;
5281}
5282
5283/*
5284 * Goto byte in buffer with offset 'cnt'.
5285 */
5286 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01005287goto_byte(long cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288{
5289 long boff = cnt;
5290 linenr_T lnum;
5291
5292 ml_flush_line(curbuf); /* cached line may be dirty */
5293 setpcmark();
5294 if (boff)
5295 --boff;
5296 lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
5297 if (lnum < 1) /* past the end */
5298 {
5299 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5300 curwin->w_curswant = MAXCOL;
5301 coladvance((colnr_T)MAXCOL);
5302 }
5303 else
5304 {
5305 curwin->w_cursor.lnum = lnum;
5306 curwin->w_cursor.col = (colnr_T)boff;
Bram Moolenaar943d2b52005-12-02 00:50:49 +00005307# ifdef FEAT_VIRTUALEDIT
5308 curwin->w_cursor.coladd = 0;
5309# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005310 curwin->w_set_curswant = TRUE;
5311 }
5312 check_cursor();
5313
5314# ifdef FEAT_MBYTE
5315 /* Make sure the cursor is on the first byte of a multi-byte char. */
5316 if (has_mbyte)
5317 mb_adjust_cursor();
5318# endif
5319}
5320#endif