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