blob: 1cb1bb083e97e9d0b8670adf8029f39a89bebe5a [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/* for debugging */
11/* #define CHECK(c, s) if (c) EMSG(s) */
12#define CHECK(c, s)
13
14/*
15 * memline.c: Contains the functions for appending, deleting and changing the
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 Moolenaar92b8b2d2016-01-29 22:36:45 +0100269static 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
329#if defined(MSDOS) && !defined(DJGPP)
330 /* for 16 bit MS-DOS create a swapfile now, because we run out of
331 * memory very quickly */
332 if (p_uc != 0)
Bram Moolenaar4770d092006-01-12 23:22:24 +0000333 ml_open_file(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000334#endif
335
336/*
337 * fill block0 struct and write page 0
338 */
339 if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
340 goto error;
341 if (hp->bh_bnum != 0)
342 {
343 EMSG(_("E298: Didn't get block nr 0?"));
344 goto error;
345 }
346 b0p = (ZERO_BL *)(hp->bh_data);
347
348 b0p->b0_id[0] = BLOCK0_ID0;
349 b0p->b0_id[1] = BLOCK0_ID1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 b0p->b0_magic_long = (long)B0_MAGIC_LONG;
351 b0p->b0_magic_int = (int)B0_MAGIC_INT;
352 b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
353 b0p->b0_magic_char = B0_MAGIC_CHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354 STRNCPY(b0p->b0_version, "VIM ", 4);
355 STRNCPY(b0p->b0_version + 4, Version, 6);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356 long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000357
Bram Moolenaar76b92b22006-03-24 22:46:53 +0000358#ifdef FEAT_SPELL
359 if (!buf->b_spell)
360#endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000361 {
362 b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
363 b0p->b0_flags = get_fileformat(buf) + 1;
364 set_b0_fname(b0p, buf);
365 (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
366 b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
367 mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
368 b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
369 long_to_char(mch_get_pid(), b0p->b0_pid);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200370#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200371 ml_set_b0_crypt(buf, b0p);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200372#endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000373 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374
375 /*
376 * Always sync block number 0 to disk, so we can check the file name in
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200377 * the swap file in findswapname(). Don't do this for a help files or
378 * a spell buffer though.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000379 * Only works when there's a swapfile, otherwise it's done when the file
380 * is created.
381 */
382 mf_put(mfp, hp, TRUE, FALSE);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000383 if (!buf->b_help && !B_SPELL(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384 (void)mf_sync(mfp, 0);
385
Bram Moolenaar4770d092006-01-12 23:22:24 +0000386 /*
387 * Fill in root pointer block and write page 1.
388 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 if ((hp = ml_new_ptr(mfp)) == NULL)
390 goto error;
391 if (hp->bh_bnum != 1)
392 {
393 EMSG(_("E298: Didn't get block nr 1?"));
394 goto error;
395 }
396 pp = (PTR_BL *)(hp->bh_data);
397 pp->pb_count = 1;
398 pp->pb_pointer[0].pe_bnum = 2;
399 pp->pb_pointer[0].pe_page_count = 1;
400 pp->pb_pointer[0].pe_old_lnum = 1;
401 pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */
402 mf_put(mfp, hp, TRUE, FALSE);
403
Bram Moolenaar4770d092006-01-12 23:22:24 +0000404 /*
405 * Allocate first data block and create an empty line 1.
406 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407 if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
408 goto error;
409 if (hp->bh_bnum != 2)
410 {
411 EMSG(_("E298: Didn't get block nr 2?"));
412 goto error;
413 }
414
415 dp = (DATA_BL *)(hp->bh_data);
416 dp->db_index[0] = --dp->db_txt_start; /* at end of block */
417 dp->db_free -= 1 + INDEX_SIZE;
418 dp->db_line_count = 1;
Bram Moolenaarf05da212009-11-17 16:13:15 +0000419 *((char_u *)dp + dp->db_txt_start) = NUL; /* empty line */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420
421 return OK;
422
423error:
424 if (mfp != NULL)
425 {
426 if (hp)
427 mf_put(mfp, hp, FALSE, FALSE);
428 mf_close(mfp, TRUE); /* will also free(mfp->mf_fname) */
429 }
Bram Moolenaar4770d092006-01-12 23:22:24 +0000430 buf->b_ml.ml_mfp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 return FAIL;
432}
433
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200434#if defined(FEAT_CRYPT) || defined(PROTO)
435/*
Bram Moolenaar2be79502014-08-13 21:58:28 +0200436 * Prepare encryption for "buf" for the current key and method.
437 */
438 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100439ml_set_mfp_crypt(buf_T *buf)
Bram Moolenaar2be79502014-08-13 21:58:28 +0200440{
441 if (*buf->b_p_key != NUL)
442 {
443 int method_nr = crypt_get_method_nr(buf);
444
445 if (method_nr > CRYPT_M_ZIP)
446 {
447 /* Generate a seed and store it in the memfile. */
448 sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
449 }
450 }
451}
452
453/*
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200454 * Prepare encryption for "buf" with block 0 "b0p".
455 */
456 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100457ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200458{
459 if (*buf->b_p_key == NUL)
460 b0p->b0_id[1] = BLOCK0_ID1;
461 else
462 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200463 int method_nr = crypt_get_method_nr(buf);
464
465 b0p->b0_id[1] = id1_codes[method_nr];
466 if (method_nr > CRYPT_M_ZIP)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200467 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200468 /* Generate a seed and store it in block 0 and in the memfile. */
469 sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
470 mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
471 }
472 }
473}
474
475/*
476 * Called after the crypt key or 'cryptmethod' was changed for "buf".
477 * Will apply this to the swapfile.
478 * "old_key" is the previous key. It is equal to buf->b_p_key when
479 * 'cryptmethod' is changed.
Bram Moolenaar49771f42010-07-20 17:32:38 +0200480 * "old_cm" is the previous 'cryptmethod'. It is equal to the current
481 * 'cryptmethod' when 'key' is changed.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200482 */
483 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100484ml_set_crypt_key(
485 buf_T *buf,
486 char_u *old_key,
487 char_u *old_cm)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200488{
489 memfile_T *mfp = buf->b_ml.ml_mfp;
490 bhdr_T *hp;
491 int page_count;
492 int idx;
493 long error;
494 infoptr_T *ip;
495 PTR_BL *pp;
496 DATA_BL *dp;
497 blocknr_T bnum;
498 int top;
Bram Moolenaarbc563362015-06-09 18:35:25 +0200499 int old_method;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200500
Bram Moolenaar3832c462010-08-04 15:32:46 +0200501 if (mfp == NULL)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200502 return; /* no memfile yet, nothing to do */
Bram Moolenaarbc563362015-06-09 18:35:25 +0200503 old_method = crypt_method_nr_from_name(old_cm);
504
505 /* First make sure the swapfile is in a consistent state, using the old
506 * key and method. */
507 {
508 char_u *new_key = buf->b_p_key;
509 char_u *new_buf_cm = buf->b_p_cm;
510
511 buf->b_p_key = old_key;
512 buf->b_p_cm = old_cm;
513 ml_preserve(buf, FALSE);
514 buf->b_p_key = new_key;
515 buf->b_p_cm = new_buf_cm;
516 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200517
518 /* Set the key, method and seed to be used for reading, these must be the
519 * old values. */
520 mfp->mf_old_key = old_key;
Bram Moolenaarbc563362015-06-09 18:35:25 +0200521 mfp->mf_old_cm = old_method;
522 if (old_method > 0 && *old_key != NUL)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200523 mch_memmove(mfp->mf_old_seed, mfp->mf_seed, MF_SEED_LEN);
524
525 /* Update block 0 with the crypt flag and may set a new seed. */
526 ml_upd_block0(buf, UB_CRYPT);
527
528 if (mfp->mf_infile_count > 2)
529 {
530 /*
531 * Need to read back all data blocks from disk, decrypt them with the
532 * old key/method and mark them to be written. The algorithm is
533 * similar to what happens in ml_recover(), but we skip negative block
534 * numbers.
535 */
536 ml_flush_line(buf); /* flush buffered line */
537 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
538
539 hp = NULL;
540 bnum = 1; /* start with block 1 */
541 page_count = 1; /* which is 1 page */
542 idx = 0; /* start with first index in block 1 */
543 error = 0;
544 buf->b_ml.ml_stack_top = 0;
Bram Moolenaare242b832010-06-24 05:39:03 +0200545 vim_free(buf->b_ml.ml_stack);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200546 buf->b_ml.ml_stack = NULL;
547 buf->b_ml.ml_stack_size = 0; /* no stack yet */
548
549 for ( ; !got_int; line_breakcheck())
550 {
551 if (hp != NULL)
552 mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
553
554 /* get the block (pointer or data) */
555 if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
556 {
557 if (bnum == 1)
558 break;
559 ++error;
560 }
561 else
562 {
563 pp = (PTR_BL *)(hp->bh_data);
564 if (pp->pb_id == PTR_ID) /* it is a pointer block */
565 {
566 if (pp->pb_count == 0)
567 {
568 /* empty block? */
569 ++error;
570 }
571 else if (idx < (int)pp->pb_count) /* go a block deeper */
572 {
573 if (pp->pb_pointer[idx].pe_bnum < 0)
574 {
Bram Moolenaarbc563362015-06-09 18:35:25 +0200575 /* Skip data block with negative block number.
576 * Should not happen, because of the ml_preserve()
577 * above. Get same block again for next index. */
578 ++idx;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200579 continue;
580 }
581
582 /* going one block deeper in the tree, new entry in
583 * stack */
584 if ((top = ml_add_stack(buf)) < 0)
585 {
586 ++error;
587 break; /* out of memory */
588 }
589 ip = &(buf->b_ml.ml_stack[top]);
590 ip->ip_bnum = bnum;
591 ip->ip_index = idx;
592
593 bnum = pp->pb_pointer[idx].pe_bnum;
594 page_count = pp->pb_pointer[idx].pe_page_count;
Bram Moolenaarbc563362015-06-09 18:35:25 +0200595 idx = 0;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200596 continue;
597 }
598 }
599 else /* not a pointer block */
600 {
601 dp = (DATA_BL *)(hp->bh_data);
602 if (dp->db_id != DATA_ID) /* block id wrong */
603 ++error;
604 else
605 {
606 /* It is a data block, need to write it back to disk. */
607 mf_put(mfp, hp, TRUE, FALSE);
608 hp = NULL;
609 }
610 }
611 }
612
613 if (buf->b_ml.ml_stack_top == 0) /* finished */
614 break;
615
616 /* go one block up in the tree */
617 ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
618 bnum = ip->ip_bnum;
619 idx = ip->ip_index + 1; /* go to next index */
620 page_count = 1;
621 }
Bram Moolenaarbc563362015-06-09 18:35:25 +0200622 if (hp != NULL)
623 mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +0100624
625 if (error > 0)
626 EMSG(_("E843: Error while updating swap file crypt"));
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200627 }
628
629 mfp->mf_old_key = NULL;
630}
631#endif
632
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633/*
634 * ml_setname() is called when the file name of "buf" has been changed.
635 * It may rename the swap file.
636 */
637 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100638ml_setname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639{
640 int success = FALSE;
641 memfile_T *mfp;
642 char_u *fname;
643 char_u *dirp;
644#if defined(MSDOS) || defined(MSWIN)
645 char_u *p;
646#endif
647
648 mfp = buf->b_ml.ml_mfp;
649 if (mfp->mf_fd < 0) /* there is no swap file yet */
650 {
651 /*
652 * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
653 * For help files we will make a swap file now.
654 */
Bram Moolenaar5803ae62014-03-23 16:04:02 +0100655 if (p_uc != 0 && !cmdmod.noswapfile)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656 ml_open_file(buf); /* create a swap file */
657 return;
658 }
659
660 /*
661 * Try all directories in the 'directory' option.
662 */
663 dirp = p_dir;
664 for (;;)
665 {
666 if (*dirp == NUL) /* tried all directories, fail */
667 break;
Bram Moolenaar8fc061c2004-12-29 21:03:02 +0000668 fname = findswapname(buf, &dirp, mfp->mf_fname);
669 /* alloc's fname */
Bram Moolenaarf541c362011-10-26 11:44:18 +0200670 if (dirp == NULL) /* out of memory */
671 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 if (fname == NULL) /* no file name found for this dir */
673 continue;
674
675#if defined(MSDOS) || defined(MSWIN)
676 /*
677 * Set full pathname for swap file now, because a ":!cd dir" may
678 * change directory without us knowing it.
679 */
680 p = FullName_save(fname, FALSE);
681 vim_free(fname);
682 fname = p;
683 if (fname == NULL)
684 continue;
685#endif
686 /* if the file name is the same we don't have to do anything */
687 if (fnamecmp(fname, mfp->mf_fname) == 0)
688 {
689 vim_free(fname);
690 success = TRUE;
691 break;
692 }
693 /* need to close the swap file before renaming */
694 if (mfp->mf_fd >= 0)
695 {
696 close(mfp->mf_fd);
697 mfp->mf_fd = -1;
698 }
699
700 /* try to rename the swap file */
701 if (vim_rename(mfp->mf_fname, fname) == 0)
702 {
703 success = TRUE;
704 vim_free(mfp->mf_fname);
705 mfp->mf_fname = fname;
706 vim_free(mfp->mf_ffname);
707#if defined(MSDOS) || defined(MSWIN)
708 mfp->mf_ffname = NULL; /* mf_fname is full pathname already */
709#else
710 mf_set_ffname(mfp);
711#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200712 ml_upd_block0(buf, UB_SAME_DIR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713 break;
714 }
715 vim_free(fname); /* this fname didn't work, try another */
716 }
717
718 if (mfp->mf_fd == -1) /* need to (re)open the swap file */
719 {
720 mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
721 if (mfp->mf_fd < 0)
722 {
723 /* could not (re)open the swap file, what can we do???? */
724 EMSG(_("E301: Oops, lost the swap file!!!"));
725 return;
726 }
Bram Moolenaarf05da212009-11-17 16:13:15 +0000727#ifdef HAVE_FD_CLOEXEC
728 {
729 int fdflags = fcntl(mfp->mf_fd, F_GETFD);
730 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarfbc4b4d2016-02-07 15:14:01 +0100731 (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaarf05da212009-11-17 16:13:15 +0000732 }
733#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 }
735 if (!success)
736 EMSG(_("E302: Could not rename swap file"));
737}
738
739/*
740 * Open a file for the memfile for all buffers that are not readonly or have
741 * been modified.
742 * Used when 'updatecount' changes from zero to non-zero.
743 */
744 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100745ml_open_files(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746{
747 buf_T *buf;
748
749 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
750 if (!buf->b_p_ro || buf->b_changed)
751 ml_open_file(buf);
752}
753
754/*
755 * Open a swap file for an existing memfile, if there is no swap file yet.
756 * If we are unable to find a file name, mf_fname will be NULL
757 * and the memfile will be in memory only (no recovery possible).
758 */
759 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100760ml_open_file(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000761{
762 memfile_T *mfp;
763 char_u *fname;
764 char_u *dirp;
765
766 mfp = buf->b_ml.ml_mfp;
Bram Moolenaar5803ae62014-03-23 16:04:02 +0100767 if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || cmdmod.noswapfile)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 return; /* nothing to do */
769
Bram Moolenaara1956f62006-03-12 22:18:00 +0000770#ifdef FEAT_SPELL
Bram Moolenaar4770d092006-01-12 23:22:24 +0000771 /* For a spell buffer use a temp file name. */
772 if (buf->b_spell)
773 {
Bram Moolenaare5c421c2015-03-31 13:33:08 +0200774 fname = vim_tempname('s', FALSE);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000775 if (fname != NULL)
776 (void)mf_open_file(mfp, fname); /* consumes fname! */
777 buf->b_may_swap = FALSE;
778 return;
779 }
780#endif
781
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 /*
783 * Try all directories in 'directory' option.
784 */
785 dirp = p_dir;
786 for (;;)
787 {
788 if (*dirp == NUL)
789 break;
Bram Moolenaare242b832010-06-24 05:39:03 +0200790 /* There is a small chance that between choosing the swap file name
791 * and creating it, another Vim creates the file. In that case the
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 * creation will fail and we will use another directory. */
Bram Moolenaar8fc061c2004-12-29 21:03:02 +0000793 fname = findswapname(buf, &dirp, NULL); /* allocates fname */
Bram Moolenaarf541c362011-10-26 11:44:18 +0200794 if (dirp == NULL)
795 break; /* out of memory */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 if (fname == NULL)
797 continue;
798 if (mf_open_file(mfp, fname) == OK) /* consumes fname! */
799 {
Bram Moolenaare60acc12011-05-10 16:41:25 +0200800#if defined(MSDOS) || defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 /*
802 * set full pathname for swap file now, because a ":!cd dir" may
803 * change directory without us knowing it.
804 */
805 mf_fullname(mfp);
806#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200807 ml_upd_block0(buf, UB_SAME_DIR);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000808
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 /* Flush block zero, so others can read it */
810 if (mf_sync(mfp, MFS_ZERO) == OK)
Bram Moolenaarc32840f2006-01-14 21:23:38 +0000811 {
812 /* Mark all blocks that should be in the swapfile as dirty.
813 * Needed for when the 'swapfile' option was reset, so that
814 * the swap file was deleted, and then on again. */
815 mf_set_dirty(mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816 break;
Bram Moolenaarc32840f2006-01-14 21:23:38 +0000817 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 /* Writing block 0 failed: close the file and try another dir */
819 mf_close_file(buf, FALSE);
820 }
821 }
822
823 if (mfp->mf_fname == NULL) /* Failed! */
824 {
825 need_wait_return = TRUE; /* call wait_return later */
826 ++no_wait_return;
827 (void)EMSG2(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200828 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829 --no_wait_return;
830 }
831
832 /* don't try to open a swap file again */
833 buf->b_may_swap = FALSE;
834}
835
836/*
837 * If still need to create a swap file, and starting to edit a not-readonly
838 * file, or reading into an existing buffer, create a swap file now.
839 */
840 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100841check_need_swap(
842 int newfile) /* reading file into new buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843{
844 if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
845 ml_open_file(curbuf);
846}
847
848/*
849 * Close memline for buffer 'buf'.
850 * If 'del_file' is TRUE, delete the swap file
851 */
852 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100853ml_close(buf_T *buf, int del_file)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854{
855 if (buf->b_ml.ml_mfp == NULL) /* not open */
856 return;
857 mf_close(buf->b_ml.ml_mfp, del_file); /* close the .swp file */
858 if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
859 vim_free(buf->b_ml.ml_line_ptr);
860 vim_free(buf->b_ml.ml_stack);
861#ifdef FEAT_BYTEOFF
862 vim_free(buf->b_ml.ml_chunksize);
863 buf->b_ml.ml_chunksize = NULL;
864#endif
865 buf->b_ml.ml_mfp = NULL;
866
867 /* Reset the "recovered" flag, give the ATTENTION prompt the next time
868 * this buffer is loaded. */
869 buf->b_flags &= ~BF_RECOVERED;
870}
871
872/*
873 * Close all existing memlines and memfiles.
874 * Only used when exiting.
875 * When 'del_file' is TRUE, delete the memfiles.
Bram Moolenaar81bf7082005-02-12 14:31:42 +0000876 * But don't delete files that were ":preserve"d when we are POSIX compatible.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 */
878 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100879ml_close_all(int del_file)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880{
881 buf_T *buf;
882
883 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
Bram Moolenaar81bf7082005-02-12 14:31:42 +0000884 ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0
885 || vim_strchr(p_cpo, CPO_PRESERVE) == NULL));
Bram Moolenaar34b466e2013-11-28 17:41:46 +0100886#ifdef FEAT_SPELL
887 spell_delete_wordlist(); /* delete the internal wordlist */
888#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889#ifdef TEMPDIRNAMES
Bram Moolenaar34b466e2013-11-28 17:41:46 +0100890 vim_deltempdir(); /* delete created temp directory */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000891#endif
892}
893
894/*
895 * Close all memfiles for not modified buffers.
896 * Only use just before exiting!
897 */
898 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100899ml_close_notmod(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900{
901 buf_T *buf;
902
903 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
904 if (!bufIsChanged(buf))
905 ml_close(buf, TRUE); /* close all not-modified buffers */
906}
907
908/*
909 * Update the timestamp in the .swp file.
910 * Used when the file has been written.
911 */
912 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100913ml_timestamp(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000914{
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200915 ml_upd_block0(buf, UB_FNAME);
916}
917
918/*
919 * Return FAIL when the ID of "b0p" is wrong.
920 */
921 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100922ml_check_b0_id(ZERO_BL *b0p)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200923{
924 if (b0p->b0_id[0] != BLOCK0_ID0
925 || (b0p->b0_id[1] != BLOCK0_ID1
926 && b0p->b0_id[1] != BLOCK0_ID1_C0
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200927 && b0p->b0_id[1] != BLOCK0_ID1_C1
928 && b0p->b0_id[1] != BLOCK0_ID1_C2)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200929 )
930 return FAIL;
931 return OK;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000932}
933
934/*
935 * Update the timestamp or the B0_SAME_DIR flag of the .swp file.
936 */
937 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100938ml_upd_block0(buf_T *buf, upd_block0_T what)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000939{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000940 memfile_T *mfp;
941 bhdr_T *hp;
942 ZERO_BL *b0p;
943
944 mfp = buf->b_ml.ml_mfp;
Bram Moolenaar2be79502014-08-13 21:58:28 +0200945 if (mfp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 return;
Bram Moolenaar2be79502014-08-13 21:58:28 +0200947 hp = mf_get(mfp, (blocknr_T)0, 1);
948 if (hp == NULL)
949 {
950#ifdef FEAT_CRYPT
951 /* Possibly update the seed in the memfile before there is a block0. */
952 if (what == UB_CRYPT)
953 ml_set_mfp_crypt(buf);
954#endif
955 return;
956 }
957
Bram Moolenaar071d4272004-06-13 20:20:40 +0000958 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200959 if (ml_check_b0_id(b0p) == FAIL)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000960 EMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961 else
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000962 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200963 if (what == UB_FNAME)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000964 set_b0_fname(b0p, buf);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200965#ifdef FEAT_CRYPT
966 else if (what == UB_CRYPT)
967 ml_set_b0_crypt(buf, b0p);
968#endif
969 else /* what == UB_SAME_DIR */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000970 set_b0_dir_flag(b0p, buf);
971 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972 mf_put(mfp, hp, TRUE, FALSE);
973}
974
975/*
976 * Write file name and timestamp into block 0 of a swap file.
977 * Also set buf->b_mtime.
978 * Don't use NameBuff[]!!!
979 */
980 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100981set_b0_fname(ZERO_BL *b0p, buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000982{
983 struct stat st;
984
985 if (buf->b_ffname == NULL)
986 b0p->b0_fname[0] = NUL;
987 else
988 {
Bram Moolenaare60acc12011-05-10 16:41:25 +0200989#if defined(MSDOS) || defined(MSWIN) || defined(AMIGA)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000990 /* Systems that cannot translate "~user" back into a path: copy the
991 * file name unmodified. Do use slashes instead of backslashes for
992 * portability. */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +0200993 vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT - 1);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000994# ifdef BACKSLASH_IN_FILENAME
995 forward_slash(b0p->b0_fname);
996# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000997#else
998 size_t flen, ulen;
999 char_u uname[B0_UNAME_SIZE];
1000
1001 /*
1002 * For a file under the home directory of the current user, we try to
1003 * replace the home directory path with "~user". This helps when
1004 * editing the same file on different machines over a network.
1005 * First replace home dir path with "~/" with home_replace().
1006 * Then insert the user name to get "~user/".
1007 */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001008 home_replace(NULL, buf->b_ffname, b0p->b0_fname,
1009 B0_FNAME_SIZE_CRYPT, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010 if (b0p->b0_fname[0] == '~')
1011 {
1012 flen = STRLEN(b0p->b0_fname);
1013 /* If there is no user name or it is too long, don't use "~/" */
1014 if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001015 || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE_CRYPT - 1)
1016 vim_strncpy(b0p->b0_fname, buf->b_ffname,
1017 B0_FNAME_SIZE_CRYPT - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018 else
1019 {
1020 mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
1021 mch_memmove(b0p->b0_fname + 1, uname, ulen);
1022 }
1023 }
1024#endif
1025 if (mch_stat((char *)buf->b_ffname, &st) >= 0)
1026 {
1027 long_to_char((long)st.st_mtime, b0p->b0_mtime);
1028#ifdef CHECK_INODE
1029 long_to_char((long)st.st_ino, b0p->b0_ino);
1030#endif
1031 buf_store_time(buf, &st, buf->b_ffname);
1032 buf->b_mtime_read = buf->b_mtime;
1033 }
1034 else
1035 {
1036 long_to_char(0L, b0p->b0_mtime);
1037#ifdef CHECK_INODE
1038 long_to_char(0L, b0p->b0_ino);
1039#endif
1040 buf->b_mtime = 0;
1041 buf->b_mtime_read = 0;
1042 buf->b_orig_size = 0;
1043 buf->b_orig_mode = 0;
1044 }
1045 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001046
1047#ifdef FEAT_MBYTE
1048 /* Also add the 'fileencoding' if there is room. */
1049 add_b0_fenc(b0p, curbuf);
1050#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051}
1052
1053/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001054 * Update the B0_SAME_DIR flag of the swap file. It's set if the file and the
1055 * swapfile for "buf" are in the same directory.
1056 * This is fail safe: if we are not sure the directories are equal the flag is
1057 * not set.
1058 */
1059 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001060set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001061{
1062 if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
1063 b0p->b0_flags |= B0_SAME_DIR;
1064 else
1065 b0p->b0_flags &= ~B0_SAME_DIR;
1066}
1067
1068#ifdef FEAT_MBYTE
1069/*
1070 * When there is room, add the 'fileencoding' to block zero.
1071 */
1072 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001073add_b0_fenc(
1074 ZERO_BL *b0p,
1075 buf_T *buf)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001076{
1077 int n;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001078 int size = B0_FNAME_SIZE_NOCRYPT;
1079
1080# ifdef FEAT_CRYPT
1081 /* Without encryption use the same offset as in Vim 7.2 to be compatible.
1082 * With encryption it's OK to move elsewhere, the swap file is not
1083 * compatible anyway. */
1084 if (*buf->b_p_key != NUL)
1085 size = B0_FNAME_SIZE_CRYPT;
1086# endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001087
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001088 n = (int)STRLEN(buf->b_p_fenc);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001089 if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001090 b0p->b0_flags &= ~B0_HAS_FENC;
1091 else
1092 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001093 mch_memmove((char *)b0p->b0_fname + size - n,
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001094 (char *)buf->b_p_fenc, (size_t)n);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001095 *(b0p->b0_fname + size - n - 1) = NUL;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001096 b0p->b0_flags |= B0_HAS_FENC;
1097 }
1098}
1099#endif
1100
1101
1102/*
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001103 * Try to recover curbuf from the .swp file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 */
1105 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001106ml_recover(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107{
1108 buf_T *buf = NULL;
1109 memfile_T *mfp = NULL;
1110 char_u *fname;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001111 char_u *fname_used = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 bhdr_T *hp = NULL;
1113 ZERO_BL *b0p;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001114 int b0_ff;
1115 char_u *b0_fenc = NULL;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001116#ifdef FEAT_CRYPT
1117 int b0_cm = -1;
1118#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001119 PTR_BL *pp;
1120 DATA_BL *dp;
1121 infoptr_T *ip;
1122 blocknr_T bnum;
1123 int page_count;
1124 struct stat org_stat, swp_stat;
1125 int len;
1126 int directly;
1127 linenr_T lnum;
1128 char_u *p;
1129 int i;
1130 long error;
1131 int cannot_open;
1132 linenr_T line_count;
1133 int has_error;
1134 int idx;
1135 int top;
1136 int txt_start;
1137 off_t size;
1138 int called_from_main;
1139 int serious_error = TRUE;
1140 long mtime;
1141 int attr;
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001142 int orig_file_status = NOTDONE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143
1144 recoverymode = TRUE;
1145 called_from_main = (curbuf->b_ml.ml_mfp == NULL);
1146 attr = hl_attr(HLF_E);
Bram Moolenaard0ba34a2009-11-03 12:06:23 +00001147
1148 /*
1149 * If the file name ends in ".s[uvw][a-z]" we assume this is the swap file.
1150 * Otherwise a search is done to find the swap file(s).
1151 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 fname = curbuf->b_fname;
1153 if (fname == NULL) /* When there is no file name */
1154 fname = (char_u *)"";
1155 len = (int)STRLEN(fname);
1156 if (len >= 4 &&
Bram Moolenaare60acc12011-05-10 16:41:25 +02001157#if defined(VMS)
Bram Moolenaard0ba34a2009-11-03 12:06:23 +00001158 STRNICMP(fname + len - 4, "_s" , 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159#else
Bram Moolenaard0ba34a2009-11-03 12:06:23 +00001160 STRNICMP(fname + len - 4, ".s" , 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161#endif
Bram Moolenaard0ba34a2009-11-03 12:06:23 +00001162 == 0
1163 && vim_strchr((char_u *)"UVWuvw", fname[len - 2]) != NULL
1164 && ASCII_ISALPHA(fname[len - 1]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 {
1166 directly = TRUE;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001167 fname_used = vim_strsave(fname); /* make a copy for mf_open() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168 }
1169 else
1170 {
1171 directly = FALSE;
1172
1173 /* count the number of matching swap files */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001174 len = recover_names(fname, FALSE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175 if (len == 0) /* no swap files found */
1176 {
1177 EMSG2(_("E305: No swap file found for %s"), fname);
1178 goto theend;
1179 }
1180 if (len == 1) /* one swap file found, use it */
1181 i = 1;
1182 else /* several swap files found, choose */
1183 {
1184 /* list the names of the swap files */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001185 (void)recover_names(fname, TRUE, 0, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186 msg_putchar('\n');
1187 MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00001188 i = get_number(FALSE, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001189 if (i < 1 || i > len)
1190 goto theend;
1191 }
1192 /* get the swap file name that will be used */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001193 (void)recover_names(fname, FALSE, i, &fname_used);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001194 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001195 if (fname_used == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 goto theend; /* out of memory */
1197
1198 /* When called from main() still need to initialize storage structure */
Bram Moolenaar4770d092006-01-12 23:22:24 +00001199 if (called_from_main && ml_open(curbuf) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200 getout(1);
1201
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001202 /*
1203 * Allocate a buffer structure for the swap file that is used for recovery.
Bram Moolenaar0ad014c2010-07-25 14:00:46 +02001204 * Only the memline and crypt information in it are really used.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001205 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
1207 if (buf == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001210 /*
1211 * init fields in memline struct
1212 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001213 buf->b_ml.ml_stack_size = 0; /* no stack yet */
1214 buf->b_ml.ml_stack = NULL; /* no stack yet */
1215 buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
1216 buf->b_ml.ml_line_lnum = 0; /* no cached line */
1217 buf->b_ml.ml_locked = NULL; /* no locked block */
1218 buf->b_ml.ml_flags = 0;
Bram Moolenaar0fe849a2010-07-25 15:11:11 +02001219#ifdef FEAT_CRYPT
1220 buf->b_p_key = empty_option;
1221 buf->b_p_cm = empty_option;
1222#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001224 /*
1225 * open the memfile from the old swap file
1226 */
1227 p = vim_strsave(fname_used); /* save "fname_used" for the message:
1228 mf_open() will consume "fname_used"! */
1229 mfp = mf_open(fname_used, O_RDONLY);
1230 fname_used = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231 if (mfp == NULL || mfp->mf_fd < 0)
1232 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001233 if (fname_used != NULL)
1234 EMSG2(_("E306: Cannot open %s"), fname_used);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001235 goto theend;
1236 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 buf->b_ml.ml_mfp = mfp;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001238#ifdef FEAT_CRYPT
1239 mfp->mf_buffer = buf;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001240#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241
1242 /*
1243 * The page size set in mf_open() might be different from the page size
1244 * used in the swap file, we must get it from block 0. But to read block
1245 * 0 we need a page size. Use the minimal size for block 0 here, it will
1246 * be set to the real value below.
1247 */
1248 mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
1249
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001250 /*
1251 * try to read block 0
1252 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253 if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
1254 {
1255 msg_start();
1256 MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
1257 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001258 MSG_PUTS_ATTR(_("\nMaybe no changes were made or Vim did not update the swap file."),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 attr | MSG_HIST);
1260 msg_end();
1261 goto theend;
1262 }
1263 b0p = (ZERO_BL *)(hp->bh_data);
1264 if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
1265 {
1266 msg_start();
1267 msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
1268 MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
1269 MSG_HIST);
1270 MSG_PUTS_ATTR(_("Use Vim version 3.0.\n"), MSG_HIST);
1271 msg_end();
1272 goto theend;
1273 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001274 if (ml_check_b0_id(b0p) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001275 {
1276 EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
1277 goto theend;
1278 }
1279 if (b0_magic_wrong(b0p))
1280 {
1281 msg_start();
1282 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1283#if defined(MSDOS) || defined(MSWIN)
1284 if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
1285 MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
1286 attr | MSG_HIST);
1287 else
1288#endif
1289 MSG_PUTS_ATTR(_(" cannot be used on this computer.\n"),
1290 attr | MSG_HIST);
1291 MSG_PUTS_ATTR(_("The file was created on "), attr | MSG_HIST);
Bram Moolenaare242b832010-06-24 05:39:03 +02001292 /* avoid going past the end of a corrupted hostname */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 b0p->b0_fname[0] = NUL;
1294 MSG_PUTS_ATTR(b0p->b0_hname, attr | MSG_HIST);
1295 MSG_PUTS_ATTR(_(",\nor the file has been damaged."), attr | MSG_HIST);
1296 msg_end();
1297 goto theend;
1298 }
Bram Moolenaar1c536282007-04-26 15:21:56 +00001299
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001300#ifdef FEAT_CRYPT
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001301 for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
1302 if (id1_codes[i] == b0p->b0_id[1])
1303 b0_cm = i;
1304 if (b0_cm > 0)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001305 mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001306 crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001307#else
1308 if (b0p->b0_id[1] != BLOCK0_ID1)
1309 {
Bram Moolenaar996343d2010-07-04 22:20:21 +02001310 EMSG2(_("E833: %s is encrypted and this version of Vim does not support encryption"), mfp->mf_fname);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001311 goto theend;
1312 }
1313#endif
1314
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 /*
1316 * If we guessed the wrong page size, we have to recalculate the
1317 * highest block number in the file.
1318 */
1319 if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
1320 {
Bram Moolenaar1c536282007-04-26 15:21:56 +00001321 unsigned previous_page_size = mfp->mf_page_size;
1322
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323 mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
Bram Moolenaar1c536282007-04-26 15:21:56 +00001324 if (mfp->mf_page_size < previous_page_size)
1325 {
1326 msg_start();
1327 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1328 MSG_PUTS_ATTR(_(" has been damaged (page size is smaller than minimum value).\n"),
1329 attr | MSG_HIST);
1330 msg_end();
1331 goto theend;
1332 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001333 if ((size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
1334 mfp->mf_blocknr_max = 0; /* no file or empty file */
1335 else
1336 mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
1337 mfp->mf_infile_count = mfp->mf_blocknr_max;
Bram Moolenaar1c536282007-04-26 15:21:56 +00001338
1339 /* need to reallocate the memory used to store the data */
1340 p = alloc(mfp->mf_page_size);
1341 if (p == NULL)
1342 goto theend;
1343 mch_memmove(p, hp->bh_data, previous_page_size);
1344 vim_free(hp->bh_data);
1345 hp->bh_data = p;
1346 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001347 }
1348
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001349 /*
1350 * If .swp file name given directly, use name from swap file for buffer.
1351 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352 if (directly)
1353 {
1354 expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
1355 if (setfname(curbuf, NameBuff, NULL, TRUE) == FAIL)
1356 goto theend;
1357 }
1358
1359 home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar555b2802005-05-19 21:08:39 +00001360 smsg((char_u *)_("Using swap file \"%s\""), NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001361
1362 if (buf_spname(curbuf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001363 vim_strncpy(NameBuff, buf_spname(curbuf), MAXPATHL - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001364 else
1365 home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar555b2802005-05-19 21:08:39 +00001366 smsg((char_u *)_("Original file \"%s\""), NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001367 msg_putchar('\n');
1368
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001369 /*
1370 * check date of swap file and original file
1371 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372 mtime = char_to_long(b0p->b0_mtime);
1373 if (curbuf->b_ffname != NULL
1374 && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
1375 && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
1376 && org_stat.st_mtime > swp_stat.st_mtime)
1377 || org_stat.st_mtime != mtime))
1378 {
1379 EMSG(_("E308: Warning: Original file may have been changed"));
1380 }
1381 out_flush();
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001382
1383 /* Get the 'fileformat' and 'fileencoding' from block zero. */
1384 b0_ff = (b0p->b0_flags & B0_FF_MASK);
1385 if (b0p->b0_flags & B0_HAS_FENC)
1386 {
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001387 int fnsize = B0_FNAME_SIZE_NOCRYPT;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001388
1389#ifdef FEAT_CRYPT
1390 /* Use the same size as in add_b0_fenc(). */
1391 if (b0p->b0_id[1] != BLOCK0_ID1)
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001392 fnsize = B0_FNAME_SIZE_CRYPT;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001393#endif
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001394 for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; --p)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001395 ;
Bram Moolenaarf506c5b2010-06-22 06:28:58 +02001396 b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + fnsize - p));
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001397 }
1398
Bram Moolenaar071d4272004-06-13 20:20:40 +00001399 mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
1400 hp = NULL;
1401
1402 /*
1403 * Now that we are sure that the file is going to be recovered, clear the
1404 * contents of the current buffer.
1405 */
1406 while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
1407 ml_delete((linenr_T)1, FALSE);
1408
1409 /*
1410 * Try reading the original file to obtain the values of 'fileformat',
1411 * 'fileencoding', etc. Ignore errors. The text itself is not used.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001412 * When the file is encrypted the user is asked to enter the key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413 */
1414 if (curbuf->b_ffname != NULL)
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001415 orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416 (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001417
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001418#ifdef FEAT_CRYPT
1419 if (b0_cm >= 0)
1420 {
1421 /* Need to ask the user for the crypt key. If this fails we continue
1422 * without a key, will probably get garbage text. */
1423 if (*curbuf->b_p_key != NUL)
1424 {
1425 smsg((char_u *)_("Swap file is encrypted: \"%s\""), fname_used);
1426 MSG_PUTS(_("\nIf you entered a new crypt key but did not write the text file,"));
1427 MSG_PUTS(_("\nenter the new crypt key."));
1428 MSG_PUTS(_("\nIf you wrote the text file after changing the crypt key press enter"));
1429 MSG_PUTS(_("\nto use the same key for text file and swap file"));
1430 }
1431 else
1432 smsg((char_u *)_(need_key_msg), fname_used);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02001433 buf->b_p_key = crypt_get_key(FALSE, FALSE);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001434 if (buf->b_p_key == NULL)
1435 buf->b_p_key = curbuf->b_p_key;
1436 else if (*buf->b_p_key == NUL)
1437 {
1438 vim_free(buf->b_p_key);
1439 buf->b_p_key = curbuf->b_p_key;
1440 }
1441 if (buf->b_p_key == NULL)
1442 buf->b_p_key = empty_option;
1443 }
1444#endif
1445
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001446 /* Use the 'fileformat' and 'fileencoding' as stored in the swap file. */
1447 if (b0_ff != 0)
1448 set_fileformat(b0_ff - 1, OPT_LOCAL);
1449 if (b0_fenc != NULL)
1450 {
1451 set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
1452 vim_free(b0_fenc);
1453 }
1454 unchanged(curbuf, TRUE);
1455
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456 bnum = 1; /* start with block 1 */
1457 page_count = 1; /* which is 1 page */
1458 lnum = 0; /* append after line 0 in curbuf */
1459 line_count = 0;
1460 idx = 0; /* start with first index in block 1 */
1461 error = 0;
1462 buf->b_ml.ml_stack_top = 0;
1463 buf->b_ml.ml_stack = NULL;
1464 buf->b_ml.ml_stack_size = 0; /* no stack yet */
1465
1466 if (curbuf->b_ffname == NULL)
1467 cannot_open = TRUE;
1468 else
1469 cannot_open = FALSE;
1470
1471 serious_error = FALSE;
1472 for ( ; !got_int; line_breakcheck())
1473 {
1474 if (hp != NULL)
1475 mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
1476
1477 /*
1478 * get block
1479 */
1480 if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
1481 {
1482 if (bnum == 1)
1483 {
1484 EMSG2(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
1485 goto theend;
1486 }
1487 ++error;
1488 ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
1489 (colnr_T)0, TRUE);
1490 }
1491 else /* there is a block */
1492 {
1493 pp = (PTR_BL *)(hp->bh_data);
1494 if (pp->pb_id == PTR_ID) /* it is a pointer block */
1495 {
1496 /* check line count when using pointer block first time */
1497 if (idx == 0 && line_count != 0)
1498 {
1499 for (i = 0; i < (int)pp->pb_count; ++i)
1500 line_count -= pp->pb_pointer[i].pe_line_count;
1501 if (line_count != 0)
1502 {
1503 ++error;
1504 ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
1505 (colnr_T)0, TRUE);
1506 }
1507 }
1508
1509 if (pp->pb_count == 0)
1510 {
1511 ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
1512 (colnr_T)0, TRUE);
1513 ++error;
1514 }
1515 else if (idx < (int)pp->pb_count) /* go a block deeper */
1516 {
1517 if (pp->pb_pointer[idx].pe_bnum < 0)
1518 {
1519 /*
1520 * Data block with negative block number.
1521 * Try to read lines from the original file.
1522 * This is slow, but it works.
1523 */
1524 if (!cannot_open)
1525 {
1526 line_count = pp->pb_pointer[idx].pe_line_count;
1527 if (readfile(curbuf->b_ffname, NULL, lnum,
1528 pp->pb_pointer[idx].pe_old_lnum - 1,
1529 line_count, NULL, 0) == FAIL)
1530 cannot_open = TRUE;
1531 else
1532 lnum += line_count;
1533 }
1534 if (cannot_open)
1535 {
1536 ++error;
1537 ml_append(lnum++, (char_u *)_("???LINES MISSING"),
1538 (colnr_T)0, TRUE);
1539 }
1540 ++idx; /* get same block again for next index */
1541 continue;
1542 }
1543
1544 /*
1545 * going one block deeper in the tree
1546 */
1547 if ((top = ml_add_stack(buf)) < 0) /* new entry in stack */
1548 {
1549 ++error;
1550 break; /* out of memory */
1551 }
1552 ip = &(buf->b_ml.ml_stack[top]);
1553 ip->ip_bnum = bnum;
1554 ip->ip_index = idx;
1555
1556 bnum = pp->pb_pointer[idx].pe_bnum;
1557 line_count = pp->pb_pointer[idx].pe_line_count;
1558 page_count = pp->pb_pointer[idx].pe_page_count;
Bram Moolenaar986a0032011-06-13 01:07:27 +02001559 idx = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560 continue;
1561 }
1562 }
1563 else /* not a pointer block */
1564 {
1565 dp = (DATA_BL *)(hp->bh_data);
1566 if (dp->db_id != DATA_ID) /* block id wrong */
1567 {
1568 if (bnum == 1)
1569 {
1570 EMSG2(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
1571 mfp->mf_fname);
1572 goto theend;
1573 }
1574 ++error;
1575 ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
1576 (colnr_T)0, TRUE);
1577 }
1578 else
1579 {
1580 /*
1581 * it is a data block
1582 * Append all the lines in this block
1583 */
1584 has_error = FALSE;
1585 /*
1586 * check length of block
1587 * if wrong, use length in pointer block
1588 */
1589 if (page_count * mfp->mf_page_size != dp->db_txt_end)
1590 {
1591 ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
1592 (colnr_T)0, TRUE);
1593 ++error;
1594 has_error = TRUE;
1595 dp->db_txt_end = page_count * mfp->mf_page_size;
1596 }
1597
1598 /* make sure there is a NUL at the end of the block */
1599 *((char_u *)dp + dp->db_txt_end - 1) = NUL;
1600
1601 /*
1602 * check number of lines in block
1603 * if wrong, use count in data block
1604 */
1605 if (line_count != dp->db_line_count)
1606 {
1607 ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
1608 (colnr_T)0, TRUE);
1609 ++error;
1610 has_error = TRUE;
1611 }
1612
1613 for (i = 0; i < dp->db_line_count; ++i)
1614 {
1615 txt_start = (dp->db_index[i] & DB_INDEX_MASK);
Bram Moolenaar740885b2009-11-03 14:33:17 +00001616 if (txt_start <= (int)HEADER_SIZE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 || txt_start >= (int)dp->db_txt_end)
1618 {
1619 p = (char_u *)"???";
1620 ++error;
1621 }
1622 else
1623 p = (char_u *)dp + txt_start;
1624 ml_append(lnum++, p, (colnr_T)0, TRUE);
1625 }
1626 if (has_error)
Bram Moolenaar740885b2009-11-03 14:33:17 +00001627 ml_append(lnum++, (char_u *)_("???END"),
1628 (colnr_T)0, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629 }
1630 }
1631 }
1632
1633 if (buf->b_ml.ml_stack_top == 0) /* finished */
1634 break;
1635
1636 /*
1637 * go one block up in the tree
1638 */
1639 ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
1640 bnum = ip->ip_bnum;
1641 idx = ip->ip_index + 1; /* go to next index */
1642 page_count = 1;
1643 }
1644
1645 /*
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001646 * Compare the buffer contents with the original file. When they differ
1647 * set the 'modified' flag.
1648 * Lines 1 - lnum are the new contents.
1649 * Lines lnum + 1 to ml_line_count are the original contents.
1650 * Line ml_line_count + 1 in the dummy empty line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651 */
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001652 if (orig_file_status != OK || curbuf->b_ml.ml_line_count != lnum * 2 + 1)
1653 {
1654 /* Recovering an empty file results in two lines and the first line is
1655 * empty. Don't set the modified flag then. */
1656 if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL))
1657 {
1658 changed_int();
1659 ++curbuf->b_changedtick;
1660 }
1661 }
1662 else
1663 {
1664 for (idx = 1; idx <= lnum; ++idx)
1665 {
1666 /* Need to copy one line, fetching the other one may flush it. */
1667 p = vim_strsave(ml_get(idx));
1668 i = STRCMP(p, ml_get(idx + lnum));
1669 vim_free(p);
1670 if (i != 0)
1671 {
1672 changed_int();
1673 ++curbuf->b_changedtick;
1674 break;
1675 }
1676 }
1677 }
1678
1679 /*
1680 * Delete the lines from the original file and the dummy line from the
1681 * empty buffer. These will now be after the last line in the buffer.
1682 */
1683 while (curbuf->b_ml.ml_line_count > lnum
1684 && !(curbuf->b_ml.ml_flags & ML_EMPTY))
1685 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686 curbuf->b_flags |= BF_RECOVERED;
1687
1688 recoverymode = FALSE;
1689 if (got_int)
1690 EMSG(_("E311: Recovery Interrupted"));
1691 else if (error)
1692 {
1693 ++no_wait_return;
1694 MSG(">>>>>>>>>>>>>");
1695 EMSG(_("E312: Errors detected while recovering; look for lines starting with ???"));
1696 --no_wait_return;
1697 MSG(_("See \":help E312\" for more information."));
1698 MSG(">>>>>>>>>>>>>");
1699 }
1700 else
1701 {
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001702 if (curbuf->b_changed)
1703 {
1704 MSG(_("Recovery completed. You should check if everything is OK."));
1705 MSG_PUTS(_("\n(You might want to write out this file under another name\n"));
1706 MSG_PUTS(_("and run diff with the original file to check for changes)"));
1707 }
1708 else
1709 MSG(_("Recovery completed. Buffer contents equals file contents."));
1710 MSG_PUTS(_("\nYou may want to delete the .swp file now.\n\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 cmdline_row = msg_row;
1712 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001713#ifdef FEAT_CRYPT
1714 if (*buf->b_p_key != NUL && STRCMP(curbuf->b_p_key, buf->b_p_key) != 0)
1715 {
1716 MSG_PUTS(_("Using crypt key from swap file for the text file.\n"));
1717 set_option_value((char_u *)"key", 0L, buf->b_p_key, OPT_LOCAL);
1718 }
1719#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720 redraw_curbuf_later(NOT_VALID);
1721
1722theend:
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001723 vim_free(fname_used);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 recoverymode = FALSE;
1725 if (mfp != NULL)
1726 {
1727 if (hp != NULL)
1728 mf_put(mfp, hp, FALSE, FALSE);
1729 mf_close(mfp, FALSE); /* will also vim_free(mfp->mf_fname) */
1730 }
Bram Moolenaardf88dda2007-01-09 13:34:50 +00001731 if (buf != NULL)
1732 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001733#ifdef FEAT_CRYPT
1734 if (buf->b_p_key != curbuf->b_p_key)
1735 free_string_option(buf->b_p_key);
Bram Moolenaar0ad014c2010-07-25 14:00:46 +02001736 free_string_option(buf->b_p_cm);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001737#endif
Bram Moolenaardf88dda2007-01-09 13:34:50 +00001738 vim_free(buf->b_ml.ml_stack);
1739 vim_free(buf);
1740 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 if (serious_error && called_from_main)
1742 ml_close(curbuf, TRUE);
1743#ifdef FEAT_AUTOCMD
1744 else
1745 {
1746 apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
1747 apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
1748 }
1749#endif
1750 return;
1751}
1752
1753/*
1754 * Find the names of swap files in current directory and the directory given
1755 * with the 'directory' option.
1756 *
1757 * Used to:
1758 * - list the swap files for "vim -r"
1759 * - count the number of swap files when recovering
1760 * - list the swap files when recovering
1761 * - find the name of the n'th swap file when recovering
1762 */
1763 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001764recover_names(
1765 char_u *fname, /* base for swap file name */
1766 int list, /* when TRUE, list the swap file names */
1767 int nr, /* when non-zero, return nr'th swap file name */
1768 char_u **fname_out) /* result when "nr" > 0 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001769{
1770 int num_names;
1771 char_u *(names[6]);
1772 char_u *tail;
1773 char_u *p;
1774 int num_files;
1775 int file_count = 0;
1776 char_u **files;
1777 int i;
1778 char_u *dirp;
1779 char_u *dir_name;
Bram Moolenaar64354da2010-05-25 21:37:17 +02001780 char_u *fname_res = NULL;
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001781#ifdef HAVE_READLINK
1782 char_u fname_buf[MAXPATHL];
Bram Moolenaar64354da2010-05-25 21:37:17 +02001783#endif
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001784
Bram Moolenaar64354da2010-05-25 21:37:17 +02001785 if (fname != NULL)
1786 {
1787#ifdef HAVE_READLINK
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001788 /* Expand symlink in the file name, because the swap file is created
1789 * with the actual file instead of with the symlink. */
1790 if (resolve_symlink(fname, fname_buf) == OK)
1791 fname_res = fname_buf;
1792 else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001793#endif
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001794 fname_res = fname;
Bram Moolenaar64354da2010-05-25 21:37:17 +02001795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796
1797 if (list)
1798 {
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001799 /* use msg() to start the scrolling properly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 msg((char_u *)_("Swap files found:"));
1801 msg_putchar('\n');
1802 }
1803
1804 /*
1805 * Do the loop for every directory in 'directory'.
1806 * First allocate some memory to put the directory name in.
1807 */
1808 dir_name = alloc((unsigned)STRLEN(p_dir) + 1);
1809 dirp = p_dir;
1810 while (dir_name != NULL && *dirp)
1811 {
1812 /*
1813 * Isolate a directory name from *dirp and put it in dir_name (we know
1814 * it is large enough, so use 31000 for length).
1815 * Advance dirp to next directory name.
1816 */
1817 (void)copy_option_part(&dirp, dir_name, 31000, ",");
1818
1819 if (dir_name[0] == '.' && dir_name[1] == NUL) /* check current dir */
1820 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001821 if (fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001822 {
1823#ifdef VMS
1824 names[0] = vim_strsave((char_u *)"*_sw%");
1825#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 names[0] = vim_strsave((char_u *)"*.sw?");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827#endif
Bram Moolenaar2cc93182006-10-10 19:56:03 +00001828#if defined(UNIX) || defined(WIN3264)
1829 /* For Unix names starting with a dot are special. MS-Windows
1830 * supports this too, on some file systems. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 names[1] = vim_strsave((char_u *)".*.sw?");
1832 names[2] = vim_strsave((char_u *)".sw?");
1833 num_names = 3;
1834#else
1835# ifdef VMS
1836 names[1] = vim_strsave((char_u *)".*_sw%");
1837 num_names = 2;
1838# else
1839 num_names = 1;
1840# endif
1841#endif
1842 }
1843 else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001844 num_names = recov_file_names(names, fname_res, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 }
1846 else /* check directory dir_name */
1847 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001848 if (fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 {
1850#ifdef VMS
1851 names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
1852#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854#endif
Bram Moolenaar2cc93182006-10-10 19:56:03 +00001855#if defined(UNIX) || defined(WIN3264)
1856 /* For Unix names starting with a dot are special. MS-Windows
1857 * supports this too, on some file systems. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001858 names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
1859 names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
1860 num_names = 3;
1861#else
1862# ifdef VMS
1863 names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
1864 num_names = 2;
1865# else
1866 num_names = 1;
1867# endif
1868#endif
1869 }
1870 else
1871 {
1872#if defined(UNIX) || defined(WIN3264)
1873 p = dir_name + STRLEN(dir_name);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001874 if (after_pathsep(dir_name, p) && p[-1] == p[-2])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 {
1876 /* Ends with '//', Use Full path for swap name */
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001877 tail = make_percent_swname(dir_name, fname_res);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001878 }
1879 else
1880#endif
1881 {
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001882 tail = gettail(fname_res);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001883 tail = concat_fnames(dir_name, tail, TRUE);
1884 }
1885 if (tail == NULL)
1886 num_names = 0;
1887 else
1888 {
1889 num_names = recov_file_names(names, tail, FALSE);
1890 vim_free(tail);
1891 }
1892 }
1893 }
1894
1895 /* check for out-of-memory */
1896 for (i = 0; i < num_names; ++i)
1897 {
1898 if (names[i] == NULL)
1899 {
1900 for (i = 0; i < num_names; ++i)
1901 vim_free(names[i]);
1902 num_names = 0;
1903 }
1904 }
1905 if (num_names == 0)
1906 num_files = 0;
1907 else if (expand_wildcards(num_names, names, &num_files, &files,
1908 EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
1909 num_files = 0;
1910
1911 /*
1912 * When no swap file found, wildcard expansion might have failed (e.g.
1913 * not able to execute the shell).
1914 * Try finding a swap file by simply adding ".swp" to the file name.
1915 */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001916 if (*dirp == NUL && file_count + num_files == 0 && fname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001917 {
1918 struct stat st;
1919 char_u *swapname;
1920
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001921 swapname = modname(fname_res,
Bram Moolenaare60acc12011-05-10 16:41:25 +02001922#if defined(VMS)
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001923 (char_u *)"_swp", FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924#else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001925 (char_u *)".swp", TRUE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926#endif
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001927 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 if (swapname != NULL)
1929 {
1930 if (mch_stat((char *)swapname, &st) != -1) /* It exists! */
1931 {
1932 files = (char_u **)alloc((unsigned)sizeof(char_u *));
1933 if (files != NULL)
1934 {
1935 files[0] = swapname;
1936 swapname = NULL;
1937 num_files = 1;
1938 }
1939 }
1940 vim_free(swapname);
1941 }
1942 }
1943
1944 /*
1945 * remove swapfile name of the current buffer, it must be ignored
1946 */
1947 if (curbuf->b_ml.ml_mfp != NULL
1948 && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
1949 {
1950 for (i = 0; i < num_files; ++i)
1951 if (fullpathcmp(p, files[i], TRUE) & FPC_SAME)
1952 {
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00001953 /* Remove the name from files[i]. Move further entries
1954 * down. When the array becomes empty free it here, since
1955 * FreeWild() won't be called below. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 vim_free(files[i]);
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00001957 if (--num_files == 0)
1958 vim_free(files);
1959 else
1960 for ( ; i < num_files; ++i)
1961 files[i] = files[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962 }
1963 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001964 if (nr > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 {
1966 file_count += num_files;
1967 if (nr <= file_count)
1968 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001969 *fname_out = vim_strsave(
1970 files[nr - 1 + num_files - file_count]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971 dirp = (char_u *)""; /* stop searching */
1972 }
1973 }
1974 else if (list)
1975 {
1976 if (dir_name[0] == '.' && dir_name[1] == NUL)
1977 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02001978 if (fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001979 MSG_PUTS(_(" In current directory:\n"));
1980 else
1981 MSG_PUTS(_(" Using specified name:\n"));
1982 }
1983 else
1984 {
1985 MSG_PUTS(_(" In directory "));
1986 msg_home_replace(dir_name);
1987 MSG_PUTS(":\n");
1988 }
1989
1990 if (num_files)
1991 {
1992 for (i = 0; i < num_files; ++i)
1993 {
1994 /* print the swap file name */
1995 msg_outnum((long)++file_count);
1996 MSG_PUTS(". ");
1997 msg_puts(gettail(files[i]));
1998 msg_putchar('\n');
1999 (void)swapfile_info(files[i]);
2000 }
2001 }
2002 else
2003 MSG_PUTS(_(" -- none --\n"));
2004 out_flush();
2005 }
2006 else
2007 file_count += num_files;
2008
2009 for (i = 0; i < num_names; ++i)
2010 vim_free(names[i]);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00002011 if (num_files > 0)
2012 FreeWild(num_files, files);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013 }
2014 vim_free(dir_name);
2015 return file_count;
2016}
2017
2018#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
2019/*
2020 * Append the full path to name with path separators made into percent
2021 * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
2022 */
2023 static char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002024make_percent_swname(char_u *dir, char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002026 char_u *d, *s, *f;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002027
2028 f = fix_fname(name != NULL ? name : (char_u *) "");
2029 d = NULL;
2030 if (f != NULL)
2031 {
2032 s = alloc((unsigned)(STRLEN(f) + 1));
2033 if (s != NULL)
2034 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002035 STRCPY(s, f);
2036 for (d = s; *d != NUL; mb_ptr_adv(d))
2037 if (vim_ispathsep(*d))
2038 *d = '%';
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 d = concat_fnames(dir, s, TRUE);
2040 vim_free(s);
2041 }
2042 vim_free(f);
2043 }
2044 return d;
2045}
2046#endif
2047
2048#if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
2049static int process_still_running;
2050#endif
2051
2052/*
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00002053 * Give information about an existing swap file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002054 * Returns timestamp (0 when unknown).
2055 */
2056 static time_t
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002057swapfile_info(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058{
2059 struct stat st;
2060 int fd;
2061 struct block0 b0;
2062 time_t x = (time_t)0;
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00002063 char *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064#ifdef UNIX
2065 char_u uname[B0_UNAME_SIZE];
2066#endif
2067
2068 /* print the swap file date */
2069 if (mch_stat((char *)fname, &st) != -1)
2070 {
2071#ifdef UNIX
2072 /* print name of owner of the file */
2073 if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
2074 {
2075 MSG_PUTS(_(" owned by: "));
2076 msg_outtrans(uname);
2077 MSG_PUTS(_(" dated: "));
2078 }
2079 else
2080#endif
2081 MSG_PUTS(_(" dated: "));
2082 x = st.st_mtime; /* Manx C can't do &st.st_mtime */
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00002083 p = ctime(&x); /* includes '\n' */
2084 if (p == NULL)
2085 MSG_PUTS("(invalid)\n");
2086 else
2087 MSG_PUTS(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 }
2089
2090 /*
2091 * print the original file name
2092 */
2093 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
2094 if (fd >= 0)
2095 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01002096 if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002097 {
2098 if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
2099 {
2100 MSG_PUTS(_(" [from Vim version 3.0]"));
2101 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02002102 else if (ml_check_b0_id(&b0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 {
2104 MSG_PUTS(_(" [does not look like a Vim swap file]"));
2105 }
2106 else
2107 {
2108 MSG_PUTS(_(" file name: "));
2109 if (b0.b0_fname[0] == NUL)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00002110 MSG_PUTS(_("[No Name]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002111 else
2112 msg_outtrans(b0.b0_fname);
2113
2114 MSG_PUTS(_("\n modified: "));
2115 MSG_PUTS(b0.b0_dirty ? _("YES") : _("no"));
2116
2117 if (*(b0.b0_uname) != NUL)
2118 {
2119 MSG_PUTS(_("\n user name: "));
2120 msg_outtrans(b0.b0_uname);
2121 }
2122
2123 if (*(b0.b0_hname) != NUL)
2124 {
2125 if (*(b0.b0_uname) != NUL)
2126 MSG_PUTS(_(" host name: "));
2127 else
2128 MSG_PUTS(_("\n host name: "));
2129 msg_outtrans(b0.b0_hname);
2130 }
2131
2132 if (char_to_long(b0.b0_pid) != 0L)
2133 {
2134 MSG_PUTS(_("\n process ID: "));
2135 msg_outnum(char_to_long(b0.b0_pid));
2136#if defined(UNIX) || defined(__EMX__)
2137 /* EMX kill() not working correctly, it seems */
2138 if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
2139 {
2140 MSG_PUTS(_(" (still running)"));
2141# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2142 process_still_running = TRUE;
2143# endif
2144 }
2145#endif
2146 }
2147
2148 if (b0_magic_wrong(&b0))
2149 {
2150#if defined(MSDOS) || defined(MSWIN)
2151 if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
2152 MSG_PUTS(_("\n [not usable with this version of Vim]"));
2153 else
2154#endif
2155 MSG_PUTS(_("\n [not usable on this computer]"));
2156 }
2157 }
2158 }
2159 else
2160 MSG_PUTS(_(" [cannot be read]"));
2161 close(fd);
2162 }
2163 else
2164 MSG_PUTS(_(" [cannot be opened]"));
2165 msg_putchar('\n');
2166
2167 return x;
2168}
2169
2170 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002171recov_file_names(char_u **names, char_u *path, int prepend_dot)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172{
2173 int num_names;
2174
2175#ifdef SHORT_FNAME
2176 /*
2177 * (MS-DOS) always short names
2178 */
2179 names[0] = modname(path, (char_u *)".sw?", FALSE);
2180 num_names = 1;
2181#else /* !SHORT_FNAME */
2182 /*
2183 * (Win32 and Win64) never short names, but do prepend a dot.
2184 * (Not MS-DOS or Win32 or Win64) maybe short name, maybe not: Try both.
2185 * Only use the short name if it is different.
2186 */
2187 char_u *p;
2188 int i;
2189# ifndef WIN3264
2190 int shortname = curbuf->b_shortname;
2191
2192 curbuf->b_shortname = FALSE;
2193# endif
2194
2195 num_names = 0;
2196
2197 /*
2198 * May also add the file name with a dot prepended, for swap file in same
2199 * dir as original file.
2200 */
2201 if (prepend_dot)
2202 {
2203 names[num_names] = modname(path, (char_u *)".sw?", TRUE);
2204 if (names[num_names] == NULL)
2205 goto end;
2206 ++num_names;
2207 }
2208
2209 /*
2210 * Form the normal swap file name pattern by appending ".sw?".
2211 */
2212#ifdef VMS
2213 names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
2214#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002215 names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002216#endif
2217 if (names[num_names] == NULL)
2218 goto end;
2219 if (num_names >= 1) /* check if we have the same name twice */
2220 {
2221 p = names[num_names - 1];
2222 i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
2223 if (i > 0)
2224 p += i; /* file name has been expanded to full path */
2225
2226 if (STRCMP(p, names[num_names]) != 0)
2227 ++num_names;
2228 else
2229 vim_free(names[num_names]);
2230 }
2231 else
2232 ++num_names;
2233
2234# ifndef WIN3264
2235 /*
2236 * Also try with 'shortname' set, in case the file is on a DOS filesystem.
2237 */
2238 curbuf->b_shortname = TRUE;
2239#ifdef VMS
2240 names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
2241#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242 names[num_names] = modname(path, (char_u *)".sw?", FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243#endif
2244 if (names[num_names] == NULL)
2245 goto end;
2246
2247 /*
2248 * Remove the one from 'shortname', if it's the same as with 'noshortname'.
2249 */
2250 p = names[num_names];
2251 i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
2252 if (i > 0)
2253 p += i; /* file name has been expanded to full path */
2254 if (STRCMP(names[num_names - 1], p) == 0)
2255 vim_free(names[num_names]);
2256 else
2257 ++num_names;
2258# endif
2259
2260end:
2261# ifndef WIN3264
2262 curbuf->b_shortname = shortname;
2263# endif
2264
2265#endif /* !SHORT_FNAME */
2266
2267 return num_names;
2268}
2269
2270/*
2271 * sync all memlines
2272 *
2273 * If 'check_file' is TRUE, check if original file exists and was not changed.
2274 * If 'check_char' is TRUE, stop syncing when character becomes available, but
2275 * always sync at least one block.
2276 */
2277 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002278ml_sync_all(int check_file, int check_char)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279{
2280 buf_T *buf;
2281 struct stat st;
2282
2283 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2284 {
2285 if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
2286 continue; /* no file */
2287
2288 ml_flush_line(buf); /* flush buffered line */
2289 /* flush locked block */
2290 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
2291 if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
2292 && buf->b_ffname != NULL)
2293 {
2294 /*
2295 * If the original file does not exist anymore or has been changed
2296 * call ml_preserve() to get rid of all negative numbered blocks.
2297 */
2298 if (mch_stat((char *)buf->b_ffname, &st) == -1
2299 || st.st_mtime != buf->b_mtime_read
Bram Moolenaar914703b2010-05-31 21:59:46 +02002300 || st.st_size != buf->b_orig_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 {
2302 ml_preserve(buf, FALSE);
2303 did_check_timestamps = FALSE;
2304 need_check_timestamps = TRUE; /* give message later */
2305 }
2306 }
2307 if (buf->b_ml.ml_mfp->mf_dirty)
2308 {
2309 (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
2310 | (bufIsChanged(buf) ? MFS_FLUSH : 0));
2311 if (check_char && ui_char_avail()) /* character available now */
2312 break;
2313 }
2314 }
2315}
2316
2317/*
2318 * sync one buffer, including negative blocks
2319 *
2320 * after this all the blocks are in the swap file
2321 *
2322 * Used for the :preserve command and when the original file has been
2323 * changed or deleted.
2324 *
2325 * when message is TRUE the success of preserving is reported
2326 */
2327 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002328ml_preserve(buf_T *buf, int message)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329{
2330 bhdr_T *hp;
2331 linenr_T lnum;
2332 memfile_T *mfp = buf->b_ml.ml_mfp;
2333 int status;
2334 int got_int_save = got_int;
2335
2336 if (mfp == NULL || mfp->mf_fname == NULL)
2337 {
2338 if (message)
2339 EMSG(_("E313: Cannot preserve, there is no swap file"));
2340 return;
2341 }
2342
2343 /* We only want to stop when interrupted here, not when interrupted
2344 * before. */
2345 got_int = FALSE;
2346
2347 ml_flush_line(buf); /* flush buffered line */
2348 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
2349 status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
2350
2351 /* stack is invalid after mf_sync(.., MFS_ALL) */
2352 buf->b_ml.ml_stack_top = 0;
2353
2354 /*
2355 * Some of the data blocks may have been changed from negative to
2356 * positive block number. In that case the pointer blocks need to be
2357 * updated.
2358 *
2359 * We don't know in which pointer block the references are, so we visit
2360 * all data blocks until there are no more translations to be done (or
2361 * we hit the end of the file, which can only happen in case a write fails,
2362 * e.g. when file system if full).
2363 * ml_find_line() does the work by translating the negative block numbers
2364 * when getting the first line of each data block.
2365 */
2366 if (mf_need_trans(mfp) && !got_int)
2367 {
2368 lnum = 1;
2369 while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
2370 {
2371 hp = ml_find_line(buf, lnum, ML_FIND);
2372 if (hp == NULL)
2373 {
2374 status = FAIL;
2375 goto theend;
2376 }
2377 CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
2378 lnum = buf->b_ml.ml_locked_high + 1;
2379 }
2380 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
2381 /* sync the updated pointer blocks */
2382 if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
2383 status = FAIL;
2384 buf->b_ml.ml_stack_top = 0; /* stack is invalid now */
2385 }
2386theend:
2387 got_int |= got_int_save;
2388
2389 if (message)
2390 {
2391 if (status == OK)
2392 MSG(_("File preserved"));
2393 else
2394 EMSG(_("E314: Preserve failed"));
2395 }
2396}
2397
2398/*
2399 * NOTE: The pointer returned by the ml_get_*() functions only remains valid
2400 * until the next call!
2401 * line1 = ml_get(1);
2402 * line2 = ml_get(2); // line1 is now invalid!
2403 * Make a copy of the line if necessary.
2404 */
2405/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002406 * Return a pointer to a (read-only copy of a) line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407 *
2408 * On failure an error message is given and IObuff is returned (to avoid
2409 * having to check for error everywhere).
2410 */
2411 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002412ml_get(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413{
2414 return ml_get_buf(curbuf, lnum, FALSE);
2415}
2416
2417/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002418 * Return pointer to position "pos".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 */
2420 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002421ml_get_pos(pos_T *pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002422{
2423 return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
2424}
2425
2426/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002427 * Return pointer to cursor line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428 */
2429 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002430ml_get_curline(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002431{
2432 return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
2433}
2434
2435/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002436 * Return pointer to cursor position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 */
2438 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002439ml_get_cursor(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440{
2441 return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
2442 curwin->w_cursor.col);
2443}
2444
2445/*
Bram Moolenaar2e2e13c2010-12-08 13:17:03 +01002446 * Return a pointer to a line in a specific buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 *
2448 * "will_change": if TRUE mark the buffer dirty (chars in the line will be
2449 * changed)
2450 */
2451 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002452ml_get_buf(
2453 buf_T *buf,
2454 linenr_T lnum,
2455 int will_change) /* line will be changed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456{
Bram Moolenaarad40f022007-02-13 03:01:39 +00002457 bhdr_T *hp;
2458 DATA_BL *dp;
2459 char_u *ptr;
2460 static int recursive = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461
2462 if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
2463 {
Bram Moolenaarad40f022007-02-13 03:01:39 +00002464 if (recursive == 0)
2465 {
2466 /* Avoid giving this message for a recursive call, may happen when
2467 * the GUI redraws part of the text. */
2468 ++recursive;
2469 EMSGN(_("E315: ml_get: invalid lnum: %ld"), lnum);
2470 --recursive;
2471 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472errorret:
2473 STRCPY(IObuff, "???");
2474 return IObuff;
2475 }
2476 if (lnum <= 0) /* pretend line 0 is line 1 */
2477 lnum = 1;
2478
2479 if (buf->b_ml.ml_mfp == NULL) /* there are no lines */
2480 return (char_u *)"";
2481
Bram Moolenaar37d619f2010-03-10 14:46:26 +01002482 /*
2483 * See if it is the same line as requested last time.
2484 * Otherwise may need to flush last used line.
2485 * Don't use the last used line when 'swapfile' is reset, need to load all
2486 * blocks.
2487 */
Bram Moolenaar47b8b152007-02-07 02:41:57 +00002488 if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489 {
2490 ml_flush_line(buf);
2491
2492 /*
2493 * Find the data block containing the line.
2494 * This also fills the stack with the blocks from the root to the data
2495 * block and releases any locked block.
2496 */
2497 if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
2498 {
Bram Moolenaarad40f022007-02-13 03:01:39 +00002499 if (recursive == 0)
2500 {
2501 /* Avoid giving this message for a recursive call, may happen
2502 * when the GUI redraws part of the text. */
2503 ++recursive;
2504 EMSGN(_("E316: ml_get: cannot find line %ld"), lnum);
2505 --recursive;
2506 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 goto errorret;
2508 }
2509
2510 dp = (DATA_BL *)(hp->bh_data);
2511
2512 ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
2513 buf->b_ml.ml_line_ptr = ptr;
2514 buf->b_ml.ml_line_lnum = lnum;
2515 buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
2516 }
2517 if (will_change)
2518 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
2519
2520 return buf->b_ml.ml_line_ptr;
2521}
2522
2523/*
2524 * Check if a line that was just obtained by a call to ml_get
2525 * is in allocated memory.
2526 */
2527 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002528ml_line_alloced(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529{
2530 return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
2531}
2532
2533/*
2534 * Append a line after lnum (may be 0 to insert a line in front of the file).
2535 * "line" does not need to be allocated, but can't be another line in a
2536 * buffer, unlocking may make it invalid.
2537 *
2538 * newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
2539 * will be set for recovery
2540 * Check: The caller of this function should probably also call
2541 * appended_lines().
2542 *
2543 * return FAIL for failure, OK otherwise
2544 */
2545 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002546ml_append(
2547 linenr_T lnum, /* append after this line (can be 0) */
2548 char_u *line, /* text of the new line */
2549 colnr_T len, /* length of new line, including NUL, or 0 */
2550 int newfile) /* flag, see above */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551{
2552 /* When starting up, we might still need to create the memfile */
Bram Moolenaar59f931e2010-07-24 20:27:03 +02002553 if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 return FAIL;
2555
2556 if (curbuf->b_ml.ml_line_lnum != 0)
2557 ml_flush_line(curbuf);
2558 return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
2559}
2560
Bram Moolenaara1956f62006-03-12 22:18:00 +00002561#if defined(FEAT_SPELL) || defined(PROTO)
Bram Moolenaar4770d092006-01-12 23:22:24 +00002562/*
2563 * Like ml_append() but for an arbitrary buffer. The buffer must already have
2564 * a memline.
2565 */
2566 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002567ml_append_buf(
2568 buf_T *buf,
2569 linenr_T lnum, /* append after this line (can be 0) */
2570 char_u *line, /* text of the new line */
2571 colnr_T len, /* length of new line, including NUL, or 0 */
2572 int newfile) /* flag, see above */
Bram Moolenaar4770d092006-01-12 23:22:24 +00002573{
2574 if (buf->b_ml.ml_mfp == NULL)
2575 return FAIL;
2576
2577 if (buf->b_ml.ml_line_lnum != 0)
2578 ml_flush_line(buf);
2579 return ml_append_int(buf, lnum, line, len, newfile, FALSE);
2580}
2581#endif
2582
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01002584ml_append_int(
2585 buf_T *buf,
2586 linenr_T lnum, /* append after this line (can be 0) */
2587 char_u *line, /* text of the new line */
2588 colnr_T len, /* length of line, including NUL, or 0 */
2589 int newfile, /* flag, see above */
2590 int mark) /* mark the new line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591{
2592 int i;
2593 int line_count; /* number of indexes in current block */
2594 int offset;
2595 int from, to;
2596 int space_needed; /* space needed for new line */
2597 int page_size;
2598 int page_count;
2599 int db_idx; /* index for lnum in data block */
2600 bhdr_T *hp;
2601 memfile_T *mfp;
2602 DATA_BL *dp;
2603 PTR_BL *pp;
2604 infoptr_T *ip;
2605
2606 /* lnum out of range */
2607 if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
2608 return FAIL;
2609
2610 if (lowest_marked && lowest_marked > lnum)
2611 lowest_marked = lnum + 1;
2612
2613 if (len == 0)
2614 len = (colnr_T)STRLEN(line) + 1; /* space needed for the text */
2615 space_needed = len + INDEX_SIZE; /* space needed for text + index */
2616
2617 mfp = buf->b_ml.ml_mfp;
2618 page_size = mfp->mf_page_size;
2619
2620/*
2621 * find the data block containing the previous line
2622 * This also fills the stack with the blocks from the root to the data block
2623 * This also releases any locked block.
2624 */
2625 if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
2626 ML_INSERT)) == NULL)
2627 return FAIL;
2628
2629 buf->b_ml.ml_flags &= ~ML_EMPTY;
2630
2631 if (lnum == 0) /* got line one instead, correct db_idx */
2632 db_idx = -1; /* careful, it is negative! */
2633 else
2634 db_idx = lnum - buf->b_ml.ml_locked_low;
2635 /* get line count before the insertion */
2636 line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2637
2638 dp = (DATA_BL *)(hp->bh_data);
2639
2640/*
2641 * If
2642 * - there is not enough room in the current block
2643 * - appending to the last line in the block
2644 * - not appending to the last line in the file
2645 * insert in front of the next block.
2646 */
2647 if ((int)dp->db_free < space_needed && db_idx == line_count - 1
2648 && lnum < buf->b_ml.ml_line_count)
2649 {
2650 /*
2651 * Now that the line is not going to be inserted in the block that we
2652 * expected, the line count has to be adjusted in the pointer blocks
2653 * by using ml_locked_lineadd.
2654 */
2655 --(buf->b_ml.ml_locked_lineadd);
2656 --(buf->b_ml.ml_locked_high);
2657 if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
2658 return FAIL;
2659
2660 db_idx = -1; /* careful, it is negative! */
2661 /* get line count before the insertion */
2662 line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2663 CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
2664
2665 dp = (DATA_BL *)(hp->bh_data);
2666 }
2667
2668 ++buf->b_ml.ml_line_count;
2669
2670 if ((int)dp->db_free >= space_needed) /* enough room in data block */
2671 {
2672/*
2673 * Insert new line in existing data block, or in data block allocated above.
2674 */
2675 dp->db_txt_start -= len;
2676 dp->db_free -= space_needed;
2677 ++(dp->db_line_count);
2678
2679 /*
2680 * move the text of the lines that follow to the front
2681 * adjust the indexes of the lines that follow
2682 */
2683 if (line_count > db_idx + 1) /* if there are following lines */
2684 {
2685 /*
2686 * Offset is the start of the previous line.
2687 * This will become the character just after the new line.
2688 */
2689 if (db_idx < 0)
2690 offset = dp->db_txt_end;
2691 else
2692 offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
2693 mch_memmove((char *)dp + dp->db_txt_start,
2694 (char *)dp + dp->db_txt_start + len,
2695 (size_t)(offset - (dp->db_txt_start + len)));
2696 for (i = line_count - 1; i > db_idx; --i)
2697 dp->db_index[i + 1] = dp->db_index[i] - len;
2698 dp->db_index[db_idx + 1] = offset - len;
2699 }
2700 else /* add line at the end */
2701 dp->db_index[db_idx + 1] = dp->db_txt_start;
2702
2703 /*
2704 * copy the text into the block
2705 */
2706 mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
2707 if (mark)
2708 dp->db_index[db_idx + 1] |= DB_MARKED;
2709
2710 /*
2711 * Mark the block dirty.
2712 */
2713 buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2714 if (!newfile)
2715 buf->b_ml.ml_flags |= ML_LOCKED_POS;
2716 }
2717 else /* not enough space in data block */
2718 {
2719/*
2720 * If there is not enough room we have to create a new data block and copy some
2721 * lines into it.
2722 * Then we have to insert an entry in the pointer block.
2723 * If this pointer block also is full, we go up another block, and so on, up
2724 * to the root if necessary.
2725 * The line counts in the pointer blocks have already been adjusted by
2726 * ml_find_line().
2727 */
2728 long line_count_left, line_count_right;
2729 int page_count_left, page_count_right;
2730 bhdr_T *hp_left;
2731 bhdr_T *hp_right;
2732 bhdr_T *hp_new;
2733 int lines_moved;
2734 int data_moved = 0; /* init to shut up gcc */
2735 int total_moved = 0; /* init to shut up gcc */
2736 DATA_BL *dp_right, *dp_left;
2737 int stack_idx;
2738 int in_left;
2739 int lineadd;
2740 blocknr_T bnum_left, bnum_right;
2741 linenr_T lnum_left, lnum_right;
2742 int pb_idx;
2743 PTR_BL *pp_new;
2744
2745 /*
2746 * We are going to allocate a new data block. Depending on the
2747 * situation it will be put to the left or right of the existing
2748 * block. If possible we put the new line in the left block and move
2749 * the lines after it to the right block. Otherwise the new line is
2750 * also put in the right block. This method is more efficient when
2751 * inserting a lot of lines at one place.
2752 */
2753 if (db_idx < 0) /* left block is new, right block is existing */
2754 {
2755 lines_moved = 0;
2756 in_left = TRUE;
2757 /* space_needed does not change */
2758 }
2759 else /* left block is existing, right block is new */
2760 {
2761 lines_moved = line_count - db_idx - 1;
2762 if (lines_moved == 0)
2763 in_left = FALSE; /* put new line in right block */
2764 /* space_needed does not change */
2765 else
2766 {
2767 data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
2768 dp->db_txt_start;
2769 total_moved = data_moved + lines_moved * INDEX_SIZE;
2770 if ((int)dp->db_free + total_moved >= space_needed)
2771 {
2772 in_left = TRUE; /* put new line in left block */
2773 space_needed = total_moved;
2774 }
2775 else
2776 {
2777 in_left = FALSE; /* put new line in right block */
2778 space_needed += total_moved;
2779 }
2780 }
2781 }
2782
2783 page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
2784 if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
2785 {
2786 /* correct line counts in pointer blocks */
2787 --(buf->b_ml.ml_locked_lineadd);
2788 --(buf->b_ml.ml_locked_high);
2789 return FAIL;
2790 }
2791 if (db_idx < 0) /* left block is new */
2792 {
2793 hp_left = hp_new;
2794 hp_right = hp;
2795 line_count_left = 0;
2796 line_count_right = line_count;
2797 }
2798 else /* right block is new */
2799 {
2800 hp_left = hp;
2801 hp_right = hp_new;
2802 line_count_left = line_count;
2803 line_count_right = 0;
2804 }
2805 dp_right = (DATA_BL *)(hp_right->bh_data);
2806 dp_left = (DATA_BL *)(hp_left->bh_data);
2807 bnum_left = hp_left->bh_bnum;
2808 bnum_right = hp_right->bh_bnum;
2809 page_count_left = hp_left->bh_page_count;
2810 page_count_right = hp_right->bh_page_count;
2811
2812 /*
2813 * May move the new line into the right/new block.
2814 */
2815 if (!in_left)
2816 {
2817 dp_right->db_txt_start -= len;
2818 dp_right->db_free -= len + INDEX_SIZE;
2819 dp_right->db_index[0] = dp_right->db_txt_start;
2820 if (mark)
2821 dp_right->db_index[0] |= DB_MARKED;
2822
2823 mch_memmove((char *)dp_right + dp_right->db_txt_start,
2824 line, (size_t)len);
2825 ++line_count_right;
2826 }
2827 /*
2828 * may move lines from the left/old block to the right/new one.
2829 */
2830 if (lines_moved)
2831 {
2832 /*
2833 */
2834 dp_right->db_txt_start -= data_moved;
2835 dp_right->db_free -= total_moved;
2836 mch_memmove((char *)dp_right + dp_right->db_txt_start,
2837 (char *)dp_left + dp_left->db_txt_start,
2838 (size_t)data_moved);
2839 offset = dp_right->db_txt_start - dp_left->db_txt_start;
2840 dp_left->db_txt_start += data_moved;
2841 dp_left->db_free += total_moved;
2842
2843 /*
2844 * update indexes in the new block
2845 */
2846 for (to = line_count_right, from = db_idx + 1;
2847 from < line_count_left; ++from, ++to)
2848 dp_right->db_index[to] = dp->db_index[from] + offset;
2849 line_count_right += lines_moved;
2850 line_count_left -= lines_moved;
2851 }
2852
2853 /*
2854 * May move the new line into the left (old or new) block.
2855 */
2856 if (in_left)
2857 {
2858 dp_left->db_txt_start -= len;
2859 dp_left->db_free -= len + INDEX_SIZE;
2860 dp_left->db_index[line_count_left] = dp_left->db_txt_start;
2861 if (mark)
2862 dp_left->db_index[line_count_left] |= DB_MARKED;
2863 mch_memmove((char *)dp_left + dp_left->db_txt_start,
2864 line, (size_t)len);
2865 ++line_count_left;
2866 }
2867
2868 if (db_idx < 0) /* left block is new */
2869 {
2870 lnum_left = lnum + 1;
2871 lnum_right = 0;
2872 }
2873 else /* right block is new */
2874 {
2875 lnum_left = 0;
2876 if (in_left)
2877 lnum_right = lnum + 2;
2878 else
2879 lnum_right = lnum + 1;
2880 }
2881 dp_left->db_line_count = line_count_left;
2882 dp_right->db_line_count = line_count_right;
2883
2884 /*
2885 * release the two data blocks
2886 * The new one (hp_new) already has a correct blocknumber.
2887 * The old one (hp, in ml_locked) gets a positive blocknumber if
2888 * we changed it and we are not editing a new file.
2889 */
2890 if (lines_moved || in_left)
2891 buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2892 if (!newfile && db_idx >= 0 && in_left)
2893 buf->b_ml.ml_flags |= ML_LOCKED_POS;
2894 mf_put(mfp, hp_new, TRUE, FALSE);
2895
2896 /*
2897 * flush the old data block
2898 * set ml_locked_lineadd to 0, because the updating of the
2899 * pointer blocks is done below
2900 */
2901 lineadd = buf->b_ml.ml_locked_lineadd;
2902 buf->b_ml.ml_locked_lineadd = 0;
2903 ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush data block */
2904
2905 /*
2906 * update pointer blocks for the new data block
2907 */
2908 for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
2909 --stack_idx)
2910 {
2911 ip = &(buf->b_ml.ml_stack[stack_idx]);
2912 pb_idx = ip->ip_index;
2913 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
2914 return FAIL;
2915 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
2916 if (pp->pb_id != PTR_ID)
2917 {
2918 EMSG(_("E317: pointer block id wrong 3"));
2919 mf_put(mfp, hp, FALSE, FALSE);
2920 return FAIL;
2921 }
2922 /*
2923 * TODO: If the pointer block is full and we are adding at the end
2924 * try to insert in front of the next block
2925 */
2926 /* block not full, add one entry */
2927 if (pp->pb_count < pp->pb_count_max)
2928 {
2929 if (pb_idx + 1 < (int)pp->pb_count)
2930 mch_memmove(&pp->pb_pointer[pb_idx + 2],
2931 &pp->pb_pointer[pb_idx + 1],
2932 (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
2933 ++pp->pb_count;
2934 pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
2935 pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
2936 pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
2937 pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
2938 pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
2939 pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
2940
2941 if (lnum_left != 0)
2942 pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
2943 if (lnum_right != 0)
2944 pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
2945
2946 mf_put(mfp, hp, TRUE, FALSE);
2947 buf->b_ml.ml_stack_top = stack_idx + 1; /* truncate stack */
2948
2949 if (lineadd)
2950 {
2951 --(buf->b_ml.ml_stack_top);
Bram Moolenaar6b803a72007-05-06 14:25:46 +00002952 /* fix line count for rest of blocks in the stack */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953 ml_lineadd(buf, lineadd);
2954 /* fix stack itself */
2955 buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
2956 lineadd;
2957 ++(buf->b_ml.ml_stack_top);
2958 }
2959
2960 /*
2961 * We are finished, break the loop here.
2962 */
2963 break;
2964 }
2965 else /* pointer block full */
2966 {
2967 /*
2968 * split the pointer block
2969 * allocate a new pointer block
2970 * move some of the pointer into the new block
2971 * prepare for updating the parent block
2972 */
2973 for (;;) /* do this twice when splitting block 1 */
2974 {
2975 hp_new = ml_new_ptr(mfp);
2976 if (hp_new == NULL) /* TODO: try to fix tree */
2977 return FAIL;
2978 pp_new = (PTR_BL *)(hp_new->bh_data);
2979
2980 if (hp->bh_bnum != 1)
2981 break;
2982
2983 /*
2984 * if block 1 becomes full the tree is given an extra level
2985 * The pointers from block 1 are moved into the new block.
2986 * block 1 is updated to point to the new block
2987 * then continue to split the new block
2988 */
2989 mch_memmove(pp_new, pp, (size_t)page_size);
2990 pp->pb_count = 1;
2991 pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
2992 pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
2993 pp->pb_pointer[0].pe_old_lnum = 1;
2994 pp->pb_pointer[0].pe_page_count = 1;
2995 mf_put(mfp, hp, TRUE, FALSE); /* release block 1 */
2996 hp = hp_new; /* new block is to be split */
2997 pp = pp_new;
2998 CHECK(stack_idx != 0, _("stack_idx should be 0"));
2999 ip->ip_index = 0;
3000 ++stack_idx; /* do block 1 again later */
3001 }
3002 /*
3003 * move the pointers after the current one to the new block
3004 * If there are none, the new entry will be in the new block.
3005 */
3006 total_moved = pp->pb_count - pb_idx - 1;
3007 if (total_moved)
3008 {
3009 mch_memmove(&pp_new->pb_pointer[0],
3010 &pp->pb_pointer[pb_idx + 1],
3011 (size_t)(total_moved) * sizeof(PTR_EN));
3012 pp_new->pb_count = total_moved;
3013 pp->pb_count -= total_moved - 1;
3014 pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
3015 pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
3016 pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
3017 if (lnum_right)
3018 pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
3019 }
3020 else
3021 {
3022 pp_new->pb_count = 1;
3023 pp_new->pb_pointer[0].pe_bnum = bnum_right;
3024 pp_new->pb_pointer[0].pe_line_count = line_count_right;
3025 pp_new->pb_pointer[0].pe_page_count = page_count_right;
3026 pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
3027 }
3028 pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
3029 pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
3030 pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
3031 if (lnum_left)
3032 pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
3033 lnum_left = 0;
3034 lnum_right = 0;
3035
3036 /*
3037 * recompute line counts
3038 */
3039 line_count_right = 0;
3040 for (i = 0; i < (int)pp_new->pb_count; ++i)
3041 line_count_right += pp_new->pb_pointer[i].pe_line_count;
3042 line_count_left = 0;
3043 for (i = 0; i < (int)pp->pb_count; ++i)
3044 line_count_left += pp->pb_pointer[i].pe_line_count;
3045
3046 bnum_left = hp->bh_bnum;
3047 bnum_right = hp_new->bh_bnum;
3048 page_count_left = 1;
3049 page_count_right = 1;
3050 mf_put(mfp, hp, TRUE, FALSE);
3051 mf_put(mfp, hp_new, TRUE, FALSE);
3052 }
3053 }
3054
3055 /*
3056 * Safety check: fallen out of for loop?
3057 */
3058 if (stack_idx < 0)
3059 {
3060 EMSG(_("E318: Updated too many blocks?"));
3061 buf->b_ml.ml_stack_top = 0; /* invalidate stack */
3062 }
3063 }
3064
3065#ifdef FEAT_BYTEOFF
3066 /* The line was inserted below 'lnum' */
3067 ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
3068#endif
3069#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003070 if (netbeans_active())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 {
3072 if (STRLEN(line) > 0)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003073 netbeans_inserted(buf, lnum+1, (colnr_T)0, line, (int)STRLEN(line));
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00003074 netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075 (char_u *)"\n", 1);
3076 }
3077#endif
3078 return OK;
3079}
3080
3081/*
Bram Moolenaar4770d092006-01-12 23:22:24 +00003082 * Replace line lnum, with buffering, in current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083 *
Bram Moolenaar1056d982006-03-09 22:37:52 +00003084 * If "copy" is TRUE, make a copy of the line, otherwise the line has been
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085 * copied to allocated memory already.
3086 *
3087 * Check: The caller of this function should probably also call
3088 * changed_lines(), unless update_screen(NOT_VALID) is used.
3089 *
3090 * return FAIL for failure, OK otherwise
3091 */
3092 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003093ml_replace(linenr_T lnum, char_u *line, int copy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094{
3095 if (line == NULL) /* just checking... */
3096 return FAIL;
3097
3098 /* When starting up, we might still need to create the memfile */
Bram Moolenaar59f931e2010-07-24 20:27:03 +02003099 if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 return FAIL;
3101
3102 if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */
3103 return FAIL;
3104#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003105 if (netbeans_active())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106 {
3107 netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003108 netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109 }
3110#endif
3111 if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
3112 ml_flush_line(curbuf); /* flush it */
3113 else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
3114 vim_free(curbuf->b_ml.ml_line_ptr); /* free it */
3115 curbuf->b_ml.ml_line_ptr = line;
3116 curbuf->b_ml.ml_line_lnum = lnum;
3117 curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
3118
3119 return OK;
3120}
3121
3122/*
Bram Moolenaar4770d092006-01-12 23:22:24 +00003123 * Delete line 'lnum' in the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003124 *
3125 * Check: The caller of this function should probably also call
3126 * deleted_lines() after this.
3127 *
3128 * return FAIL for failure, OK otherwise
3129 */
3130 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003131ml_delete(linenr_T lnum, int message)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132{
3133 ml_flush_line(curbuf);
3134 return ml_delete_int(curbuf, lnum, message);
3135}
3136
3137 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003138ml_delete_int(buf_T *buf, linenr_T lnum, int message)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139{
3140 bhdr_T *hp;
3141 memfile_T *mfp;
3142 DATA_BL *dp;
3143 PTR_BL *pp;
3144 infoptr_T *ip;
3145 int count; /* number of entries in block */
3146 int idx;
3147 int stack_idx;
3148 int text_start;
3149 int line_start;
3150 long line_size;
3151 int i;
3152
3153 if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
3154 return FAIL;
3155
3156 if (lowest_marked && lowest_marked > lnum)
3157 lowest_marked--;
3158
3159/*
3160 * If the file becomes empty the last line is replaced by an empty line.
3161 */
3162 if (buf->b_ml.ml_line_count == 1) /* file becomes empty */
3163 {
3164 if (message
3165#ifdef FEAT_NETBEANS_INTG
3166 && !netbeansSuppressNoLines
3167#endif
3168 )
Bram Moolenaar238a5642006-02-21 22:12:05 +00003169 set_keep_msg((char_u *)_(no_lines_msg), 0);
3170
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003171 /* FEAT_BYTEOFF already handled in there, don't worry 'bout it below */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172 i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
3173 buf->b_ml.ml_flags |= ML_EMPTY;
3174
3175 return i;
3176 }
3177
3178/*
3179 * find the data block containing the line
3180 * This also fills the stack with the blocks from the root to the data block
3181 * This also releases any locked block.
3182 */
3183 mfp = buf->b_ml.ml_mfp;
3184 if (mfp == NULL)
3185 return FAIL;
3186
3187 if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
3188 return FAIL;
3189
3190 dp = (DATA_BL *)(hp->bh_data);
3191 /* compute line count before the delete */
3192 count = (long)(buf->b_ml.ml_locked_high)
3193 - (long)(buf->b_ml.ml_locked_low) + 2;
3194 idx = lnum - buf->b_ml.ml_locked_low;
3195
3196 --buf->b_ml.ml_line_count;
3197
3198 line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3199 if (idx == 0) /* first line in block, text at the end */
3200 line_size = dp->db_txt_end - line_start;
3201 else
3202 line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
3203
3204#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003205 if (netbeans_active())
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00003206 netbeans_removed(buf, lnum, 0, (long)line_size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207#endif
3208
3209/*
3210 * special case: If there is only one line in the data block it becomes empty.
3211 * Then we have to remove the entry, pointing to this data block, from the
3212 * pointer block. If this pointer block also becomes empty, we go up another
3213 * block, and so on, up to the root if necessary.
3214 * The line counts in the pointer blocks have already been adjusted by
3215 * ml_find_line().
3216 */
3217 if (count == 1)
3218 {
3219 mf_free(mfp, hp); /* free the data block */
3220 buf->b_ml.ml_locked = NULL;
3221
Bram Moolenaare60acc12011-05-10 16:41:25 +02003222 for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
3223 --stack_idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224 {
3225 buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */
3226 ip = &(buf->b_ml.ml_stack[stack_idx]);
3227 idx = ip->ip_index;
3228 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3229 return FAIL;
3230 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
3231 if (pp->pb_id != PTR_ID)
3232 {
3233 EMSG(_("E317: pointer block id wrong 4"));
3234 mf_put(mfp, hp, FALSE, FALSE);
3235 return FAIL;
3236 }
3237 count = --(pp->pb_count);
3238 if (count == 0) /* the pointer block becomes empty! */
3239 mf_free(mfp, hp);
3240 else
3241 {
3242 if (count != idx) /* move entries after the deleted one */
3243 mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
3244 (size_t)(count - idx) * sizeof(PTR_EN));
3245 mf_put(mfp, hp, TRUE, FALSE);
3246
3247 buf->b_ml.ml_stack_top = stack_idx; /* truncate stack */
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003248 /* fix line count for rest of blocks in the stack */
3249 if (buf->b_ml.ml_locked_lineadd != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003250 {
3251 ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
3252 buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003253 buf->b_ml.ml_locked_lineadd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254 }
3255 ++(buf->b_ml.ml_stack_top);
3256
3257 break;
3258 }
3259 }
3260 CHECK(stack_idx < 0, _("deleted block 1?"));
3261 }
3262 else
3263 {
3264 /*
3265 * delete the text by moving the next lines forwards
3266 */
3267 text_start = dp->db_txt_start;
3268 mch_memmove((char *)dp + text_start + line_size,
3269 (char *)dp + text_start, (size_t)(line_start - text_start));
3270
3271 /*
3272 * delete the index by moving the next indexes backwards
3273 * Adjust the indexes for the text movement.
3274 */
3275 for (i = idx; i < count - 1; ++i)
3276 dp->db_index[i] = dp->db_index[i + 1] + line_size;
3277
3278 dp->db_free += line_size + INDEX_SIZE;
3279 dp->db_txt_start += line_size;
3280 --(dp->db_line_count);
3281
3282 /*
3283 * mark the block dirty and make sure it is in the file (for recovery)
3284 */
3285 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3286 }
3287
3288#ifdef FEAT_BYTEOFF
3289 ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
3290#endif
3291 return OK;
3292}
3293
3294/*
3295 * set the B_MARKED flag for line 'lnum'
3296 */
3297 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003298ml_setmarked(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299{
3300 bhdr_T *hp;
3301 DATA_BL *dp;
3302 /* invalid line number */
3303 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
3304 || curbuf->b_ml.ml_mfp == NULL)
3305 return; /* give error message? */
3306
3307 if (lowest_marked == 0 || lowest_marked > lnum)
3308 lowest_marked = lnum;
3309
3310 /*
3311 * find the data block containing the line
3312 * This also fills the stack with the blocks from the root to the data block
3313 * This also releases any locked block.
3314 */
3315 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3316 return; /* give error message? */
3317
3318 dp = (DATA_BL *)(hp->bh_data);
3319 dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
3320 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3321}
3322
3323/*
3324 * find the first line with its B_MARKED flag set
3325 */
3326 linenr_T
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003327ml_firstmarked(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328{
3329 bhdr_T *hp;
3330 DATA_BL *dp;
3331 linenr_T lnum;
3332 int i;
3333
3334 if (curbuf->b_ml.ml_mfp == NULL)
3335 return (linenr_T) 0;
3336
3337 /*
3338 * The search starts with lowest_marked line. This is the last line where
3339 * a mark was found, adjusted by inserting/deleting lines.
3340 */
3341 for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3342 {
3343 /*
3344 * Find the data block containing the line.
3345 * This also fills the stack with the blocks from the root to the data
3346 * block This also releases any locked block.
3347 */
3348 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3349 return (linenr_T)0; /* give error message? */
3350
3351 dp = (DATA_BL *)(hp->bh_data);
3352
3353 for (i = lnum - curbuf->b_ml.ml_locked_low;
3354 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3355 if ((dp->db_index[i]) & DB_MARKED)
3356 {
3357 (dp->db_index[i]) &= DB_INDEX_MASK;
3358 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3359 lowest_marked = lnum + 1;
3360 return lnum;
3361 }
3362 }
3363
3364 return (linenr_T) 0;
3365}
3366
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367/*
3368 * clear all DB_MARKED flags
3369 */
3370 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003371ml_clearmarked(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372{
3373 bhdr_T *hp;
3374 DATA_BL *dp;
3375 linenr_T lnum;
3376 int i;
3377
3378 if (curbuf->b_ml.ml_mfp == NULL) /* nothing to do */
3379 return;
3380
3381 /*
3382 * The search starts with line lowest_marked.
3383 */
3384 for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3385 {
3386 /*
3387 * Find the data block containing the line.
3388 * This also fills the stack with the blocks from the root to the data
3389 * block and releases any locked block.
3390 */
3391 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3392 return; /* give error message? */
3393
3394 dp = (DATA_BL *)(hp->bh_data);
3395
3396 for (i = lnum - curbuf->b_ml.ml_locked_low;
3397 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3398 if ((dp->db_index[i]) & DB_MARKED)
3399 {
3400 (dp->db_index[i]) &= DB_INDEX_MASK;
3401 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3402 }
3403 }
3404
3405 lowest_marked = 0;
3406 return;
3407}
3408
3409/*
3410 * flush ml_line if necessary
3411 */
3412 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003413ml_flush_line(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414{
3415 bhdr_T *hp;
3416 DATA_BL *dp;
3417 linenr_T lnum;
3418 char_u *new_line;
3419 char_u *old_line;
3420 colnr_T new_len;
3421 int old_len;
3422 int extra;
3423 int idx;
3424 int start;
3425 int count;
3426 int i;
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003427 static int entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003428
3429 if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
3430 return; /* nothing to do */
3431
3432 if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
3433 {
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003434 /* This code doesn't work recursively, but Netbeans may call back here
3435 * when obtaining the cursor position. */
3436 if (entered)
3437 return;
3438 entered = TRUE;
3439
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440 lnum = buf->b_ml.ml_line_lnum;
3441 new_line = buf->b_ml.ml_line_ptr;
3442
3443 hp = ml_find_line(buf, lnum, ML_FIND);
3444 if (hp == NULL)
3445 EMSGN(_("E320: Cannot find line %ld"), lnum);
3446 else
3447 {
3448 dp = (DATA_BL *)(hp->bh_data);
3449 idx = lnum - buf->b_ml.ml_locked_low;
3450 start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3451 old_line = (char_u *)dp + start;
3452 if (idx == 0) /* line is last in block */
3453 old_len = dp->db_txt_end - start;
3454 else /* text of previous line follows */
3455 old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
3456 new_len = (colnr_T)STRLEN(new_line) + 1;
3457 extra = new_len - old_len; /* negative if lines gets smaller */
3458
3459 /*
3460 * if new line fits in data block, replace directly
3461 */
3462 if ((int)dp->db_free >= extra)
3463 {
3464 /* if the length changes and there are following lines */
3465 count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
3466 if (extra != 0 && idx < count - 1)
3467 {
3468 /* move text of following lines */
3469 mch_memmove((char *)dp + dp->db_txt_start - extra,
3470 (char *)dp + dp->db_txt_start,
3471 (size_t)(start - dp->db_txt_start));
3472
3473 /* adjust pointers of this and following lines */
3474 for (i = idx + 1; i < count; ++i)
3475 dp->db_index[i] -= extra;
3476 }
3477 dp->db_index[idx] -= extra;
3478
3479 /* adjust free space */
3480 dp->db_free -= extra;
3481 dp->db_txt_start -= extra;
3482
3483 /* copy new line into the data block */
3484 mch_memmove(old_line - extra, new_line, (size_t)new_len);
3485 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3486#ifdef FEAT_BYTEOFF
3487 /* The else case is already covered by the insert and delete */
3488 ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
3489#endif
3490 }
3491 else
3492 {
3493 /*
3494 * Cannot do it in one data block: Delete and append.
3495 * Append first, because ml_delete_int() cannot delete the
3496 * last line in a buffer, which causes trouble for a buffer
3497 * that has only one line.
3498 * Don't forget to copy the mark!
3499 */
3500 /* How about handling errors??? */
3501 (void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
3502 (dp->db_index[idx] & DB_MARKED));
3503 (void)ml_delete_int(buf, lnum, FALSE);
3504 }
3505 }
3506 vim_free(new_line);
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003507
3508 entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509 }
3510
3511 buf->b_ml.ml_line_lnum = 0;
3512}
3513
3514/*
3515 * create a new, empty, data block
3516 */
3517 static bhdr_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003518ml_new_data(memfile_T *mfp, int negative, int page_count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519{
3520 bhdr_T *hp;
3521 DATA_BL *dp;
3522
3523 if ((hp = mf_new(mfp, negative, page_count)) == NULL)
3524 return NULL;
3525
3526 dp = (DATA_BL *)(hp->bh_data);
3527 dp->db_id = DATA_ID;
3528 dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
3529 dp->db_free = dp->db_txt_start - HEADER_SIZE;
3530 dp->db_line_count = 0;
3531
3532 return hp;
3533}
3534
3535/*
3536 * create a new, empty, pointer block
3537 */
3538 static bhdr_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003539ml_new_ptr(memfile_T *mfp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540{
3541 bhdr_T *hp;
3542 PTR_BL *pp;
3543
3544 if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
3545 return NULL;
3546
3547 pp = (PTR_BL *)(hp->bh_data);
3548 pp->pb_id = PTR_ID;
3549 pp->pb_count = 0;
Bram Moolenaar20a825a2010-05-31 21:27:30 +02003550 pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL))
3551 / sizeof(PTR_EN) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552
3553 return hp;
3554}
3555
3556/*
3557 * lookup line 'lnum' in a memline
3558 *
3559 * action: if ML_DELETE or ML_INSERT the line count is updated while searching
3560 * if ML_FLUSH only flush a locked block
3561 * if ML_FIND just find the line
3562 *
3563 * If the block was found it is locked and put in ml_locked.
3564 * The stack is updated to lead to the locked block. The ip_high field in
3565 * the stack is updated to reflect the last line in the block AFTER the
3566 * insert or delete, also if the pointer block has not been updated yet. But
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003567 * if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003568 *
3569 * return: NULL for failure, pointer to block header otherwise
3570 */
3571 static bhdr_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003572ml_find_line(buf_T *buf, linenr_T lnum, int action)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573{
3574 DATA_BL *dp;
3575 PTR_BL *pp;
3576 infoptr_T *ip;
3577 bhdr_T *hp;
3578 memfile_T *mfp;
3579 linenr_T t;
3580 blocknr_T bnum, bnum2;
3581 int dirty;
3582 linenr_T low, high;
3583 int top;
3584 int page_count;
3585 int idx;
3586
3587 mfp = buf->b_ml.ml_mfp;
3588
3589 /*
3590 * If there is a locked block check if the wanted line is in it.
3591 * If not, flush and release the locked block.
3592 * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
3593 * Don't do this for ML_FLUSH, because we want to flush the locked block.
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003594 * Don't do this when 'swapfile' is reset, we want to load all the blocks.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595 */
3596 if (buf->b_ml.ml_locked)
3597 {
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003598 if (ML_SIMPLE(action)
3599 && buf->b_ml.ml_locked_low <= lnum
3600 && buf->b_ml.ml_locked_high >= lnum
3601 && !mf_dont_release)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 {
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003603 /* remember to update pointer blocks and stack later */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003604 if (action == ML_INSERT)
3605 {
3606 ++(buf->b_ml.ml_locked_lineadd);
3607 ++(buf->b_ml.ml_locked_high);
3608 }
3609 else if (action == ML_DELETE)
3610 {
3611 --(buf->b_ml.ml_locked_lineadd);
3612 --(buf->b_ml.ml_locked_high);
3613 }
3614 return (buf->b_ml.ml_locked);
3615 }
3616
3617 mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
3618 buf->b_ml.ml_flags & ML_LOCKED_POS);
3619 buf->b_ml.ml_locked = NULL;
3620
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003621 /*
3622 * If lines have been added or deleted in the locked block, need to
3623 * update the line count in pointer blocks.
3624 */
3625 if (buf->b_ml.ml_locked_lineadd != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003626 ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
3627 }
3628
3629 if (action == ML_FLUSH) /* nothing else to do */
3630 return NULL;
3631
3632 bnum = 1; /* start at the root of the tree */
3633 page_count = 1;
3634 low = 1;
3635 high = buf->b_ml.ml_line_count;
3636
3637 if (action == ML_FIND) /* first try stack entries */
3638 {
3639 for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
3640 {
3641 ip = &(buf->b_ml.ml_stack[top]);
3642 if (ip->ip_low <= lnum && ip->ip_high >= lnum)
3643 {
3644 bnum = ip->ip_bnum;
3645 low = ip->ip_low;
3646 high = ip->ip_high;
3647 buf->b_ml.ml_stack_top = top; /* truncate stack at prev entry */
3648 break;
3649 }
3650 }
3651 if (top < 0)
3652 buf->b_ml.ml_stack_top = 0; /* not found, start at the root */
3653 }
3654 else /* ML_DELETE or ML_INSERT */
3655 buf->b_ml.ml_stack_top = 0; /* start at the root */
3656
3657/*
3658 * search downwards in the tree until a data block is found
3659 */
3660 for (;;)
3661 {
3662 if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
3663 goto error_noblock;
3664
3665 /*
3666 * update high for insert/delete
3667 */
3668 if (action == ML_INSERT)
3669 ++high;
3670 else if (action == ML_DELETE)
3671 --high;
3672
3673 dp = (DATA_BL *)(hp->bh_data);
3674 if (dp->db_id == DATA_ID) /* data block */
3675 {
3676 buf->b_ml.ml_locked = hp;
3677 buf->b_ml.ml_locked_low = low;
3678 buf->b_ml.ml_locked_high = high;
3679 buf->b_ml.ml_locked_lineadd = 0;
3680 buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
3681 return hp;
3682 }
3683
3684 pp = (PTR_BL *)(dp); /* must be pointer block */
3685 if (pp->pb_id != PTR_ID)
3686 {
3687 EMSG(_("E317: pointer block id wrong"));
3688 goto error_block;
3689 }
3690
3691 if ((top = ml_add_stack(buf)) < 0) /* add new entry to stack */
3692 goto error_block;
3693 ip = &(buf->b_ml.ml_stack[top]);
3694 ip->ip_bnum = bnum;
3695 ip->ip_low = low;
3696 ip->ip_high = high;
3697 ip->ip_index = -1; /* index not known yet */
3698
3699 dirty = FALSE;
3700 for (idx = 0; idx < (int)pp->pb_count; ++idx)
3701 {
3702 t = pp->pb_pointer[idx].pe_line_count;
3703 CHECK(t == 0, _("pe_line_count is zero"));
3704 if ((low += t) > lnum)
3705 {
3706 ip->ip_index = idx;
3707 bnum = pp->pb_pointer[idx].pe_bnum;
3708 page_count = pp->pb_pointer[idx].pe_page_count;
3709 high = low - 1;
3710 low -= t;
3711
3712 /*
3713 * a negative block number may have been changed
3714 */
3715 if (bnum < 0)
3716 {
3717 bnum2 = mf_trans_del(mfp, bnum);
3718 if (bnum != bnum2)
3719 {
3720 bnum = bnum2;
3721 pp->pb_pointer[idx].pe_bnum = bnum;
3722 dirty = TRUE;
3723 }
3724 }
3725
3726 break;
3727 }
3728 }
3729 if (idx >= (int)pp->pb_count) /* past the end: something wrong! */
3730 {
3731 if (lnum > buf->b_ml.ml_line_count)
3732 EMSGN(_("E322: line number out of range: %ld past the end"),
3733 lnum - buf->b_ml.ml_line_count);
3734
3735 else
3736 EMSGN(_("E323: line count wrong in block %ld"), bnum);
3737 goto error_block;
3738 }
3739 if (action == ML_DELETE)
3740 {
3741 pp->pb_pointer[idx].pe_line_count--;
3742 dirty = TRUE;
3743 }
3744 else if (action == ML_INSERT)
3745 {
3746 pp->pb_pointer[idx].pe_line_count++;
3747 dirty = TRUE;
3748 }
3749 mf_put(mfp, hp, dirty, FALSE);
3750 }
3751
3752error_block:
3753 mf_put(mfp, hp, FALSE, FALSE);
3754error_noblock:
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003755 /*
3756 * If action is ML_DELETE or ML_INSERT we have to correct the tree for
3757 * the incremented/decremented line counts, because there won't be a line
3758 * inserted/deleted after all.
3759 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003760 if (action == ML_DELETE)
3761 ml_lineadd(buf, 1);
3762 else if (action == ML_INSERT)
3763 ml_lineadd(buf, -1);
3764 buf->b_ml.ml_stack_top = 0;
3765 return NULL;
3766}
3767
3768/*
3769 * add an entry to the info pointer stack
3770 *
3771 * return -1 for failure, number of the new entry otherwise
3772 */
3773 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003774ml_add_stack(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003775{
3776 int top;
3777 infoptr_T *newstack;
3778
3779 top = buf->b_ml.ml_stack_top;
3780
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003781 /* may have to increase the stack size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003782 if (top == buf->b_ml.ml_stack_size)
3783 {
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02003784 CHECK(top > 0, _("Stack size increases")); /* more than 5 levels??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785
3786 newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
3787 (buf->b_ml.ml_stack_size + STACK_INCR));
3788 if (newstack == NULL)
3789 return -1;
Bram Moolenaarfbd302f2015-08-08 18:23:46 +02003790 if (top > 0)
3791 mch_memmove(newstack, buf->b_ml.ml_stack,
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003792 (size_t)top * sizeof(infoptr_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793 vim_free(buf->b_ml.ml_stack);
3794 buf->b_ml.ml_stack = newstack;
3795 buf->b_ml.ml_stack_size += STACK_INCR;
3796 }
3797
3798 buf->b_ml.ml_stack_top++;
3799 return top;
3800}
3801
3802/*
3803 * Update the pointer blocks on the stack for inserted/deleted lines.
3804 * The stack itself is also updated.
3805 *
3806 * When a insert/delete line action fails, the line is not inserted/deleted,
3807 * but the pointer blocks have already been updated. That is fixed here by
3808 * walking through the stack.
3809 *
3810 * Count is the number of lines added, negative if lines have been deleted.
3811 */
3812 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003813ml_lineadd(buf_T *buf, int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814{
3815 int idx;
3816 infoptr_T *ip;
3817 PTR_BL *pp;
3818 memfile_T *mfp = buf->b_ml.ml_mfp;
3819 bhdr_T *hp;
3820
3821 for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
3822 {
3823 ip = &(buf->b_ml.ml_stack[idx]);
3824 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3825 break;
3826 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
3827 if (pp->pb_id != PTR_ID)
3828 {
3829 mf_put(mfp, hp, FALSE, FALSE);
3830 EMSG(_("E317: pointer block id wrong 2"));
3831 break;
3832 }
3833 pp->pb_pointer[ip->ip_index].pe_line_count += count;
3834 ip->ip_high += count;
3835 mf_put(mfp, hp, TRUE, FALSE);
3836 }
3837}
3838
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003839#if defined(HAVE_READLINK) || defined(PROTO)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003840/*
3841 * Resolve a symlink in the last component of a file name.
3842 * Note that f_resolve() does it for every part of the path, we don't do that
3843 * here.
3844 * If it worked returns OK and the resolved link in "buf[MAXPATHL]".
3845 * Otherwise returns FAIL.
3846 */
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003847 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003848resolve_symlink(char_u *fname, char_u *buf)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003849{
3850 char_u tmp[MAXPATHL];
3851 int ret;
3852 int depth = 0;
3853
3854 if (fname == NULL)
3855 return FAIL;
3856
3857 /* Put the result so far in tmp[], starting with the original name. */
3858 vim_strncpy(tmp, fname, MAXPATHL - 1);
3859
3860 for (;;)
3861 {
3862 /* Limit symlink depth to 100, catch recursive loops. */
3863 if (++depth == 100)
3864 {
3865 EMSG2(_("E773: Symlink loop for \"%s\""), fname);
3866 return FAIL;
3867 }
3868
3869 ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
3870 if (ret <= 0)
3871 {
Bram Moolenaarcc984262005-12-23 22:19:46 +00003872 if (errno == EINVAL || errno == ENOENT)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003873 {
Bram Moolenaarcc984262005-12-23 22:19:46 +00003874 /* Found non-symlink or not existing file, stop here.
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00003875 * When at the first level use the unmodified name, skip the
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003876 * call to vim_FullName(). */
3877 if (depth == 1)
3878 return FAIL;
3879
3880 /* Use the resolved name in tmp[]. */
3881 break;
3882 }
3883
3884 /* There must be some error reading links, use original name. */
3885 return FAIL;
3886 }
3887 buf[ret] = NUL;
3888
3889 /*
3890 * Check whether the symlink is relative or absolute.
3891 * If it's relative, build a new path based on the directory
3892 * portion of the filename (if any) and the path the symlink
3893 * points to.
3894 */
3895 if (mch_isFullName(buf))
3896 STRCPY(tmp, buf);
3897 else
3898 {
3899 char_u *tail;
3900
3901 tail = gettail(tmp);
3902 if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
3903 return FAIL;
3904 STRCPY(tail, buf);
3905 }
3906 }
3907
3908 /*
3909 * Try to resolve the full name of the file so that the swapfile name will
3910 * be consistent even when opening a relative symlink from different
3911 * working directories.
3912 */
3913 return vim_FullName(tmp, buf, MAXPATHL, TRUE);
3914}
3915#endif
3916
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917/*
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003918 * Make swap file name out of the file name and a directory name.
3919 * Returns pointer to allocated memory or NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 */
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003921 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003922makeswapname(
3923 char_u *fname,
3924 char_u *ffname UNUSED,
3925 buf_T *buf,
3926 char_u *dir_name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927{
3928 char_u *r, *s;
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02003929 char_u *fname_res = fname;
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003930#ifdef HAVE_READLINK
3931 char_u fname_buf[MAXPATHL];
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003932#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933
3934#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
3935 s = dir_name + STRLEN(dir_name);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003936 if (after_pathsep(dir_name, s) && s[-1] == s[-2])
Bram Moolenaar071d4272004-06-13 20:20:40 +00003937 { /* Ends with '//', Use Full path */
3938 r = NULL;
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003939 if ((s = make_percent_swname(dir_name, fname)) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 {
3941 r = modname(s, (char_u *)".swp", FALSE);
3942 vim_free(s);
3943 }
3944 return r;
3945 }
3946#endif
3947
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003948#ifdef HAVE_READLINK
3949 /* Expand symlink in the file name, so that we put the swap file with the
3950 * actual file instead of with the symlink. */
3951 if (resolve_symlink(fname, fname_buf) == OK)
3952 fname_res = fname_buf;
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003953#endif
3954
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 r = buf_modname(
3956#ifdef SHORT_FNAME
3957 TRUE,
3958#else
3959 (buf->b_p_sn || buf->b_shortname),
3960#endif
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003961 fname_res,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962 (char_u *)
Bram Moolenaare60acc12011-05-10 16:41:25 +02003963#if defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003964 "_swp",
3965#else
3966 ".swp",
3967#endif
3968#ifdef SHORT_FNAME /* always 8.3 file name */
3969 FALSE
3970#else
3971 /* Prepend a '.' to the swap file name for the current directory. */
3972 dir_name[0] == '.' && dir_name[1] == NUL
3973#endif
3974 );
3975 if (r == NULL) /* out of memory */
3976 return NULL;
3977
3978 s = get_file_in_dir(r, dir_name);
3979 vim_free(r);
3980 return s;
3981}
3982
3983/*
3984 * Get file name to use for swap file or backup file.
3985 * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
3986 * option "dname".
3987 * - If "dname" is ".", return "fname" (swap file in dir of file).
3988 * - If "dname" starts with "./", insert "dname" in "fname" (swap file
3989 * relative to dir of file).
3990 * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
3991 * dir).
3992 *
3993 * The return value is an allocated string and can be NULL.
3994 */
3995 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01003996get_file_in_dir(
3997 char_u *fname,
3998 char_u *dname) /* don't use "dirname", it is a global for Alpha */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999{
4000 char_u *t;
4001 char_u *tail;
4002 char_u *retval;
4003 int save_char;
4004
4005 tail = gettail(fname);
4006
4007 if (dname[0] == '.' && dname[1] == NUL)
4008 retval = vim_strsave(fname);
4009 else if (dname[0] == '.' && vim_ispathsep(dname[1]))
4010 {
4011 if (tail == fname) /* no path before file name */
4012 retval = concat_fnames(dname + 2, tail, TRUE);
4013 else
4014 {
4015 save_char = *tail;
4016 *tail = NUL;
4017 t = concat_fnames(fname, dname + 2, TRUE);
4018 *tail = save_char;
4019 if (t == NULL) /* out of memory */
4020 retval = NULL;
4021 else
4022 {
4023 retval = concat_fnames(t, tail, TRUE);
4024 vim_free(t);
4025 }
4026 }
4027 }
4028 else
4029 retval = concat_fnames(dname, tail, TRUE);
4030
Bram Moolenaar69c35002013-11-04 02:54:12 +01004031#ifdef WIN3264
4032 if (retval != NULL)
4033 for (t = gettail(retval); *t != NUL; mb_ptr_adv(t))
4034 if (*t == ':')
4035 *t = '%';
4036#endif
4037
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038 return retval;
4039}
4040
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01004041static void attention_message(buf_T *buf, char_u *fname);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004042
4043/*
4044 * Print the ATTENTION message: info about an existing swap file.
4045 */
4046 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004047attention_message(
4048 buf_T *buf, /* buffer being edited */
4049 char_u *fname) /* swap file name */
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004050{
4051 struct stat st;
4052 time_t x, sx;
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00004053 char *p;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004054
4055 ++no_wait_return;
4056 (void)EMSG(_("E325: ATTENTION"));
4057 MSG_PUTS(_("\nFound a swap file by the name \""));
4058 msg_home_replace(fname);
4059 MSG_PUTS("\"\n");
4060 sx = swapfile_info(fname);
4061 MSG_PUTS(_("While opening file \""));
4062 msg_outtrans(buf->b_fname);
4063 MSG_PUTS("\"\n");
4064 if (mch_stat((char *)buf->b_fname, &st) != -1)
4065 {
4066 MSG_PUTS(_(" dated: "));
4067 x = st.st_mtime; /* Manx C can't do &st.st_mtime */
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00004068 p = ctime(&x); /* includes '\n' */
4069 if (p == NULL)
4070 MSG_PUTS("(invalid)\n");
4071 else
4072 MSG_PUTS(p);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004073 if (sx != 0 && x > sx)
4074 MSG_PUTS(_(" NEWER than swap file!\n"));
4075 }
4076 /* Some of these messages are long to allow translation to
4077 * other languages. */
Bram Moolenaard9ea9062016-02-02 12:38:02 +01004078 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 +01004079 MSG_PUTS(_("(2) An edit session for this file crashed.\n"));
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004080 MSG_PUTS(_(" If this is the case, use \":recover\" or \"vim -r "));
4081 msg_outtrans(buf->b_fname);
4082 MSG_PUTS(_("\"\n to recover the changes (see \":help recovery\").\n"));
4083 MSG_PUTS(_(" If you did this already, delete the swap file \""));
4084 msg_outtrans(fname);
4085 MSG_PUTS(_("\"\n to avoid this message.\n"));
4086 cmdline_row = msg_row;
4087 --no_wait_return;
4088}
4089
4090#ifdef FEAT_AUTOCMD
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01004091static int do_swapexists(buf_T *buf, char_u *fname);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004092
4093/*
4094 * Trigger the SwapExists autocommands.
4095 * Returns a value for equivalent to do_dialog() (see below):
4096 * 0: still need to ask for a choice
4097 * 1: open read-only
4098 * 2: edit anyway
4099 * 3: recover
4100 * 4: delete it
4101 * 5: quit
4102 * 6: abort
4103 */
4104 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004105do_swapexists(buf_T *buf, char_u *fname)
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004106{
4107 set_vim_var_string(VV_SWAPNAME, fname, -1);
4108 set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
4109
4110 /* Trigger SwapExists autocommands with <afile> set to the file being
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00004111 * edited. Disallow changing directory here. */
4112 ++allbuf_lock;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004113 apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, FALSE, NULL);
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00004114 --allbuf_lock;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004115
4116 set_vim_var_string(VV_SWAPNAME, NULL, -1);
4117
4118 switch (*get_vim_var_str(VV_SWAPCHOICE))
4119 {
4120 case 'o': return 1;
4121 case 'e': return 2;
4122 case 'r': return 3;
4123 case 'd': return 4;
4124 case 'q': return 5;
4125 case 'a': return 6;
4126 }
4127
4128 return 0;
4129}
4130#endif
4131
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132/*
4133 * Find out what name to use for the swap file for buffer 'buf'.
4134 *
4135 * Several names are tried to find one that does not exist
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004136 * Returns the name in allocated memory or NULL.
Bram Moolenaarf541c362011-10-26 11:44:18 +02004137 * When out of memory "dirp" is set to NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 *
4139 * Note: If BASENAMELEN is not correct, you will get error messages for
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004140 * not being able to open the swap or undo file
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00004141 * Note: May trigger SwapExists autocmd, pointers may change!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142 */
4143 static char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004144findswapname(
4145 buf_T *buf,
4146 char_u **dirp, /* pointer to list of directories */
4147 char_u *old_fname) /* don't give warning for this file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148{
4149 char_u *fname;
4150 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004151 char_u *dir_name;
4152#ifdef AMIGA
4153 BPTR fh;
4154#endif
4155#ifndef SHORT_FNAME
4156 int r;
4157#endif
Bram Moolenaar69c35002013-11-04 02:54:12 +01004158 char_u *buf_fname = buf->b_fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159
Bram Moolenaar53076832015-12-31 19:53:21 +01004160#if !defined(SHORT_FNAME) && !defined(UNIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161# define CREATE_DUMMY_FILE
4162 FILE *dummyfd = NULL;
4163
Bram Moolenaar69c35002013-11-04 02:54:12 +01004164# ifdef WIN3264
4165 if (buf_fname != NULL && !mch_isFullName(buf_fname)
4166 && vim_strchr(gettail(buf_fname), ':'))
4167 {
4168 char_u *t;
4169
4170 buf_fname = vim_strsave(buf_fname);
4171 if (buf_fname == NULL)
4172 buf_fname = buf->b_fname;
4173 else
4174 for (t = gettail(buf_fname); *t != NUL; mb_ptr_adv(t))
4175 if (*t == ':')
4176 *t = '%';
4177 }
4178# endif
4179
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004180 /*
4181 * If we start editing a new file, e.g. "test.doc", which resides on an
4182 * MSDOS compatible filesystem, it is possible that the file
4183 * "test.doc.swp" which we create will be exactly the same file. To avoid
4184 * this problem we temporarily create "test.doc". Don't do this when the
4185 * check below for a 8.3 file name is used.
4186 */
Bram Moolenaar69c35002013-11-04 02:54:12 +01004187 if (!(buf->b_p_sn || buf->b_shortname) && buf_fname != NULL
4188 && mch_getperm(buf_fname) < 0)
4189 dummyfd = mch_fopen((char *)buf_fname, "w");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004190#endif
4191
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004192 /*
4193 * Isolate a directory name from *dirp and put it in dir_name.
4194 * First allocate some memory to put the directory name in.
4195 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004196 dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
Bram Moolenaarf541c362011-10-26 11:44:18 +02004197 if (dir_name == NULL)
4198 *dirp = NULL;
4199 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 (void)copy_option_part(dirp, dir_name, 31000, ",");
4201
Bram Moolenaar55debbe2010-05-23 23:34:36 +02004202 /*
4203 * we try different names until we find one that does not exist yet
4204 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205 if (dir_name == NULL) /* out of memory */
4206 fname = NULL;
4207 else
Bram Moolenaar69c35002013-11-04 02:54:12 +01004208 fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209
4210 for (;;)
4211 {
4212 if (fname == NULL) /* must be out of memory */
4213 break;
4214 if ((n = (int)STRLEN(fname)) == 0) /* safety check */
4215 {
4216 vim_free(fname);
4217 fname = NULL;
4218 break;
4219 }
Bram Moolenaar53076832015-12-31 19:53:21 +01004220#if defined(UNIX) && !defined(SHORT_FNAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221/*
4222 * Some systems have a MS-DOS compatible filesystem that use 8.3 character
4223 * file names. If this is the first try and the swap file name does not fit in
4224 * 8.3, detect if this is the case, set shortname and try again.
4225 */
4226 if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
4227 && !(buf->b_p_sn || buf->b_shortname))
4228 {
4229 char_u *tail;
4230 char_u *fname2;
4231 struct stat s1, s2;
4232 int f1, f2;
4233 int created1 = FALSE, created2 = FALSE;
4234 int same = FALSE;
4235
4236 /*
4237 * Check if swapfile name does not fit in 8.3:
4238 * It either contains two dots, is longer than 8 chars, or starts
4239 * with a dot.
4240 */
Bram Moolenaar69c35002013-11-04 02:54:12 +01004241 tail = gettail(buf_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242 if ( vim_strchr(tail, '.') != NULL
4243 || STRLEN(tail) > (size_t)8
4244 || *gettail(fname) == '.')
4245 {
4246 fname2 = alloc(n + 2);
4247 if (fname2 != NULL)
4248 {
4249 STRCPY(fname2, fname);
4250 /* if fname == "xx.xx.swp", fname2 = "xx.xx.swx"
4251 * if fname == ".xx.swp", fname2 = ".xx.swpx"
4252 * if fname == "123456789.swp", fname2 = "12345678x.swp"
4253 */
4254 if (vim_strchr(tail, '.') != NULL)
4255 fname2[n - 1] = 'x';
4256 else if (*gettail(fname) == '.')
4257 {
4258 fname2[n] = 'x';
4259 fname2[n + 1] = NUL;
4260 }
4261 else
4262 fname2[n - 5] += 1;
4263 /*
4264 * may need to create the files to be able to use mch_stat()
4265 */
4266 f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
4267 if (f1 < 0)
4268 {
4269 f1 = mch_open_rw((char *)fname,
4270 O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 created1 = TRUE;
4272 }
4273 if (f1 >= 0)
4274 {
4275 f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
4276 if (f2 < 0)
4277 {
4278 f2 = mch_open_rw((char *)fname2,
4279 O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
4280 created2 = TRUE;
4281 }
4282 if (f2 >= 0)
4283 {
4284 /*
4285 * Both files exist now. If mch_stat() returns the
4286 * same device and inode they are the same file.
4287 */
4288 if (mch_fstat(f1, &s1) != -1
4289 && mch_fstat(f2, &s2) != -1
4290 && s1.st_dev == s2.st_dev
4291 && s1.st_ino == s2.st_ino)
4292 same = TRUE;
4293 close(f2);
4294 if (created2)
4295 mch_remove(fname2);
4296 }
4297 close(f1);
4298 if (created1)
4299 mch_remove(fname);
4300 }
4301 vim_free(fname2);
4302 if (same)
4303 {
4304 buf->b_shortname = TRUE;
4305 vim_free(fname);
Bram Moolenaar69c35002013-11-04 02:54:12 +01004306 fname = makeswapname(buf_fname, buf->b_ffname,
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004307 buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308 continue; /* try again with b_shortname set */
4309 }
4310 }
4311 }
4312 }
4313#endif
4314 /*
4315 * check if the swapfile already exists
4316 */
4317 if (mch_getperm(fname) < 0) /* it does not exist */
4318 {
4319#ifdef HAVE_LSTAT
4320 struct stat sb;
4321
4322 /*
4323 * Extra security check: When a swap file is a symbolic link, this
4324 * is most likely a symlink attack.
4325 */
4326 if (mch_lstat((char *)fname, &sb) < 0)
4327#else
4328# ifdef AMIGA
4329 fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
4330 /*
4331 * on the Amiga mch_getperm() will return -1 when the file exists
4332 * but is being used by another program. This happens if you edit
4333 * a file twice.
4334 */
4335 if (fh != (BPTR)NULL) /* can open file, OK */
4336 {
4337 Close(fh);
4338 mch_remove(fname);
4339 break;
4340 }
4341 if (IoErr() != ERROR_OBJECT_IN_USE
4342 && IoErr() != ERROR_OBJECT_EXISTS)
4343# endif
4344#endif
4345 break;
4346 }
4347
4348 /*
4349 * A file name equal to old_fname is OK to use.
4350 */
4351 if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
4352 break;
4353
4354 /*
4355 * get here when file already exists
4356 */
4357 if (fname[n - 2] == 'w' && fname[n - 1] == 'p') /* first try */
4358 {
4359#ifndef SHORT_FNAME
4360 /*
4361 * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
4362 * and file.doc are the same file. To guess if this problem is
4363 * present try if file.doc.swx exists. If it does, we set
4364 * buf->b_shortname and try file_doc.swp (dots replaced by
4365 * underscores for this file), and try again. If it doesn't we
4366 * assume that "file.doc.swp" already exists.
4367 */
4368 if (!(buf->b_p_sn || buf->b_shortname)) /* not tried yet */
4369 {
4370 fname[n - 1] = 'x';
4371 r = mch_getperm(fname); /* try "file.swx" */
4372 fname[n - 1] = 'p';
4373 if (r >= 0) /* "file.swx" seems to exist */
4374 {
4375 buf->b_shortname = TRUE;
4376 vim_free(fname);
Bram Moolenaar69c35002013-11-04 02:54:12 +01004377 fname = makeswapname(buf_fname, buf->b_ffname,
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004378 buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004379 continue; /* try again with '.' replaced with '_' */
4380 }
4381 }
4382#endif
4383 /*
4384 * If we get here the ".swp" file really exists.
4385 * Give an error message, unless recovering, no file name, we are
4386 * viewing a help file or when the path of the file is different
4387 * (happens when all .swp files are in one directory).
4388 */
Bram Moolenaar69c35002013-11-04 02:54:12 +01004389 if (!recoverymode && buf_fname != NULL
Bram Moolenaar8fc061c2004-12-29 21:03:02 +00004390 && !buf->b_help && !(buf->b_flags & BF_DUMMY))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 {
4392 int fd;
4393 struct block0 b0;
4394 int differ = FALSE;
4395
4396 /*
4397 * Try to read block 0 from the swap file to get the original
4398 * file name (and inode number).
4399 */
4400 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
4401 if (fd >= 0)
4402 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004403 if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404 {
4405 /*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004406 * If the swapfile has the same directory as the
4407 * buffer don't compare the directory names, they can
4408 * have a different mountpoint.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004410 if (b0.b0_flags & B0_SAME_DIR)
4411 {
4412 if (fnamecmp(gettail(buf->b_ffname),
4413 gettail(b0.b0_fname)) != 0
4414 || !same_directory(fname, buf->b_ffname))
Bram Moolenaar900b4d72005-12-12 22:05:50 +00004415 {
4416#ifdef CHECK_INODE
4417 /* Symlinks may point to the same file even
4418 * when the name differs, need to check the
4419 * inode too. */
4420 expand_env(b0.b0_fname, NameBuff, MAXPATHL);
4421 if (fnamecmp_ino(buf->b_ffname, NameBuff,
4422 char_to_long(b0.b0_ino)))
4423#endif
4424 differ = TRUE;
4425 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004426 }
4427 else
4428 {
4429 /*
4430 * The name in the swap file may be
4431 * "~user/path/file". Expand it first.
4432 */
4433 expand_env(b0.b0_fname, NameBuff, MAXPATHL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434#ifdef CHECK_INODE
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004435 if (fnamecmp_ino(buf->b_ffname, NameBuff,
Bram Moolenaar900b4d72005-12-12 22:05:50 +00004436 char_to_long(b0.b0_ino)))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004437 differ = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438#else
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004439 if (fnamecmp(NameBuff, buf->b_ffname) != 0)
4440 differ = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004442 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 }
4444 close(fd);
4445 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004446
4447 /* give the ATTENTION message when there is an old swap file
4448 * for the current file, and the buffer was not recovered. */
4449 if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
4450 && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
4451 {
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004452#if defined(HAS_SWAP_EXISTS_ACTION)
4453 int choice = 0;
4454#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455#ifdef CREATE_DUMMY_FILE
4456 int did_use_dummy = FALSE;
4457
4458 /* Avoid getting a warning for the file being created
4459 * outside of Vim, it was created at the start of this
4460 * function. Delete the file now, because Vim might exit
4461 * here if the window is closed. */
4462 if (dummyfd != NULL)
4463 {
4464 fclose(dummyfd);
4465 dummyfd = NULL;
Bram Moolenaar69c35002013-11-04 02:54:12 +01004466 mch_remove(buf_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467 did_use_dummy = TRUE;
4468 }
4469#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470
4471#if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
4472 process_still_running = FALSE;
4473#endif
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004474#ifdef FEAT_AUTOCMD
4475 /*
4476 * If there is an SwapExists autocommand and we can handle
4477 * the response, trigger it. It may return 0 to ask the
4478 * user anyway.
4479 */
4480 if (swap_exists_action != SEA_NONE
Bram Moolenaar69c35002013-11-04 02:54:12 +01004481 && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004482 choice = do_swapexists(buf, fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004484 if (choice == 0)
4485#endif
4486 {
4487#ifdef FEAT_GUI
4488 /* If we are supposed to start the GUI but it wasn't
4489 * completely started yet, start it now. This makes
4490 * the messages displayed in the Vim window when
4491 * loading a session from the .gvimrc file. */
4492 if (gui.starting && !gui.in_use)
4493 gui_start();
4494#endif
4495 /* Show info about the existing swap file. */
4496 attention_message(buf, fname);
4497
4498 /* We don't want a 'q' typed at the more-prompt
4499 * interrupt loading a file. */
4500 got_int = FALSE;
4501 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502
4503#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004504 if (swap_exists_action != SEA_NONE && choice == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505 {
4506 char_u *name;
4507
4508 name = alloc((unsigned)(STRLEN(fname)
4509 + STRLEN(_("Swap file \""))
4510 + STRLEN(_("\" already exists!")) + 5));
4511 if (name != NULL)
4512 {
4513 STRCPY(name, _("Swap file \""));
4514 home_replace(NULL, fname, name + STRLEN(name),
4515 1000, TRUE);
4516 STRCAT(name, _("\" already exists!"));
4517 }
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004518 choice = do_dialog(VIM_WARNING,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519 (char_u *)_("VIM - ATTENTION"),
4520 name == NULL
4521 ? (char_u *)_("Swap file already exists!")
4522 : name,
4523# if defined(UNIX) || defined(__EMX__) || defined(VMS)
4524 process_still_running
4525 ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") :
4526# endif
Bram Moolenaard2c340a2011-01-17 20:08:11 +01004527 (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 +00004528
4529# if defined(UNIX) || defined(__EMX__) || defined(VMS)
4530 if (process_still_running && choice >= 4)
4531 choice++; /* Skip missing "Delete it" button */
4532# endif
4533 vim_free(name);
4534
4535 /* pretend screen didn't scroll, need redraw anyway */
4536 msg_scrolled = 0;
4537 redraw_all_later(NOT_VALID);
4538 }
4539#endif
4540
4541#if defined(HAS_SWAP_EXISTS_ACTION)
4542 if (choice > 0)
4543 {
4544 switch (choice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545 {
4546 case 1:
4547 buf->b_p_ro = TRUE;
4548 break;
4549 case 2:
4550 break;
4551 case 3:
4552 swap_exists_action = SEA_RECOVER;
4553 break;
4554 case 4:
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004555 mch_remove(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 break;
4557 case 5:
4558 swap_exists_action = SEA_QUIT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 break;
4560 case 6:
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004561 swap_exists_action = SEA_QUIT;
4562 got_int = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 break;
4564 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565
4566 /* If the file was deleted this fname can be used. */
4567 if (mch_getperm(fname) < 0)
4568 break;
4569 }
4570 else
4571#endif
4572 {
4573 MSG_PUTS("\n");
Bram Moolenaar4770d092006-01-12 23:22:24 +00004574 if (msg_silent == 0)
4575 /* call wait_return() later */
4576 need_wait_return = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577 }
4578
4579#ifdef CREATE_DUMMY_FILE
4580 /* Going to try another name, need the dummy file again. */
4581 if (did_use_dummy)
Bram Moolenaar69c35002013-11-04 02:54:12 +01004582 dummyfd = mch_fopen((char *)buf_fname, "w");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583#endif
4584 }
4585 }
4586 }
4587
4588 /*
4589 * Change the ".swp" extension to find another file that can be used.
4590 * First decrement the last char: ".swo", ".swn", etc.
4591 * If that still isn't enough decrement the last but one char: ".svz"
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004592 * Can happen when editing many "No Name" buffers.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593 */
4594 if (fname[n - 1] == 'a') /* ".s?a" */
4595 {
4596 if (fname[n - 2] == 'a') /* ".saa": tried enough, give up */
4597 {
4598 EMSG(_("E326: Too many swap files found"));
4599 vim_free(fname);
4600 fname = NULL;
4601 break;
4602 }
4603 --fname[n - 2]; /* ".svz", ".suz", etc. */
4604 fname[n - 1] = 'z' + 1;
4605 }
4606 --fname[n - 1]; /* ".swo", ".swn", etc. */
4607 }
4608
4609 vim_free(dir_name);
4610#ifdef CREATE_DUMMY_FILE
4611 if (dummyfd != NULL) /* file has been created temporarily */
4612 {
4613 fclose(dummyfd);
Bram Moolenaar69c35002013-11-04 02:54:12 +01004614 mch_remove(buf_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615 }
4616#endif
Bram Moolenaar69c35002013-11-04 02:54:12 +01004617#ifdef WIN3264
4618 if (buf_fname != buf->b_fname)
4619 vim_free(buf_fname);
4620#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621 return fname;
4622}
4623
4624 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004625b0_magic_wrong(ZERO_BL *b0p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626{
4627 return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
4628 || b0p->b0_magic_int != (int)B0_MAGIC_INT
4629 || b0p->b0_magic_short != (short)B0_MAGIC_SHORT
4630 || b0p->b0_magic_char != B0_MAGIC_CHAR);
4631}
4632
4633#ifdef CHECK_INODE
4634/*
4635 * Compare current file name with file name from swap file.
4636 * Try to use inode numbers when possible.
4637 * Return non-zero when files are different.
4638 *
4639 * When comparing file names a few things have to be taken into consideration:
4640 * - When working over a network the full path of a file depends on the host.
4641 * We check the inode number if possible. It is not 100% reliable though,
4642 * because the device number cannot be used over a network.
4643 * - When a file does not exist yet (editing a new file) there is no inode
4644 * number.
4645 * - The file name in a swap file may not be valid on the current host. The
4646 * "~user" form is used whenever possible to avoid this.
4647 *
4648 * This is getting complicated, let's make a table:
4649 *
4650 * ino_c ino_s fname_c fname_s differ =
4651 *
4652 * both files exist -> compare inode numbers:
4653 * != 0 != 0 X X ino_c != ino_s
4654 *
4655 * inode number(s) unknown, file names available -> compare file names
4656 * == 0 X OK OK fname_c != fname_s
4657 * X == 0 OK OK fname_c != fname_s
4658 *
4659 * current file doesn't exist, file for swap file exist, file name(s) not
4660 * available -> probably different
4661 * == 0 != 0 FAIL X TRUE
4662 * == 0 != 0 X FAIL TRUE
4663 *
4664 * current file exists, inode for swap unknown, file name(s) not
4665 * available -> probably different
4666 * != 0 == 0 FAIL X TRUE
4667 * != 0 == 0 X FAIL TRUE
4668 *
4669 * current file doesn't exist, inode for swap unknown, one file name not
4670 * available -> probably different
4671 * == 0 == 0 FAIL OK TRUE
4672 * == 0 == 0 OK FAIL TRUE
4673 *
4674 * current file doesn't exist, inode for swap unknown, both file names not
4675 * available -> probably same file
4676 * == 0 == 0 FAIL FAIL FALSE
4677 *
4678 * Note that when the ino_t is 64 bits, only the last 32 will be used. This
4679 * can't be changed without making the block 0 incompatible with 32 bit
4680 * versions.
4681 */
4682
4683 static int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004684fnamecmp_ino(
4685 char_u *fname_c, /* current file name */
4686 char_u *fname_s, /* file name from swap file */
4687 long ino_block0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004688{
4689 struct stat st;
4690 ino_t ino_c = 0; /* ino of current file */
4691 ino_t ino_s; /* ino of file from swap file */
4692 char_u buf_c[MAXPATHL]; /* full path of fname_c */
4693 char_u buf_s[MAXPATHL]; /* full path of fname_s */
4694 int retval_c; /* flag: buf_c valid */
4695 int retval_s; /* flag: buf_s valid */
4696
4697 if (mch_stat((char *)fname_c, &st) == 0)
4698 ino_c = (ino_t)st.st_ino;
4699
4700 /*
4701 * First we try to get the inode from the file name, because the inode in
4702 * the swap file may be outdated. If that fails (e.g. this path is not
4703 * valid on this machine), use the inode from block 0.
4704 */
4705 if (mch_stat((char *)fname_s, &st) == 0)
4706 ino_s = (ino_t)st.st_ino;
4707 else
4708 ino_s = (ino_t)ino_block0;
4709
4710 if (ino_c && ino_s)
4711 return (ino_c != ino_s);
4712
4713 /*
4714 * One of the inode numbers is unknown, try a forced vim_FullName() and
4715 * compare the file names.
4716 */
4717 retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
4718 retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
4719 if (retval_c == OK && retval_s == OK)
4720 return (STRCMP(buf_c, buf_s) != 0);
4721
4722 /*
4723 * Can't compare inodes or file names, guess that the files are different,
4724 * unless both appear not to exist at all.
4725 */
4726 if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
4727 return FALSE;
4728 return TRUE;
4729}
4730#endif /* CHECK_INODE */
4731
4732/*
4733 * Move a long integer into a four byte character array.
4734 * Used for machine independency in block zero.
4735 */
4736 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004737long_to_char(long n, char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738{
4739 s[0] = (char_u)(n & 0xff);
4740 n = (unsigned)n >> 8;
4741 s[1] = (char_u)(n & 0xff);
4742 n = (unsigned)n >> 8;
4743 s[2] = (char_u)(n & 0xff);
4744 n = (unsigned)n >> 8;
4745 s[3] = (char_u)(n & 0xff);
4746}
4747
4748 static long
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004749char_to_long(char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750{
4751 long retval;
4752
4753 retval = s[3];
4754 retval <<= 8;
4755 retval |= s[2];
4756 retval <<= 8;
4757 retval |= s[1];
4758 retval <<= 8;
4759 retval |= s[0];
4760
4761 return retval;
4762}
4763
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004764/*
4765 * Set the flags in the first block of the swap file:
4766 * - file is modified or not: buf->b_changed
4767 * - 'fileformat'
4768 * - 'fileencoding'
4769 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004771ml_setflags(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772{
4773 bhdr_T *hp;
4774 ZERO_BL *b0p;
4775
4776 if (!buf->b_ml.ml_mfp)
4777 return;
4778 for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
4779 {
4780 if (hp->bh_bnum == 0)
4781 {
4782 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004783 b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
4784 b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
4785 | (get_fileformat(buf) + 1);
4786#ifdef FEAT_MBYTE
4787 add_b0_fenc(b0p, buf);
4788#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 hp->bh_flags |= BH_DIRTY;
4790 mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
4791 break;
4792 }
4793 }
4794}
4795
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004796#if defined(FEAT_CRYPT) || defined(PROTO)
4797/*
4798 * If "data" points to a data block encrypt the text in it and return a copy
4799 * in allocated memory. Return NULL when out of memory.
4800 * Otherwise return "data".
4801 */
4802 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004803ml_encrypt_data(
4804 memfile_T *mfp,
4805 char_u *data,
4806 off_t offset,
4807 unsigned size)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004808{
4809 DATA_BL *dp = (DATA_BL *)data;
4810 char_u *head_end;
4811 char_u *text_start;
4812 char_u *new_data;
4813 int text_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004814 cryptstate_T *state;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004815
4816 if (dp->db_id != DATA_ID)
4817 return data;
4818
Bram Moolenaarbc563362015-06-09 18:35:25 +02004819 state = ml_crypt_prepare(mfp, offset, FALSE);
4820 if (state == NULL)
4821 return data;
4822
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004823 new_data = (char_u *)alloc(size);
4824 if (new_data == NULL)
4825 return NULL;
4826 head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
4827 text_start = (char_u *)dp + dp->db_txt_start;
4828 text_len = size - dp->db_txt_start;
4829
4830 /* Copy the header and the text. */
4831 mch_memmove(new_data, dp, head_end - (char_u *)dp);
4832
4833 /* Encrypt the text. */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004834 crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
4835 crypt_free_state(state);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004836
4837 /* Clear the gap. */
4838 if (head_end < text_start)
4839 vim_memset(new_data + (head_end - data), 0, text_start - head_end);
4840
4841 return new_data;
4842}
4843
4844/*
Bram Moolenaarbc563362015-06-09 18:35:25 +02004845 * Decrypt the text in "data" if it points to an encrypted data block.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004846 */
4847 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004848ml_decrypt_data(
4849 memfile_T *mfp,
4850 char_u *data,
4851 off_t offset,
4852 unsigned size)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004853{
4854 DATA_BL *dp = (DATA_BL *)data;
4855 char_u *head_end;
4856 char_u *text_start;
4857 int text_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004858 cryptstate_T *state;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004859
4860 if (dp->db_id == DATA_ID)
4861 {
4862 head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
4863 text_start = (char_u *)dp + dp->db_txt_start;
4864 text_len = dp->db_txt_end - dp->db_txt_start;
4865
4866 if (head_end > text_start || dp->db_txt_start > size
4867 || dp->db_txt_end > size)
4868 return; /* data was messed up */
4869
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004870 state = ml_crypt_prepare(mfp, offset, TRUE);
Bram Moolenaarbc563362015-06-09 18:35:25 +02004871 if (state != NULL)
4872 {
4873 /* Decrypt the text in place. */
4874 crypt_decode_inplace(state, text_start, text_len);
4875 crypt_free_state(state);
4876 }
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004877 }
4878}
4879
4880/*
4881 * Prepare for encryption/decryption, using the key, seed and offset.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004882 * Return an allocated cryptstate_T *.
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004883 */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004884 static cryptstate_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004885ml_crypt_prepare(memfile_T *mfp, off_t offset, int reading)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004886{
4887 buf_T *buf = mfp->mf_buffer;
4888 char_u salt[50];
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004889 int method_nr;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004890 char_u *key;
4891 char_u *seed;
4892
4893 if (reading && mfp->mf_old_key != NULL)
4894 {
4895 /* Reading back blocks with the previous key/method/seed. */
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004896 method_nr = mfp->mf_old_cm;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004897 key = mfp->mf_old_key;
4898 seed = mfp->mf_old_seed;
4899 }
4900 else
4901 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004902 method_nr = crypt_get_method_nr(buf);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004903 key = buf->b_p_key;
4904 seed = mfp->mf_seed;
4905 }
Bram Moolenaarbc563362015-06-09 18:35:25 +02004906 if (*key == NUL)
4907 return NULL;
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004908
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004909 if (method_nr == CRYPT_M_ZIP)
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004910 {
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004911 /* For PKzip: Append the offset to the key, so that we use a different
4912 * key for every block. */
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004913 vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004914 return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004915 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02004916
4917 /* Using blowfish or better: add salt and seed. We use the byte offset
4918 * of the block for the salt. */
4919 vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
4920 return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
4921 seed, MF_SEED_LEN);
Bram Moolenaara8ffcbb2010-06-21 06:15:46 +02004922}
4923
4924#endif
4925
4926
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927#if defined(FEAT_BYTEOFF) || defined(PROTO)
4928
4929#define MLCS_MAXL 800 /* max no of lines in chunk */
4930#define MLCS_MINL 400 /* should be half of MLCS_MAXL */
4931
4932/*
Bram Moolenaar0ad014c2010-07-25 14:00:46 +02004933 * Keep information for finding byte offset of a line, updtype may be one of:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934 * ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
4935 * Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
4936 * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
4937 * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
4938 */
4939 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01004940ml_updatechunk(
4941 buf_T *buf,
4942 linenr_T line,
4943 long len,
4944 int updtype)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945{
4946 static buf_T *ml_upd_lastbuf = NULL;
4947 static linenr_T ml_upd_lastline;
4948 static linenr_T ml_upd_lastcurline;
4949 static int ml_upd_lastcurix;
4950
4951 linenr_T curline = ml_upd_lastcurline;
4952 int curix = ml_upd_lastcurix;
4953 long size;
4954 chunksize_T *curchnk;
4955 int rest;
4956 bhdr_T *hp;
4957 DATA_BL *dp;
4958
4959 if (buf->b_ml.ml_usedchunks == -1 || len == 0)
4960 return;
4961 if (buf->b_ml.ml_chunksize == NULL)
4962 {
4963 buf->b_ml.ml_chunksize = (chunksize_T *)
4964 alloc((unsigned)sizeof(chunksize_T) * 100);
4965 if (buf->b_ml.ml_chunksize == NULL)
4966 {
4967 buf->b_ml.ml_usedchunks = -1;
4968 return;
4969 }
4970 buf->b_ml.ml_numchunks = 100;
4971 buf->b_ml.ml_usedchunks = 1;
4972 buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
4973 buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
4974 }
4975
4976 if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
4977 {
4978 /*
4979 * First line in empty buffer from ml_flush_line() -- reset
4980 */
4981 buf->b_ml.ml_usedchunks = 1;
4982 buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
4983 buf->b_ml.ml_chunksize[0].mlcs_totalsize =
4984 (long)STRLEN(buf->b_ml.ml_line_ptr) + 1;
4985 return;
4986 }
4987
4988 /*
4989 * Find chunk that our line belongs to, curline will be at start of the
4990 * chunk.
4991 */
4992 if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
4993 || updtype != ML_CHNK_ADDLINE)
4994 {
4995 for (curline = 1, curix = 0;
4996 curix < buf->b_ml.ml_usedchunks - 1
4997 && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4998 curix++)
4999 {
5000 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5001 }
5002 }
5003 else if (line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines
5004 && curix < buf->b_ml.ml_usedchunks - 1)
5005 {
5006 /* Adjust cached curix & curline */
5007 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5008 curix++;
5009 }
5010 curchnk = buf->b_ml.ml_chunksize + curix;
5011
5012 if (updtype == ML_CHNK_DELLINE)
Bram Moolenaar5a6404c2006-11-01 17:12:57 +00005013 len = -len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014 curchnk->mlcs_totalsize += len;
5015 if (updtype == ML_CHNK_ADDLINE)
5016 {
5017 curchnk->mlcs_numlines++;
5018
5019 /* May resize here so we don't have to do it in both cases below */
5020 if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
5021 {
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01005022 chunksize_T *t_chunksize = buf->b_ml.ml_chunksize;
5023
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024 buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
5025 buf->b_ml.ml_chunksize = (chunksize_T *)
5026 vim_realloc(buf->b_ml.ml_chunksize,
5027 sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
5028 if (buf->b_ml.ml_chunksize == NULL)
5029 {
5030 /* Hmmmm, Give up on offset for this buffer */
Bram Moolenaar9abd5c62015-02-10 18:34:01 +01005031 vim_free(t_chunksize);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032 buf->b_ml.ml_usedchunks = -1;
5033 return;
5034 }
5035 }
5036
5037 if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
5038 {
5039 int count; /* number of entries in block */
5040 int idx;
5041 int text_end;
5042 int linecnt;
5043
5044 mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
5045 buf->b_ml.ml_chunksize + curix,
5046 (buf->b_ml.ml_usedchunks - curix) *
5047 sizeof(chunksize_T));
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00005048 /* Compute length of first half of lines in the split chunk */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 size = 0;
5050 linecnt = 0;
5051 while (curline < buf->b_ml.ml_line_count
5052 && linecnt < MLCS_MINL)
5053 {
5054 if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
5055 {
5056 buf->b_ml.ml_usedchunks = -1;
5057 return;
5058 }
5059 dp = (DATA_BL *)(hp->bh_data);
5060 count = (long)(buf->b_ml.ml_locked_high) -
5061 (long)(buf->b_ml.ml_locked_low) + 1;
5062 idx = curline - buf->b_ml.ml_locked_low;
5063 curline = buf->b_ml.ml_locked_high + 1;
5064 if (idx == 0)/* first line in block, text at the end */
5065 text_end = dp->db_txt_end;
5066 else
5067 text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5068 /* Compute index of last line to use in this MEMLINE */
5069 rest = count - idx;
5070 if (linecnt + rest > MLCS_MINL)
5071 {
5072 idx += MLCS_MINL - linecnt - 1;
5073 linecnt = MLCS_MINL;
5074 }
5075 else
5076 {
5077 idx = count - 1;
5078 linecnt += rest;
5079 }
5080 size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
5081 }
5082 buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
5083 buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
5084 buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
5085 buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
5086 buf->b_ml.ml_usedchunks++;
5087 ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
5088 return;
5089 }
5090 else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
5091 && curix == buf->b_ml.ml_usedchunks - 1
5092 && buf->b_ml.ml_line_count - line <= 1)
5093 {
5094 /*
5095 * We are in the last chunk and it is cheap to crate a new one
5096 * after this. Do it now to avoid the loop above later on
5097 */
5098 curchnk = buf->b_ml.ml_chunksize + curix + 1;
5099 buf->b_ml.ml_usedchunks++;
5100 if (line == buf->b_ml.ml_line_count)
5101 {
5102 curchnk->mlcs_numlines = 0;
5103 curchnk->mlcs_totalsize = 0;
5104 }
5105 else
5106 {
5107 /*
5108 * Line is just prior to last, move count for last
5109 * This is the common case when loading a new file
5110 */
5111 hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
5112 if (hp == NULL)
5113 {
5114 buf->b_ml.ml_usedchunks = -1;
5115 return;
5116 }
5117 dp = (DATA_BL *)(hp->bh_data);
5118 if (dp->db_line_count == 1)
5119 rest = dp->db_txt_end - dp->db_txt_start;
5120 else
5121 rest =
5122 ((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
5123 - dp->db_txt_start;
5124 curchnk->mlcs_totalsize = rest;
5125 curchnk->mlcs_numlines = 1;
5126 curchnk[-1].mlcs_totalsize -= rest;
5127 curchnk[-1].mlcs_numlines -= 1;
5128 }
5129 }
5130 }
5131 else if (updtype == ML_CHNK_DELLINE)
5132 {
5133 curchnk->mlcs_numlines--;
5134 ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
5135 if (curix < (buf->b_ml.ml_usedchunks - 1)
5136 && (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
5137 <= MLCS_MINL)
5138 {
5139 curix++;
5140 curchnk = buf->b_ml.ml_chunksize + curix;
5141 }
5142 else if (curix == 0 && curchnk->mlcs_numlines <= 0)
5143 {
5144 buf->b_ml.ml_usedchunks--;
5145 mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
5146 buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
5147 return;
5148 }
5149 else if (curix == 0 || (curchnk->mlcs_numlines > 10
5150 && (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
5151 > MLCS_MINL))
5152 {
5153 return;
5154 }
5155
5156 /* Collapse chunks */
5157 curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
5158 curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
5159 buf->b_ml.ml_usedchunks--;
5160 if (curix < buf->b_ml.ml_usedchunks)
5161 {
5162 mch_memmove(buf->b_ml.ml_chunksize + curix,
5163 buf->b_ml.ml_chunksize + curix + 1,
5164 (buf->b_ml.ml_usedchunks - curix) *
5165 sizeof(chunksize_T));
5166 }
5167 return;
5168 }
5169 ml_upd_lastbuf = buf;
5170 ml_upd_lastline = line;
5171 ml_upd_lastcurline = curline;
5172 ml_upd_lastcurix = curix;
5173}
5174
5175/*
5176 * Find offset for line or line with offset.
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005177 * Find line with offset if "lnum" is 0; return remaining offset in offp
5178 * Find offset of line if "lnum" > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005179 * return -1 if information is not available
5180 */
5181 long
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01005182ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005183{
5184 linenr_T curline;
5185 int curix;
5186 long size;
5187 bhdr_T *hp;
5188 DATA_BL *dp;
5189 int count; /* number of entries in block */
5190 int idx;
5191 int start_idx;
5192 int text_end;
5193 long offset;
5194 int len;
5195 int ffdos = (get_fileformat(buf) == EOL_DOS);
5196 int extra = 0;
5197
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005198 /* take care of cached line first */
5199 ml_flush_line(curbuf);
5200
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201 if (buf->b_ml.ml_usedchunks == -1
5202 || buf->b_ml.ml_chunksize == NULL
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005203 || lnum < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005204 return -1;
5205
5206 if (offp == NULL)
5207 offset = 0;
5208 else
5209 offset = *offp;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005210 if (lnum == 0 && offset <= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 return 1; /* Not a "find offset" and offset 0 _must_ be in line 1 */
5212 /*
5213 * Find the last chunk before the one containing our line. Last chunk is
5214 * special because it will never qualify
5215 */
5216 curline = 1;
5217 curix = size = 0;
5218 while (curix < buf->b_ml.ml_usedchunks - 1
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005219 && ((lnum != 0
5220 && lnum >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 || (offset != 0
5222 && offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
5223 + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
5224 {
5225 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5226 size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
5227 if (offset && ffdos)
5228 size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
5229 curix++;
5230 }
5231
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005232 while ((lnum != 0 && curline < lnum) || (offset != 0 && size < offset))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005233 {
5234 if (curline > buf->b_ml.ml_line_count
5235 || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
5236 return -1;
5237 dp = (DATA_BL *)(hp->bh_data);
5238 count = (long)(buf->b_ml.ml_locked_high) -
5239 (long)(buf->b_ml.ml_locked_low) + 1;
5240 start_idx = idx = curline - buf->b_ml.ml_locked_low;
5241 if (idx == 0)/* first line in block, text at the end */
5242 text_end = dp->db_txt_end;
5243 else
5244 text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
5245 /* Compute index of last line to use in this MEMLINE */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005246 if (lnum != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005248 if (curline + (count - idx) >= lnum)
5249 idx += lnum - curline - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250 else
5251 idx = count - 1;
5252 }
5253 else
5254 {
5255 extra = 0;
5256 while (offset >= size
5257 + text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
5258 + ffdos)
5259 {
5260 if (ffdos)
5261 size++;
5262 if (idx == count - 1)
5263 {
5264 extra = 1;
5265 break;
5266 }
5267 idx++;
5268 }
5269 }
5270 len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
5271 size += len;
5272 if (offset != 0 && size >= offset)
5273 {
5274 if (size + ffdos == offset)
5275 *offp = 0;
5276 else if (idx == start_idx)
5277 *offp = offset - size + len;
5278 else
5279 *offp = offset - size + len
5280 - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
5281 curline += idx - start_idx + extra;
5282 if (curline > buf->b_ml.ml_line_count)
5283 return -1; /* exactly one byte beyond the end */
5284 return curline;
5285 }
5286 curline = buf->b_ml.ml_locked_high + 1;
5287 }
5288
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005289 if (lnum != 0)
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005290 {
5291 /* Count extra CR characters. */
5292 if (ffdos)
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00005293 size += lnum - 1;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005294
Bram Moolenaar34d72d42015-07-17 14:18:08 +02005295 /* Don't count the last line break if 'noeol' and ('bin' or
5296 * 'nofixeol'). */
5297 if ((!buf->b_p_fixeol || buf->b_p_bin) && !buf->b_p_eol
5298 && buf->b_ml.ml_line_count == lnum)
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005299 size -= ffdos + 1;
5300 }
5301
Bram Moolenaar071d4272004-06-13 20:20:40 +00005302 return size;
5303}
5304
5305/*
5306 * Goto byte in buffer with offset 'cnt'.
5307 */
5308 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01005309goto_byte(long cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005310{
5311 long boff = cnt;
5312 linenr_T lnum;
5313
5314 ml_flush_line(curbuf); /* cached line may be dirty */
5315 setpcmark();
5316 if (boff)
5317 --boff;
5318 lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
5319 if (lnum < 1) /* past the end */
5320 {
5321 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5322 curwin->w_curswant = MAXCOL;
5323 coladvance((colnr_T)MAXCOL);
5324 }
5325 else
5326 {
5327 curwin->w_cursor.lnum = lnum;
5328 curwin->w_cursor.col = (colnr_T)boff;
Bram Moolenaar943d2b52005-12-02 00:50:49 +00005329# ifdef FEAT_VIRTUALEDIT
5330 curwin->w_cursor.coladd = 0;
5331# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005332 curwin->w_set_curswant = TRUE;
5333 }
5334 check_cursor();
5335
5336# ifdef FEAT_MBYTE
5337 /* Make sure the cursor is on the first byte of a multi-byte char. */
5338 if (has_mbyte)
5339 mb_adjust_cursor();
5340# endif
5341}
5342#endif