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