blob: d9043dce63d9cb4ec3671a8e9328ac340690c143 [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 Moolenaarc236c162008-07-13 17:41:49 +000045#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64)
Bram Moolenaar8c8de832008-06-24 22:58:06 +000046# include "vimio.h" /* for mch_open(), must be before vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +000047#endif
48
49#include "vim.h"
50
Bram Moolenaar071d4272004-06-13 20:20:40 +000051#ifndef UNIX /* it's in os_unix.h for Unix */
52# include <time.h>
53#endif
54
Bram Moolenaar5a6404c2006-11-01 17:12:57 +000055#if defined(SASC) || defined(__amigaos4__)
Bram Moolenaar071d4272004-06-13 20:20:40 +000056# include <proto/dos.h> /* for Open() and Close() */
57#endif
58
Bram Moolenaar5a6404c2006-11-01 17:12:57 +000059#ifdef HAVE_ERRNO_H
60# include <errno.h>
61#endif
62
Bram Moolenaar071d4272004-06-13 20:20:40 +000063typedef struct block0 ZERO_BL; /* contents of the first block */
64typedef struct pointer_block PTR_BL; /* contents of a pointer block */
65typedef struct data_block DATA_BL; /* contents of a data block */
66typedef struct pointer_entry PTR_EN; /* block/line-count pair */
67
68#define DATA_ID (('d' << 8) + 'a') /* data block id */
69#define PTR_ID (('p' << 8) + 't') /* pointer block id */
70#define BLOCK0_ID0 'b' /* block 0 id 0 */
71#define BLOCK0_ID1 '0' /* block 0 id 1 */
72
73/*
74 * pointer to a block, used in a pointer block
75 */
76struct pointer_entry
77{
78 blocknr_T pe_bnum; /* block number */
79 linenr_T pe_line_count; /* number of lines in this branch */
80 linenr_T pe_old_lnum; /* lnum for this block (for recovery) */
81 int pe_page_count; /* number of pages in block pe_bnum */
82};
83
84/*
85 * A pointer block contains a list of branches in the tree.
86 */
87struct pointer_block
88{
89 short_u pb_id; /* ID for pointer block: PTR_ID */
Bram Moolenaar20a825a2010-05-31 21:27:30 +020090 short_u pb_count; /* number of pointers in this block */
Bram Moolenaar071d4272004-06-13 20:20:40 +000091 short_u pb_count_max; /* maximum value for pb_count */
92 PTR_EN pb_pointer[1]; /* list of pointers to blocks (actually longer)
93 * followed by empty space until end of page */
94};
95
96/*
97 * A data block is a leaf in the tree.
98 *
99 * The text of the lines is at the end of the block. The text of the first line
100 * in the block is put at the end, the text of the second line in front of it,
101 * etc. Thus the order of the lines is the opposite of the line number.
102 */
103struct data_block
104{
105 short_u db_id; /* ID for data block: DATA_ID */
106 unsigned db_free; /* free space available */
107 unsigned db_txt_start; /* byte where text starts */
108 unsigned db_txt_end; /* byte just after data block */
109 linenr_T db_line_count; /* number of lines in this block */
110 unsigned db_index[1]; /* index for start of line (actually bigger)
111 * followed by empty space upto db_txt_start
112 * followed by the text in the lines until
113 * end of page */
114};
115
116/*
117 * The low bits of db_index hold the actual index. The topmost bit is
118 * used for the global command to be able to mark a line.
119 * This method is not clean, but otherwise there would be at least one extra
120 * byte used for each line.
121 * The mark has to be in this place to keep it with the correct line when other
122 * lines are inserted or deleted.
123 */
124#define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
125#define DB_INDEX_MASK (~DB_MARKED)
126
127#define INDEX_SIZE (sizeof(unsigned)) /* size of one db_index entry */
128#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */
129
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000130#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
131#define B0_FNAME_SIZE 898
132#define B0_UNAME_SIZE 40
133#define B0_HNAME_SIZE 40
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134/*
135 * Restrict the numbers to 32 bits, otherwise most compilers will complain.
136 * This won't detect a 64 bit machine that only swaps a byte in the top 32
137 * bits, but that is crazy anyway.
138 */
139#define B0_MAGIC_LONG 0x30313233L
140#define B0_MAGIC_INT 0x20212223L
141#define B0_MAGIC_SHORT 0x10111213L
142#define B0_MAGIC_CHAR 0x55
143
144/*
145 * Block zero holds all info about the swap file.
146 *
147 * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing
148 * swap files unusable!
149 *
150 * If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!!
151 *
Bram Moolenaarbae0c162007-05-10 19:30:25 +0000152 * This block is built up of single bytes, to make it portable across
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 * different machines. b0_magic_* is used to check the byte order and size of
154 * variables, because the rest of the swap file is not portable.
155 */
156struct block0
157{
158 char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */
159 char_u b0_version[10]; /* Vim version string */
160 char_u b0_page_size[4];/* number of bytes per page */
161 char_u b0_mtime[4]; /* last modification time of file */
162 char_u b0_ino[4]; /* inode of b0_fname */
163 char_u b0_pid[4]; /* process id of creator (or 0) */
164 char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
165 char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000166 char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167 long b0_magic_long; /* check for byte order of long */
168 int b0_magic_int; /* check for byte order of int */
169 short b0_magic_short; /* check for byte order of short */
170 char_u b0_magic_char; /* check for last char */
171};
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000172
173/*
Bram Moolenaar4770d092006-01-12 23:22:24 +0000174 * Note: b0_dirty and b0_flags are put at the end of the file name. For very
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000175 * long file names in older versions of Vim they are invalid.
176 * The 'fileencoding' comes before b0_flags, with a NUL in front. But only
177 * when there is room, for very long file names it's omitted.
178 */
179#define B0_DIRTY 0x55
180#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG-1]
181
182/*
183 * The b0_flags field is new in Vim 7.0.
184 */
185#define b0_flags b0_fname[B0_FNAME_SIZE_ORG-2]
186
187/* The lowest two bits contain the fileformat. Zero means it's not set
188 * (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or
189 * EOL_MAC + 1. */
190#define B0_FF_MASK 3
191
192/* Swap file is in directory of edited file. Used to find the file from
193 * different mount points. */
194#define B0_SAME_DIR 4
195
196/* The 'fileencoding' is at the end of b0_fname[], with a NUL in front of it.
197 * When empty there is only the NUL. */
198#define B0_HAS_FENC 8
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199
200#define STACK_INCR 5 /* nr of entries added to ml_stack at a time */
201
202/*
203 * The line number where the first mark may be is remembered.
204 * If it is 0 there are no marks at all.
205 * (always used for the current buffer only, no buffer change possible while
206 * executing a global command).
207 */
208static linenr_T lowest_marked = 0;
209
210/*
211 * arguments for ml_find_line()
212 */
213#define ML_DELETE 0x11 /* delete line */
214#define ML_INSERT 0x12 /* insert line */
215#define ML_FIND 0x13 /* just find the line */
216#define ML_FLUSH 0x02 /* flush locked block */
217#define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */
218
Bram Moolenaar89d40322006-08-29 15:30:07 +0000219static void ml_upd_block0 __ARGS((buf_T *buf, int set_fname));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf));
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000221static void set_b0_dir_flag __ARGS((ZERO_BL *b0p, buf_T *buf));
222#ifdef FEAT_MBYTE
223static void add_b0_fenc __ARGS((ZERO_BL *b0p, buf_T *buf));
224#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225static time_t swapfile_info __ARGS((char_u *));
226static int recov_file_names __ARGS((char_u **, char_u *, int prepend_dot));
227static int ml_append_int __ARGS((buf_T *, linenr_T, char_u *, colnr_T, int, int));
228static int ml_delete_int __ARGS((buf_T *, linenr_T, int));
229static char_u *findswapname __ARGS((buf_T *, char_u **, char_u *));
230static void ml_flush_line __ARGS((buf_T *));
231static bhdr_T *ml_new_data __ARGS((memfile_T *, int, int));
232static bhdr_T *ml_new_ptr __ARGS((memfile_T *));
233static bhdr_T *ml_find_line __ARGS((buf_T *, linenr_T, int));
234static int ml_add_stack __ARGS((buf_T *));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235static void ml_lineadd __ARGS((buf_T *, int));
236static int b0_magic_wrong __ARGS((ZERO_BL *));
237#ifdef CHECK_INODE
238static int fnamecmp_ino __ARGS((char_u *, char_u *, long));
239#endif
240static void long_to_char __ARGS((long, char_u *));
241static long char_to_long __ARGS((char_u *));
242#if defined(UNIX) || defined(WIN3264)
243static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
244#endif
245#ifdef FEAT_BYTEOFF
246static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
247#endif
248
249/*
Bram Moolenaar4770d092006-01-12 23:22:24 +0000250 * Open a new memline for "buf".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000251 *
Bram Moolenaar4770d092006-01-12 23:22:24 +0000252 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253 */
254 int
Bram Moolenaar4770d092006-01-12 23:22:24 +0000255ml_open(buf)
256 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000257{
258 memfile_T *mfp;
259 bhdr_T *hp = NULL;
260 ZERO_BL *b0p;
261 PTR_BL *pp;
262 DATA_BL *dp;
263
Bram Moolenaar4770d092006-01-12 23:22:24 +0000264 /*
265 * init fields in memline struct
266 */
267 buf->b_ml.ml_stack_size = 0; /* no stack yet */
268 buf->b_ml.ml_stack = NULL; /* no stack yet */
269 buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
270 buf->b_ml.ml_locked = NULL; /* no cached block */
271 buf->b_ml.ml_line_lnum = 0; /* no cached line */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272#ifdef FEAT_BYTEOFF
Bram Moolenaar4770d092006-01-12 23:22:24 +0000273 buf->b_ml.ml_chunksize = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274#endif
275
Bram Moolenaar4770d092006-01-12 23:22:24 +0000276 /*
277 * When 'updatecount' is non-zero swap file may be opened later.
278 */
279 if (p_uc && buf->b_p_swf)
280 buf->b_may_swap = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000281 else
Bram Moolenaar4770d092006-01-12 23:22:24 +0000282 buf->b_may_swap = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000283
Bram Moolenaar4770d092006-01-12 23:22:24 +0000284 /*
285 * Open the memfile. No swap file is created yet.
286 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287 mfp = mf_open(NULL, 0);
288 if (mfp == NULL)
289 goto error;
290
Bram Moolenaar4770d092006-01-12 23:22:24 +0000291 buf->b_ml.ml_mfp = mfp;
292 buf->b_ml.ml_flags = ML_EMPTY;
293 buf->b_ml.ml_line_count = 1;
Bram Moolenaar592e0a22004-07-03 16:05:59 +0000294#ifdef FEAT_LINEBREAK
295 curwin->w_nrwidth_line_count = 0;
296#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297
298#if defined(MSDOS) && !defined(DJGPP)
299 /* for 16 bit MS-DOS create a swapfile now, because we run out of
300 * memory very quickly */
301 if (p_uc != 0)
Bram Moolenaar4770d092006-01-12 23:22:24 +0000302 ml_open_file(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000303#endif
304
305/*
306 * fill block0 struct and write page 0
307 */
308 if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
309 goto error;
310 if (hp->bh_bnum != 0)
311 {
312 EMSG(_("E298: Didn't get block nr 0?"));
313 goto error;
314 }
315 b0p = (ZERO_BL *)(hp->bh_data);
316
317 b0p->b0_id[0] = BLOCK0_ID0;
318 b0p->b0_id[1] = BLOCK0_ID1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 b0p->b0_magic_long = (long)B0_MAGIC_LONG;
320 b0p->b0_magic_int = (int)B0_MAGIC_INT;
321 b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
322 b0p->b0_magic_char = B0_MAGIC_CHAR;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000323 STRNCPY(b0p->b0_version, "VIM ", 4);
324 STRNCPY(b0p->b0_version + 4, Version, 6);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000325 long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000326
Bram Moolenaar76b92b22006-03-24 22:46:53 +0000327#ifdef FEAT_SPELL
328 if (!buf->b_spell)
329#endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000330 {
331 b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
332 b0p->b0_flags = get_fileformat(buf) + 1;
333 set_b0_fname(b0p, buf);
334 (void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
335 b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
336 mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
337 b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
338 long_to_char(mch_get_pid(), b0p->b0_pid);
339 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000340
341 /*
342 * Always sync block number 0 to disk, so we can check the file name in
Bram Moolenaar4770d092006-01-12 23:22:24 +0000343 * the swap file in findswapname(). Don't do this for help files though
344 * and spell buffer though.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000345 * Only works when there's a swapfile, otherwise it's done when the file
346 * is created.
347 */
348 mf_put(mfp, hp, TRUE, FALSE);
Bram Moolenaar4770d092006-01-12 23:22:24 +0000349 if (!buf->b_help && !B_SPELL(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 (void)mf_sync(mfp, 0);
351
Bram Moolenaar4770d092006-01-12 23:22:24 +0000352 /*
353 * Fill in root pointer block and write page 1.
354 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355 if ((hp = ml_new_ptr(mfp)) == NULL)
356 goto error;
357 if (hp->bh_bnum != 1)
358 {
359 EMSG(_("E298: Didn't get block nr 1?"));
360 goto error;
361 }
362 pp = (PTR_BL *)(hp->bh_data);
363 pp->pb_count = 1;
364 pp->pb_pointer[0].pe_bnum = 2;
365 pp->pb_pointer[0].pe_page_count = 1;
366 pp->pb_pointer[0].pe_old_lnum = 1;
367 pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */
368 mf_put(mfp, hp, TRUE, FALSE);
369
Bram Moolenaar4770d092006-01-12 23:22:24 +0000370 /*
371 * Allocate first data block and create an empty line 1.
372 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
374 goto error;
375 if (hp->bh_bnum != 2)
376 {
377 EMSG(_("E298: Didn't get block nr 2?"));
378 goto error;
379 }
380
381 dp = (DATA_BL *)(hp->bh_data);
382 dp->db_index[0] = --dp->db_txt_start; /* at end of block */
383 dp->db_free -= 1 + INDEX_SIZE;
384 dp->db_line_count = 1;
Bram Moolenaarf05da212009-11-17 16:13:15 +0000385 *((char_u *)dp + dp->db_txt_start) = NUL; /* empty line */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386
387 return OK;
388
389error:
390 if (mfp != NULL)
391 {
392 if (hp)
393 mf_put(mfp, hp, FALSE, FALSE);
394 mf_close(mfp, TRUE); /* will also free(mfp->mf_fname) */
395 }
Bram Moolenaar4770d092006-01-12 23:22:24 +0000396 buf->b_ml.ml_mfp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397 return FAIL;
398}
399
400/*
401 * ml_setname() is called when the file name of "buf" has been changed.
402 * It may rename the swap file.
403 */
404 void
405ml_setname(buf)
406 buf_T *buf;
407{
408 int success = FALSE;
409 memfile_T *mfp;
410 char_u *fname;
411 char_u *dirp;
412#if defined(MSDOS) || defined(MSWIN)
413 char_u *p;
414#endif
415
416 mfp = buf->b_ml.ml_mfp;
417 if (mfp->mf_fd < 0) /* there is no swap file yet */
418 {
419 /*
420 * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
421 * For help files we will make a swap file now.
422 */
423 if (p_uc != 0)
424 ml_open_file(buf); /* create a swap file */
425 return;
426 }
427
428 /*
429 * Try all directories in the 'directory' option.
430 */
431 dirp = p_dir;
432 for (;;)
433 {
434 if (*dirp == NUL) /* tried all directories, fail */
435 break;
Bram Moolenaar8fc061c2004-12-29 21:03:02 +0000436 fname = findswapname(buf, &dirp, mfp->mf_fname);
437 /* alloc's fname */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 if (fname == NULL) /* no file name found for this dir */
439 continue;
440
441#if defined(MSDOS) || defined(MSWIN)
442 /*
443 * Set full pathname for swap file now, because a ":!cd dir" may
444 * change directory without us knowing it.
445 */
446 p = FullName_save(fname, FALSE);
447 vim_free(fname);
448 fname = p;
449 if (fname == NULL)
450 continue;
451#endif
452 /* if the file name is the same we don't have to do anything */
453 if (fnamecmp(fname, mfp->mf_fname) == 0)
454 {
455 vim_free(fname);
456 success = TRUE;
457 break;
458 }
459 /* need to close the swap file before renaming */
460 if (mfp->mf_fd >= 0)
461 {
462 close(mfp->mf_fd);
463 mfp->mf_fd = -1;
464 }
465
466 /* try to rename the swap file */
467 if (vim_rename(mfp->mf_fname, fname) == 0)
468 {
469 success = TRUE;
470 vim_free(mfp->mf_fname);
471 mfp->mf_fname = fname;
472 vim_free(mfp->mf_ffname);
473#if defined(MSDOS) || defined(MSWIN)
474 mfp->mf_ffname = NULL; /* mf_fname is full pathname already */
475#else
476 mf_set_ffname(mfp);
477#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000478 ml_upd_block0(buf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479 break;
480 }
481 vim_free(fname); /* this fname didn't work, try another */
482 }
483
484 if (mfp->mf_fd == -1) /* need to (re)open the swap file */
485 {
486 mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
487 if (mfp->mf_fd < 0)
488 {
489 /* could not (re)open the swap file, what can we do???? */
490 EMSG(_("E301: Oops, lost the swap file!!!"));
491 return;
492 }
Bram Moolenaarf05da212009-11-17 16:13:15 +0000493#ifdef HAVE_FD_CLOEXEC
494 {
495 int fdflags = fcntl(mfp->mf_fd, F_GETFD);
496 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
497 fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
498 }
499#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 }
501 if (!success)
502 EMSG(_("E302: Could not rename swap file"));
503}
504
505/*
506 * Open a file for the memfile for all buffers that are not readonly or have
507 * been modified.
508 * Used when 'updatecount' changes from zero to non-zero.
509 */
510 void
511ml_open_files()
512{
513 buf_T *buf;
514
515 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
516 if (!buf->b_p_ro || buf->b_changed)
517 ml_open_file(buf);
518}
519
520/*
521 * Open a swap file for an existing memfile, if there is no swap file yet.
522 * If we are unable to find a file name, mf_fname will be NULL
523 * and the memfile will be in memory only (no recovery possible).
524 */
525 void
526ml_open_file(buf)
527 buf_T *buf;
528{
529 memfile_T *mfp;
530 char_u *fname;
531 char_u *dirp;
532
533 mfp = buf->b_ml.ml_mfp;
534 if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf)
535 return; /* nothing to do */
536
Bram Moolenaara1956f62006-03-12 22:18:00 +0000537#ifdef FEAT_SPELL
Bram Moolenaar4770d092006-01-12 23:22:24 +0000538 /* For a spell buffer use a temp file name. */
539 if (buf->b_spell)
540 {
541 fname = vim_tempname('s');
542 if (fname != NULL)
543 (void)mf_open_file(mfp, fname); /* consumes fname! */
544 buf->b_may_swap = FALSE;
545 return;
546 }
547#endif
548
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 /*
550 * Try all directories in 'directory' option.
551 */
552 dirp = p_dir;
553 for (;;)
554 {
555 if (*dirp == NUL)
556 break;
557 /* There is a small chance that between chosing the swap file name and
558 * creating it, another Vim creates the file. In that case the
559 * creation will fail and we will use another directory. */
Bram Moolenaar8fc061c2004-12-29 21:03:02 +0000560 fname = findswapname(buf, &dirp, NULL); /* allocates fname */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561 if (fname == NULL)
562 continue;
563 if (mf_open_file(mfp, fname) == OK) /* consumes fname! */
564 {
565#if defined(MSDOS) || defined(MSWIN) || defined(RISCOS)
566 /*
567 * set full pathname for swap file now, because a ":!cd dir" may
568 * change directory without us knowing it.
569 */
570 mf_fullname(mfp);
571#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000572 ml_upd_block0(buf, FALSE);
573
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 /* Flush block zero, so others can read it */
575 if (mf_sync(mfp, MFS_ZERO) == OK)
Bram Moolenaarc32840f2006-01-14 21:23:38 +0000576 {
577 /* Mark all blocks that should be in the swapfile as dirty.
578 * Needed for when the 'swapfile' option was reset, so that
579 * the swap file was deleted, and then on again. */
580 mf_set_dirty(mfp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581 break;
Bram Moolenaarc32840f2006-01-14 21:23:38 +0000582 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583 /* Writing block 0 failed: close the file and try another dir */
584 mf_close_file(buf, FALSE);
585 }
586 }
587
588 if (mfp->mf_fname == NULL) /* Failed! */
589 {
590 need_wait_return = TRUE; /* call wait_return later */
591 ++no_wait_return;
592 (void)EMSG2(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
593 buf_spname(buf) != NULL
594 ? (char_u *)buf_spname(buf)
595 : buf->b_fname);
596 --no_wait_return;
597 }
598
599 /* don't try to open a swap file again */
600 buf->b_may_swap = FALSE;
601}
602
603/*
604 * If still need to create a swap file, and starting to edit a not-readonly
605 * file, or reading into an existing buffer, create a swap file now.
606 */
607 void
608check_need_swap(newfile)
609 int newfile; /* reading file into new buffer */
610{
611 if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
612 ml_open_file(curbuf);
613}
614
615/*
616 * Close memline for buffer 'buf'.
617 * If 'del_file' is TRUE, delete the swap file
618 */
619 void
620ml_close(buf, del_file)
621 buf_T *buf;
622 int del_file;
623{
624 if (buf->b_ml.ml_mfp == NULL) /* not open */
625 return;
626 mf_close(buf->b_ml.ml_mfp, del_file); /* close the .swp file */
627 if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
628 vim_free(buf->b_ml.ml_line_ptr);
629 vim_free(buf->b_ml.ml_stack);
630#ifdef FEAT_BYTEOFF
631 vim_free(buf->b_ml.ml_chunksize);
632 buf->b_ml.ml_chunksize = NULL;
633#endif
634 buf->b_ml.ml_mfp = NULL;
635
636 /* Reset the "recovered" flag, give the ATTENTION prompt the next time
637 * this buffer is loaded. */
638 buf->b_flags &= ~BF_RECOVERED;
639}
640
641/*
642 * Close all existing memlines and memfiles.
643 * Only used when exiting.
644 * When 'del_file' is TRUE, delete the memfiles.
Bram Moolenaar81bf7082005-02-12 14:31:42 +0000645 * But don't delete files that were ":preserve"d when we are POSIX compatible.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 */
647 void
648ml_close_all(del_file)
649 int del_file;
650{
651 buf_T *buf;
652
653 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
Bram Moolenaar81bf7082005-02-12 14:31:42 +0000654 ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0
655 || vim_strchr(p_cpo, CPO_PRESERVE) == NULL));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656#ifdef TEMPDIRNAMES
657 vim_deltempdir(); /* delete created temp directory */
658#endif
659}
660
661/*
662 * Close all memfiles for not modified buffers.
663 * Only use just before exiting!
664 */
665 void
666ml_close_notmod()
667{
668 buf_T *buf;
669
670 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
671 if (!bufIsChanged(buf))
672 ml_close(buf, TRUE); /* close all not-modified buffers */
673}
674
675/*
676 * Update the timestamp in the .swp file.
677 * Used when the file has been written.
678 */
679 void
680ml_timestamp(buf)
681 buf_T *buf;
682{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000683 ml_upd_block0(buf, TRUE);
684}
685
686/*
687 * Update the timestamp or the B0_SAME_DIR flag of the .swp file.
688 */
689 static void
Bram Moolenaar89d40322006-08-29 15:30:07 +0000690ml_upd_block0(buf, set_fname)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000691 buf_T *buf;
Bram Moolenaar89d40322006-08-29 15:30:07 +0000692 int set_fname;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000693{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694 memfile_T *mfp;
695 bhdr_T *hp;
696 ZERO_BL *b0p;
697
698 mfp = buf->b_ml.ml_mfp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 if (mfp == NULL || (hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
700 return;
701 b0p = (ZERO_BL *)(hp->bh_data);
702 if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000703 EMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 else
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000705 {
Bram Moolenaar89d40322006-08-29 15:30:07 +0000706 if (set_fname)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000707 set_b0_fname(b0p, buf);
708 else
709 set_b0_dir_flag(b0p, buf);
710 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 mf_put(mfp, hp, TRUE, FALSE);
712}
713
714/*
715 * Write file name and timestamp into block 0 of a swap file.
716 * Also set buf->b_mtime.
717 * Don't use NameBuff[]!!!
718 */
719 static void
720set_b0_fname(b0p, buf)
721 ZERO_BL *b0p;
722 buf_T *buf;
723{
724 struct stat st;
725
726 if (buf->b_ffname == NULL)
727 b0p->b0_fname[0] = NUL;
728 else
729 {
730#if defined(MSDOS) || defined(MSWIN) || defined(AMIGA) || defined(RISCOS)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000731 /* Systems that cannot translate "~user" back into a path: copy the
732 * file name unmodified. Do use slashes instead of backslashes for
733 * portability. */
Bram Moolenaarce0842a2005-07-18 21:58:11 +0000734 vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE - 1);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000735# ifdef BACKSLASH_IN_FILENAME
736 forward_slash(b0p->b0_fname);
737# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738#else
739 size_t flen, ulen;
740 char_u uname[B0_UNAME_SIZE];
741
742 /*
743 * For a file under the home directory of the current user, we try to
744 * replace the home directory path with "~user". This helps when
745 * editing the same file on different machines over a network.
746 * First replace home dir path with "~/" with home_replace().
747 * Then insert the user name to get "~user/".
748 */
749 home_replace(NULL, buf->b_ffname, b0p->b0_fname, B0_FNAME_SIZE, TRUE);
750 if (b0p->b0_fname[0] == '~')
751 {
752 flen = STRLEN(b0p->b0_fname);
753 /* If there is no user name or it is too long, don't use "~/" */
754 if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
755 || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
Bram Moolenaarce0842a2005-07-18 21:58:11 +0000756 vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 else
758 {
759 mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
760 mch_memmove(b0p->b0_fname + 1, uname, ulen);
761 }
762 }
763#endif
764 if (mch_stat((char *)buf->b_ffname, &st) >= 0)
765 {
766 long_to_char((long)st.st_mtime, b0p->b0_mtime);
767#ifdef CHECK_INODE
768 long_to_char((long)st.st_ino, b0p->b0_ino);
769#endif
770 buf_store_time(buf, &st, buf->b_ffname);
771 buf->b_mtime_read = buf->b_mtime;
772 }
773 else
774 {
775 long_to_char(0L, b0p->b0_mtime);
776#ifdef CHECK_INODE
777 long_to_char(0L, b0p->b0_ino);
778#endif
779 buf->b_mtime = 0;
780 buf->b_mtime_read = 0;
781 buf->b_orig_size = 0;
782 buf->b_orig_mode = 0;
783 }
784 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000785
786#ifdef FEAT_MBYTE
787 /* Also add the 'fileencoding' if there is room. */
788 add_b0_fenc(b0p, curbuf);
789#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790}
791
792/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000793 * Update the B0_SAME_DIR flag of the swap file. It's set if the file and the
794 * swapfile for "buf" are in the same directory.
795 * This is fail safe: if we are not sure the directories are equal the flag is
796 * not set.
797 */
798 static void
799set_b0_dir_flag(b0p, buf)
800 ZERO_BL *b0p;
801 buf_T *buf;
802{
803 if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
804 b0p->b0_flags |= B0_SAME_DIR;
805 else
806 b0p->b0_flags &= ~B0_SAME_DIR;
807}
808
809#ifdef FEAT_MBYTE
810/*
811 * When there is room, add the 'fileencoding' to block zero.
812 */
813 static void
814add_b0_fenc(b0p, buf)
815 ZERO_BL *b0p;
816 buf_T *buf;
817{
818 int n;
819
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000820 n = (int)STRLEN(buf->b_p_fenc);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000821 if (STRLEN(b0p->b0_fname) + n + 1 > B0_FNAME_SIZE)
822 b0p->b0_flags &= ~B0_HAS_FENC;
823 else
824 {
825 mch_memmove((char *)b0p->b0_fname + B0_FNAME_SIZE - n,
826 (char *)buf->b_p_fenc, (size_t)n);
827 *(b0p->b0_fname + B0_FNAME_SIZE - n - 1) = NUL;
828 b0p->b0_flags |= B0_HAS_FENC;
829 }
830}
831#endif
832
833
834/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 * try to recover curbuf from the .swp file
836 */
837 void
838ml_recover()
839{
840 buf_T *buf = NULL;
841 memfile_T *mfp = NULL;
842 char_u *fname;
843 bhdr_T *hp = NULL;
844 ZERO_BL *b0p;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000845 int b0_ff;
846 char_u *b0_fenc = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 PTR_BL *pp;
848 DATA_BL *dp;
849 infoptr_T *ip;
850 blocknr_T bnum;
851 int page_count;
852 struct stat org_stat, swp_stat;
853 int len;
854 int directly;
855 linenr_T lnum;
856 char_u *p;
857 int i;
858 long error;
859 int cannot_open;
860 linenr_T line_count;
861 int has_error;
862 int idx;
863 int top;
864 int txt_start;
865 off_t size;
866 int called_from_main;
867 int serious_error = TRUE;
868 long mtime;
869 int attr;
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +0200870 int orig_file_status = NOTDONE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871
872 recoverymode = TRUE;
873 called_from_main = (curbuf->b_ml.ml_mfp == NULL);
874 attr = hl_attr(HLF_E);
Bram Moolenaard0ba34a2009-11-03 12:06:23 +0000875
876 /*
877 * If the file name ends in ".s[uvw][a-z]" we assume this is the swap file.
878 * Otherwise a search is done to find the swap file(s).
879 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 fname = curbuf->b_fname;
881 if (fname == NULL) /* When there is no file name */
882 fname = (char_u *)"";
883 len = (int)STRLEN(fname);
884 if (len >= 4 &&
885#if defined(VMS) || defined(RISCOS)
Bram Moolenaard0ba34a2009-11-03 12:06:23 +0000886 STRNICMP(fname + len - 4, "_s" , 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887#else
Bram Moolenaard0ba34a2009-11-03 12:06:23 +0000888 STRNICMP(fname + len - 4, ".s" , 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889#endif
Bram Moolenaard0ba34a2009-11-03 12:06:23 +0000890 == 0
891 && vim_strchr((char_u *)"UVWuvw", fname[len - 2]) != NULL
892 && ASCII_ISALPHA(fname[len - 1]))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 {
894 directly = TRUE;
895 fname = vim_strsave(fname); /* make a copy for mf_open() */
896 }
897 else
898 {
899 directly = FALSE;
900
901 /* count the number of matching swap files */
902 len = recover_names(&fname, FALSE, 0);
903 if (len == 0) /* no swap files found */
904 {
905 EMSG2(_("E305: No swap file found for %s"), fname);
906 goto theend;
907 }
908 if (len == 1) /* one swap file found, use it */
909 i = 1;
910 else /* several swap files found, choose */
911 {
912 /* list the names of the swap files */
913 (void)recover_names(&fname, TRUE, 0);
914 msg_putchar('\n');
915 MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +0000916 i = get_number(FALSE, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 if (i < 1 || i > len)
918 goto theend;
919 }
920 /* get the swap file name that will be used */
921 (void)recover_names(&fname, FALSE, i);
922 }
923 if (fname == NULL)
924 goto theend; /* out of memory */
925
926 /* When called from main() still need to initialize storage structure */
Bram Moolenaar4770d092006-01-12 23:22:24 +0000927 if (called_from_main && ml_open(curbuf) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 getout(1);
929
930/*
931 * allocate a buffer structure (only the memline in it is really used)
932 */
933 buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
934 if (buf == NULL)
935 {
936 vim_free(fname);
937 goto theend;
938 }
939
940/*
941 * init fields in memline struct
942 */
943 buf->b_ml.ml_stack_size = 0; /* no stack yet */
944 buf->b_ml.ml_stack = NULL; /* no stack yet */
945 buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
946 buf->b_ml.ml_line_lnum = 0; /* no cached line */
947 buf->b_ml.ml_locked = NULL; /* no locked block */
948 buf->b_ml.ml_flags = 0;
949
950/*
951 * open the memfile from the old swap file
952 */
953 p = vim_strsave(fname); /* save fname for the message
954 (mf_open() may free fname) */
955 mfp = mf_open(fname, O_RDONLY); /* consumes fname! */
956 if (mfp == NULL || mfp->mf_fd < 0)
957 {
958 if (p != NULL)
959 {
960 EMSG2(_("E306: Cannot open %s"), p);
961 vim_free(p);
962 }
963 goto theend;
964 }
965 vim_free(p);
966 buf->b_ml.ml_mfp = mfp;
967
968 /*
969 * The page size set in mf_open() might be different from the page size
970 * used in the swap file, we must get it from block 0. But to read block
971 * 0 we need a page size. Use the minimal size for block 0 here, it will
972 * be set to the real value below.
973 */
974 mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
975
976/*
977 * try to read block 0
978 */
979 if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
980 {
981 msg_start();
982 MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
983 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
984 MSG_PUTS_ATTR(
985 _("\nMaybe no changes were made or Vim did not update the swap file."),
986 attr | MSG_HIST);
987 msg_end();
988 goto theend;
989 }
990 b0p = (ZERO_BL *)(hp->bh_data);
991 if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
992 {
993 msg_start();
994 msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
995 MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
996 MSG_HIST);
997 MSG_PUTS_ATTR(_("Use Vim version 3.0.\n"), MSG_HIST);
998 msg_end();
999 goto theend;
1000 }
1001 if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
1002 {
1003 EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
1004 goto theend;
1005 }
1006 if (b0_magic_wrong(b0p))
1007 {
1008 msg_start();
1009 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1010#if defined(MSDOS) || defined(MSWIN)
1011 if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
1012 MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
1013 attr | MSG_HIST);
1014 else
1015#endif
1016 MSG_PUTS_ATTR(_(" cannot be used on this computer.\n"),
1017 attr | MSG_HIST);
1018 MSG_PUTS_ATTR(_("The file was created on "), attr | MSG_HIST);
1019 /* avoid going past the end of a currupted hostname */
1020 b0p->b0_fname[0] = NUL;
1021 MSG_PUTS_ATTR(b0p->b0_hname, attr | MSG_HIST);
1022 MSG_PUTS_ATTR(_(",\nor the file has been damaged."), attr | MSG_HIST);
1023 msg_end();
1024 goto theend;
1025 }
Bram Moolenaar1c536282007-04-26 15:21:56 +00001026
Bram Moolenaar071d4272004-06-13 20:20:40 +00001027 /*
1028 * If we guessed the wrong page size, we have to recalculate the
1029 * highest block number in the file.
1030 */
1031 if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
1032 {
Bram Moolenaar1c536282007-04-26 15:21:56 +00001033 unsigned previous_page_size = mfp->mf_page_size;
1034
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035 mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
Bram Moolenaar1c536282007-04-26 15:21:56 +00001036 if (mfp->mf_page_size < previous_page_size)
1037 {
1038 msg_start();
1039 msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
1040 MSG_PUTS_ATTR(_(" has been damaged (page size is smaller than minimum value).\n"),
1041 attr | MSG_HIST);
1042 msg_end();
1043 goto theend;
1044 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 if ((size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
1046 mfp->mf_blocknr_max = 0; /* no file or empty file */
1047 else
1048 mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
1049 mfp->mf_infile_count = mfp->mf_blocknr_max;
Bram Moolenaar1c536282007-04-26 15:21:56 +00001050
1051 /* need to reallocate the memory used to store the data */
1052 p = alloc(mfp->mf_page_size);
1053 if (p == NULL)
1054 goto theend;
1055 mch_memmove(p, hp->bh_data, previous_page_size);
1056 vim_free(hp->bh_data);
1057 hp->bh_data = p;
1058 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001059 }
1060
1061/*
1062 * If .swp file name given directly, use name from swap file for buffer.
1063 */
1064 if (directly)
1065 {
1066 expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
1067 if (setfname(curbuf, NameBuff, NULL, TRUE) == FAIL)
1068 goto theend;
1069 }
1070
1071 home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar555b2802005-05-19 21:08:39 +00001072 smsg((char_u *)_("Using swap file \"%s\""), NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073
1074 if (buf_spname(curbuf) != NULL)
1075 STRCPY(NameBuff, buf_spname(curbuf));
1076 else
1077 home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar555b2802005-05-19 21:08:39 +00001078 smsg((char_u *)_("Original file \"%s\""), NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 msg_putchar('\n');
1080
1081/*
1082 * check date of swap file and original file
1083 */
1084 mtime = char_to_long(b0p->b0_mtime);
1085 if (curbuf->b_ffname != NULL
1086 && mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
1087 && ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
1088 && org_stat.st_mtime > swp_stat.st_mtime)
1089 || org_stat.st_mtime != mtime))
1090 {
1091 EMSG(_("E308: Warning: Original file may have been changed"));
1092 }
1093 out_flush();
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001094
1095 /* Get the 'fileformat' and 'fileencoding' from block zero. */
1096 b0_ff = (b0p->b0_flags & B0_FF_MASK);
1097 if (b0p->b0_flags & B0_HAS_FENC)
1098 {
1099 for (p = b0p->b0_fname + B0_FNAME_SIZE;
1100 p > b0p->b0_fname && p[-1] != NUL; --p)
1101 ;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001102 b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + B0_FNAME_SIZE - p));
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001103 }
1104
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
1106 hp = NULL;
1107
1108 /*
1109 * Now that we are sure that the file is going to be recovered, clear the
1110 * contents of the current buffer.
1111 */
1112 while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
1113 ml_delete((linenr_T)1, FALSE);
1114
1115 /*
1116 * Try reading the original file to obtain the values of 'fileformat',
1117 * 'fileencoding', etc. Ignore errors. The text itself is not used.
1118 */
1119 if (curbuf->b_ffname != NULL)
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001120 orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001122
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001123 /* Use the 'fileformat' and 'fileencoding' as stored in the swap file. */
1124 if (b0_ff != 0)
1125 set_fileformat(b0_ff - 1, OPT_LOCAL);
1126 if (b0_fenc != NULL)
1127 {
1128 set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
1129 vim_free(b0_fenc);
1130 }
1131 unchanged(curbuf, TRUE);
1132
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 bnum = 1; /* start with block 1 */
1134 page_count = 1; /* which is 1 page */
1135 lnum = 0; /* append after line 0 in curbuf */
1136 line_count = 0;
1137 idx = 0; /* start with first index in block 1 */
1138 error = 0;
1139 buf->b_ml.ml_stack_top = 0;
1140 buf->b_ml.ml_stack = NULL;
1141 buf->b_ml.ml_stack_size = 0; /* no stack yet */
1142
1143 if (curbuf->b_ffname == NULL)
1144 cannot_open = TRUE;
1145 else
1146 cannot_open = FALSE;
1147
1148 serious_error = FALSE;
1149 for ( ; !got_int; line_breakcheck())
1150 {
1151 if (hp != NULL)
1152 mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
1153
1154 /*
1155 * get block
1156 */
1157 if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
1158 {
1159 if (bnum == 1)
1160 {
1161 EMSG2(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
1162 goto theend;
1163 }
1164 ++error;
1165 ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
1166 (colnr_T)0, TRUE);
1167 }
1168 else /* there is a block */
1169 {
1170 pp = (PTR_BL *)(hp->bh_data);
1171 if (pp->pb_id == PTR_ID) /* it is a pointer block */
1172 {
1173 /* check line count when using pointer block first time */
1174 if (idx == 0 && line_count != 0)
1175 {
1176 for (i = 0; i < (int)pp->pb_count; ++i)
1177 line_count -= pp->pb_pointer[i].pe_line_count;
1178 if (line_count != 0)
1179 {
1180 ++error;
1181 ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
1182 (colnr_T)0, TRUE);
1183 }
1184 }
1185
1186 if (pp->pb_count == 0)
1187 {
1188 ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
1189 (colnr_T)0, TRUE);
1190 ++error;
1191 }
1192 else if (idx < (int)pp->pb_count) /* go a block deeper */
1193 {
1194 if (pp->pb_pointer[idx].pe_bnum < 0)
1195 {
1196 /*
1197 * Data block with negative block number.
1198 * Try to read lines from the original file.
1199 * This is slow, but it works.
1200 */
1201 if (!cannot_open)
1202 {
1203 line_count = pp->pb_pointer[idx].pe_line_count;
1204 if (readfile(curbuf->b_ffname, NULL, lnum,
1205 pp->pb_pointer[idx].pe_old_lnum - 1,
1206 line_count, NULL, 0) == FAIL)
1207 cannot_open = TRUE;
1208 else
1209 lnum += line_count;
1210 }
1211 if (cannot_open)
1212 {
1213 ++error;
1214 ml_append(lnum++, (char_u *)_("???LINES MISSING"),
1215 (colnr_T)0, TRUE);
1216 }
1217 ++idx; /* get same block again for next index */
1218 continue;
1219 }
1220
1221 /*
1222 * going one block deeper in the tree
1223 */
1224 if ((top = ml_add_stack(buf)) < 0) /* new entry in stack */
1225 {
1226 ++error;
1227 break; /* out of memory */
1228 }
1229 ip = &(buf->b_ml.ml_stack[top]);
1230 ip->ip_bnum = bnum;
1231 ip->ip_index = idx;
1232
1233 bnum = pp->pb_pointer[idx].pe_bnum;
1234 line_count = pp->pb_pointer[idx].pe_line_count;
1235 page_count = pp->pb_pointer[idx].pe_page_count;
1236 continue;
1237 }
1238 }
1239 else /* not a pointer block */
1240 {
1241 dp = (DATA_BL *)(hp->bh_data);
1242 if (dp->db_id != DATA_ID) /* block id wrong */
1243 {
1244 if (bnum == 1)
1245 {
1246 EMSG2(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
1247 mfp->mf_fname);
1248 goto theend;
1249 }
1250 ++error;
1251 ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
1252 (colnr_T)0, TRUE);
1253 }
1254 else
1255 {
1256 /*
1257 * it is a data block
1258 * Append all the lines in this block
1259 */
1260 has_error = FALSE;
1261 /*
1262 * check length of block
1263 * if wrong, use length in pointer block
1264 */
1265 if (page_count * mfp->mf_page_size != dp->db_txt_end)
1266 {
1267 ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
1268 (colnr_T)0, TRUE);
1269 ++error;
1270 has_error = TRUE;
1271 dp->db_txt_end = page_count * mfp->mf_page_size;
1272 }
1273
1274 /* make sure there is a NUL at the end of the block */
1275 *((char_u *)dp + dp->db_txt_end - 1) = NUL;
1276
1277 /*
1278 * check number of lines in block
1279 * if wrong, use count in data block
1280 */
1281 if (line_count != dp->db_line_count)
1282 {
1283 ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
1284 (colnr_T)0, TRUE);
1285 ++error;
1286 has_error = TRUE;
1287 }
1288
1289 for (i = 0; i < dp->db_line_count; ++i)
1290 {
1291 txt_start = (dp->db_index[i] & DB_INDEX_MASK);
Bram Moolenaar740885b2009-11-03 14:33:17 +00001292 if (txt_start <= (int)HEADER_SIZE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 || txt_start >= (int)dp->db_txt_end)
1294 {
1295 p = (char_u *)"???";
1296 ++error;
1297 }
1298 else
1299 p = (char_u *)dp + txt_start;
1300 ml_append(lnum++, p, (colnr_T)0, TRUE);
1301 }
1302 if (has_error)
Bram Moolenaar740885b2009-11-03 14:33:17 +00001303 ml_append(lnum++, (char_u *)_("???END"),
1304 (colnr_T)0, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 }
1306 }
1307 }
1308
1309 if (buf->b_ml.ml_stack_top == 0) /* finished */
1310 break;
1311
1312 /*
1313 * go one block up in the tree
1314 */
1315 ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
1316 bnum = ip->ip_bnum;
1317 idx = ip->ip_index + 1; /* go to next index */
1318 page_count = 1;
1319 }
1320
1321 /*
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001322 * Compare the buffer contents with the original file. When they differ
1323 * set the 'modified' flag.
1324 * Lines 1 - lnum are the new contents.
1325 * Lines lnum + 1 to ml_line_count are the original contents.
1326 * Line ml_line_count + 1 in the dummy empty line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327 */
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001328 if (orig_file_status != OK || curbuf->b_ml.ml_line_count != lnum * 2 + 1)
1329 {
1330 /* Recovering an empty file results in two lines and the first line is
1331 * empty. Don't set the modified flag then. */
1332 if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL))
1333 {
1334 changed_int();
1335 ++curbuf->b_changedtick;
1336 }
1337 }
1338 else
1339 {
1340 for (idx = 1; idx <= lnum; ++idx)
1341 {
1342 /* Need to copy one line, fetching the other one may flush it. */
1343 p = vim_strsave(ml_get(idx));
1344 i = STRCMP(p, ml_get(idx + lnum));
1345 vim_free(p);
1346 if (i != 0)
1347 {
1348 changed_int();
1349 ++curbuf->b_changedtick;
1350 break;
1351 }
1352 }
1353 }
1354
1355 /*
1356 * Delete the lines from the original file and the dummy line from the
1357 * empty buffer. These will now be after the last line in the buffer.
1358 */
1359 while (curbuf->b_ml.ml_line_count > lnum
1360 && !(curbuf->b_ml.ml_flags & ML_EMPTY))
1361 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362 curbuf->b_flags |= BF_RECOVERED;
1363
1364 recoverymode = FALSE;
1365 if (got_int)
1366 EMSG(_("E311: Recovery Interrupted"));
1367 else if (error)
1368 {
1369 ++no_wait_return;
1370 MSG(">>>>>>>>>>>>>");
1371 EMSG(_("E312: Errors detected while recovering; look for lines starting with ???"));
1372 --no_wait_return;
1373 MSG(_("See \":help E312\" for more information."));
1374 MSG(">>>>>>>>>>>>>");
1375 }
1376 else
1377 {
Bram Moolenaarfc2d5bd2010-05-15 17:06:53 +02001378 if (curbuf->b_changed)
1379 {
1380 MSG(_("Recovery completed. You should check if everything is OK."));
1381 MSG_PUTS(_("\n(You might want to write out this file under another name\n"));
1382 MSG_PUTS(_("and run diff with the original file to check for changes)"));
1383 }
1384 else
1385 MSG(_("Recovery completed. Buffer contents equals file contents."));
1386 MSG_PUTS(_("\nYou may want to delete the .swp file now.\n\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001387 cmdline_row = msg_row;
1388 }
1389 redraw_curbuf_later(NOT_VALID);
1390
1391theend:
1392 recoverymode = FALSE;
1393 if (mfp != NULL)
1394 {
1395 if (hp != NULL)
1396 mf_put(mfp, hp, FALSE, FALSE);
1397 mf_close(mfp, FALSE); /* will also vim_free(mfp->mf_fname) */
1398 }
Bram Moolenaardf88dda2007-01-09 13:34:50 +00001399 if (buf != NULL)
1400 {
1401 vim_free(buf->b_ml.ml_stack);
1402 vim_free(buf);
1403 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001404 if (serious_error && called_from_main)
1405 ml_close(curbuf, TRUE);
1406#ifdef FEAT_AUTOCMD
1407 else
1408 {
1409 apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
1410 apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
1411 }
1412#endif
1413 return;
1414}
1415
1416/*
1417 * Find the names of swap files in current directory and the directory given
1418 * with the 'directory' option.
1419 *
1420 * Used to:
1421 * - list the swap files for "vim -r"
1422 * - count the number of swap files when recovering
1423 * - list the swap files when recovering
1424 * - find the name of the n'th swap file when recovering
1425 */
1426 int
1427recover_names(fname, list, nr)
1428 char_u **fname; /* base for swap file name */
1429 int list; /* when TRUE, list the swap file names */
1430 int nr; /* when non-zero, return nr'th swap file name */
1431{
1432 int num_names;
1433 char_u *(names[6]);
1434 char_u *tail;
1435 char_u *p;
1436 int num_files;
1437 int file_count = 0;
1438 char_u **files;
1439 int i;
1440 char_u *dirp;
1441 char_u *dir_name;
Bram Moolenaar64354da2010-05-25 21:37:17 +02001442 char_u *fname_res = NULL;
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001443#ifdef HAVE_READLINK
1444 char_u fname_buf[MAXPATHL];
Bram Moolenaar64354da2010-05-25 21:37:17 +02001445#endif
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001446
Bram Moolenaar64354da2010-05-25 21:37:17 +02001447 if (fname != NULL)
1448 {
1449#ifdef HAVE_READLINK
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001450 /* Expand symlink in the file name, because the swap file is created with
1451 * the actual file instead of with the symlink. */
1452 if (resolve_symlink(*fname, fname_buf) == OK)
1453 fname_res = fname_buf;
Bram Moolenaar64354da2010-05-25 21:37:17 +02001454 else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001455#endif
Bram Moolenaar64354da2010-05-25 21:37:17 +02001456 fname_res = *fname;
1457 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001458
1459 if (list)
1460 {
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001461 /* use msg() to start the scrolling properly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462 msg((char_u *)_("Swap files found:"));
1463 msg_putchar('\n');
1464 }
1465
1466 /*
1467 * Do the loop for every directory in 'directory'.
1468 * First allocate some memory to put the directory name in.
1469 */
1470 dir_name = alloc((unsigned)STRLEN(p_dir) + 1);
1471 dirp = p_dir;
1472 while (dir_name != NULL && *dirp)
1473 {
1474 /*
1475 * Isolate a directory name from *dirp and put it in dir_name (we know
1476 * it is large enough, so use 31000 for length).
1477 * Advance dirp to next directory name.
1478 */
1479 (void)copy_option_part(&dirp, dir_name, 31000, ",");
1480
1481 if (dir_name[0] == '.' && dir_name[1] == NUL) /* check current dir */
1482 {
1483 if (fname == NULL || *fname == NULL)
1484 {
1485#ifdef VMS
1486 names[0] = vim_strsave((char_u *)"*_sw%");
1487#else
1488# ifdef RISCOS
1489 names[0] = vim_strsave((char_u *)"*_sw#");
1490# else
1491 names[0] = vim_strsave((char_u *)"*.sw?");
1492# endif
1493#endif
Bram Moolenaar2cc93182006-10-10 19:56:03 +00001494#if defined(UNIX) || defined(WIN3264)
1495 /* For Unix names starting with a dot are special. MS-Windows
1496 * supports this too, on some file systems. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001497 names[1] = vim_strsave((char_u *)".*.sw?");
1498 names[2] = vim_strsave((char_u *)".sw?");
1499 num_names = 3;
1500#else
1501# ifdef VMS
1502 names[1] = vim_strsave((char_u *)".*_sw%");
1503 num_names = 2;
1504# else
1505 num_names = 1;
1506# endif
1507#endif
1508 }
1509 else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001510 num_names = recov_file_names(names, fname_res, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511 }
1512 else /* check directory dir_name */
1513 {
1514 if (fname == NULL || *fname == NULL)
1515 {
1516#ifdef VMS
1517 names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
1518#else
1519# ifdef RISCOS
1520 names[0] = concat_fnames(dir_name, (char_u *)"*_sw#", TRUE);
1521# else
1522 names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
1523# endif
1524#endif
Bram Moolenaar2cc93182006-10-10 19:56:03 +00001525#if defined(UNIX) || defined(WIN3264)
1526 /* For Unix names starting with a dot are special. MS-Windows
1527 * supports this too, on some file systems. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528 names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
1529 names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
1530 num_names = 3;
1531#else
1532# ifdef VMS
1533 names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
1534 num_names = 2;
1535# else
1536 num_names = 1;
1537# endif
1538#endif
1539 }
1540 else
1541 {
1542#if defined(UNIX) || defined(WIN3264)
1543 p = dir_name + STRLEN(dir_name);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001544 if (after_pathsep(dir_name, p) && p[-1] == p[-2])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545 {
1546 /* Ends with '//', Use Full path for swap name */
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001547 tail = make_percent_swname(dir_name, fname_res);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548 }
1549 else
1550#endif
1551 {
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001552 tail = gettail(fname_res);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553 tail = concat_fnames(dir_name, tail, TRUE);
1554 }
1555 if (tail == NULL)
1556 num_names = 0;
1557 else
1558 {
1559 num_names = recov_file_names(names, tail, FALSE);
1560 vim_free(tail);
1561 }
1562 }
1563 }
1564
1565 /* check for out-of-memory */
1566 for (i = 0; i < num_names; ++i)
1567 {
1568 if (names[i] == NULL)
1569 {
1570 for (i = 0; i < num_names; ++i)
1571 vim_free(names[i]);
1572 num_names = 0;
1573 }
1574 }
1575 if (num_names == 0)
1576 num_files = 0;
1577 else if (expand_wildcards(num_names, names, &num_files, &files,
1578 EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
1579 num_files = 0;
1580
1581 /*
1582 * When no swap file found, wildcard expansion might have failed (e.g.
1583 * not able to execute the shell).
1584 * Try finding a swap file by simply adding ".swp" to the file name.
1585 */
1586 if (*dirp == NUL && file_count + num_files == 0
1587 && fname != NULL && *fname != NULL)
1588 {
1589 struct stat st;
1590 char_u *swapname;
1591
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001592 swapname = modname(fname_res,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593#if defined(VMS) || defined(RISCOS)
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001594 (char_u *)"_swp", FALSE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001595#else
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001596 (char_u *)".swp", TRUE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597#endif
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02001598 );
Bram Moolenaar071d4272004-06-13 20:20:40 +00001599 if (swapname != NULL)
1600 {
1601 if (mch_stat((char *)swapname, &st) != -1) /* It exists! */
1602 {
1603 files = (char_u **)alloc((unsigned)sizeof(char_u *));
1604 if (files != NULL)
1605 {
1606 files[0] = swapname;
1607 swapname = NULL;
1608 num_files = 1;
1609 }
1610 }
1611 vim_free(swapname);
1612 }
1613 }
1614
1615 /*
1616 * remove swapfile name of the current buffer, it must be ignored
1617 */
1618 if (curbuf->b_ml.ml_mfp != NULL
1619 && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
1620 {
1621 for (i = 0; i < num_files; ++i)
1622 if (fullpathcmp(p, files[i], TRUE) & FPC_SAME)
1623 {
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00001624 /* Remove the name from files[i]. Move further entries
1625 * down. When the array becomes empty free it here, since
1626 * FreeWild() won't be called below. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627 vim_free(files[i]);
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00001628 if (--num_files == 0)
1629 vim_free(files);
1630 else
1631 for ( ; i < num_files; ++i)
1632 files[i] = files[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633 }
1634 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001635 if (nr > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 {
1637 file_count += num_files;
1638 if (nr <= file_count)
1639 {
1640 *fname = vim_strsave(files[nr - 1 + num_files - file_count]);
1641 dirp = (char_u *)""; /* stop searching */
1642 }
1643 }
1644 else if (list)
1645 {
1646 if (dir_name[0] == '.' && dir_name[1] == NUL)
1647 {
1648 if (fname == NULL || *fname == NULL)
1649 MSG_PUTS(_(" In current directory:\n"));
1650 else
1651 MSG_PUTS(_(" Using specified name:\n"));
1652 }
1653 else
1654 {
1655 MSG_PUTS(_(" In directory "));
1656 msg_home_replace(dir_name);
1657 MSG_PUTS(":\n");
1658 }
1659
1660 if (num_files)
1661 {
1662 for (i = 0; i < num_files; ++i)
1663 {
1664 /* print the swap file name */
1665 msg_outnum((long)++file_count);
1666 MSG_PUTS(". ");
1667 msg_puts(gettail(files[i]));
1668 msg_putchar('\n');
1669 (void)swapfile_info(files[i]);
1670 }
1671 }
1672 else
1673 MSG_PUTS(_(" -- none --\n"));
1674 out_flush();
1675 }
1676 else
1677 file_count += num_files;
1678
1679 for (i = 0; i < num_names; ++i)
1680 vim_free(names[i]);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001681 if (num_files > 0)
1682 FreeWild(num_files, files);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001683 }
1684 vim_free(dir_name);
1685 return file_count;
1686}
1687
1688#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
1689/*
1690 * Append the full path to name with path separators made into percent
1691 * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
1692 */
1693 static char_u *
1694make_percent_swname(dir, name)
1695 char_u *dir;
1696 char_u *name;
1697{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001698 char_u *d, *s, *f;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699
1700 f = fix_fname(name != NULL ? name : (char_u *) "");
1701 d = NULL;
1702 if (f != NULL)
1703 {
1704 s = alloc((unsigned)(STRLEN(f) + 1));
1705 if (s != NULL)
1706 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001707 STRCPY(s, f);
1708 for (d = s; *d != NUL; mb_ptr_adv(d))
1709 if (vim_ispathsep(*d))
1710 *d = '%';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 d = concat_fnames(dir, s, TRUE);
1712 vim_free(s);
1713 }
1714 vim_free(f);
1715 }
1716 return d;
1717}
1718#endif
1719
1720#if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
1721static int process_still_running;
1722#endif
1723
1724/*
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00001725 * Give information about an existing swap file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001726 * Returns timestamp (0 when unknown).
1727 */
1728 static time_t
1729swapfile_info(fname)
1730 char_u *fname;
1731{
1732 struct stat st;
1733 int fd;
1734 struct block0 b0;
1735 time_t x = (time_t)0;
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00001736 char *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737#ifdef UNIX
1738 char_u uname[B0_UNAME_SIZE];
1739#endif
1740
1741 /* print the swap file date */
1742 if (mch_stat((char *)fname, &st) != -1)
1743 {
1744#ifdef UNIX
1745 /* print name of owner of the file */
1746 if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
1747 {
1748 MSG_PUTS(_(" owned by: "));
1749 msg_outtrans(uname);
1750 MSG_PUTS(_(" dated: "));
1751 }
1752 else
1753#endif
1754 MSG_PUTS(_(" dated: "));
1755 x = st.st_mtime; /* Manx C can't do &st.st_mtime */
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00001756 p = ctime(&x); /* includes '\n' */
1757 if (p == NULL)
1758 MSG_PUTS("(invalid)\n");
1759 else
1760 MSG_PUTS(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 }
1762
1763 /*
1764 * print the original file name
1765 */
1766 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
1767 if (fd >= 0)
1768 {
1769 if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
1770 {
1771 if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
1772 {
1773 MSG_PUTS(_(" [from Vim version 3.0]"));
1774 }
1775 else if (b0.b0_id[0] != BLOCK0_ID0 || b0.b0_id[1] != BLOCK0_ID1)
1776 {
1777 MSG_PUTS(_(" [does not look like a Vim swap file]"));
1778 }
1779 else
1780 {
1781 MSG_PUTS(_(" file name: "));
1782 if (b0.b0_fname[0] == NUL)
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001783 MSG_PUTS(_("[No Name]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784 else
1785 msg_outtrans(b0.b0_fname);
1786
1787 MSG_PUTS(_("\n modified: "));
1788 MSG_PUTS(b0.b0_dirty ? _("YES") : _("no"));
1789
1790 if (*(b0.b0_uname) != NUL)
1791 {
1792 MSG_PUTS(_("\n user name: "));
1793 msg_outtrans(b0.b0_uname);
1794 }
1795
1796 if (*(b0.b0_hname) != NUL)
1797 {
1798 if (*(b0.b0_uname) != NUL)
1799 MSG_PUTS(_(" host name: "));
1800 else
1801 MSG_PUTS(_("\n host name: "));
1802 msg_outtrans(b0.b0_hname);
1803 }
1804
1805 if (char_to_long(b0.b0_pid) != 0L)
1806 {
1807 MSG_PUTS(_("\n process ID: "));
1808 msg_outnum(char_to_long(b0.b0_pid));
1809#if defined(UNIX) || defined(__EMX__)
1810 /* EMX kill() not working correctly, it seems */
1811 if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
1812 {
1813 MSG_PUTS(_(" (still running)"));
1814# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1815 process_still_running = TRUE;
1816# endif
1817 }
1818#endif
1819 }
1820
1821 if (b0_magic_wrong(&b0))
1822 {
1823#if defined(MSDOS) || defined(MSWIN)
1824 if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
1825 MSG_PUTS(_("\n [not usable with this version of Vim]"));
1826 else
1827#endif
1828 MSG_PUTS(_("\n [not usable on this computer]"));
1829 }
1830 }
1831 }
1832 else
1833 MSG_PUTS(_(" [cannot be read]"));
1834 close(fd);
1835 }
1836 else
1837 MSG_PUTS(_(" [cannot be opened]"));
1838 msg_putchar('\n');
1839
1840 return x;
1841}
1842
1843 static int
1844recov_file_names(names, path, prepend_dot)
1845 char_u **names;
1846 char_u *path;
1847 int prepend_dot;
1848{
1849 int num_names;
1850
1851#ifdef SHORT_FNAME
1852 /*
1853 * (MS-DOS) always short names
1854 */
1855 names[0] = modname(path, (char_u *)".sw?", FALSE);
1856 num_names = 1;
1857#else /* !SHORT_FNAME */
1858 /*
1859 * (Win32 and Win64) never short names, but do prepend a dot.
1860 * (Not MS-DOS or Win32 or Win64) maybe short name, maybe not: Try both.
1861 * Only use the short name if it is different.
1862 */
1863 char_u *p;
1864 int i;
1865# ifndef WIN3264
1866 int shortname = curbuf->b_shortname;
1867
1868 curbuf->b_shortname = FALSE;
1869# endif
1870
1871 num_names = 0;
1872
1873 /*
1874 * May also add the file name with a dot prepended, for swap file in same
1875 * dir as original file.
1876 */
1877 if (prepend_dot)
1878 {
1879 names[num_names] = modname(path, (char_u *)".sw?", TRUE);
1880 if (names[num_names] == NULL)
1881 goto end;
1882 ++num_names;
1883 }
1884
1885 /*
1886 * Form the normal swap file name pattern by appending ".sw?".
1887 */
1888#ifdef VMS
1889 names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
1890#else
1891# ifdef RISCOS
1892 names[num_names] = concat_fnames(path, (char_u *)"_sw#", FALSE);
1893# else
1894 names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
1895# endif
1896#endif
1897 if (names[num_names] == NULL)
1898 goto end;
1899 if (num_names >= 1) /* check if we have the same name twice */
1900 {
1901 p = names[num_names - 1];
1902 i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
1903 if (i > 0)
1904 p += i; /* file name has been expanded to full path */
1905
1906 if (STRCMP(p, names[num_names]) != 0)
1907 ++num_names;
1908 else
1909 vim_free(names[num_names]);
1910 }
1911 else
1912 ++num_names;
1913
1914# ifndef WIN3264
1915 /*
1916 * Also try with 'shortname' set, in case the file is on a DOS filesystem.
1917 */
1918 curbuf->b_shortname = TRUE;
1919#ifdef VMS
1920 names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
1921#else
1922# ifdef RISCOS
1923 names[num_names] = modname(path, (char_u *)"_sw#", FALSE);
1924# else
1925 names[num_names] = modname(path, (char_u *)".sw?", FALSE);
1926# endif
1927#endif
1928 if (names[num_names] == NULL)
1929 goto end;
1930
1931 /*
1932 * Remove the one from 'shortname', if it's the same as with 'noshortname'.
1933 */
1934 p = names[num_names];
1935 i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
1936 if (i > 0)
1937 p += i; /* file name has been expanded to full path */
1938 if (STRCMP(names[num_names - 1], p) == 0)
1939 vim_free(names[num_names]);
1940 else
1941 ++num_names;
1942# endif
1943
1944end:
1945# ifndef WIN3264
1946 curbuf->b_shortname = shortname;
1947# endif
1948
1949#endif /* !SHORT_FNAME */
1950
1951 return num_names;
1952}
1953
1954/*
1955 * sync all memlines
1956 *
1957 * If 'check_file' is TRUE, check if original file exists and was not changed.
1958 * If 'check_char' is TRUE, stop syncing when character becomes available, but
1959 * always sync at least one block.
1960 */
1961 void
1962ml_sync_all(check_file, check_char)
1963 int check_file;
1964 int check_char;
1965{
1966 buf_T *buf;
1967 struct stat st;
1968
1969 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1970 {
1971 if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
1972 continue; /* no file */
1973
1974 ml_flush_line(buf); /* flush buffered line */
1975 /* flush locked block */
1976 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
1977 if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
1978 && buf->b_ffname != NULL)
1979 {
1980 /*
1981 * If the original file does not exist anymore or has been changed
1982 * call ml_preserve() to get rid of all negative numbered blocks.
1983 */
1984 if (mch_stat((char *)buf->b_ffname, &st) == -1
1985 || st.st_mtime != buf->b_mtime_read
Bram Moolenaar914703b2010-05-31 21:59:46 +02001986 || st.st_size != buf->b_orig_size)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 {
1988 ml_preserve(buf, FALSE);
1989 did_check_timestamps = FALSE;
1990 need_check_timestamps = TRUE; /* give message later */
1991 }
1992 }
1993 if (buf->b_ml.ml_mfp->mf_dirty)
1994 {
1995 (void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
1996 | (bufIsChanged(buf) ? MFS_FLUSH : 0));
1997 if (check_char && ui_char_avail()) /* character available now */
1998 break;
1999 }
2000 }
2001}
2002
2003/*
2004 * sync one buffer, including negative blocks
2005 *
2006 * after this all the blocks are in the swap file
2007 *
2008 * Used for the :preserve command and when the original file has been
2009 * changed or deleted.
2010 *
2011 * when message is TRUE the success of preserving is reported
2012 */
2013 void
2014ml_preserve(buf, message)
2015 buf_T *buf;
2016 int message;
2017{
2018 bhdr_T *hp;
2019 linenr_T lnum;
2020 memfile_T *mfp = buf->b_ml.ml_mfp;
2021 int status;
2022 int got_int_save = got_int;
2023
2024 if (mfp == NULL || mfp->mf_fname == NULL)
2025 {
2026 if (message)
2027 EMSG(_("E313: Cannot preserve, there is no swap file"));
2028 return;
2029 }
2030
2031 /* We only want to stop when interrupted here, not when interrupted
2032 * before. */
2033 got_int = FALSE;
2034
2035 ml_flush_line(buf); /* flush buffered line */
2036 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
2037 status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
2038
2039 /* stack is invalid after mf_sync(.., MFS_ALL) */
2040 buf->b_ml.ml_stack_top = 0;
2041
2042 /*
2043 * Some of the data blocks may have been changed from negative to
2044 * positive block number. In that case the pointer blocks need to be
2045 * updated.
2046 *
2047 * We don't know in which pointer block the references are, so we visit
2048 * all data blocks until there are no more translations to be done (or
2049 * we hit the end of the file, which can only happen in case a write fails,
2050 * e.g. when file system if full).
2051 * ml_find_line() does the work by translating the negative block numbers
2052 * when getting the first line of each data block.
2053 */
2054 if (mf_need_trans(mfp) && !got_int)
2055 {
2056 lnum = 1;
2057 while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
2058 {
2059 hp = ml_find_line(buf, lnum, ML_FIND);
2060 if (hp == NULL)
2061 {
2062 status = FAIL;
2063 goto theend;
2064 }
2065 CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
2066 lnum = buf->b_ml.ml_locked_high + 1;
2067 }
2068 (void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
2069 /* sync the updated pointer blocks */
2070 if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
2071 status = FAIL;
2072 buf->b_ml.ml_stack_top = 0; /* stack is invalid now */
2073 }
2074theend:
2075 got_int |= got_int_save;
2076
2077 if (message)
2078 {
2079 if (status == OK)
2080 MSG(_("File preserved"));
2081 else
2082 EMSG(_("E314: Preserve failed"));
2083 }
2084}
2085
2086/*
2087 * NOTE: The pointer returned by the ml_get_*() functions only remains valid
2088 * until the next call!
2089 * line1 = ml_get(1);
2090 * line2 = ml_get(2); // line1 is now invalid!
2091 * Make a copy of the line if necessary.
2092 */
2093/*
2094 * get a pointer to a (read-only copy of a) line
2095 *
2096 * On failure an error message is given and IObuff is returned (to avoid
2097 * having to check for error everywhere).
2098 */
2099 char_u *
2100ml_get(lnum)
2101 linenr_T lnum;
2102{
2103 return ml_get_buf(curbuf, lnum, FALSE);
2104}
2105
2106/*
2107 * ml_get_pos: get pointer to position 'pos'
2108 */
2109 char_u *
2110ml_get_pos(pos)
2111 pos_T *pos;
2112{
2113 return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
2114}
2115
2116/*
2117 * ml_get_curline: get pointer to cursor line.
2118 */
2119 char_u *
2120ml_get_curline()
2121{
2122 return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
2123}
2124
2125/*
2126 * ml_get_cursor: get pointer to cursor position
2127 */
2128 char_u *
2129ml_get_cursor()
2130{
2131 return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
2132 curwin->w_cursor.col);
2133}
2134
2135/*
2136 * get a pointer to a line in a specific buffer
2137 *
2138 * "will_change": if TRUE mark the buffer dirty (chars in the line will be
2139 * changed)
2140 */
2141 char_u *
2142ml_get_buf(buf, lnum, will_change)
2143 buf_T *buf;
2144 linenr_T lnum;
2145 int will_change; /* line will be changed */
2146{
Bram Moolenaarad40f022007-02-13 03:01:39 +00002147 bhdr_T *hp;
2148 DATA_BL *dp;
2149 char_u *ptr;
2150 static int recursive = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151
2152 if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
2153 {
Bram Moolenaarad40f022007-02-13 03:01:39 +00002154 if (recursive == 0)
2155 {
2156 /* Avoid giving this message for a recursive call, may happen when
2157 * the GUI redraws part of the text. */
2158 ++recursive;
2159 EMSGN(_("E315: ml_get: invalid lnum: %ld"), lnum);
2160 --recursive;
2161 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162errorret:
2163 STRCPY(IObuff, "???");
2164 return IObuff;
2165 }
2166 if (lnum <= 0) /* pretend line 0 is line 1 */
2167 lnum = 1;
2168
2169 if (buf->b_ml.ml_mfp == NULL) /* there are no lines */
2170 return (char_u *)"";
2171
Bram Moolenaar37d619f2010-03-10 14:46:26 +01002172 /*
2173 * See if it is the same line as requested last time.
2174 * Otherwise may need to flush last used line.
2175 * Don't use the last used line when 'swapfile' is reset, need to load all
2176 * blocks.
2177 */
Bram Moolenaar47b8b152007-02-07 02:41:57 +00002178 if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002179 {
2180 ml_flush_line(buf);
2181
2182 /*
2183 * Find the data block containing the line.
2184 * This also fills the stack with the blocks from the root to the data
2185 * block and releases any locked block.
2186 */
2187 if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
2188 {
Bram Moolenaarad40f022007-02-13 03:01:39 +00002189 if (recursive == 0)
2190 {
2191 /* Avoid giving this message for a recursive call, may happen
2192 * when the GUI redraws part of the text. */
2193 ++recursive;
2194 EMSGN(_("E316: ml_get: cannot find line %ld"), lnum);
2195 --recursive;
2196 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 goto errorret;
2198 }
2199
2200 dp = (DATA_BL *)(hp->bh_data);
2201
2202 ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
2203 buf->b_ml.ml_line_ptr = ptr;
2204 buf->b_ml.ml_line_lnum = lnum;
2205 buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
2206 }
2207 if (will_change)
2208 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
2209
2210 return buf->b_ml.ml_line_ptr;
2211}
2212
2213/*
2214 * Check if a line that was just obtained by a call to ml_get
2215 * is in allocated memory.
2216 */
2217 int
2218ml_line_alloced()
2219{
2220 return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
2221}
2222
2223/*
2224 * Append a line after lnum (may be 0 to insert a line in front of the file).
2225 * "line" does not need to be allocated, but can't be another line in a
2226 * buffer, unlocking may make it invalid.
2227 *
2228 * newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
2229 * will be set for recovery
2230 * Check: The caller of this function should probably also call
2231 * appended_lines().
2232 *
2233 * return FAIL for failure, OK otherwise
2234 */
2235 int
2236ml_append(lnum, line, len, newfile)
2237 linenr_T lnum; /* append after this line (can be 0) */
2238 char_u *line; /* text of the new line */
2239 colnr_T len; /* length of new line, including NUL, or 0 */
2240 int newfile; /* flag, see above */
2241{
2242 /* When starting up, we might still need to create the memfile */
2243 if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL) == FAIL)
2244 return FAIL;
2245
2246 if (curbuf->b_ml.ml_line_lnum != 0)
2247 ml_flush_line(curbuf);
2248 return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
2249}
2250
Bram Moolenaara1956f62006-03-12 22:18:00 +00002251#if defined(FEAT_SPELL) || defined(PROTO)
Bram Moolenaar4770d092006-01-12 23:22:24 +00002252/*
2253 * Like ml_append() but for an arbitrary buffer. The buffer must already have
2254 * a memline.
2255 */
2256 int
2257ml_append_buf(buf, lnum, line, len, newfile)
2258 buf_T *buf;
2259 linenr_T lnum; /* append after this line (can be 0) */
2260 char_u *line; /* text of the new line */
2261 colnr_T len; /* length of new line, including NUL, or 0 */
2262 int newfile; /* flag, see above */
2263{
2264 if (buf->b_ml.ml_mfp == NULL)
2265 return FAIL;
2266
2267 if (buf->b_ml.ml_line_lnum != 0)
2268 ml_flush_line(buf);
2269 return ml_append_int(buf, lnum, line, len, newfile, FALSE);
2270}
2271#endif
2272
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273 static int
2274ml_append_int(buf, lnum, line, len, newfile, mark)
2275 buf_T *buf;
2276 linenr_T lnum; /* append after this line (can be 0) */
2277 char_u *line; /* text of the new line */
2278 colnr_T len; /* length of line, including NUL, or 0 */
2279 int newfile; /* flag, see above */
2280 int mark; /* mark the new line */
2281{
2282 int i;
2283 int line_count; /* number of indexes in current block */
2284 int offset;
2285 int from, to;
2286 int space_needed; /* space needed for new line */
2287 int page_size;
2288 int page_count;
2289 int db_idx; /* index for lnum in data block */
2290 bhdr_T *hp;
2291 memfile_T *mfp;
2292 DATA_BL *dp;
2293 PTR_BL *pp;
2294 infoptr_T *ip;
2295
2296 /* lnum out of range */
2297 if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
2298 return FAIL;
2299
2300 if (lowest_marked && lowest_marked > lnum)
2301 lowest_marked = lnum + 1;
2302
2303 if (len == 0)
2304 len = (colnr_T)STRLEN(line) + 1; /* space needed for the text */
2305 space_needed = len + INDEX_SIZE; /* space needed for text + index */
2306
2307 mfp = buf->b_ml.ml_mfp;
2308 page_size = mfp->mf_page_size;
2309
2310/*
2311 * find the data block containing the previous line
2312 * This also fills the stack with the blocks from the root to the data block
2313 * This also releases any locked block.
2314 */
2315 if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
2316 ML_INSERT)) == NULL)
2317 return FAIL;
2318
2319 buf->b_ml.ml_flags &= ~ML_EMPTY;
2320
2321 if (lnum == 0) /* got line one instead, correct db_idx */
2322 db_idx = -1; /* careful, it is negative! */
2323 else
2324 db_idx = lnum - buf->b_ml.ml_locked_low;
2325 /* get line count before the insertion */
2326 line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2327
2328 dp = (DATA_BL *)(hp->bh_data);
2329
2330/*
2331 * If
2332 * - there is not enough room in the current block
2333 * - appending to the last line in the block
2334 * - not appending to the last line in the file
2335 * insert in front of the next block.
2336 */
2337 if ((int)dp->db_free < space_needed && db_idx == line_count - 1
2338 && lnum < buf->b_ml.ml_line_count)
2339 {
2340 /*
2341 * Now that the line is not going to be inserted in the block that we
2342 * expected, the line count has to be adjusted in the pointer blocks
2343 * by using ml_locked_lineadd.
2344 */
2345 --(buf->b_ml.ml_locked_lineadd);
2346 --(buf->b_ml.ml_locked_high);
2347 if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
2348 return FAIL;
2349
2350 db_idx = -1; /* careful, it is negative! */
2351 /* get line count before the insertion */
2352 line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
2353 CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
2354
2355 dp = (DATA_BL *)(hp->bh_data);
2356 }
2357
2358 ++buf->b_ml.ml_line_count;
2359
2360 if ((int)dp->db_free >= space_needed) /* enough room in data block */
2361 {
2362/*
2363 * Insert new line in existing data block, or in data block allocated above.
2364 */
2365 dp->db_txt_start -= len;
2366 dp->db_free -= space_needed;
2367 ++(dp->db_line_count);
2368
2369 /*
2370 * move the text of the lines that follow to the front
2371 * adjust the indexes of the lines that follow
2372 */
2373 if (line_count > db_idx + 1) /* if there are following lines */
2374 {
2375 /*
2376 * Offset is the start of the previous line.
2377 * This will become the character just after the new line.
2378 */
2379 if (db_idx < 0)
2380 offset = dp->db_txt_end;
2381 else
2382 offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
2383 mch_memmove((char *)dp + dp->db_txt_start,
2384 (char *)dp + dp->db_txt_start + len,
2385 (size_t)(offset - (dp->db_txt_start + len)));
2386 for (i = line_count - 1; i > db_idx; --i)
2387 dp->db_index[i + 1] = dp->db_index[i] - len;
2388 dp->db_index[db_idx + 1] = offset - len;
2389 }
2390 else /* add line at the end */
2391 dp->db_index[db_idx + 1] = dp->db_txt_start;
2392
2393 /*
2394 * copy the text into the block
2395 */
2396 mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
2397 if (mark)
2398 dp->db_index[db_idx + 1] |= DB_MARKED;
2399
2400 /*
2401 * Mark the block dirty.
2402 */
2403 buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2404 if (!newfile)
2405 buf->b_ml.ml_flags |= ML_LOCKED_POS;
2406 }
2407 else /* not enough space in data block */
2408 {
2409/*
2410 * If there is not enough room we have to create a new data block and copy some
2411 * lines into it.
2412 * Then we have to insert an entry in the pointer block.
2413 * If this pointer block also is full, we go up another block, and so on, up
2414 * to the root if necessary.
2415 * The line counts in the pointer blocks have already been adjusted by
2416 * ml_find_line().
2417 */
2418 long line_count_left, line_count_right;
2419 int page_count_left, page_count_right;
2420 bhdr_T *hp_left;
2421 bhdr_T *hp_right;
2422 bhdr_T *hp_new;
2423 int lines_moved;
2424 int data_moved = 0; /* init to shut up gcc */
2425 int total_moved = 0; /* init to shut up gcc */
2426 DATA_BL *dp_right, *dp_left;
2427 int stack_idx;
2428 int in_left;
2429 int lineadd;
2430 blocknr_T bnum_left, bnum_right;
2431 linenr_T lnum_left, lnum_right;
2432 int pb_idx;
2433 PTR_BL *pp_new;
2434
2435 /*
2436 * We are going to allocate a new data block. Depending on the
2437 * situation it will be put to the left or right of the existing
2438 * block. If possible we put the new line in the left block and move
2439 * the lines after it to the right block. Otherwise the new line is
2440 * also put in the right block. This method is more efficient when
2441 * inserting a lot of lines at one place.
2442 */
2443 if (db_idx < 0) /* left block is new, right block is existing */
2444 {
2445 lines_moved = 0;
2446 in_left = TRUE;
2447 /* space_needed does not change */
2448 }
2449 else /* left block is existing, right block is new */
2450 {
2451 lines_moved = line_count - db_idx - 1;
2452 if (lines_moved == 0)
2453 in_left = FALSE; /* put new line in right block */
2454 /* space_needed does not change */
2455 else
2456 {
2457 data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
2458 dp->db_txt_start;
2459 total_moved = data_moved + lines_moved * INDEX_SIZE;
2460 if ((int)dp->db_free + total_moved >= space_needed)
2461 {
2462 in_left = TRUE; /* put new line in left block */
2463 space_needed = total_moved;
2464 }
2465 else
2466 {
2467 in_left = FALSE; /* put new line in right block */
2468 space_needed += total_moved;
2469 }
2470 }
2471 }
2472
2473 page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
2474 if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
2475 {
2476 /* correct line counts in pointer blocks */
2477 --(buf->b_ml.ml_locked_lineadd);
2478 --(buf->b_ml.ml_locked_high);
2479 return FAIL;
2480 }
2481 if (db_idx < 0) /* left block is new */
2482 {
2483 hp_left = hp_new;
2484 hp_right = hp;
2485 line_count_left = 0;
2486 line_count_right = line_count;
2487 }
2488 else /* right block is new */
2489 {
2490 hp_left = hp;
2491 hp_right = hp_new;
2492 line_count_left = line_count;
2493 line_count_right = 0;
2494 }
2495 dp_right = (DATA_BL *)(hp_right->bh_data);
2496 dp_left = (DATA_BL *)(hp_left->bh_data);
2497 bnum_left = hp_left->bh_bnum;
2498 bnum_right = hp_right->bh_bnum;
2499 page_count_left = hp_left->bh_page_count;
2500 page_count_right = hp_right->bh_page_count;
2501
2502 /*
2503 * May move the new line into the right/new block.
2504 */
2505 if (!in_left)
2506 {
2507 dp_right->db_txt_start -= len;
2508 dp_right->db_free -= len + INDEX_SIZE;
2509 dp_right->db_index[0] = dp_right->db_txt_start;
2510 if (mark)
2511 dp_right->db_index[0] |= DB_MARKED;
2512
2513 mch_memmove((char *)dp_right + dp_right->db_txt_start,
2514 line, (size_t)len);
2515 ++line_count_right;
2516 }
2517 /*
2518 * may move lines from the left/old block to the right/new one.
2519 */
2520 if (lines_moved)
2521 {
2522 /*
2523 */
2524 dp_right->db_txt_start -= data_moved;
2525 dp_right->db_free -= total_moved;
2526 mch_memmove((char *)dp_right + dp_right->db_txt_start,
2527 (char *)dp_left + dp_left->db_txt_start,
2528 (size_t)data_moved);
2529 offset = dp_right->db_txt_start - dp_left->db_txt_start;
2530 dp_left->db_txt_start += data_moved;
2531 dp_left->db_free += total_moved;
2532
2533 /*
2534 * update indexes in the new block
2535 */
2536 for (to = line_count_right, from = db_idx + 1;
2537 from < line_count_left; ++from, ++to)
2538 dp_right->db_index[to] = dp->db_index[from] + offset;
2539 line_count_right += lines_moved;
2540 line_count_left -= lines_moved;
2541 }
2542
2543 /*
2544 * May move the new line into the left (old or new) block.
2545 */
2546 if (in_left)
2547 {
2548 dp_left->db_txt_start -= len;
2549 dp_left->db_free -= len + INDEX_SIZE;
2550 dp_left->db_index[line_count_left] = dp_left->db_txt_start;
2551 if (mark)
2552 dp_left->db_index[line_count_left] |= DB_MARKED;
2553 mch_memmove((char *)dp_left + dp_left->db_txt_start,
2554 line, (size_t)len);
2555 ++line_count_left;
2556 }
2557
2558 if (db_idx < 0) /* left block is new */
2559 {
2560 lnum_left = lnum + 1;
2561 lnum_right = 0;
2562 }
2563 else /* right block is new */
2564 {
2565 lnum_left = 0;
2566 if (in_left)
2567 lnum_right = lnum + 2;
2568 else
2569 lnum_right = lnum + 1;
2570 }
2571 dp_left->db_line_count = line_count_left;
2572 dp_right->db_line_count = line_count_right;
2573
2574 /*
2575 * release the two data blocks
2576 * The new one (hp_new) already has a correct blocknumber.
2577 * The old one (hp, in ml_locked) gets a positive blocknumber if
2578 * we changed it and we are not editing a new file.
2579 */
2580 if (lines_moved || in_left)
2581 buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2582 if (!newfile && db_idx >= 0 && in_left)
2583 buf->b_ml.ml_flags |= ML_LOCKED_POS;
2584 mf_put(mfp, hp_new, TRUE, FALSE);
2585
2586 /*
2587 * flush the old data block
2588 * set ml_locked_lineadd to 0, because the updating of the
2589 * pointer blocks is done below
2590 */
2591 lineadd = buf->b_ml.ml_locked_lineadd;
2592 buf->b_ml.ml_locked_lineadd = 0;
2593 ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush data block */
2594
2595 /*
2596 * update pointer blocks for the new data block
2597 */
2598 for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
2599 --stack_idx)
2600 {
2601 ip = &(buf->b_ml.ml_stack[stack_idx]);
2602 pb_idx = ip->ip_index;
2603 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
2604 return FAIL;
2605 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
2606 if (pp->pb_id != PTR_ID)
2607 {
2608 EMSG(_("E317: pointer block id wrong 3"));
2609 mf_put(mfp, hp, FALSE, FALSE);
2610 return FAIL;
2611 }
2612 /*
2613 * TODO: If the pointer block is full and we are adding at the end
2614 * try to insert in front of the next block
2615 */
2616 /* block not full, add one entry */
2617 if (pp->pb_count < pp->pb_count_max)
2618 {
2619 if (pb_idx + 1 < (int)pp->pb_count)
2620 mch_memmove(&pp->pb_pointer[pb_idx + 2],
2621 &pp->pb_pointer[pb_idx + 1],
2622 (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
2623 ++pp->pb_count;
2624 pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
2625 pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
2626 pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
2627 pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
2628 pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
2629 pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
2630
2631 if (lnum_left != 0)
2632 pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
2633 if (lnum_right != 0)
2634 pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
2635
2636 mf_put(mfp, hp, TRUE, FALSE);
2637 buf->b_ml.ml_stack_top = stack_idx + 1; /* truncate stack */
2638
2639 if (lineadd)
2640 {
2641 --(buf->b_ml.ml_stack_top);
Bram Moolenaar6b803a72007-05-06 14:25:46 +00002642 /* fix line count for rest of blocks in the stack */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 ml_lineadd(buf, lineadd);
2644 /* fix stack itself */
2645 buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
2646 lineadd;
2647 ++(buf->b_ml.ml_stack_top);
2648 }
2649
2650 /*
2651 * We are finished, break the loop here.
2652 */
2653 break;
2654 }
2655 else /* pointer block full */
2656 {
2657 /*
2658 * split the pointer block
2659 * allocate a new pointer block
2660 * move some of the pointer into the new block
2661 * prepare for updating the parent block
2662 */
2663 for (;;) /* do this twice when splitting block 1 */
2664 {
2665 hp_new = ml_new_ptr(mfp);
2666 if (hp_new == NULL) /* TODO: try to fix tree */
2667 return FAIL;
2668 pp_new = (PTR_BL *)(hp_new->bh_data);
2669
2670 if (hp->bh_bnum != 1)
2671 break;
2672
2673 /*
2674 * if block 1 becomes full the tree is given an extra level
2675 * The pointers from block 1 are moved into the new block.
2676 * block 1 is updated to point to the new block
2677 * then continue to split the new block
2678 */
2679 mch_memmove(pp_new, pp, (size_t)page_size);
2680 pp->pb_count = 1;
2681 pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
2682 pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
2683 pp->pb_pointer[0].pe_old_lnum = 1;
2684 pp->pb_pointer[0].pe_page_count = 1;
2685 mf_put(mfp, hp, TRUE, FALSE); /* release block 1 */
2686 hp = hp_new; /* new block is to be split */
2687 pp = pp_new;
2688 CHECK(stack_idx != 0, _("stack_idx should be 0"));
2689 ip->ip_index = 0;
2690 ++stack_idx; /* do block 1 again later */
2691 }
2692 /*
2693 * move the pointers after the current one to the new block
2694 * If there are none, the new entry will be in the new block.
2695 */
2696 total_moved = pp->pb_count - pb_idx - 1;
2697 if (total_moved)
2698 {
2699 mch_memmove(&pp_new->pb_pointer[0],
2700 &pp->pb_pointer[pb_idx + 1],
2701 (size_t)(total_moved) * sizeof(PTR_EN));
2702 pp_new->pb_count = total_moved;
2703 pp->pb_count -= total_moved - 1;
2704 pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
2705 pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
2706 pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
2707 if (lnum_right)
2708 pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
2709 }
2710 else
2711 {
2712 pp_new->pb_count = 1;
2713 pp_new->pb_pointer[0].pe_bnum = bnum_right;
2714 pp_new->pb_pointer[0].pe_line_count = line_count_right;
2715 pp_new->pb_pointer[0].pe_page_count = page_count_right;
2716 pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
2717 }
2718 pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
2719 pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
2720 pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
2721 if (lnum_left)
2722 pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
2723 lnum_left = 0;
2724 lnum_right = 0;
2725
2726 /*
2727 * recompute line counts
2728 */
2729 line_count_right = 0;
2730 for (i = 0; i < (int)pp_new->pb_count; ++i)
2731 line_count_right += pp_new->pb_pointer[i].pe_line_count;
2732 line_count_left = 0;
2733 for (i = 0; i < (int)pp->pb_count; ++i)
2734 line_count_left += pp->pb_pointer[i].pe_line_count;
2735
2736 bnum_left = hp->bh_bnum;
2737 bnum_right = hp_new->bh_bnum;
2738 page_count_left = 1;
2739 page_count_right = 1;
2740 mf_put(mfp, hp, TRUE, FALSE);
2741 mf_put(mfp, hp_new, TRUE, FALSE);
2742 }
2743 }
2744
2745 /*
2746 * Safety check: fallen out of for loop?
2747 */
2748 if (stack_idx < 0)
2749 {
2750 EMSG(_("E318: Updated too many blocks?"));
2751 buf->b_ml.ml_stack_top = 0; /* invalidate stack */
2752 }
2753 }
2754
2755#ifdef FEAT_BYTEOFF
2756 /* The line was inserted below 'lnum' */
2757 ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
2758#endif
2759#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002760 if (netbeans_active())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761 {
2762 if (STRLEN(line) > 0)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002763 netbeans_inserted(buf, lnum+1, (colnr_T)0, line, (int)STRLEN(line));
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00002764 netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002765 (char_u *)"\n", 1);
2766 }
2767#endif
2768 return OK;
2769}
2770
2771/*
Bram Moolenaar4770d092006-01-12 23:22:24 +00002772 * Replace line lnum, with buffering, in current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773 *
Bram Moolenaar1056d982006-03-09 22:37:52 +00002774 * If "copy" is TRUE, make a copy of the line, otherwise the line has been
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 * copied to allocated memory already.
2776 *
2777 * Check: The caller of this function should probably also call
2778 * changed_lines(), unless update_screen(NOT_VALID) is used.
2779 *
2780 * return FAIL for failure, OK otherwise
2781 */
2782 int
2783ml_replace(lnum, line, copy)
2784 linenr_T lnum;
2785 char_u *line;
2786 int copy;
2787{
2788 if (line == NULL) /* just checking... */
2789 return FAIL;
2790
2791 /* When starting up, we might still need to create the memfile */
2792 if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL) == FAIL)
2793 return FAIL;
2794
2795 if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */
2796 return FAIL;
2797#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002798 if (netbeans_active())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 {
2800 netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002801 netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002802 }
2803#endif
2804 if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
2805 ml_flush_line(curbuf); /* flush it */
2806 else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
2807 vim_free(curbuf->b_ml.ml_line_ptr); /* free it */
2808 curbuf->b_ml.ml_line_ptr = line;
2809 curbuf->b_ml.ml_line_lnum = lnum;
2810 curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
2811
2812 return OK;
2813}
2814
2815/*
Bram Moolenaar4770d092006-01-12 23:22:24 +00002816 * Delete line 'lnum' in the current buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817 *
2818 * Check: The caller of this function should probably also call
2819 * deleted_lines() after this.
2820 *
2821 * return FAIL for failure, OK otherwise
2822 */
2823 int
2824ml_delete(lnum, message)
2825 linenr_T lnum;
2826 int message;
2827{
2828 ml_flush_line(curbuf);
2829 return ml_delete_int(curbuf, lnum, message);
2830}
2831
2832 static int
2833ml_delete_int(buf, lnum, message)
2834 buf_T *buf;
2835 linenr_T lnum;
2836 int message;
2837{
2838 bhdr_T *hp;
2839 memfile_T *mfp;
2840 DATA_BL *dp;
2841 PTR_BL *pp;
2842 infoptr_T *ip;
2843 int count; /* number of entries in block */
2844 int idx;
2845 int stack_idx;
2846 int text_start;
2847 int line_start;
2848 long line_size;
2849 int i;
2850
2851 if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
2852 return FAIL;
2853
2854 if (lowest_marked && lowest_marked > lnum)
2855 lowest_marked--;
2856
2857/*
2858 * If the file becomes empty the last line is replaced by an empty line.
2859 */
2860 if (buf->b_ml.ml_line_count == 1) /* file becomes empty */
2861 {
2862 if (message
2863#ifdef FEAT_NETBEANS_INTG
2864 && !netbeansSuppressNoLines
2865#endif
2866 )
Bram Moolenaar238a5642006-02-21 22:12:05 +00002867 set_keep_msg((char_u *)_(no_lines_msg), 0);
2868
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869 /* FEAT_BYTEOFF already handled in there, dont worry 'bout it below */
2870 i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
2871 buf->b_ml.ml_flags |= ML_EMPTY;
2872
2873 return i;
2874 }
2875
2876/*
2877 * find the data block containing the line
2878 * This also fills the stack with the blocks from the root to the data block
2879 * This also releases any locked block.
2880 */
2881 mfp = buf->b_ml.ml_mfp;
2882 if (mfp == NULL)
2883 return FAIL;
2884
2885 if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
2886 return FAIL;
2887
2888 dp = (DATA_BL *)(hp->bh_data);
2889 /* compute line count before the delete */
2890 count = (long)(buf->b_ml.ml_locked_high)
2891 - (long)(buf->b_ml.ml_locked_low) + 2;
2892 idx = lnum - buf->b_ml.ml_locked_low;
2893
2894 --buf->b_ml.ml_line_count;
2895
2896 line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
2897 if (idx == 0) /* first line in block, text at the end */
2898 line_size = dp->db_txt_end - line_start;
2899 else
2900 line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
2901
2902#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02002903 if (netbeans_active())
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00002904 netbeans_removed(buf, lnum, 0, (long)line_size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905#endif
2906
2907/*
2908 * special case: If there is only one line in the data block it becomes empty.
2909 * Then we have to remove the entry, pointing to this data block, from the
2910 * pointer block. If this pointer block also becomes empty, we go up another
2911 * block, and so on, up to the root if necessary.
2912 * The line counts in the pointer blocks have already been adjusted by
2913 * ml_find_line().
2914 */
2915 if (count == 1)
2916 {
2917 mf_free(mfp, hp); /* free the data block */
2918 buf->b_ml.ml_locked = NULL;
2919
2920 for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; --stack_idx)
2921 {
2922 buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */
2923 ip = &(buf->b_ml.ml_stack[stack_idx]);
2924 idx = ip->ip_index;
2925 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
2926 return FAIL;
2927 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
2928 if (pp->pb_id != PTR_ID)
2929 {
2930 EMSG(_("E317: pointer block id wrong 4"));
2931 mf_put(mfp, hp, FALSE, FALSE);
2932 return FAIL;
2933 }
2934 count = --(pp->pb_count);
2935 if (count == 0) /* the pointer block becomes empty! */
2936 mf_free(mfp, hp);
2937 else
2938 {
2939 if (count != idx) /* move entries after the deleted one */
2940 mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
2941 (size_t)(count - idx) * sizeof(PTR_EN));
2942 mf_put(mfp, hp, TRUE, FALSE);
2943
2944 buf->b_ml.ml_stack_top = stack_idx; /* truncate stack */
Bram Moolenaar6b803a72007-05-06 14:25:46 +00002945 /* fix line count for rest of blocks in the stack */
2946 if (buf->b_ml.ml_locked_lineadd != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947 {
2948 ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
2949 buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
Bram Moolenaar6b803a72007-05-06 14:25:46 +00002950 buf->b_ml.ml_locked_lineadd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951 }
2952 ++(buf->b_ml.ml_stack_top);
2953
2954 break;
2955 }
2956 }
2957 CHECK(stack_idx < 0, _("deleted block 1?"));
2958 }
2959 else
2960 {
2961 /*
2962 * delete the text by moving the next lines forwards
2963 */
2964 text_start = dp->db_txt_start;
2965 mch_memmove((char *)dp + text_start + line_size,
2966 (char *)dp + text_start, (size_t)(line_start - text_start));
2967
2968 /*
2969 * delete the index by moving the next indexes backwards
2970 * Adjust the indexes for the text movement.
2971 */
2972 for (i = idx; i < count - 1; ++i)
2973 dp->db_index[i] = dp->db_index[i + 1] + line_size;
2974
2975 dp->db_free += line_size + INDEX_SIZE;
2976 dp->db_txt_start += line_size;
2977 --(dp->db_line_count);
2978
2979 /*
2980 * mark the block dirty and make sure it is in the file (for recovery)
2981 */
2982 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
2983 }
2984
2985#ifdef FEAT_BYTEOFF
2986 ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
2987#endif
2988 return OK;
2989}
2990
2991/*
2992 * set the B_MARKED flag for line 'lnum'
2993 */
2994 void
2995ml_setmarked(lnum)
2996 linenr_T lnum;
2997{
2998 bhdr_T *hp;
2999 DATA_BL *dp;
3000 /* invalid line number */
3001 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
3002 || curbuf->b_ml.ml_mfp == NULL)
3003 return; /* give error message? */
3004
3005 if (lowest_marked == 0 || lowest_marked > lnum)
3006 lowest_marked = lnum;
3007
3008 /*
3009 * find the data block containing the line
3010 * This also fills the stack with the blocks from the root to the data block
3011 * This also releases any locked block.
3012 */
3013 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3014 return; /* give error message? */
3015
3016 dp = (DATA_BL *)(hp->bh_data);
3017 dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
3018 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3019}
3020
3021/*
3022 * find the first line with its B_MARKED flag set
3023 */
3024 linenr_T
3025ml_firstmarked()
3026{
3027 bhdr_T *hp;
3028 DATA_BL *dp;
3029 linenr_T lnum;
3030 int i;
3031
3032 if (curbuf->b_ml.ml_mfp == NULL)
3033 return (linenr_T) 0;
3034
3035 /*
3036 * The search starts with lowest_marked line. This is the last line where
3037 * a mark was found, adjusted by inserting/deleting lines.
3038 */
3039 for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3040 {
3041 /*
3042 * Find the data block containing the line.
3043 * This also fills the stack with the blocks from the root to the data
3044 * block This also releases any locked block.
3045 */
3046 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3047 return (linenr_T)0; /* give error message? */
3048
3049 dp = (DATA_BL *)(hp->bh_data);
3050
3051 for (i = lnum - curbuf->b_ml.ml_locked_low;
3052 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3053 if ((dp->db_index[i]) & DB_MARKED)
3054 {
3055 (dp->db_index[i]) &= DB_INDEX_MASK;
3056 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3057 lowest_marked = lnum + 1;
3058 return lnum;
3059 }
3060 }
3061
3062 return (linenr_T) 0;
3063}
3064
3065#if 0 /* not used */
3066/*
3067 * return TRUE if line 'lnum' has a mark
3068 */
3069 int
3070ml_has_mark(lnum)
3071 linenr_T lnum;
3072{
3073 bhdr_T *hp;
3074 DATA_BL *dp;
3075
3076 if (curbuf->b_ml.ml_mfp == NULL
3077 || (hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3078 return FALSE;
3079
3080 dp = (DATA_BL *)(hp->bh_data);
3081 return (int)((dp->db_index[lnum - curbuf->b_ml.ml_locked_low]) & DB_MARKED);
3082}
3083#endif
3084
3085/*
3086 * clear all DB_MARKED flags
3087 */
3088 void
3089ml_clearmarked()
3090{
3091 bhdr_T *hp;
3092 DATA_BL *dp;
3093 linenr_T lnum;
3094 int i;
3095
3096 if (curbuf->b_ml.ml_mfp == NULL) /* nothing to do */
3097 return;
3098
3099 /*
3100 * The search starts with line lowest_marked.
3101 */
3102 for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
3103 {
3104 /*
3105 * Find the data block containing the line.
3106 * This also fills the stack with the blocks from the root to the data
3107 * block and releases any locked block.
3108 */
3109 if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
3110 return; /* give error message? */
3111
3112 dp = (DATA_BL *)(hp->bh_data);
3113
3114 for (i = lnum - curbuf->b_ml.ml_locked_low;
3115 lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
3116 if ((dp->db_index[i]) & DB_MARKED)
3117 {
3118 (dp->db_index[i]) &= DB_INDEX_MASK;
3119 curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
3120 }
3121 }
3122
3123 lowest_marked = 0;
3124 return;
3125}
3126
3127/*
3128 * flush ml_line if necessary
3129 */
3130 static void
3131ml_flush_line(buf)
3132 buf_T *buf;
3133{
3134 bhdr_T *hp;
3135 DATA_BL *dp;
3136 linenr_T lnum;
3137 char_u *new_line;
3138 char_u *old_line;
3139 colnr_T new_len;
3140 int old_len;
3141 int extra;
3142 int idx;
3143 int start;
3144 int count;
3145 int i;
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003146 static int entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147
3148 if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
3149 return; /* nothing to do */
3150
3151 if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
3152 {
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003153 /* This code doesn't work recursively, but Netbeans may call back here
3154 * when obtaining the cursor position. */
3155 if (entered)
3156 return;
3157 entered = TRUE;
3158
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 lnum = buf->b_ml.ml_line_lnum;
3160 new_line = buf->b_ml.ml_line_ptr;
3161
3162 hp = ml_find_line(buf, lnum, ML_FIND);
3163 if (hp == NULL)
3164 EMSGN(_("E320: Cannot find line %ld"), lnum);
3165 else
3166 {
3167 dp = (DATA_BL *)(hp->bh_data);
3168 idx = lnum - buf->b_ml.ml_locked_low;
3169 start = ((dp->db_index[idx]) & DB_INDEX_MASK);
3170 old_line = (char_u *)dp + start;
3171 if (idx == 0) /* line is last in block */
3172 old_len = dp->db_txt_end - start;
3173 else /* text of previous line follows */
3174 old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
3175 new_len = (colnr_T)STRLEN(new_line) + 1;
3176 extra = new_len - old_len; /* negative if lines gets smaller */
3177
3178 /*
3179 * if new line fits in data block, replace directly
3180 */
3181 if ((int)dp->db_free >= extra)
3182 {
3183 /* if the length changes and there are following lines */
3184 count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
3185 if (extra != 0 && idx < count - 1)
3186 {
3187 /* move text of following lines */
3188 mch_memmove((char *)dp + dp->db_txt_start - extra,
3189 (char *)dp + dp->db_txt_start,
3190 (size_t)(start - dp->db_txt_start));
3191
3192 /* adjust pointers of this and following lines */
3193 for (i = idx + 1; i < count; ++i)
3194 dp->db_index[i] -= extra;
3195 }
3196 dp->db_index[idx] -= extra;
3197
3198 /* adjust free space */
3199 dp->db_free -= extra;
3200 dp->db_txt_start -= extra;
3201
3202 /* copy new line into the data block */
3203 mch_memmove(old_line - extra, new_line, (size_t)new_len);
3204 buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
3205#ifdef FEAT_BYTEOFF
3206 /* The else case is already covered by the insert and delete */
3207 ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
3208#endif
3209 }
3210 else
3211 {
3212 /*
3213 * Cannot do it in one data block: Delete and append.
3214 * Append first, because ml_delete_int() cannot delete the
3215 * last line in a buffer, which causes trouble for a buffer
3216 * that has only one line.
3217 * Don't forget to copy the mark!
3218 */
3219 /* How about handling errors??? */
3220 (void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
3221 (dp->db_index[idx] & DB_MARKED));
3222 (void)ml_delete_int(buf, lnum, FALSE);
3223 }
3224 }
3225 vim_free(new_line);
Bram Moolenaar0ca4b352010-02-11 18:54:43 +01003226
3227 entered = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 }
3229
3230 buf->b_ml.ml_line_lnum = 0;
3231}
3232
3233/*
3234 * create a new, empty, data block
3235 */
3236 static bhdr_T *
3237ml_new_data(mfp, negative, page_count)
3238 memfile_T *mfp;
3239 int negative;
3240 int page_count;
3241{
3242 bhdr_T *hp;
3243 DATA_BL *dp;
3244
3245 if ((hp = mf_new(mfp, negative, page_count)) == NULL)
3246 return NULL;
3247
3248 dp = (DATA_BL *)(hp->bh_data);
3249 dp->db_id = DATA_ID;
3250 dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
3251 dp->db_free = dp->db_txt_start - HEADER_SIZE;
3252 dp->db_line_count = 0;
3253
3254 return hp;
3255}
3256
3257/*
3258 * create a new, empty, pointer block
3259 */
3260 static bhdr_T *
3261ml_new_ptr(mfp)
3262 memfile_T *mfp;
3263{
3264 bhdr_T *hp;
3265 PTR_BL *pp;
3266
3267 if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
3268 return NULL;
3269
3270 pp = (PTR_BL *)(hp->bh_data);
3271 pp->pb_id = PTR_ID;
3272 pp->pb_count = 0;
Bram Moolenaar20a825a2010-05-31 21:27:30 +02003273 pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL))
3274 / sizeof(PTR_EN) + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003275
3276 return hp;
3277}
3278
3279/*
3280 * lookup line 'lnum' in a memline
3281 *
3282 * action: if ML_DELETE or ML_INSERT the line count is updated while searching
3283 * if ML_FLUSH only flush a locked block
3284 * if ML_FIND just find the line
3285 *
3286 * If the block was found it is locked and put in ml_locked.
3287 * The stack is updated to lead to the locked block. The ip_high field in
3288 * the stack is updated to reflect the last line in the block AFTER the
3289 * insert or delete, also if the pointer block has not been updated yet. But
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003290 * if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 *
3292 * return: NULL for failure, pointer to block header otherwise
3293 */
3294 static bhdr_T *
3295ml_find_line(buf, lnum, action)
3296 buf_T *buf;
3297 linenr_T lnum;
3298 int action;
3299{
3300 DATA_BL *dp;
3301 PTR_BL *pp;
3302 infoptr_T *ip;
3303 bhdr_T *hp;
3304 memfile_T *mfp;
3305 linenr_T t;
3306 blocknr_T bnum, bnum2;
3307 int dirty;
3308 linenr_T low, high;
3309 int top;
3310 int page_count;
3311 int idx;
3312
3313 mfp = buf->b_ml.ml_mfp;
3314
3315 /*
3316 * If there is a locked block check if the wanted line is in it.
3317 * If not, flush and release the locked block.
3318 * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
3319 * Don't do this for ML_FLUSH, because we want to flush the locked block.
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003320 * Don't do this when 'swapfile' is reset, we want to load all the blocks.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003321 */
3322 if (buf->b_ml.ml_locked)
3323 {
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003324 if (ML_SIMPLE(action)
3325 && buf->b_ml.ml_locked_low <= lnum
3326 && buf->b_ml.ml_locked_high >= lnum
3327 && !mf_dont_release)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003328 {
Bram Moolenaar47b8b152007-02-07 02:41:57 +00003329 /* remember to update pointer blocks and stack later */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003330 if (action == ML_INSERT)
3331 {
3332 ++(buf->b_ml.ml_locked_lineadd);
3333 ++(buf->b_ml.ml_locked_high);
3334 }
3335 else if (action == ML_DELETE)
3336 {
3337 --(buf->b_ml.ml_locked_lineadd);
3338 --(buf->b_ml.ml_locked_high);
3339 }
3340 return (buf->b_ml.ml_locked);
3341 }
3342
3343 mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
3344 buf->b_ml.ml_flags & ML_LOCKED_POS);
3345 buf->b_ml.ml_locked = NULL;
3346
Bram Moolenaar6b803a72007-05-06 14:25:46 +00003347 /*
3348 * If lines have been added or deleted in the locked block, need to
3349 * update the line count in pointer blocks.
3350 */
3351 if (buf->b_ml.ml_locked_lineadd != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
3353 }
3354
3355 if (action == ML_FLUSH) /* nothing else to do */
3356 return NULL;
3357
3358 bnum = 1; /* start at the root of the tree */
3359 page_count = 1;
3360 low = 1;
3361 high = buf->b_ml.ml_line_count;
3362
3363 if (action == ML_FIND) /* first try stack entries */
3364 {
3365 for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
3366 {
3367 ip = &(buf->b_ml.ml_stack[top]);
3368 if (ip->ip_low <= lnum && ip->ip_high >= lnum)
3369 {
3370 bnum = ip->ip_bnum;
3371 low = ip->ip_low;
3372 high = ip->ip_high;
3373 buf->b_ml.ml_stack_top = top; /* truncate stack at prev entry */
3374 break;
3375 }
3376 }
3377 if (top < 0)
3378 buf->b_ml.ml_stack_top = 0; /* not found, start at the root */
3379 }
3380 else /* ML_DELETE or ML_INSERT */
3381 buf->b_ml.ml_stack_top = 0; /* start at the root */
3382
3383/*
3384 * search downwards in the tree until a data block is found
3385 */
3386 for (;;)
3387 {
3388 if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
3389 goto error_noblock;
3390
3391 /*
3392 * update high for insert/delete
3393 */
3394 if (action == ML_INSERT)
3395 ++high;
3396 else if (action == ML_DELETE)
3397 --high;
3398
3399 dp = (DATA_BL *)(hp->bh_data);
3400 if (dp->db_id == DATA_ID) /* data block */
3401 {
3402 buf->b_ml.ml_locked = hp;
3403 buf->b_ml.ml_locked_low = low;
3404 buf->b_ml.ml_locked_high = high;
3405 buf->b_ml.ml_locked_lineadd = 0;
3406 buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
3407 return hp;
3408 }
3409
3410 pp = (PTR_BL *)(dp); /* must be pointer block */
3411 if (pp->pb_id != PTR_ID)
3412 {
3413 EMSG(_("E317: pointer block id wrong"));
3414 goto error_block;
3415 }
3416
3417 if ((top = ml_add_stack(buf)) < 0) /* add new entry to stack */
3418 goto error_block;
3419 ip = &(buf->b_ml.ml_stack[top]);
3420 ip->ip_bnum = bnum;
3421 ip->ip_low = low;
3422 ip->ip_high = high;
3423 ip->ip_index = -1; /* index not known yet */
3424
3425 dirty = FALSE;
3426 for (idx = 0; idx < (int)pp->pb_count; ++idx)
3427 {
3428 t = pp->pb_pointer[idx].pe_line_count;
3429 CHECK(t == 0, _("pe_line_count is zero"));
3430 if ((low += t) > lnum)
3431 {
3432 ip->ip_index = idx;
3433 bnum = pp->pb_pointer[idx].pe_bnum;
3434 page_count = pp->pb_pointer[idx].pe_page_count;
3435 high = low - 1;
3436 low -= t;
3437
3438 /*
3439 * a negative block number may have been changed
3440 */
3441 if (bnum < 0)
3442 {
3443 bnum2 = mf_trans_del(mfp, bnum);
3444 if (bnum != bnum2)
3445 {
3446 bnum = bnum2;
3447 pp->pb_pointer[idx].pe_bnum = bnum;
3448 dirty = TRUE;
3449 }
3450 }
3451
3452 break;
3453 }
3454 }
3455 if (idx >= (int)pp->pb_count) /* past the end: something wrong! */
3456 {
3457 if (lnum > buf->b_ml.ml_line_count)
3458 EMSGN(_("E322: line number out of range: %ld past the end"),
3459 lnum - buf->b_ml.ml_line_count);
3460
3461 else
3462 EMSGN(_("E323: line count wrong in block %ld"), bnum);
3463 goto error_block;
3464 }
3465 if (action == ML_DELETE)
3466 {
3467 pp->pb_pointer[idx].pe_line_count--;
3468 dirty = TRUE;
3469 }
3470 else if (action == ML_INSERT)
3471 {
3472 pp->pb_pointer[idx].pe_line_count++;
3473 dirty = TRUE;
3474 }
3475 mf_put(mfp, hp, dirty, FALSE);
3476 }
3477
3478error_block:
3479 mf_put(mfp, hp, FALSE, FALSE);
3480error_noblock:
3481/*
3482 * If action is ML_DELETE or ML_INSERT we have to correct the tree for
3483 * the incremented/decremented line counts, because there won't be a line
3484 * inserted/deleted after all.
3485 */
3486 if (action == ML_DELETE)
3487 ml_lineadd(buf, 1);
3488 else if (action == ML_INSERT)
3489 ml_lineadd(buf, -1);
3490 buf->b_ml.ml_stack_top = 0;
3491 return NULL;
3492}
3493
3494/*
3495 * add an entry to the info pointer stack
3496 *
3497 * return -1 for failure, number of the new entry otherwise
3498 */
3499 static int
3500ml_add_stack(buf)
3501 buf_T *buf;
3502{
3503 int top;
3504 infoptr_T *newstack;
3505
3506 top = buf->b_ml.ml_stack_top;
3507
3508 /* may have to increase the stack size */
3509 if (top == buf->b_ml.ml_stack_size)
3510 {
3511 CHECK(top > 0, _("Stack size increases")); /* more than 5 levels??? */
3512
3513 newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
3514 (buf->b_ml.ml_stack_size + STACK_INCR));
3515 if (newstack == NULL)
3516 return -1;
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003517 mch_memmove(newstack, buf->b_ml.ml_stack,
3518 (size_t)top * sizeof(infoptr_T));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 vim_free(buf->b_ml.ml_stack);
3520 buf->b_ml.ml_stack = newstack;
3521 buf->b_ml.ml_stack_size += STACK_INCR;
3522 }
3523
3524 buf->b_ml.ml_stack_top++;
3525 return top;
3526}
3527
3528/*
3529 * Update the pointer blocks on the stack for inserted/deleted lines.
3530 * The stack itself is also updated.
3531 *
3532 * When a insert/delete line action fails, the line is not inserted/deleted,
3533 * but the pointer blocks have already been updated. That is fixed here by
3534 * walking through the stack.
3535 *
3536 * Count is the number of lines added, negative if lines have been deleted.
3537 */
3538 static void
3539ml_lineadd(buf, count)
3540 buf_T *buf;
3541 int count;
3542{
3543 int idx;
3544 infoptr_T *ip;
3545 PTR_BL *pp;
3546 memfile_T *mfp = buf->b_ml.ml_mfp;
3547 bhdr_T *hp;
3548
3549 for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
3550 {
3551 ip = &(buf->b_ml.ml_stack[idx]);
3552 if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
3553 break;
3554 pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
3555 if (pp->pb_id != PTR_ID)
3556 {
3557 mf_put(mfp, hp, FALSE, FALSE);
3558 EMSG(_("E317: pointer block id wrong 2"));
3559 break;
3560 }
3561 pp->pb_pointer[ip->ip_index].pe_line_count += count;
3562 ip->ip_high += count;
3563 mf_put(mfp, hp, TRUE, FALSE);
3564 }
3565}
3566
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003567#if defined(HAVE_READLINK) || defined(PROTO)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003568/*
3569 * Resolve a symlink in the last component of a file name.
3570 * Note that f_resolve() does it for every part of the path, we don't do that
3571 * here.
3572 * If it worked returns OK and the resolved link in "buf[MAXPATHL]".
3573 * Otherwise returns FAIL.
3574 */
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003575 int
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003576resolve_symlink(fname, buf)
3577 char_u *fname;
3578 char_u *buf;
3579{
3580 char_u tmp[MAXPATHL];
3581 int ret;
3582 int depth = 0;
3583
3584 if (fname == NULL)
3585 return FAIL;
3586
3587 /* Put the result so far in tmp[], starting with the original name. */
3588 vim_strncpy(tmp, fname, MAXPATHL - 1);
3589
3590 for (;;)
3591 {
3592 /* Limit symlink depth to 100, catch recursive loops. */
3593 if (++depth == 100)
3594 {
3595 EMSG2(_("E773: Symlink loop for \"%s\""), fname);
3596 return FAIL;
3597 }
3598
3599 ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
3600 if (ret <= 0)
3601 {
Bram Moolenaarcc984262005-12-23 22:19:46 +00003602 if (errno == EINVAL || errno == ENOENT)
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003603 {
Bram Moolenaarcc984262005-12-23 22:19:46 +00003604 /* Found non-symlink or not existing file, stop here.
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00003605 * When at the first level use the unmodified name, skip the
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003606 * call to vim_FullName(). */
3607 if (depth == 1)
3608 return FAIL;
3609
3610 /* Use the resolved name in tmp[]. */
3611 break;
3612 }
3613
3614 /* There must be some error reading links, use original name. */
3615 return FAIL;
3616 }
3617 buf[ret] = NUL;
3618
3619 /*
3620 * Check whether the symlink is relative or absolute.
3621 * If it's relative, build a new path based on the directory
3622 * portion of the filename (if any) and the path the symlink
3623 * points to.
3624 */
3625 if (mch_isFullName(buf))
3626 STRCPY(tmp, buf);
3627 else
3628 {
3629 char_u *tail;
3630
3631 tail = gettail(tmp);
3632 if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
3633 return FAIL;
3634 STRCPY(tail, buf);
3635 }
3636 }
3637
3638 /*
3639 * Try to resolve the full name of the file so that the swapfile name will
3640 * be consistent even when opening a relative symlink from different
3641 * working directories.
3642 */
3643 return vim_FullName(tmp, buf, MAXPATHL, TRUE);
3644}
3645#endif
3646
Bram Moolenaar071d4272004-06-13 20:20:40 +00003647/*
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003648 * Make swap file name out of the file name and a directory name.
3649 * Returns pointer to allocated memory or NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650 */
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003651 char_u *
3652makeswapname(fname, ffname, buf, dir_name)
3653 char_u *fname;
Bram Moolenaar740885b2009-11-03 14:33:17 +00003654 char_u *ffname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655 buf_T *buf;
3656 char_u *dir_name;
3657{
3658 char_u *r, *s;
Bram Moolenaar9dbe4752010-05-14 17:52:42 +02003659 char_u *fname_res = fname;
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003660#ifdef HAVE_READLINK
3661 char_u fname_buf[MAXPATHL];
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003662#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663
3664#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
3665 s = dir_name + STRLEN(dir_name);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003666 if (after_pathsep(dir_name, s) && s[-1] == s[-2])
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 { /* Ends with '//', Use Full path */
3668 r = NULL;
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003669 if ((s = make_percent_swname(dir_name, fname)) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670 {
3671 r = modname(s, (char_u *)".swp", FALSE);
3672 vim_free(s);
3673 }
3674 return r;
3675 }
3676#endif
3677
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003678#ifdef HAVE_READLINK
3679 /* Expand symlink in the file name, so that we put the swap file with the
3680 * actual file instead of with the symlink. */
3681 if (resolve_symlink(fname, fname_buf) == OK)
3682 fname_res = fname_buf;
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003683#endif
3684
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685 r = buf_modname(
3686#ifdef SHORT_FNAME
3687 TRUE,
3688#else
3689 (buf->b_p_sn || buf->b_shortname),
3690#endif
Bram Moolenaar38323e42007-03-06 19:22:53 +00003691#ifdef RISCOS
3692 /* Avoid problems if fname has special chars, eg <Wimp$Scrap> */
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003693 ffname,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694#else
Bram Moolenaar900b4d72005-12-12 22:05:50 +00003695 fname_res,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696#endif
3697 (char_u *)
3698#if defined(VMS) || defined(RISCOS)
3699 "_swp",
3700#else
3701 ".swp",
3702#endif
3703#ifdef SHORT_FNAME /* always 8.3 file name */
3704 FALSE
3705#else
3706 /* Prepend a '.' to the swap file name for the current directory. */
3707 dir_name[0] == '.' && dir_name[1] == NUL
3708#endif
3709 );
3710 if (r == NULL) /* out of memory */
3711 return NULL;
3712
3713 s = get_file_in_dir(r, dir_name);
3714 vim_free(r);
3715 return s;
3716}
3717
3718/*
3719 * Get file name to use for swap file or backup file.
3720 * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
3721 * option "dname".
3722 * - If "dname" is ".", return "fname" (swap file in dir of file).
3723 * - If "dname" starts with "./", insert "dname" in "fname" (swap file
3724 * relative to dir of file).
3725 * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
3726 * dir).
3727 *
3728 * The return value is an allocated string and can be NULL.
3729 */
3730 char_u *
3731get_file_in_dir(fname, dname)
3732 char_u *fname;
3733 char_u *dname; /* don't use "dirname", it is a global for Alpha */
3734{
3735 char_u *t;
3736 char_u *tail;
3737 char_u *retval;
3738 int save_char;
3739
3740 tail = gettail(fname);
3741
3742 if (dname[0] == '.' && dname[1] == NUL)
3743 retval = vim_strsave(fname);
3744 else if (dname[0] == '.' && vim_ispathsep(dname[1]))
3745 {
3746 if (tail == fname) /* no path before file name */
3747 retval = concat_fnames(dname + 2, tail, TRUE);
3748 else
3749 {
3750 save_char = *tail;
3751 *tail = NUL;
3752 t = concat_fnames(fname, dname + 2, TRUE);
3753 *tail = save_char;
3754 if (t == NULL) /* out of memory */
3755 retval = NULL;
3756 else
3757 {
3758 retval = concat_fnames(t, tail, TRUE);
3759 vim_free(t);
3760 }
3761 }
3762 }
3763 else
3764 retval = concat_fnames(dname, tail, TRUE);
3765
3766 return retval;
3767}
3768
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00003769static void attention_message __ARGS((buf_T *buf, char_u *fname));
3770
3771/*
3772 * Print the ATTENTION message: info about an existing swap file.
3773 */
3774 static void
3775attention_message(buf, fname)
3776 buf_T *buf; /* buffer being edited */
3777 char_u *fname; /* swap file name */
3778{
3779 struct stat st;
3780 time_t x, sx;
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00003781 char *p;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00003782
3783 ++no_wait_return;
3784 (void)EMSG(_("E325: ATTENTION"));
3785 MSG_PUTS(_("\nFound a swap file by the name \""));
3786 msg_home_replace(fname);
3787 MSG_PUTS("\"\n");
3788 sx = swapfile_info(fname);
3789 MSG_PUTS(_("While opening file \""));
3790 msg_outtrans(buf->b_fname);
3791 MSG_PUTS("\"\n");
3792 if (mch_stat((char *)buf->b_fname, &st) != -1)
3793 {
3794 MSG_PUTS(_(" dated: "));
3795 x = st.st_mtime; /* Manx C can't do &st.st_mtime */
Bram Moolenaar31e97bf2006-10-10 14:20:13 +00003796 p = ctime(&x); /* includes '\n' */
3797 if (p == NULL)
3798 MSG_PUTS("(invalid)\n");
3799 else
3800 MSG_PUTS(p);
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00003801 if (sx != 0 && x > sx)
3802 MSG_PUTS(_(" NEWER than swap file!\n"));
3803 }
3804 /* Some of these messages are long to allow translation to
3805 * other languages. */
3806 MSG_PUTS(_("\n(1) Another program may be editing the same file.\n If this is the case, be careful not to end up with two\n different instances of the same file when making changes.\n"));
3807 MSG_PUTS(_(" Quit, or continue with caution.\n"));
3808 MSG_PUTS(_("\n(2) An edit session for this file crashed.\n"));
3809 MSG_PUTS(_(" If this is the case, use \":recover\" or \"vim -r "));
3810 msg_outtrans(buf->b_fname);
3811 MSG_PUTS(_("\"\n to recover the changes (see \":help recovery\").\n"));
3812 MSG_PUTS(_(" If you did this already, delete the swap file \""));
3813 msg_outtrans(fname);
3814 MSG_PUTS(_("\"\n to avoid this message.\n"));
3815 cmdline_row = msg_row;
3816 --no_wait_return;
3817}
3818
3819#ifdef FEAT_AUTOCMD
3820static int do_swapexists __ARGS((buf_T *buf, char_u *fname));
3821
3822/*
3823 * Trigger the SwapExists autocommands.
3824 * Returns a value for equivalent to do_dialog() (see below):
3825 * 0: still need to ask for a choice
3826 * 1: open read-only
3827 * 2: edit anyway
3828 * 3: recover
3829 * 4: delete it
3830 * 5: quit
3831 * 6: abort
3832 */
3833 static int
3834do_swapexists(buf, fname)
3835 buf_T *buf;
3836 char_u *fname;
3837{
3838 set_vim_var_string(VV_SWAPNAME, fname, -1);
3839 set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
3840
3841 /* Trigger SwapExists autocommands with <afile> set to the file being
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00003842 * edited. Disallow changing directory here. */
3843 ++allbuf_lock;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00003844 apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, FALSE, NULL);
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00003845 --allbuf_lock;
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00003846
3847 set_vim_var_string(VV_SWAPNAME, NULL, -1);
3848
3849 switch (*get_vim_var_str(VV_SWAPCHOICE))
3850 {
3851 case 'o': return 1;
3852 case 'e': return 2;
3853 case 'r': return 3;
3854 case 'd': return 4;
3855 case 'q': return 5;
3856 case 'a': return 6;
3857 }
3858
3859 return 0;
3860}
3861#endif
3862
Bram Moolenaar071d4272004-06-13 20:20:40 +00003863/*
3864 * Find out what name to use for the swap file for buffer 'buf'.
3865 *
3866 * Several names are tried to find one that does not exist
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003867 * Returns the name in allocated memory or NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868 *
3869 * Note: If BASENAMELEN is not correct, you will get error messages for
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003870 * not being able to open the swap or undo file
Bram Moolenaar12c22ce2009-04-22 13:58:46 +00003871 * Note: May trigger SwapExists autocmd, pointers may change!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 */
3873 static char_u *
3874findswapname(buf, dirp, old_fname)
3875 buf_T *buf;
3876 char_u **dirp; /* pointer to list of directories */
3877 char_u *old_fname; /* don't give warning for this file name */
3878{
3879 char_u *fname;
3880 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 char_u *dir_name;
3882#ifdef AMIGA
3883 BPTR fh;
3884#endif
3885#ifndef SHORT_FNAME
3886 int r;
3887#endif
3888
3889#if !defined(SHORT_FNAME) \
3890 && ((!defined(UNIX) && !defined(OS2)) || defined(ARCHIE))
3891# define CREATE_DUMMY_FILE
3892 FILE *dummyfd = NULL;
3893
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003894 /*
3895 * If we start editing a new file, e.g. "test.doc", which resides on an
3896 * MSDOS compatible filesystem, it is possible that the file
3897 * "test.doc.swp" which we create will be exactly the same file. To avoid
3898 * this problem we temporarily create "test.doc". Don't do this when the
3899 * check below for a 8.3 file name is used.
3900 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 if (!(buf->b_p_sn || buf->b_shortname) && buf->b_fname != NULL
3902 && mch_getperm(buf->b_fname) < 0)
3903 dummyfd = mch_fopen((char *)buf->b_fname, "w");
3904#endif
3905
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003906 /*
3907 * Isolate a directory name from *dirp and put it in dir_name.
3908 * First allocate some memory to put the directory name in.
3909 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003910 dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
3911 if (dir_name != NULL)
3912 (void)copy_option_part(dirp, dir_name, 31000, ",");
3913
Bram Moolenaar55debbe2010-05-23 23:34:36 +02003914 /*
3915 * we try different names until we find one that does not exist yet
3916 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 if (dir_name == NULL) /* out of memory */
3918 fname = NULL;
3919 else
Bram Moolenaar04a09c12005-08-01 22:02:32 +00003920 fname = makeswapname(buf->b_fname, buf->b_ffname, buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003921
3922 for (;;)
3923 {
3924 if (fname == NULL) /* must be out of memory */
3925 break;
3926 if ((n = (int)STRLEN(fname)) == 0) /* safety check */
3927 {
3928 vim_free(fname);
3929 fname = NULL;
3930 break;
3931 }
3932#if (defined(UNIX) || defined(OS2)) && !defined(ARCHIE) && !defined(SHORT_FNAME)
3933/*
3934 * Some systems have a MS-DOS compatible filesystem that use 8.3 character
3935 * file names. If this is the first try and the swap file name does not fit in
3936 * 8.3, detect if this is the case, set shortname and try again.
3937 */
3938 if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
3939 && !(buf->b_p_sn || buf->b_shortname))
3940 {
3941 char_u *tail;
3942 char_u *fname2;
3943 struct stat s1, s2;
3944 int f1, f2;
3945 int created1 = FALSE, created2 = FALSE;
3946 int same = FALSE;
3947
3948 /*
3949 * Check if swapfile name does not fit in 8.3:
3950 * It either contains two dots, is longer than 8 chars, or starts
3951 * with a dot.
3952 */
3953 tail = gettail(buf->b_fname);
3954 if ( vim_strchr(tail, '.') != NULL
3955 || STRLEN(tail) > (size_t)8
3956 || *gettail(fname) == '.')
3957 {
3958 fname2 = alloc(n + 2);
3959 if (fname2 != NULL)
3960 {
3961 STRCPY(fname2, fname);
3962 /* if fname == "xx.xx.swp", fname2 = "xx.xx.swx"
3963 * if fname == ".xx.swp", fname2 = ".xx.swpx"
3964 * if fname == "123456789.swp", fname2 = "12345678x.swp"
3965 */
3966 if (vim_strchr(tail, '.') != NULL)
3967 fname2[n - 1] = 'x';
3968 else if (*gettail(fname) == '.')
3969 {
3970 fname2[n] = 'x';
3971 fname2[n + 1] = NUL;
3972 }
3973 else
3974 fname2[n - 5] += 1;
3975 /*
3976 * may need to create the files to be able to use mch_stat()
3977 */
3978 f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
3979 if (f1 < 0)
3980 {
3981 f1 = mch_open_rw((char *)fname,
3982 O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
3983#if defined(OS2)
3984 if (f1 < 0 && errno == ENOENT)
3985 same = TRUE;
3986#endif
3987 created1 = TRUE;
3988 }
3989 if (f1 >= 0)
3990 {
3991 f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
3992 if (f2 < 0)
3993 {
3994 f2 = mch_open_rw((char *)fname2,
3995 O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
3996 created2 = TRUE;
3997 }
3998 if (f2 >= 0)
3999 {
4000 /*
4001 * Both files exist now. If mch_stat() returns the
4002 * same device and inode they are the same file.
4003 */
4004 if (mch_fstat(f1, &s1) != -1
4005 && mch_fstat(f2, &s2) != -1
4006 && s1.st_dev == s2.st_dev
4007 && s1.st_ino == s2.st_ino)
4008 same = TRUE;
4009 close(f2);
4010 if (created2)
4011 mch_remove(fname2);
4012 }
4013 close(f1);
4014 if (created1)
4015 mch_remove(fname);
4016 }
4017 vim_free(fname2);
4018 if (same)
4019 {
4020 buf->b_shortname = TRUE;
4021 vim_free(fname);
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004022 fname = makeswapname(buf->b_fname, buf->b_ffname,
4023 buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024 continue; /* try again with b_shortname set */
4025 }
4026 }
4027 }
4028 }
4029#endif
4030 /*
4031 * check if the swapfile already exists
4032 */
4033 if (mch_getperm(fname) < 0) /* it does not exist */
4034 {
4035#ifdef HAVE_LSTAT
4036 struct stat sb;
4037
4038 /*
4039 * Extra security check: When a swap file is a symbolic link, this
4040 * is most likely a symlink attack.
4041 */
4042 if (mch_lstat((char *)fname, &sb) < 0)
4043#else
4044# ifdef AMIGA
4045 fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
4046 /*
4047 * on the Amiga mch_getperm() will return -1 when the file exists
4048 * but is being used by another program. This happens if you edit
4049 * a file twice.
4050 */
4051 if (fh != (BPTR)NULL) /* can open file, OK */
4052 {
4053 Close(fh);
4054 mch_remove(fname);
4055 break;
4056 }
4057 if (IoErr() != ERROR_OBJECT_IN_USE
4058 && IoErr() != ERROR_OBJECT_EXISTS)
4059# endif
4060#endif
4061 break;
4062 }
4063
4064 /*
4065 * A file name equal to old_fname is OK to use.
4066 */
4067 if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
4068 break;
4069
4070 /*
4071 * get here when file already exists
4072 */
4073 if (fname[n - 2] == 'w' && fname[n - 1] == 'p') /* first try */
4074 {
4075#ifndef SHORT_FNAME
4076 /*
4077 * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
4078 * and file.doc are the same file. To guess if this problem is
4079 * present try if file.doc.swx exists. If it does, we set
4080 * buf->b_shortname and try file_doc.swp (dots replaced by
4081 * underscores for this file), and try again. If it doesn't we
4082 * assume that "file.doc.swp" already exists.
4083 */
4084 if (!(buf->b_p_sn || buf->b_shortname)) /* not tried yet */
4085 {
4086 fname[n - 1] = 'x';
4087 r = mch_getperm(fname); /* try "file.swx" */
4088 fname[n - 1] = 'p';
4089 if (r >= 0) /* "file.swx" seems to exist */
4090 {
4091 buf->b_shortname = TRUE;
4092 vim_free(fname);
Bram Moolenaar04a09c12005-08-01 22:02:32 +00004093 fname = makeswapname(buf->b_fname, buf->b_ffname,
4094 buf, dir_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095 continue; /* try again with '.' replaced with '_' */
4096 }
4097 }
4098#endif
4099 /*
4100 * If we get here the ".swp" file really exists.
4101 * Give an error message, unless recovering, no file name, we are
4102 * viewing a help file or when the path of the file is different
4103 * (happens when all .swp files are in one directory).
4104 */
Bram Moolenaar8fc061c2004-12-29 21:03:02 +00004105 if (!recoverymode && buf->b_fname != NULL
4106 && !buf->b_help && !(buf->b_flags & BF_DUMMY))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004107 {
4108 int fd;
4109 struct block0 b0;
4110 int differ = FALSE;
4111
4112 /*
4113 * Try to read block 0 from the swap file to get the original
4114 * file name (and inode number).
4115 */
4116 fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
4117 if (fd >= 0)
4118 {
4119 if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
4120 {
4121 /*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004122 * If the swapfile has the same directory as the
4123 * buffer don't compare the directory names, they can
4124 * have a different mountpoint.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004126 if (b0.b0_flags & B0_SAME_DIR)
4127 {
4128 if (fnamecmp(gettail(buf->b_ffname),
4129 gettail(b0.b0_fname)) != 0
4130 || !same_directory(fname, buf->b_ffname))
Bram Moolenaar900b4d72005-12-12 22:05:50 +00004131 {
4132#ifdef CHECK_INODE
4133 /* Symlinks may point to the same file even
4134 * when the name differs, need to check the
4135 * inode too. */
4136 expand_env(b0.b0_fname, NameBuff, MAXPATHL);
4137 if (fnamecmp_ino(buf->b_ffname, NameBuff,
4138 char_to_long(b0.b0_ino)))
4139#endif
4140 differ = TRUE;
4141 }
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004142 }
4143 else
4144 {
4145 /*
4146 * The name in the swap file may be
4147 * "~user/path/file". Expand it first.
4148 */
4149 expand_env(b0.b0_fname, NameBuff, MAXPATHL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150#ifdef CHECK_INODE
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004151 if (fnamecmp_ino(buf->b_ffname, NameBuff,
Bram Moolenaar900b4d72005-12-12 22:05:50 +00004152 char_to_long(b0.b0_ino)))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004153 differ = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154#else
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004155 if (fnamecmp(NameBuff, buf->b_ffname) != 0)
4156 differ = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004158 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 }
4160 close(fd);
4161 }
4162#ifdef RISCOS
4163 else
4164 /* Can't open swap file, though it does exist.
4165 * Assume that the user is editing two files with
4166 * the same name in different directories. No error.
4167 */
4168 differ = TRUE;
4169#endif
4170
4171 /* give the ATTENTION message when there is an old swap file
4172 * for the current file, and the buffer was not recovered. */
4173 if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
4174 && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
4175 {
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004176#if defined(HAS_SWAP_EXISTS_ACTION)
4177 int choice = 0;
4178#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179#ifdef CREATE_DUMMY_FILE
4180 int did_use_dummy = FALSE;
4181
4182 /* Avoid getting a warning for the file being created
4183 * outside of Vim, it was created at the start of this
4184 * function. Delete the file now, because Vim might exit
4185 * here if the window is closed. */
4186 if (dummyfd != NULL)
4187 {
4188 fclose(dummyfd);
4189 dummyfd = NULL;
4190 mch_remove(buf->b_fname);
4191 did_use_dummy = TRUE;
4192 }
4193#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194
4195#if (defined(UNIX) || defined(__EMX__) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
4196 process_still_running = FALSE;
4197#endif
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004198#ifdef FEAT_AUTOCMD
4199 /*
4200 * If there is an SwapExists autocommand and we can handle
4201 * the response, trigger it. It may return 0 to ask the
4202 * user anyway.
4203 */
4204 if (swap_exists_action != SEA_NONE
4205 && has_autocmd(EVENT_SWAPEXISTS, buf->b_fname, buf))
4206 choice = do_swapexists(buf, fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004208 if (choice == 0)
4209#endif
4210 {
4211#ifdef FEAT_GUI
4212 /* If we are supposed to start the GUI but it wasn't
4213 * completely started yet, start it now. This makes
4214 * the messages displayed in the Vim window when
4215 * loading a session from the .gvimrc file. */
4216 if (gui.starting && !gui.in_use)
4217 gui_start();
4218#endif
4219 /* Show info about the existing swap file. */
4220 attention_message(buf, fname);
4221
4222 /* We don't want a 'q' typed at the more-prompt
4223 * interrupt loading a file. */
4224 got_int = FALSE;
4225 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226
4227#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004228 if (swap_exists_action != SEA_NONE && choice == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229 {
4230 char_u *name;
4231
4232 name = alloc((unsigned)(STRLEN(fname)
4233 + STRLEN(_("Swap file \""))
4234 + STRLEN(_("\" already exists!")) + 5));
4235 if (name != NULL)
4236 {
4237 STRCPY(name, _("Swap file \""));
4238 home_replace(NULL, fname, name + STRLEN(name),
4239 1000, TRUE);
4240 STRCAT(name, _("\" already exists!"));
4241 }
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004242 choice = do_dialog(VIM_WARNING,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243 (char_u *)_("VIM - ATTENTION"),
4244 name == NULL
4245 ? (char_u *)_("Swap file already exists!")
4246 : name,
4247# if defined(UNIX) || defined(__EMX__) || defined(VMS)
4248 process_still_running
4249 ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") :
4250# endif
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004251 (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL);
4252
4253# if defined(UNIX) || defined(__EMX__) || defined(VMS)
4254 if (process_still_running && choice >= 4)
4255 choice++; /* Skip missing "Delete it" button */
4256# endif
4257 vim_free(name);
4258
4259 /* pretend screen didn't scroll, need redraw anyway */
4260 msg_scrolled = 0;
4261 redraw_all_later(NOT_VALID);
4262 }
4263#endif
4264
4265#if defined(HAS_SWAP_EXISTS_ACTION)
4266 if (choice > 0)
4267 {
4268 switch (choice)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269 {
4270 case 1:
4271 buf->b_p_ro = TRUE;
4272 break;
4273 case 2:
4274 break;
4275 case 3:
4276 swap_exists_action = SEA_RECOVER;
4277 break;
4278 case 4:
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004279 mch_remove(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280 break;
4281 case 5:
4282 swap_exists_action = SEA_QUIT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004283 break;
4284 case 6:
Bram Moolenaard5bc83f2005-12-07 21:07:59 +00004285 swap_exists_action = SEA_QUIT;
4286 got_int = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287 break;
4288 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289
4290 /* If the file was deleted this fname can be used. */
4291 if (mch_getperm(fname) < 0)
4292 break;
4293 }
4294 else
4295#endif
4296 {
4297 MSG_PUTS("\n");
Bram Moolenaar4770d092006-01-12 23:22:24 +00004298 if (msg_silent == 0)
4299 /* call wait_return() later */
4300 need_wait_return = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 }
4302
4303#ifdef CREATE_DUMMY_FILE
4304 /* Going to try another name, need the dummy file again. */
4305 if (did_use_dummy)
4306 dummyfd = mch_fopen((char *)buf->b_fname, "w");
4307#endif
4308 }
4309 }
4310 }
4311
4312 /*
4313 * Change the ".swp" extension to find another file that can be used.
4314 * First decrement the last char: ".swo", ".swn", etc.
4315 * If that still isn't enough decrement the last but one char: ".svz"
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00004316 * Can happen when editing many "No Name" buffers.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004317 */
4318 if (fname[n - 1] == 'a') /* ".s?a" */
4319 {
4320 if (fname[n - 2] == 'a') /* ".saa": tried enough, give up */
4321 {
4322 EMSG(_("E326: Too many swap files found"));
4323 vim_free(fname);
4324 fname = NULL;
4325 break;
4326 }
4327 --fname[n - 2]; /* ".svz", ".suz", etc. */
4328 fname[n - 1] = 'z' + 1;
4329 }
4330 --fname[n - 1]; /* ".swo", ".swn", etc. */
4331 }
4332
4333 vim_free(dir_name);
4334#ifdef CREATE_DUMMY_FILE
4335 if (dummyfd != NULL) /* file has been created temporarily */
4336 {
4337 fclose(dummyfd);
4338 mch_remove(buf->b_fname);
4339 }
4340#endif
4341 return fname;
4342}
4343
4344 static int
4345b0_magic_wrong(b0p)
4346 ZERO_BL *b0p;
4347{
4348 return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
4349 || b0p->b0_magic_int != (int)B0_MAGIC_INT
4350 || b0p->b0_magic_short != (short)B0_MAGIC_SHORT
4351 || b0p->b0_magic_char != B0_MAGIC_CHAR);
4352}
4353
4354#ifdef CHECK_INODE
4355/*
4356 * Compare current file name with file name from swap file.
4357 * Try to use inode numbers when possible.
4358 * Return non-zero when files are different.
4359 *
4360 * When comparing file names a few things have to be taken into consideration:
4361 * - When working over a network the full path of a file depends on the host.
4362 * We check the inode number if possible. It is not 100% reliable though,
4363 * because the device number cannot be used over a network.
4364 * - When a file does not exist yet (editing a new file) there is no inode
4365 * number.
4366 * - The file name in a swap file may not be valid on the current host. The
4367 * "~user" form is used whenever possible to avoid this.
4368 *
4369 * This is getting complicated, let's make a table:
4370 *
4371 * ino_c ino_s fname_c fname_s differ =
4372 *
4373 * both files exist -> compare inode numbers:
4374 * != 0 != 0 X X ino_c != ino_s
4375 *
4376 * inode number(s) unknown, file names available -> compare file names
4377 * == 0 X OK OK fname_c != fname_s
4378 * X == 0 OK OK fname_c != fname_s
4379 *
4380 * current file doesn't exist, file for swap file exist, file name(s) not
4381 * available -> probably different
4382 * == 0 != 0 FAIL X TRUE
4383 * == 0 != 0 X FAIL TRUE
4384 *
4385 * current file exists, inode for swap unknown, file name(s) not
4386 * available -> probably different
4387 * != 0 == 0 FAIL X TRUE
4388 * != 0 == 0 X FAIL TRUE
4389 *
4390 * current file doesn't exist, inode for swap unknown, one file name not
4391 * available -> probably different
4392 * == 0 == 0 FAIL OK TRUE
4393 * == 0 == 0 OK FAIL TRUE
4394 *
4395 * current file doesn't exist, inode for swap unknown, both file names not
4396 * available -> probably same file
4397 * == 0 == 0 FAIL FAIL FALSE
4398 *
4399 * Note that when the ino_t is 64 bits, only the last 32 will be used. This
4400 * can't be changed without making the block 0 incompatible with 32 bit
4401 * versions.
4402 */
4403
4404 static int
4405fnamecmp_ino(fname_c, fname_s, ino_block0)
4406 char_u *fname_c; /* current file name */
4407 char_u *fname_s; /* file name from swap file */
4408 long ino_block0;
4409{
4410 struct stat st;
4411 ino_t ino_c = 0; /* ino of current file */
4412 ino_t ino_s; /* ino of file from swap file */
4413 char_u buf_c[MAXPATHL]; /* full path of fname_c */
4414 char_u buf_s[MAXPATHL]; /* full path of fname_s */
4415 int retval_c; /* flag: buf_c valid */
4416 int retval_s; /* flag: buf_s valid */
4417
4418 if (mch_stat((char *)fname_c, &st) == 0)
4419 ino_c = (ino_t)st.st_ino;
4420
4421 /*
4422 * First we try to get the inode from the file name, because the inode in
4423 * the swap file may be outdated. If that fails (e.g. this path is not
4424 * valid on this machine), use the inode from block 0.
4425 */
4426 if (mch_stat((char *)fname_s, &st) == 0)
4427 ino_s = (ino_t)st.st_ino;
4428 else
4429 ino_s = (ino_t)ino_block0;
4430
4431 if (ino_c && ino_s)
4432 return (ino_c != ino_s);
4433
4434 /*
4435 * One of the inode numbers is unknown, try a forced vim_FullName() and
4436 * compare the file names.
4437 */
4438 retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
4439 retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
4440 if (retval_c == OK && retval_s == OK)
4441 return (STRCMP(buf_c, buf_s) != 0);
4442
4443 /*
4444 * Can't compare inodes or file names, guess that the files are different,
4445 * unless both appear not to exist at all.
4446 */
4447 if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
4448 return FALSE;
4449 return TRUE;
4450}
4451#endif /* CHECK_INODE */
4452
4453/*
4454 * Move a long integer into a four byte character array.
4455 * Used for machine independency in block zero.
4456 */
4457 static void
4458long_to_char(n, s)
4459 long n;
4460 char_u *s;
4461{
4462 s[0] = (char_u)(n & 0xff);
4463 n = (unsigned)n >> 8;
4464 s[1] = (char_u)(n & 0xff);
4465 n = (unsigned)n >> 8;
4466 s[2] = (char_u)(n & 0xff);
4467 n = (unsigned)n >> 8;
4468 s[3] = (char_u)(n & 0xff);
4469}
4470
4471 static long
4472char_to_long(s)
4473 char_u *s;
4474{
4475 long retval;
4476
4477 retval = s[3];
4478 retval <<= 8;
4479 retval |= s[2];
4480 retval <<= 8;
4481 retval |= s[1];
4482 retval <<= 8;
4483 retval |= s[0];
4484
4485 return retval;
4486}
4487
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004488/*
4489 * Set the flags in the first block of the swap file:
4490 * - file is modified or not: buf->b_changed
4491 * - 'fileformat'
4492 * - 'fileencoding'
4493 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494 void
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004495ml_setflags(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497{
4498 bhdr_T *hp;
4499 ZERO_BL *b0p;
4500
4501 if (!buf->b_ml.ml_mfp)
4502 return;
4503 for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
4504 {
4505 if (hp->bh_bnum == 0)
4506 {
4507 b0p = (ZERO_BL *)(hp->bh_data);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004508 b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
4509 b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
4510 | (get_fileformat(buf) + 1);
4511#ifdef FEAT_MBYTE
4512 add_b0_fenc(b0p, buf);
4513#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514 hp->bh_flags |= BH_DIRTY;
4515 mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
4516 break;
4517 }
4518 }
4519}
4520
4521#if defined(FEAT_BYTEOFF) || defined(PROTO)
4522
4523#define MLCS_MAXL 800 /* max no of lines in chunk */
4524#define MLCS_MINL 400 /* should be half of MLCS_MAXL */
4525
4526/*
4527 * Keep information for finding byte offset of a line, updtytpe may be one of:
4528 * ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
4529 * Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
4530 * ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
4531 * ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
4532 */
4533 static void
4534ml_updatechunk(buf, line, len, updtype)
4535 buf_T *buf;
4536 linenr_T line;
4537 long len;
4538 int updtype;
4539{
4540 static buf_T *ml_upd_lastbuf = NULL;
4541 static linenr_T ml_upd_lastline;
4542 static linenr_T ml_upd_lastcurline;
4543 static int ml_upd_lastcurix;
4544
4545 linenr_T curline = ml_upd_lastcurline;
4546 int curix = ml_upd_lastcurix;
4547 long size;
4548 chunksize_T *curchnk;
4549 int rest;
4550 bhdr_T *hp;
4551 DATA_BL *dp;
4552
4553 if (buf->b_ml.ml_usedchunks == -1 || len == 0)
4554 return;
4555 if (buf->b_ml.ml_chunksize == NULL)
4556 {
4557 buf->b_ml.ml_chunksize = (chunksize_T *)
4558 alloc((unsigned)sizeof(chunksize_T) * 100);
4559 if (buf->b_ml.ml_chunksize == NULL)
4560 {
4561 buf->b_ml.ml_usedchunks = -1;
4562 return;
4563 }
4564 buf->b_ml.ml_numchunks = 100;
4565 buf->b_ml.ml_usedchunks = 1;
4566 buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
4567 buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
4568 }
4569
4570 if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
4571 {
4572 /*
4573 * First line in empty buffer from ml_flush_line() -- reset
4574 */
4575 buf->b_ml.ml_usedchunks = 1;
4576 buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
4577 buf->b_ml.ml_chunksize[0].mlcs_totalsize =
4578 (long)STRLEN(buf->b_ml.ml_line_ptr) + 1;
4579 return;
4580 }
4581
4582 /*
4583 * Find chunk that our line belongs to, curline will be at start of the
4584 * chunk.
4585 */
4586 if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
4587 || updtype != ML_CHNK_ADDLINE)
4588 {
4589 for (curline = 1, curix = 0;
4590 curix < buf->b_ml.ml_usedchunks - 1
4591 && line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4592 curix++)
4593 {
4594 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4595 }
4596 }
4597 else if (line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines
4598 && curix < buf->b_ml.ml_usedchunks - 1)
4599 {
4600 /* Adjust cached curix & curline */
4601 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4602 curix++;
4603 }
4604 curchnk = buf->b_ml.ml_chunksize + curix;
4605
4606 if (updtype == ML_CHNK_DELLINE)
Bram Moolenaar5a6404c2006-11-01 17:12:57 +00004607 len = -len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608 curchnk->mlcs_totalsize += len;
4609 if (updtype == ML_CHNK_ADDLINE)
4610 {
4611 curchnk->mlcs_numlines++;
4612
4613 /* May resize here so we don't have to do it in both cases below */
4614 if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
4615 {
4616 buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
4617 buf->b_ml.ml_chunksize = (chunksize_T *)
4618 vim_realloc(buf->b_ml.ml_chunksize,
4619 sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
4620 if (buf->b_ml.ml_chunksize == NULL)
4621 {
4622 /* Hmmmm, Give up on offset for this buffer */
4623 buf->b_ml.ml_usedchunks = -1;
4624 return;
4625 }
4626 }
4627
4628 if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
4629 {
4630 int count; /* number of entries in block */
4631 int idx;
4632 int text_end;
4633 int linecnt;
4634
4635 mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
4636 buf->b_ml.ml_chunksize + curix,
4637 (buf->b_ml.ml_usedchunks - curix) *
4638 sizeof(chunksize_T));
Bram Moolenaar9439cdd2009-04-22 13:39:36 +00004639 /* Compute length of first half of lines in the split chunk */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004640 size = 0;
4641 linecnt = 0;
4642 while (curline < buf->b_ml.ml_line_count
4643 && linecnt < MLCS_MINL)
4644 {
4645 if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
4646 {
4647 buf->b_ml.ml_usedchunks = -1;
4648 return;
4649 }
4650 dp = (DATA_BL *)(hp->bh_data);
4651 count = (long)(buf->b_ml.ml_locked_high) -
4652 (long)(buf->b_ml.ml_locked_low) + 1;
4653 idx = curline - buf->b_ml.ml_locked_low;
4654 curline = buf->b_ml.ml_locked_high + 1;
4655 if (idx == 0)/* first line in block, text at the end */
4656 text_end = dp->db_txt_end;
4657 else
4658 text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
4659 /* Compute index of last line to use in this MEMLINE */
4660 rest = count - idx;
4661 if (linecnt + rest > MLCS_MINL)
4662 {
4663 idx += MLCS_MINL - linecnt - 1;
4664 linecnt = MLCS_MINL;
4665 }
4666 else
4667 {
4668 idx = count - 1;
4669 linecnt += rest;
4670 }
4671 size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
4672 }
4673 buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
4674 buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
4675 buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
4676 buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
4677 buf->b_ml.ml_usedchunks++;
4678 ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
4679 return;
4680 }
4681 else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
4682 && curix == buf->b_ml.ml_usedchunks - 1
4683 && buf->b_ml.ml_line_count - line <= 1)
4684 {
4685 /*
4686 * We are in the last chunk and it is cheap to crate a new one
4687 * after this. Do it now to avoid the loop above later on
4688 */
4689 curchnk = buf->b_ml.ml_chunksize + curix + 1;
4690 buf->b_ml.ml_usedchunks++;
4691 if (line == buf->b_ml.ml_line_count)
4692 {
4693 curchnk->mlcs_numlines = 0;
4694 curchnk->mlcs_totalsize = 0;
4695 }
4696 else
4697 {
4698 /*
4699 * Line is just prior to last, move count for last
4700 * This is the common case when loading a new file
4701 */
4702 hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
4703 if (hp == NULL)
4704 {
4705 buf->b_ml.ml_usedchunks = -1;
4706 return;
4707 }
4708 dp = (DATA_BL *)(hp->bh_data);
4709 if (dp->db_line_count == 1)
4710 rest = dp->db_txt_end - dp->db_txt_start;
4711 else
4712 rest =
4713 ((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
4714 - dp->db_txt_start;
4715 curchnk->mlcs_totalsize = rest;
4716 curchnk->mlcs_numlines = 1;
4717 curchnk[-1].mlcs_totalsize -= rest;
4718 curchnk[-1].mlcs_numlines -= 1;
4719 }
4720 }
4721 }
4722 else if (updtype == ML_CHNK_DELLINE)
4723 {
4724 curchnk->mlcs_numlines--;
4725 ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
4726 if (curix < (buf->b_ml.ml_usedchunks - 1)
4727 && (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
4728 <= MLCS_MINL)
4729 {
4730 curix++;
4731 curchnk = buf->b_ml.ml_chunksize + curix;
4732 }
4733 else if (curix == 0 && curchnk->mlcs_numlines <= 0)
4734 {
4735 buf->b_ml.ml_usedchunks--;
4736 mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
4737 buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
4738 return;
4739 }
4740 else if (curix == 0 || (curchnk->mlcs_numlines > 10
4741 && (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
4742 > MLCS_MINL))
4743 {
4744 return;
4745 }
4746
4747 /* Collapse chunks */
4748 curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
4749 curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
4750 buf->b_ml.ml_usedchunks--;
4751 if (curix < buf->b_ml.ml_usedchunks)
4752 {
4753 mch_memmove(buf->b_ml.ml_chunksize + curix,
4754 buf->b_ml.ml_chunksize + curix + 1,
4755 (buf->b_ml.ml_usedchunks - curix) *
4756 sizeof(chunksize_T));
4757 }
4758 return;
4759 }
4760 ml_upd_lastbuf = buf;
4761 ml_upd_lastline = line;
4762 ml_upd_lastcurline = curline;
4763 ml_upd_lastcurix = curix;
4764}
4765
4766/*
4767 * Find offset for line or line with offset.
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004768 * Find line with offset if "lnum" is 0; return remaining offset in offp
4769 * Find offset of line if "lnum" > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770 * return -1 if information is not available
4771 */
4772 long
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004773ml_find_line_or_offset(buf, lnum, offp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774 buf_T *buf;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004775 linenr_T lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004776 long *offp;
4777{
4778 linenr_T curline;
4779 int curix;
4780 long size;
4781 bhdr_T *hp;
4782 DATA_BL *dp;
4783 int count; /* number of entries in block */
4784 int idx;
4785 int start_idx;
4786 int text_end;
4787 long offset;
4788 int len;
4789 int ffdos = (get_fileformat(buf) == EOL_DOS);
4790 int extra = 0;
4791
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004792 /* take care of cached line first */
4793 ml_flush_line(curbuf);
4794
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 if (buf->b_ml.ml_usedchunks == -1
4796 || buf->b_ml.ml_chunksize == NULL
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004797 || lnum < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004798 return -1;
4799
4800 if (offp == NULL)
4801 offset = 0;
4802 else
4803 offset = *offp;
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004804 if (lnum == 0 && offset <= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805 return 1; /* Not a "find offset" and offset 0 _must_ be in line 1 */
4806 /*
4807 * Find the last chunk before the one containing our line. Last chunk is
4808 * special because it will never qualify
4809 */
4810 curline = 1;
4811 curix = size = 0;
4812 while (curix < buf->b_ml.ml_usedchunks - 1
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004813 && ((lnum != 0
4814 && lnum >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 || (offset != 0
4816 && offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
4817 + ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
4818 {
4819 curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4820 size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
4821 if (offset && ffdos)
4822 size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
4823 curix++;
4824 }
4825
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004826 while ((lnum != 0 && curline < lnum) || (offset != 0 && size < offset))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004827 {
4828 if (curline > buf->b_ml.ml_line_count
4829 || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
4830 return -1;
4831 dp = (DATA_BL *)(hp->bh_data);
4832 count = (long)(buf->b_ml.ml_locked_high) -
4833 (long)(buf->b_ml.ml_locked_low) + 1;
4834 start_idx = idx = curline - buf->b_ml.ml_locked_low;
4835 if (idx == 0)/* first line in block, text at the end */
4836 text_end = dp->db_txt_end;
4837 else
4838 text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
4839 /* Compute index of last line to use in this MEMLINE */
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004840 if (lnum != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004841 {
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004842 if (curline + (count - idx) >= lnum)
4843 idx += lnum - curline - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004844 else
4845 idx = count - 1;
4846 }
4847 else
4848 {
4849 extra = 0;
4850 while (offset >= size
4851 + text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
4852 + ffdos)
4853 {
4854 if (ffdos)
4855 size++;
4856 if (idx == count - 1)
4857 {
4858 extra = 1;
4859 break;
4860 }
4861 idx++;
4862 }
4863 }
4864 len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
4865 size += len;
4866 if (offset != 0 && size >= offset)
4867 {
4868 if (size + ffdos == offset)
4869 *offp = 0;
4870 else if (idx == start_idx)
4871 *offp = offset - size + len;
4872 else
4873 *offp = offset - size + len
4874 - (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
4875 curline += idx - start_idx + extra;
4876 if (curline > buf->b_ml.ml_line_count)
4877 return -1; /* exactly one byte beyond the end */
4878 return curline;
4879 }
4880 curline = buf->b_ml.ml_locked_high + 1;
4881 }
4882
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004883 if (lnum != 0)
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00004884 {
4885 /* Count extra CR characters. */
4886 if (ffdos)
Bram Moolenaar5313dcb2005-02-22 08:56:13 +00004887 size += lnum - 1;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00004888
4889 /* Don't count the last line break if 'bin' and 'noeol'. */
4890 if (buf->b_p_bin && !buf->b_p_eol)
4891 size -= ffdos + 1;
4892 }
4893
Bram Moolenaar071d4272004-06-13 20:20:40 +00004894 return size;
4895}
4896
4897/*
4898 * Goto byte in buffer with offset 'cnt'.
4899 */
4900 void
4901goto_byte(cnt)
4902 long cnt;
4903{
4904 long boff = cnt;
4905 linenr_T lnum;
4906
4907 ml_flush_line(curbuf); /* cached line may be dirty */
4908 setpcmark();
4909 if (boff)
4910 --boff;
4911 lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
4912 if (lnum < 1) /* past the end */
4913 {
4914 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4915 curwin->w_curswant = MAXCOL;
4916 coladvance((colnr_T)MAXCOL);
4917 }
4918 else
4919 {
4920 curwin->w_cursor.lnum = lnum;
4921 curwin->w_cursor.col = (colnr_T)boff;
Bram Moolenaar943d2b52005-12-02 00:50:49 +00004922# ifdef FEAT_VIRTUALEDIT
4923 curwin->w_cursor.coladd = 0;
4924# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925 curwin->w_set_curswant = TRUE;
4926 }
4927 check_cursor();
4928
4929# ifdef FEAT_MBYTE
4930 /* Make sure the cursor is on the first byte of a multi-byte char. */
4931 if (has_mbyte)
4932 mb_adjust_cursor();
4933# endif
4934}
4935#endif