Annotation of src/usr.bin/vim/memline.c, Revision 1.1.1.1
1.1 downsj 1: /* $OpenBSD$ */
2: /* vi:set ts=4 sw=4:
3: *
4: * VIM - Vi IMproved by Bram Moolenaar
5: *
6: * Do ":help uganda" in Vim to read copying and usage conditions.
7: * Do ":help credits" in Vim to see a list of people who contributed.
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
32: * containing that line is made big enough to hold the line. It may span
33: * several pages. 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
40: * a positive number. Use mf_trans_del() to get the new number, before
41: * calling mf_get().
42: */
43:
44: /*
45: * The following functions are available to work with a memline:
46: *
47: * ml_open() open a new memline for a buffer
48: * ml_setname() change the file name for a memline
49: * ml_close() close the memline for a buffer
50: * ml_close_all() close all memlines
51: * ml_recover() read a memline for recovery
52: * ml_sync_all() flush changed blocks to file for all files
53: * ml_preserve() flush everything into the file for one file
54: * ml_get() get a pointer to a line
55: * ml_get_pos() get a pointer to a position in a line
56: * ml_get_cursor() get a pointer to the char under the cursor
57: * ml_get_buf() get a pointer to a line in a specific buffer
58: * ml_line_alloced() return TRUE if line was allocated
59: * ml_append() append a new line
60: * ml_replace() replace a line
61: * ml_delete() delete a line
62: * ml_setmarked() set mark for a line (for :global command)
63: * ml_firstmarked() get first line with a mark (for :global command)
64: * ml_clearmarked() clear all line marks (for :global command)
65: */
66:
67: #if defined MSDOS || defined WIN32
68: # include <io.h>
69: #endif
70:
71: #include "vim.h"
72: #include "globals.h"
73: #include "proto.h"
74: #include "option.h"
75: #ifdef HAVE_FCNTL_H
76: # include <fcntl.h>
77: #endif
78: #ifndef UNIX /* it's in unix.h for Unix */
79: # include <time.h>
80: #endif
81:
82: #ifdef SASC
83: # include <proto/dos.h> /* for Open() and Close() */
84: #endif
85:
86: typedef struct block0 ZERO_BL; /* contents of the first block */
87: typedef struct pointer_block PTR_BL; /* contents of a pointer block */
88: typedef struct data_block DATA_BL; /* contents of a data block */
89: typedef struct pointer_entry PTR_EN; /* block/line-count pair */
90:
91: #define DATA_ID (('d' << 8) + 'a') /* data block id */
92: #define PTR_ID (('p' << 8) + 't') /* pointer block id */
93: #define BLOCK0_ID0 'b' /* block 0 id 0 */
94: #define BLOCK0_ID1 '0' /* block 0 id 1 */
95:
96: /*
97: * pointer to a block, used in a pointer block
98: */
99: struct pointer_entry
100: {
101: blocknr_t pe_bnum; /* block number */
102: linenr_t pe_line_count; /* number of lines in this branch */
103: linenr_t pe_old_lnum; /* lnum for this block (for recovery) */
104: int pe_page_count; /* number of pages in block pe_bnum */
105: };
106:
107: /*
108: * A pointer block contains a list of branches in the tree.
109: */
110: struct pointer_block
111: {
112: short_u pb_id; /* ID for pointer block: PTR_ID */
113: short_u pb_count; /* number of pointer in this block */
114: short_u pb_count_max; /* maximum value for pb_count */
115: PTR_EN pb_pointer[1]; /* list of pointers to blocks (actually longer)
116: * followed by empty space until end of page */
117: };
118:
119: /*
120: * A data block is a leaf in the tree.
121: *
122: * The text of the lines is at the end of the block. The text of the first line
123: * in the block is put at the end, the text of the second line in front of it,
124: * etc. Thus the order of the lines is the opposite of the line number.
125: */
126: struct data_block
127: {
128: short_u db_id; /* ID for data block: DATA_ID */
129: unsigned db_free; /* free space available */
130: unsigned db_txt_start; /* byte where text starts */
131: unsigned db_txt_end; /* byte just after data block */
132: linenr_t db_line_count; /* number of lines in this block */
133: unsigned db_index[1]; /* index for start of line (actually bigger)
134: * followed by empty space upto db_txt_start
135: * followed by the text in the lines until
136: * end of page */
137: };
138:
139: /*
140: * The low bits of db_index hold the actual index. The topmost bit is
141: * used for the global command to be able to mark a line.
142: * This method is not clean, but otherwise there would be at least one extra
143: * byte used for each line.
144: * The mark has to be in this place to keep it with the correct line when other
145: * lines are inserted or deleted.
146: */
147: #define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
148: #define DB_INDEX_MASK (~DB_MARKED)
149:
150: #define INDEX_SIZE (sizeof(unsigned)) /* size of one db_index entry */
151: #define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */
152:
153: #define B0_FNAME_SIZE 900
154: #define B0_UNAME_SIZE 40
155: #define B0_HNAME_SIZE 40
156: /*
157: * Restrict the numbers to 32 bits, otherwise most compilers will complain.
158: * This won't detect a 64 bit machine that only swaps a byte in the top 32
159: * bits, but that is crazy anyway.
160: */
161: #define B0_MAGIC_LONG 0x30313233
162: #define B0_MAGIC_INT 0x20212223
163: #define B0_MAGIC_SHORT 0x10111213
164: #define B0_MAGIC_CHAR 0x55
165:
166: /*
167: * Block zero holds all info about the swap file.
168: *
169: * NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE, it makes all existing swap
170: * files unusable!
171: *
172: * If size of block0 changes anyway, adjust minimal block size
173: * in mf_open()!!
174: *
175: * This block is built up of single bytes, to make it portable accros
176: * different machines. b0_magic_* is used to check the byte order and size of
177: * variables, because the rest of the swap is not portable.
178: */
179: struct block0
180: {
181: char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */
182: char_u b0_version[10]; /* Vim version string */
183: char_u b0_page_size[4];/* number of bytes per page */
184: char_u b0_mtime[4]; /* last modification time of file */
185: char_u b0_ino[4]; /* inode of b0_fname */
186: char_u b0_pid[4]; /* process id of creator (or 0) */
187: char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
188: char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
189: char_u b0_fname[B0_FNAME_SIZE]; /* name of file being edited */
190: long b0_magic_long; /* check for byte order of long */
191: int b0_magic_int; /* check for byte order of int */
192: short b0_magic_short; /* check for byte order of short */
193: char_u b0_magic_char; /* check for last char */
194: };
195:
196: #define STACK_INCR 5 /* nr of entries added to ml_stack at a time */
197:
198: /*
199: * The line number where the first mark may be is remembered.
200: * If it is 0 there are no marks at all.
201: * (always used for the current buffer only, no buffer change possible while
202: * executing a global command).
203: */
204: static linenr_t lowest_marked = 0;
205:
206: /*
207: * arguments for ml_find_line()
208: */
209: #define ML_DELETE 0x11 /* delete line */
210: #define ML_INSERT 0x12 /* insert line */
211: #define ML_FIND 0x13 /* just find the line */
212: #define ML_FLUSH 0x02 /* flush locked block */
213: #define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */
214:
215: static void ml_open_file __ARGS((BUF *));
216: static void set_b0_fname __ARGS((ZERO_BL *, BUF *buf));
217: static void swapfile_info __ARGS((char_u *));
218: static int get_names __ARGS((char_u **, char_u *));
219: static int ml_append_int __ARGS((BUF *, linenr_t, char_u *, colnr_t, int));
220: static int ml_delete_int __ARGS((BUF *, linenr_t, int));
221: static char_u *findswapname __ARGS((BUF *, char_u **, char_u *));
222: static void ml_flush_line __ARGS((BUF *));
223: static BHDR *ml_new_data __ARGS((MEMFILE *, int, int));
224: static BHDR *ml_new_ptr __ARGS((MEMFILE *));
225: static BHDR *ml_find_line __ARGS((BUF *, linenr_t, int));
226: static int ml_add_stack __ARGS((BUF *));
227: static char_u *makeswapname __ARGS((BUF *, char_u *));
228: static void ml_lineadd __ARGS((BUF *, int));
229: static int b0_magic_wrong __ARGS((ZERO_BL *));
230: #ifdef CHECK_INODE
231: static int fnamecmp_ino __ARGS((char_u *, char_u *, long));
232: #endif
233: static void long_to_char __ARGS((long, char_u *));
234: static long char_to_long __ARGS((char_u *));
235:
236: /*
237: * open a new memline for 'curbuf'
238: *
239: * return FAIL for failure, OK otherwise
240: */
241: int
242: ml_open()
243: {
244: MEMFILE *mfp;
245: char_u *fname;
246: BHDR *hp = NULL;
247: ZERO_BL *b0p;
248: PTR_BL *pp;
249: DATA_BL *dp;
250: char_u *dirp;
251:
252: /*
253: * init fields in memline struct
254: */
255: curbuf->b_ml.ml_stack_size = 0; /* no stack yet */
256: curbuf->b_ml.ml_stack = NULL; /* no stack yet */
257: curbuf->b_ml.ml_stack_top = 0; /* nothing in the stack */
258: curbuf->b_ml.ml_locked = NULL; /* no cached block */
259: curbuf->b_ml.ml_line_lnum = 0; /* no cached line */
260:
261: /*
262: * Make file name for swap file.
263: * If we are unable to find a file name, mf_fname will be NULL
264: * and the memfile will be in memory only (no recovery possible).
265: * When 'updatecount' is 0 and for help files on Unix there is never a swap
266: * file.
267: */
268: #if defined(UNIX) || defined(__EMX__)
269: /* why only on Unix an exception for help files??? */
270: if (p_uc == 0 || curbuf->b_help)
271: #else
272: if (p_uc == 0)
273: #endif
274: dirp = (char_u *)"";
275: else
276: dirp = p_dir;
277:
278: /*
279: * Open the memfile.
280: *
281: * If no swap file is wanted *dirp will be NUL, try with fname == NULL.
282: * Otherwise try all directories in 'directory' option. If that fails try
283: * with fname == NULL.
284: */
285: for (;;)
286: {
287: if (*dirp == NUL)
288: fname = NULL;
289: else
290: {
291: fname = findswapname(curbuf, &dirp, NULL);
292: if (fname == NULL)
293: continue;
294: }
295: mfp = mf_open(fname, TRUE);
296: /* stop when memfile opened or no other fname to try */
297: if (mfp != NULL || (fname == NULL && *dirp == NUL))
298: break;
299: vim_free(fname);
300: }
301:
302: if (mfp == NULL)
303: goto error;
304: curbuf->b_ml.ml_mfp = mfp;
305: curbuf->b_ml.ml_flags = ML_EMPTY;
306: curbuf->b_ml.ml_line_count = 1;
307:
308: if (!(p_uc == 0 || curbuf->b_help) && mfp->mf_fname == NULL)
309: {
310: need_wait_return = TRUE; /* call wait_return later */
311: ++no_wait_return;
312: (void)EMSG("Unable to open swap file, recovery impossible");
313: --no_wait_return;
314: }
315: #if defined(MSDOS) || defined(WIN32)
316: /*
317: * set full pathname for swap file now, because a ":!cd dir" may
318: * change directory without us knowing it.
319: */
320: mf_fullname(mfp);
321: #endif
322:
323: /*
324: * fill block0 struct and write page 0
325: */
326: if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
327: goto error;
328: if (hp->bh_bnum != 0)
329: {
330: EMSG("didn't get block nr 0?");
331: goto error;
332: }
333: b0p = (ZERO_BL *)(hp->bh_data);
334:
335: (void)vim_memset(b0p, 0, sizeof(ZERO_BL)); /* init all to zero */
336:
337: b0p->b0_id[0] = BLOCK0_ID0;
338: b0p->b0_id[1] = BLOCK0_ID1;
339: b0p->b0_magic_long = (long)B0_MAGIC_LONG;
340: b0p->b0_magic_int = (int)B0_MAGIC_INT;
341: b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
342: b0p->b0_magic_char = B0_MAGIC_CHAR;
343:
344: STRNCPY(b0p->b0_version, Version, 10);
345: set_b0_fname(b0p, curbuf);
346: long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
347: (void)mch_get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
348: b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
349: mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
350: b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
351: long_to_char(mch_get_pid(), b0p->b0_pid);
352:
353: /*
354: * Always sync block number 0 to disk, so we can check the file name in
355: * the swap file in findswapname(). Don't do this for help files though.
356: */
357: mf_put(mfp, hp, TRUE, FALSE);
358: if (!curbuf->b_help)
359: mf_sync(mfp, FALSE, FALSE, FALSE);
360:
361: /*
362: * fill in root pointer block and write page 1
363: */
364: if ((hp = ml_new_ptr(mfp)) == NULL)
365: goto error;
366: if (hp->bh_bnum != 1)
367: {
368: EMSG("didn't get block nr 1?");
369: goto error;
370: }
371: pp = (PTR_BL *)(hp->bh_data);
372: pp->pb_count = 1;
373: pp->pb_pointer[0].pe_bnum = 2;
374: pp->pb_pointer[0].pe_page_count = 1;
375: pp->pb_pointer[0].pe_old_lnum = 1;
376: pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */
377: mf_put(mfp, hp, TRUE, FALSE);
378:
379: /*
380: * allocate first data block and create an empty line 1.
381: */
382: if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
383: goto error;
384: if (hp->bh_bnum != 2)
385: {
386: EMSG("didn't get block nr 2?");
387: goto error;
388: }
389:
390: dp = (DATA_BL *)(hp->bh_data);
391: dp->db_index[0] = --dp->db_txt_start; /* at end of block */
392: dp->db_free -= 1 + INDEX_SIZE;
393: dp->db_line_count = 1;
394: *((char_u *)dp + dp->db_txt_start) = NUL; /* emtpy line */
395:
396: return OK;
397:
398: error:
399: if (mfp != NULL)
400: {
401: if (hp)
402: mf_put(mfp, hp, FALSE, FALSE);
403: mf_close(mfp, TRUE); /* will also free(mfp->mf_fname) */
404: }
405: else
406: vim_free(fname);
407: curbuf->b_ml.ml_mfp = NULL;
408: return FAIL;
409: }
410:
411: /*
412: * ml_setname() is called when the file name has been changed.
413: * It may rename the swap file.
414: */
415: void
416: ml_setname()
417: {
418: int success = FALSE;
419: MEMFILE *mfp;
420: char_u *fname;
421: char_u *dirp;
422:
423: /*
424: * When 'updatecount' is 0 there is never a swap file.
425: * For help files we will make a swap file now.
426: */
427: if (p_uc == 0)
428: return;
429:
430: mfp = curbuf->b_ml.ml_mfp;
431: if (mfp->mf_fd < 0) /* there is no swap file yet */
432: {
433: ml_open_file(curbuf); /* create a swap file */
434: return;
435: }
436:
437: /*
438: * Try all directories in the 'directory' option.
439: */
440: dirp = p_dir;
441: for (;;)
442: {
443: if (*dirp == NUL) /* tried all directories, fail */
444: break;
445: fname = findswapname(curbuf, &dirp, mfp->mf_fname);
446: if (fname == NULL) /* no file name found for this dir */
447: continue;
448:
449: #if defined(MSDOS) || defined(WIN32)
450: /*
451: * Set full pathname for swap file now, because a ":!cd dir" may
452: * change directory without us knowing it.
453: */
454: if (!did_cd)
455: {
456: char_u *p;
457:
458: p = FullName_save(fname);
459: vim_free(fname);
460: fname = p;
461: if (fname == NULL)
462: continue;
463: }
464: #endif
465: /* if the file name is the same we don't have to do anything */
466: if (fnamecmp(fname, mfp->mf_fname) == 0)
467: {
468: vim_free(fname);
469: success = TRUE;
470: break;
471: }
472: /* need to close the swap file before renaming */
473: if (mfp->mf_fd >= 0)
474: {
475: close(mfp->mf_fd);
476: mfp->mf_fd = -1;
477: }
478:
479: /* try to rename the swap file */
480: if (vim_rename(mfp->mf_fname, fname) == 0)
481: {
482: success = TRUE;
483: vim_free(mfp->mf_fname);
484: mfp->mf_fname = fname;
485: vim_free(mfp->mf_xfname);
486: mf_set_xfname(mfp);
487: break;
488: }
489: vim_free(fname); /* this fname didn't work, try another */
490: }
491:
492: if (mfp->mf_fd == -1) /* need to (re)open the swap file */
493: {
494: mfp->mf_fd = open((char *)mfp->mf_fname, O_RDWR | O_EXTRA);
495: if (mfp->mf_fd < 0)
496: {
497: /* could not (re)open the swap file, what can we do???? */
498: EMSG("Oops, lost the swap file!!!");
499: return;
500: }
501: }
502: if (!success)
503: EMSG("Could not rename swap file");
504: }
505:
506: /*
507: * Open a file for the memfile for all buffers.
508: * Used when 'updatecount' changes from zero to non-zero.
509: */
510: void
511: ml_open_files()
512: {
513: BUF *buf;
514:
515: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
516: ml_open_file(buf);
517: }
518:
519: /*
520: * Open a swap file for an existing memfile, if there is non swap file yet.
521: */
522: static void
523: ml_open_file(buf)
524: BUF *buf;
525: {
526: MEMFILE *mfp;
527: char_u *fname;
528: char_u *dirp;
529:
530: mfp = buf->b_ml.ml_mfp;
531: if (mfp == NULL || mfp->mf_fd >= 0) /* nothing to do */
532: return;
533:
534: dirp = p_dir;
535: /*
536: * Try all directories in 'directory' option.
537: */
538: for (;;)
539: {
540: if (*dirp == NUL)
541: break;
542: fname = findswapname(buf, &dirp, NULL);
543: if (fname == NULL)
544: continue;
545: if (mf_open_file(mfp, fname) == OK)
546: break;
547: vim_free(fname);
548: }
549:
550: if (mfp->mf_fname == NULL) /* Failed! */
551: {
552: need_wait_return = TRUE; /* call wait_return later */
553: ++no_wait_return;
554: (void)EMSG2("Unable to open swap file for \"%s\", recovery impossible",
555: buf->b_xfilename == NULL ? (char_u *)"No File"
556: : buf->b_xfilename);
557: --no_wait_return;
558: }
559: #if defined(MSDOS) || defined(WIN32)
560: /*
561: * set full pathname for swap file now, because a ":!cd dir" may
562: * change directory without us knowing it.
563: */
564: else
565: mf_fullname(mfp);
566: #endif
567: }
568:
569: /*
570: * Close memline for buffer 'buf'.
571: * If 'del_file' is TRUE, delete the swap file
572: */
573: void
574: ml_close(buf, del_file)
575: BUF *buf;
576: int del_file;
577: {
578: if (buf->b_ml.ml_mfp == NULL) /* not open */
579: return;
580: mf_close(buf->b_ml.ml_mfp, del_file); /* close the .swp file */
581: if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
582: vim_free(buf->b_ml.ml_line_ptr);
583: vim_free(buf->b_ml.ml_stack);
584: buf->b_ml.ml_mfp = NULL;
585: }
586:
587: /*
588: * Close all existing memlines and memfiles.
589: * Used when exiting.
590: * When 'del_file' is TRUE, delete the memfiles.
591: */
592: void
593: ml_close_all(del_file)
594: int del_file;
595: {
596: BUF *buf;
597:
598: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
599: ml_close(buf, del_file);
600: }
601:
602: /*
603: * Close all memfiles for not modified buffers.
604: * Only use just before exiting!
605: */
606: void
607: ml_close_notmod()
608: {
609: BUF *buf;
610:
611: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
612: if (!buf->b_changed)
613: ml_close(buf, TRUE); /* close all not-modified buffers */
614: }
615:
616: /*
617: * Update the timestamp in the .swp file.
618: * Used when the file has been written.
619: */
620: void
621: ml_timestamp(buf)
622: BUF *buf;
623: {
624: MEMFILE *mfp;
625: BHDR *hp;
626: ZERO_BL *b0p;
627:
628: mfp = buf->b_ml.ml_mfp;
629:
630: if (mfp == NULL || (hp = mf_get(mfp, (blocknr_t)0, 1)) == NULL)
631: return;
632: b0p = (ZERO_BL *)(hp->bh_data);
633: if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
634: EMSG("ml_timestamp: Didn't get block 0??");
635: else
636: set_b0_fname(b0p, buf);
637: mf_put(mfp, hp, TRUE, FALSE);
638: }
639:
640: /*
641: * Write file name and timestamp into block 0 of a swap file.
642: * Also set buf->b_mtime.
643: * Don't use NameBuff[]!!!
644: */
645: static void
646: set_b0_fname(b0p, buf)
647: ZERO_BL *b0p;
648: BUF *buf;
649: {
650: struct stat st;
651: size_t flen, ulen;
652: char_u uname[B0_UNAME_SIZE];
653:
654: if (buf->b_filename == NULL)
655: b0p->b0_fname[0] = NUL;
656: else
657: {
658: /*
659: * For a file under the home directory of the current user, we try to
660: * replace the home directory path with "~user". This helps when
661: * editing the same file on different machines over a network.
662: * First replace home dir path with "~/" with home_replace().
663: * Then insert the user name to get "~user/".
664: */
665: home_replace(NULL, buf->b_filename, b0p->b0_fname, B0_FNAME_SIZE);
666: if (b0p->b0_fname[0] == '~')
667: {
668: flen = STRLEN(b0p->b0_fname);
669: /* If there is no user name or it is too long, don't use "~/" */
670: if (mch_get_user_name(uname, B0_UNAME_SIZE) == FAIL ||
671: (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
672: STRNCPY(b0p->b0_fname, buf->b_filename, B0_FNAME_SIZE);
673: else
674: {
675: vim_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
676: vim_memmove(b0p->b0_fname + 1, uname, ulen);
677: }
678: }
679: if (stat((char *)buf->b_filename, &st) >= 0)
680: {
681: long_to_char((long)st.st_mtime, b0p->b0_mtime);
682: #ifdef CHECK_INODE
683: long_to_char((long)st.st_ino, b0p->b0_ino);
684: #endif
685: buf->b_mtime = st.st_mtime;
686: buf->b_mtime_read = st.st_mtime;
687: }
688: else
689: {
690: long_to_char(0L, b0p->b0_mtime);
691: #ifdef CHECK_INODE
692: long_to_char(0L, b0p->b0_ino);
693: #endif
694: buf->b_mtime = 0;
695: buf->b_mtime_read = 0;
696: }
697: }
698: }
699:
700: /*
701: * try to recover curbuf from the .swp file
702: */
703: void
704: ml_recover()
705: {
706: BUF *buf = NULL;
707: MEMFILE *mfp = NULL;
708: char_u *fname;
709: BHDR *hp = NULL;
710: ZERO_BL *b0p;
711: PTR_BL *pp;
712: DATA_BL *dp;
713: IPTR *ip;
714: blocknr_t bnum;
715: int page_count;
716: struct stat org_stat, swp_stat;
717: int len;
718: int directly;
719: linenr_t lnum;
720: char_u *p;
721: int i;
722: long error;
723: int cannot_open;
724: linenr_t line_count;
725: int has_error;
726: int idx;
727: int top;
728: int txt_start;
729: long size;
730: int called_from_main;
731: int serious_error = TRUE;
732: long mtime;
733:
734: called_from_main = (curbuf->b_ml.ml_mfp == NULL);
735: /*
736: * If the file name ends in ".sw?" we use it directly.
737: * Otherwise a search is done to find the swap file(s).
738: */
739: fname = curbuf->b_xfilename;
740: if (fname == NULL) /* When there is no file name */
741: fname = (char_u *)"";
742: len = STRLEN(fname);
743: if (len >= 4 && vim_strnicmp(fname + len - 4,
744: (char_u *)".sw", (size_t)3) == 0)
745: {
746: directly = TRUE;
747: fname = strsave(fname); /* make a copy for mf_open */
748: }
749: else
750: {
751: directly = FALSE;
752:
753: /* count the number of matching swap files */
754: len = recover_names(&fname, FALSE, 0);
755: if (len == 0) /* no swap files found */
756: {
757: EMSG2("No swap file found for %s", fname);
758: fname = NULL;
759: goto theend;
760: }
761: if (len == 1) /* one swap file found, use it */
762: i = 1;
763: else /* several swap files found, choose */
764: {
765: /* list the names of the swap files */
766: (void)recover_names(&fname, TRUE, 0);
767: msg_outchar('\n');
768: MSG_OUTSTR("Enter number of swap file to use (0 to quit): ");
769: i = get_number();
770: if (i < 1 || i > len)
771: {
772: fname = NULL;
773: goto theend;
774: }
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 *)alloc((unsigned)sizeof(BUF));
790: if (buf == NULL)
791: goto theend;
792:
793: /*
794: * init fields in memline struct
795: */
796: buf->b_ml.ml_stack_size = 0; /* no stack yet */
797: buf->b_ml.ml_stack = NULL; /* no stack yet */
798: buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
799: buf->b_ml.ml_line_lnum = 0; /* no cached line */
800: buf->b_ml.ml_locked = NULL; /* no locked block */
801: buf->b_ml.ml_flags = 0;
802:
803: /*
804: * open the memfile from the old swap file
805: */
806: mfp = mf_open(fname, FALSE);
807: if (mfp == NULL || mfp->mf_fd < 0)
808: {
809: EMSG2("Cannot open %s", fname);
810: goto theend;
811: }
812: buf->b_ml.ml_mfp = mfp;
813: #if defined(MSDOS) || defined(WIN32)
814: /*
815: * set full pathname for swap file now, because a ":!cd dir" may
816: * change directory without us knowing it.
817: * Careful: May free fname!
818: */
819: mf_fullname(mfp);
820: #endif
821:
822: /*
823: * try to read block 0
824: */
825: if ((hp = mf_get(mfp, (blocknr_t)0, 1)) == NULL)
826: {
827: msg_start();
828: MSG_OUTSTR("Unable to read block 0 from ");
829: msg_outtrans(mfp->mf_fname);
830: MSG_OUTSTR("\nMaybe no changes were made or Vim did not update the swap file");
831: msg_end();
832: goto theend;
833: }
834: b0p = (ZERO_BL *)(hp->bh_data);
835: if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
836: {
837: EMSG2("%s is not a swap file", mfp->mf_fname);
838: goto theend;
839: }
840: if (b0_magic_wrong(b0p))
841: {
842: msg_start();
843: MSG_OUTSTR("The file ");
844: msg_outtrans(mfp->mf_fname);
845: #if defined(MSDOS) || defined(WIN32)
846: if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
847: MSG_OUTSTR(" cannot be used with this version of Vim.\n");
848: else
849: #endif
850: MSG_OUTSTR(" cannot be used on this computer.\n");
851: MSG_OUTSTR("The file was created on ");
852: /* avoid going past the end of currupted hostname */
853: b0p->b0_fname[0] = NUL;
854: MSG_OUTSTR(b0p->b0_hname);
855: MSG_OUTSTR(",\nor the file has been damaged.");
856: msg_end();
857: goto theend;
858: }
859: /*
860: * If we guessed the wrong page size, we have to recalculate the
861: * highest block number in the file.
862: */
863: if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
864: {
865: mfp->mf_page_size = (unsigned)char_to_long(b0p->b0_page_size);
866: if ((size = lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0)
867: mfp->mf_blocknr_max = 0; /* no file or empty file */
868: else
869: mfp->mf_blocknr_max = size / mfp->mf_page_size;
870: mfp->mf_infile_count = mfp->mf_blocknr_max;
871: }
872:
873: /*
874: * If .swp file name given directly, use name from swap file for buffer.
875: */
876: if (directly)
877: {
878: expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
879: if (setfname(NameBuff, NULL, TRUE) == FAIL)
880: goto theend;
881: }
882:
883: home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL);
884: smsg((char_u *)"Using swap file \"%s\"", NameBuff);
885:
886: if (curbuf->b_filename == NULL)
887: STRCPY(NameBuff, "No File");
888: else
889: home_replace(NULL, curbuf->b_filename, NameBuff, MAXPATHL);
890: smsg((char_u *)"Original file \"%s\"", NameBuff);
891: msg_outchar((char_u)'\n');
892:
893: /*
894: * check date of swap file and original file
895: */
896: mtime = char_to_long(b0p->b0_mtime);
897: if (curbuf->b_filename != NULL &&
898: stat((char *)curbuf->b_filename, &org_stat) != -1 &&
899: ((stat((char *)mfp->mf_fname, &swp_stat) != -1 &&
900: org_stat.st_mtime > swp_stat.st_mtime) ||
901: org_stat.st_mtime != mtime))
902: {
903: EMSG("Warning: Original file may have been changed");
904: }
905: flushbuf();
906: mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
907: hp = NULL;
908:
909: /*
910: * Now that we are sure that the file is going to be recovered, clear the
911: * contents of the current buffer.
912: */
913: while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
914: ml_delete((linenr_t)1, FALSE);
915:
916: bnum = 1; /* start with block 1 */
917: page_count = 1; /* which is 1 page */
918: lnum = 0; /* append after line 0 in curbuf */
919: line_count = 0;
920: idx = 0; /* start with first index in block 1 */
921: error = 0;
922: buf->b_ml.ml_stack_top = 0;
923: buf->b_ml.ml_stack = NULL;
924: buf->b_ml.ml_stack_size = 0; /* no stack yet */
925:
926: if (curbuf->b_filename == NULL)
927: cannot_open = TRUE;
928: else
929: cannot_open = FALSE;
930:
931: serious_error = FALSE;
932: for ( ; !got_int; line_breakcheck())
933: {
934: if (hp != NULL)
935: mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
936:
937: /*
938: * get block
939: */
940: if ((hp = mf_get(mfp, (blocknr_t)bnum, page_count)) == NULL)
941: {
942: if (bnum == 1)
943: {
944: EMSG2("Unable to read block 1 from %s", mfp->mf_fname);
945: goto theend;
946: }
947: ++error;
948: ml_append(lnum++, (char_u *)"???MANY LINES MISSING", (colnr_t)0, TRUE);
949: }
950: else /* there is a block */
951: {
952: pp = (PTR_BL *)(hp->bh_data);
953: if (pp->pb_id == PTR_ID) /* it is a pointer block */
954: {
955: /* check line count when using pointer block first time */
956: if (idx == 0 && line_count != 0)
957: {
958: for (i = 0; i < (int)pp->pb_count; ++i)
959: line_count -= pp->pb_pointer[i].pe_line_count;
960: if (line_count != 0)
961: {
962: ++error;
963: ml_append(lnum++, (char_u *)"???LINE COUNT WRONG", (colnr_t)0, TRUE);
964: }
965: }
966:
967: if (pp->pb_count == 0)
968: {
969: ml_append(lnum++, (char_u *)"???EMPTY BLOCK", (colnr_t)0, TRUE);
970: ++error;
971: }
972: else if (idx < (int)pp->pb_count) /* go a block deeper */
973: {
974: if (pp->pb_pointer[idx].pe_bnum < 0)
975: {
976: /*
977: * Data block with negative block number.
978: * Try to read lines from the original file.
979: * This is slow, but it works.
980: */
981: if (!cannot_open)
982: {
983: line_count = pp->pb_pointer[idx].pe_line_count;
984: if (readfile(curbuf->b_filename, NULL, lnum, FALSE,
985: pp->pb_pointer[idx].pe_old_lnum - 1,
986: line_count, FALSE) == FAIL)
987: cannot_open = TRUE;
988: else
989: lnum += line_count;
990: }
991: if (cannot_open)
992: {
993: ++error;
994: ml_append(lnum++, (char_u *)"???LINES MISSING", (colnr_t)0, TRUE);
995: }
996: ++idx; /* get same block again for next index */
997: continue;
998: }
999:
1000: /*
1001: * going one block deeper in the tree
1002: */
1003: if ((top = ml_add_stack(buf)) < 0) /* new entry in stack */
1004: {
1005: ++error;
1006: break; /* out of memory */
1007: }
1008: ip = &(buf->b_ml.ml_stack[top]);
1009: ip->ip_bnum = bnum;
1010: ip->ip_index = idx;
1011:
1012: bnum = pp->pb_pointer[idx].pe_bnum;
1013: line_count = pp->pb_pointer[idx].pe_line_count;
1014: page_count = pp->pb_pointer[idx].pe_page_count;
1015: continue;
1016: }
1017: }
1018: else /* not a pointer block */
1019: {
1020: dp = (DATA_BL *)(hp->bh_data);
1021: if (dp->db_id != DATA_ID) /* block id wrong */
1022: {
1023: if (bnum == 1)
1024: {
1025: EMSG2("Block 1 ID wrong (%s not a .swp file?)",
1026: mfp->mf_fname);
1027: goto theend;
1028: }
1029: ++error;
1030: ml_append(lnum++, (char_u *)"???BLOCK MISSING", (colnr_t)0, TRUE);
1031: }
1032: else
1033: {
1034: /*
1035: * it is a data block
1036: * Append all the lines in this block
1037: */
1038: has_error = FALSE;
1039: /*
1040: * check length of block
1041: * if wrong, use length in pointer block
1042: */
1043: if (page_count * mfp->mf_page_size != dp->db_txt_end)
1044: {
1045: ml_append(lnum++, (char_u *)"??? from here until ???END lines may be messed up", (colnr_t)0, TRUE);
1046: ++error;
1047: has_error = TRUE;
1048: dp->db_txt_end = page_count * mfp->mf_page_size;
1049: }
1050:
1051: /* make sure there is a NUL at the end of the block */
1052: *((char_u *)dp + dp->db_txt_end - 1) = NUL;
1053:
1054: /*
1055: * check number of lines in block
1056: * if wrong, use count in data block
1057: */
1058: if (line_count != dp->db_line_count)
1059: {
1060: ml_append(lnum++, (char_u *)"??? from here until ???END lines may have been inserted/deleted", (colnr_t)0, TRUE);
1061: ++error;
1062: has_error = TRUE;
1063: }
1064:
1065: for (i = 0; i < dp->db_line_count; ++i)
1066: {
1067: txt_start = (dp->db_index[i] & DB_INDEX_MASK);
1068: if (txt_start <= HEADER_SIZE || txt_start >= (int)dp->db_txt_end)
1069: {
1070: p = (char_u *)"???";
1071: ++error;
1072: }
1073: else
1074: p = (char_u *)dp + txt_start;
1075: ml_append(lnum++, p, (colnr_t)0, TRUE);
1076: }
1077: if (has_error)
1078: ml_append(lnum++, (char_u *)"???END", (colnr_t)0, TRUE);
1079: }
1080: }
1081: }
1082:
1083: if (buf->b_ml.ml_stack_top == 0) /* finished */
1084: break;
1085:
1086: /*
1087: * go one block up in the tree
1088: */
1089: ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
1090: bnum = ip->ip_bnum;
1091: idx = ip->ip_index + 1; /* go to next index */
1092: page_count = 1;
1093: }
1094:
1095: /*
1096: * The dummy line from the empty buffer will now be after the last line in
1097: * the buffer. Delete it.
1098: */
1099: ml_delete(curbuf->b_ml.ml_line_count, FALSE);
1100:
1101: recoverymode = FALSE;
1102: if (got_int)
1103: EMSG("Recovery Interrupted");
1104: else if (error)
1105: EMSG("Errors detected while recovering; look for lines starting with ???");
1106: else
1107: {
1108: MSG("Recovery completed. You should check if everything is OK.");
1109: MSG_OUTSTR("\n(You might want to write out this file under another name\n");
1110: MSG_OUTSTR("and run diff with the original file to check for changes)\n");
1111: MSG_OUTSTR("Delete the .swp file afterwards.\n\n");
1112: cmdline_row = msg_row;
1113: }
1114:
1115: theend:
1116: if (mfp != NULL)
1117: {
1118: if (hp != NULL)
1119: mf_put(mfp, hp, FALSE, FALSE);
1120: mf_close(mfp, FALSE); /* will also vim_free(mfp->mf_fname) */
1121: }
1122: else
1123: vim_free(fname);
1124: vim_free(buf);
1125: if (serious_error && called_from_main)
1126: ml_close(curbuf, TRUE);
1127: return;
1128: }
1129:
1130: /*
1131: * Find the names of swap files in current directory and the directory given
1132: * with the 'directory' option.
1133: *
1134: * Used to:
1135: * - list the swap files for "vim -r"
1136: * - count the number of swap files when recovering
1137: * - list the swap files when recovering
1138: * - find the name of the n'th swap file when recovering
1139: */
1140: int
1141: recover_names(fname, list, nr)
1142: char_u **fname; /* base for swap file name */
1143: int list; /* when TRUE, list the swap file names */
1144: int nr; /* when non-zero, return nr'th swap file name */
1145: {
1146: int num_names;
1147: char_u *(names[6]);
1148: char_u *tail;
1149: char_u *p;
1150: int num_files;
1151: int file_count = 0;
1152: char_u **files;
1153: int i;
1154: char_u *dirp;
1155: char_u *dir_name;
1156:
1157: if (list)
1158: {
1159: /* use msg() to start the scrolling properly */
1160: msg((char_u *)"Swap files found:");
1161: msg_outchar('\n');
1162: }
1163: expand_interactively = TRUE;
1164: /*
1165: * Do the loop for every directory in 'directory'.
1166: */
1167: dirp = p_dir;
1168: while (*dirp)
1169: {
1170: /* find character after directory name */
1171: dir_name = dirp;
1172: while (*dirp && *dirp != ',')
1173: ++dirp;
1174: dir_name = strnsave(dir_name, (int)(dirp - dir_name));
1175: if (dir_name == NULL) /* out of memory */
1176: break;
1177: if (*dir_name == '.') /* check current dir */
1178: {
1179: if (fname == NULL || *fname == NULL)
1180: {
1181: names[0] = strsave((char_u *)"*.sw?");
1182: #ifdef UNIX
1183: /* for Unix names starting with a dot are special */
1184: names[1] = strsave((char_u *)".*.sw?");
1185: names[2] = strsave((char_u *)".sw?");
1186: num_names = 3;
1187: #else
1188: num_names = 1;
1189: #endif
1190: }
1191: else
1192: num_names = get_names(names, *fname);
1193: }
1194: else /* check directory dir_name */
1195: {
1196: if (fname == NULL || *fname == NULL)
1197: {
1198: names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
1199: #ifdef UNIX
1200: /* for Unix names starting with a dot are special */
1201: names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
1202: names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
1203: num_names = 3;
1204: #else
1205: num_names = 1;
1206: #endif
1207: }
1208: else
1209: {
1210: tail = gettail(*fname);
1211: tail = concat_fnames(dir_name, tail, TRUE);
1212: if (tail == NULL)
1213: num_names = 0;
1214: else
1215: {
1216: num_names = get_names(names, tail);
1217: vim_free(tail);
1218: }
1219: }
1220: }
1221:
1222: /* check for out-of-memory */
1223: for (i = 0; i < num_names; ++i)
1224: {
1225: if (names[i] == NULL)
1226: {
1227: for (i = 0; i < num_names; ++i)
1228: vim_free(names[i]);
1229: num_names = 0;
1230: }
1231: }
1232: if (num_names == 0)
1233: num_files = 0;
1234: else if (ExpandWildCards(num_names, names,
1235: &num_files, &files, TRUE, FALSE) == FAIL)
1236: {
1237: MSG_OUTSTR(files); /* print error message */
1238: num_files = 0;
1239: }
1240: /*
1241: * remove swapfile name of the current buffer, it must be ignored
1242: */
1243: if (curbuf->b_ml.ml_mfp != NULL &&
1244: (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
1245: {
1246: for (i = 0; i < num_files; ++i)
1247: if (fullpathcmp(p, files[i]) == FPC_SAME)
1248: {
1249: vim_free(files[i]);
1250: --num_files;
1251: for ( ; i < num_files; ++i)
1252: files[i] = files[i + 1];
1253: break;
1254: }
1255: }
1256: if (nr)
1257: {
1258: file_count += num_files;
1259: if (nr <= file_count)
1260: {
1261: *fname = strsave(files[nr - 1 + num_files - file_count]);
1262: dirp = (char_u *)""; /* stop searching */
1263: }
1264: }
1265: else if (list)
1266: {
1267: if (*dir_name == '.')
1268: {
1269: if (fname == NULL || *fname == NULL)
1270: MSG_OUTSTR(" In current directory:\n");
1271: else
1272: MSG_OUTSTR(" Using specified name:\n");
1273: }
1274: else
1275: {
1276: MSG_OUTSTR(" In directory ");
1277: msg_home_replace(dir_name);
1278: MSG_OUTSTR(":\n");
1279: }
1280:
1281: if (num_files)
1282: {
1283: for (i = 0; i < num_files; ++i)
1284: {
1285: /* print the swap file name */
1286: msg_outnum((long)++file_count);
1287: MSG_OUTSTR(". ");
1288: msg_outstr(gettail(files[i]));
1289: msg_outchar('\n');
1290: swapfile_info(files[i]);
1291: }
1292: }
1293: else
1294: MSG_OUTSTR(" -- none --\n");
1295: flushbuf();
1296: }
1297: else
1298: file_count += num_files;
1299:
1300: for (i = 0; i < num_names; ++i)
1301: vim_free(names[i]);
1302: FreeWild(num_files, files);
1303:
1304: /* advance dirp to next directory name */
1305: vim_free(dir_name);
1306: if (*dirp == ',')
1307: ++dirp;
1308: dirp = skipwhite(dirp);
1309: }
1310: expand_interactively = FALSE;
1311: return file_count;
1312: }
1313:
1314: /*
1315: * Give information about an existing swap file
1316: */
1317: static void
1318: swapfile_info(fname)
1319: char_u *fname;
1320: {
1321: struct stat st;
1322: int fd;
1323: struct block0 b0;
1324: time_t x;
1325:
1326: /* print the swap file date */
1327: if (stat((char *)fname, &st) != -1)
1328: {
1329: MSG_OUTSTR(" dated: ");
1330: x = st.st_mtime; /* Manx C can't do &st.st_mtime */
1331: MSG_OUTSTR(ctime(&x));
1332: }
1333:
1334: /*
1335: * print the original file name
1336: */
1337: fd = open((char *)fname, O_RDONLY | O_EXTRA);
1338: if (fd >= 0)
1339: {
1340: if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
1341: {
1342: if (b0.b0_id[0] != BLOCK0_ID0 ||
1343: b0.b0_id[1] != BLOCK0_ID1)
1344: MSG_OUTSTR(" [is not a swap file]");
1345: else
1346: {
1347: MSG_OUTSTR(" file name: ");
1348: msg_outstr(b0.b0_fname);
1349:
1350: if (*(b0.b0_hname) != NUL)
1351: {
1352: MSG_OUTSTR("\n host name: ");
1353: msg_outstr(b0.b0_hname);
1354: }
1355:
1356: if (*(b0.b0_uname) != NUL)
1357: {
1358: MSG_OUTSTR("\n user name: ");
1359: msg_outstr(b0.b0_uname);
1360: }
1361:
1362: if (char_to_long(b0.b0_pid) != 0L)
1363: {
1364: MSG_OUTSTR("\n process ID: ");
1365: msg_outnum(char_to_long(b0.b0_pid));
1366: #if defined(UNIX) || defined(__EMX__)
1367: /* EMX kill() not working correctly, it seems */
1368: if (kill(char_to_long(b0.b0_pid), 0) == 0)
1369: MSG_OUTSTR(" (still running)");
1370: #endif
1371: }
1372:
1373: if (b0_magic_wrong(&b0))
1374: {
1375: #if defined(MSDOS) || defined(WIN32)
1376: if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
1377: MSG_OUTSTR("\n [not usable with this version of Vim]");
1378: else
1379: #endif
1380: MSG_OUTSTR("\n [not usable on this computer]");
1381: }
1382:
1383: }
1384: }
1385: else
1386: MSG_OUTSTR(" [cannot be read]");
1387: close(fd);
1388: }
1389: else
1390: MSG_OUTSTR(" [cannot be opened]");
1391: msg_outchar('\n');
1392: }
1393:
1394: static int
1395: get_names(names, fname)
1396: char_u **names;
1397: char_u *fname;
1398: {
1399: int num_names;
1400:
1401: #ifdef SHORT_FNAME
1402: /*
1403: * (MS-DOS) always short names
1404: */
1405: names[0] = modname(fname, (char_u *)".sw?");
1406: num_names = 1;
1407: #else /* !SHORT_FNAME */
1408: # ifdef WIN32
1409: /*
1410: * (WIN32) never short names
1411: */
1412: num_names = 1;
1413: names[0] = concat_fnames(fname, (char_u *)".sw?", FALSE);
1414: # else /* !WIN32 */
1415: /*
1416: * (Not MS-DOS or WIN32) maybe short name, maybe not: try both.
1417: * Only use the short name if it is different.
1418: */
1419:
1420: int i;
1421:
1422: names[0] = concat_fnames(fname, (char_u *)".sw?", FALSE);
1423: i = curbuf->b_shortname;
1424: curbuf->b_shortname = TRUE;
1425: names[1] = modname(fname, (char_u *)".sw?");
1426: curbuf->b_shortname = i;
1427: if (STRCMP(names[0], names[1]) == 0)
1428: {
1429: vim_free(names[1]);
1430: num_names = 1;
1431: }
1432: else
1433: num_names = 2;
1434: # endif /* !WIN32 */
1435: #endif /* !SHORT_FNAME */
1436: return num_names;
1437: }
1438:
1439: /*
1440: * sync all memlines
1441: *
1442: * If 'check_file' is TRUE, check if original file exists and was not changed.
1443: * If 'check_char' is TRUE, stop syncing when character becomes available, but
1444: * always sync at least one block.
1445: */
1446: void
1447: ml_sync_all(check_file, check_char)
1448: int check_file;
1449: int check_char;
1450: {
1451: BUF *buf;
1452: struct stat st;
1453:
1454: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1455: {
1456: if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
1457: continue; /* no file */
1458:
1459: ml_flush_line(buf); /* flush buffered line */
1460: /* flush locked block */
1461: (void)ml_find_line(buf, (linenr_t)0, ML_FLUSH);
1462: if (buf->b_changed && check_file && mf_need_trans(buf->b_ml.ml_mfp) &&
1463: buf->b_filename != NULL)
1464: {
1465: /*
1466: * if original file does not exist anymore or has been changed
1467: * call ml_preserve to get rid of all negative numbered blocks
1468: */
1469: if (stat((char *)buf->b_filename, &st) == -1 ||
1470: st.st_mtime != buf->b_mtime_read)
1471: {
1472: ml_preserve(buf, FALSE);
1473: need_check_timestamps = TRUE; /* give message later */
1474: }
1475: }
1476: if (buf->b_ml.ml_mfp->mf_dirty)
1477: {
1478: mf_sync(buf->b_ml.ml_mfp, FALSE, check_char, buf->b_changed);
1479: if (check_char && mch_char_avail()) /* character available now */
1480: break;
1481: }
1482: }
1483: }
1484:
1485: /*
1486: * sync one buffer, including negative blocks
1487: *
1488: * after this all the blocks are in the swap file
1489: *
1490: * Used for the :preserve command and when the original file has been
1491: * changed or deleted.
1492: *
1493: * when message is TRUE the success of preserving is reported
1494: */
1495: void
1496: ml_preserve(buf, message)
1497: BUF *buf;
1498: int message;
1499: {
1500: BHDR *hp;
1501: linenr_t lnum;
1502: MEMFILE *mfp = buf->b_ml.ml_mfp;
1503: int status;
1504:
1505: if (mfp == NULL || mfp->mf_fname == NULL)
1506: {
1507: if (message)
1508: EMSG("Cannot preserve, there is no swap file");
1509: return;
1510: }
1511:
1512: ml_flush_line(buf); /* flush buffered line */
1513: (void)ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush locked block */
1514: status = mf_sync(mfp, TRUE, FALSE, TRUE);
1515:
1516: /* stack is invalid after mf_sync(.., TRUE, ..) */
1517: buf->b_ml.ml_stack_top = 0;
1518:
1519: /*
1520: * Some of the data blocks may have been changed from negative to
1521: * positive block number. In that case the pointer blocks need to be
1522: * updated.
1523: *
1524: * We don't know in which pointer block the references are, so we visit
1525: * all data blocks until there are no more translations to be done (or
1526: * we hit the end of the file, which can only happen in case a write fails,
1527: * e.g. when file system if full).
1528: * ml_find_line() does the work by translating the negative block numbers
1529: * when getting the first line of each data block.
1530: */
1531: if (mf_need_trans(mfp))
1532: {
1533: lnum = 1;
1534: while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
1535: {
1536: hp = ml_find_line(buf, lnum, ML_FIND);
1537: if (hp == NULL)
1538: {
1539: status = FAIL;
1540: goto theend;
1541: }
1542: CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
1543: lnum = buf->b_ml.ml_locked_high + 1;
1544: }
1545: (void)ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush locked block */
1546: if (mf_sync(mfp, TRUE, FALSE, TRUE) == FAIL) /* sync the updated pointer blocks */
1547: status = FAIL;
1548: buf->b_ml.ml_stack_top = 0; /* stack is invalid now */
1549: }
1550: theend:
1551: if (message)
1552: {
1553: if (status == OK)
1554: MSG("File preserved");
1555: else
1556: EMSG("Preserve failed");
1557: }
1558: }
1559:
1560: /*
1561: * get a pointer to a (read-only copy of a) line
1562: *
1563: * On failure an error message is given and IObuff is returned (to avoid
1564: * having to check for error everywhere).
1565: */
1566: char_u *
1567: ml_get(lnum)
1568: linenr_t lnum;
1569: {
1570: return ml_get_buf(curbuf, lnum, FALSE);
1571: }
1572:
1573: /*
1574: * ml_get_pos: get pointer to position 'pos'
1575: */
1576: char_u *
1577: ml_get_pos(pos)
1578: FPOS *pos;
1579: {
1580: return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
1581: }
1582:
1583: /*
1584: * ml_get_pos: get pointer to cursor line.
1585: */
1586: char_u *
1587: ml_get_curline()
1588: {
1589: return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
1590: }
1591:
1592: /*
1593: * ml_get_pos: get pointer to cursor position
1594: */
1595: char_u *
1596: ml_get_cursor()
1597: {
1598: return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
1599: curwin->w_cursor.col);
1600: }
1601:
1602: /*
1603: * get a pointer to a line in a specific buffer
1604: *
1605: * will_change: if TRUE mark the buffer dirty (chars in the line will be
1606: * changed)
1607: */
1608: char_u *
1609: ml_get_buf(buf, lnum, will_change)
1610: BUF *buf;
1611: linenr_t lnum;
1612: int will_change; /* line will be changed */
1613: {
1614: BHDR *hp;
1615: DATA_BL *dp;
1616: char_u *ptr;
1617:
1618: if (lnum > buf->b_ml.ml_line_count) /* invalid line number */
1619: {
1620: EMSGN("ml_get: invalid lnum: %ld", lnum);
1621: errorret:
1622: STRCPY(IObuff, "???");
1623: return IObuff;
1624: }
1625: if (lnum <= 0) /* pretend line 0 is line 1 */
1626: lnum = 1;
1627:
1628: if (buf->b_ml.ml_mfp == NULL) /* there are no lines */
1629: return (char_u *)"";
1630:
1631: /*
1632: * See if it is the same line as requested last time.
1633: * Otherwise may need to flush last used line.
1634: */
1635: if (buf->b_ml.ml_line_lnum != lnum)
1636: {
1637: ml_flush_line(buf);
1638:
1639: /*
1640: * find the data block containing the line
1641: * This also fills the stack with the blocks from the root to the data block
1642: * This also releases any locked block.
1643: */
1644: if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
1645: {
1646: EMSGN("ml_get: cannot find line %ld", lnum);
1647: goto errorret;
1648: }
1649:
1650: dp = (DATA_BL *)(hp->bh_data);
1651:
1652: ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
1653: buf->b_ml.ml_line_ptr = ptr;
1654: buf->b_ml.ml_line_lnum = lnum;
1655: buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
1656: }
1657: if (will_change)
1658: buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
1659:
1660: return buf->b_ml.ml_line_ptr;
1661: }
1662:
1663: /*
1664: * Check if a line that was just obtained by a call to ml_get
1665: * is in allocated memory.
1666: */
1667: int
1668: ml_line_alloced()
1669: {
1670: return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
1671: }
1672:
1673: /*
1674: * append a line after lnum (may be 0 to insert a line in front of the file)
1675: *
1676: * newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
1677: * will be set for recovery
1678: *
1679: * return FAIL for failure, OK otherwise
1680: */
1681: int
1682: ml_append(lnum, line, len, newfile)
1683: linenr_t lnum; /* append after this line (can be 0) */
1684: char_u *line; /* text of the new line */
1685: colnr_t len; /* length of new line, including NUL, or 0 */
1686: int newfile; /* flag, see above */
1687: {
1688: if (curbuf->b_ml.ml_line_lnum != 0)
1689: ml_flush_line(curbuf);
1690: return ml_append_int(curbuf, lnum, line, len, newfile);
1691: }
1692:
1693: static int
1694: ml_append_int(buf, lnum, line, len, newfile)
1695: BUF *buf;
1696: linenr_t lnum; /* append after this line (can be 0) */
1697: char_u *line; /* text of the new line */
1698: colnr_t len; /* length of line, including NUL, or 0 */
1699: int newfile; /* flag, see above */
1700: {
1701: int i;
1702: int line_count; /* number of indexes in current block */
1703: int offset;
1704: int from, to;
1705: int space_needed; /* space needed for new line */
1706: int page_size;
1707: int page_count;
1708: int db_idx; /* index for lnum in data block */
1709: BHDR *hp;
1710: MEMFILE *mfp;
1711: DATA_BL *dp;
1712: PTR_BL *pp;
1713: IPTR *ip;
1714:
1715: /* lnum out of range */
1716: if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
1717: return FAIL;
1718:
1719: if (lowest_marked && lowest_marked > lnum)
1720: lowest_marked = lnum + 1;
1721:
1722: if (len == 0)
1723: len = STRLEN(line) + 1; /* space needed for the text */
1724: space_needed = len + INDEX_SIZE; /* space needed for text + index */
1725:
1726: mfp = buf->b_ml.ml_mfp;
1727: page_size = mfp->mf_page_size;
1728:
1729: /*
1730: * find the data block containing the previous line
1731: * This also fills the stack with the blocks from the root to the data block
1732: * This also releases any locked block.
1733: */
1734: if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_t)1 : lnum,
1735: ML_INSERT)) == NULL)
1736: return FAIL;
1737:
1738: buf->b_ml.ml_flags &= ~ML_EMPTY;
1739:
1740: if (lnum == 0) /* got line one instead, correct db_idx */
1741: db_idx = -1; /* careful, it is negative! */
1742: else
1743: db_idx = lnum - buf->b_ml.ml_locked_low;
1744: /* get line count before the insertion */
1745: line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
1746:
1747: dp = (DATA_BL *)(hp->bh_data);
1748:
1749: /*
1750: * If
1751: * - there is not enough room in the current block
1752: * - appending to the last line in the block
1753: * - not appending to the last line in the file
1754: * insert in front of the next block.
1755: */
1756: if ((int)dp->db_free < space_needed && db_idx == line_count - 1 &&
1757: lnum < buf->b_ml.ml_line_count)
1758: {
1759: /*
1760: * Now that the line is not going to be inserted in the block that we
1761: * expected, the line count has to be adjusted in the pointer blocks
1762: * by using ml_locked_lineadd.
1763: */
1764: --(buf->b_ml.ml_locked_lineadd);
1765: --(buf->b_ml.ml_locked_high);
1766: if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
1767: return FAIL;
1768:
1769: db_idx = -1; /* careful, it is negative! */
1770: /* get line count before the insertion */
1771: line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
1772: CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
1773:
1774: dp = (DATA_BL *)(hp->bh_data);
1775: }
1776:
1777: ++buf->b_ml.ml_line_count;
1778:
1779: if ((int)dp->db_free >= space_needed) /* enough room in data block */
1780: {
1781: /*
1782: * Insert new line in existing data block, or in data block allocated above.
1783: */
1784: dp->db_txt_start -= len;
1785: dp->db_free -= space_needed;
1786: ++(dp->db_line_count);
1787:
1788: /*
1789: * move the text of the lines that follow to the front
1790: * adjust the indexes of the lines that follow
1791: */
1792: if (line_count > db_idx + 1) /* if there are following lines */
1793: {
1794: /*
1795: * Offset is the start of the previous line.
1796: * This will become the character just after the new line.
1797: */
1798: if (db_idx < 0)
1799: offset = dp->db_txt_end;
1800: else
1801: offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
1802: vim_memmove((char *)dp + dp->db_txt_start,
1803: (char *)dp + dp->db_txt_start + len,
1804: (size_t)(offset - (dp->db_txt_start + len)));
1805: for (i = line_count - 1; i > db_idx; --i)
1806: dp->db_index[i + 1] = dp->db_index[i] - len;
1807: dp->db_index[db_idx + 1] = offset - len;
1808: }
1809: else /* add line at the end */
1810: dp->db_index[db_idx + 1] = dp->db_txt_start;
1811:
1812: /*
1813: * copy the text into the block
1814: */
1815: vim_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
1816:
1817: /*
1818: * Mark the block dirty.
1819: */
1820: buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
1821: if (!newfile)
1822: buf->b_ml.ml_flags |= ML_LOCKED_POS;
1823: }
1824: else /* not enough space in data block */
1825: {
1826: /*
1827: * If there is not enough room we have to create a new data block and copy some
1828: * lines into it.
1829: * Then we have to insert an entry in the pointer block.
1830: * If this pointer block also is full, we go up another block, and so on, up
1831: * to the root if necessary.
1832: * The line counts in the pointer blocks have already been adjusted by
1833: * ml_find_line().
1834: */
1835: long line_count_left, line_count_right;
1836: int page_count_left, page_count_right;
1837: BHDR *hp_left;
1838: BHDR *hp_right;
1839: BHDR *hp_new;
1840: int lines_moved;
1841: int data_moved = 0; /* init to shut up gcc */
1842: int total_moved = 0; /* init to shut up gcc */
1843: DATA_BL *dp_right, *dp_left;
1844: int stack_idx;
1845: int in_left;
1846: int lineadd;
1847: blocknr_t bnum_left, bnum_right;
1848: linenr_t lnum_left, lnum_right;
1849: int pb_idx;
1850: PTR_BL *pp_new;
1851:
1852: /*
1853: * We are going to allocate a new data block. Depending on the
1854: * situation it will be put to the left or right of the existing
1855: * block. If possible we put the new line in the left block and move
1856: * the lines after it to the right block. Otherwise the new line is
1857: * also put in the right block. This method is more efficient when
1858: * inserting a lot of lines at one place.
1859: */
1860: if (db_idx < 0) /* left block is new, right block is existing */
1861: {
1862: lines_moved = 0;
1863: in_left = TRUE;
1864: /* space_needed does not change */
1865: }
1866: else /* left block is existing, right block is new */
1867: {
1868: lines_moved = line_count - db_idx - 1;
1869: if (lines_moved == 0)
1870: in_left = FALSE; /* put new line in right block */
1871: /* space_needed does not change */
1872: else
1873: {
1874: data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
1875: dp->db_txt_start;
1876: total_moved = data_moved + lines_moved * INDEX_SIZE;
1877: if ((int)dp->db_free + total_moved >= space_needed)
1878: {
1879: in_left = TRUE; /* put new line in left block */
1880: space_needed = total_moved;
1881: }
1882: else
1883: {
1884: in_left = FALSE; /* put new line in right block */
1885: space_needed += total_moved;
1886: }
1887: }
1888: }
1889:
1890: page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
1891: if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
1892: {
1893: /* correct line counts in pointer blocks */
1894: --(buf->b_ml.ml_locked_lineadd);
1895: --(buf->b_ml.ml_locked_high);
1896: return FAIL;
1897: }
1898: if (db_idx < 0) /* left block is new */
1899: {
1900: hp_left = hp_new;
1901: hp_right = hp;
1902: line_count_left = 0;
1903: line_count_right = line_count;
1904: }
1905: else /* right block is new */
1906: {
1907: hp_left = hp;
1908: hp_right = hp_new;
1909: line_count_left = line_count;
1910: line_count_right = 0;
1911: }
1912: dp_right = (DATA_BL *)(hp_right->bh_data);
1913: dp_left = (DATA_BL *)(hp_left->bh_data);
1914: bnum_left = hp_left->bh_bnum;
1915: bnum_right = hp_right->bh_bnum;
1916: page_count_left = hp_left->bh_page_count;
1917: page_count_right = hp_right->bh_page_count;
1918:
1919: /*
1920: * May move the new line into the right/new block.
1921: */
1922: if (!in_left)
1923: {
1924: dp_right->db_txt_start -= len;
1925: dp_right->db_free -= len + INDEX_SIZE;
1926: dp_right->db_index[0] = dp_right->db_txt_start;
1927: vim_memmove((char *)dp_right + dp_right->db_txt_start,
1928: line, (size_t)len);
1929: ++line_count_right;
1930: }
1931: /*
1932: * may move lines from the left/old block to the right/new one.
1933: */
1934: if (lines_moved)
1935: {
1936: /*
1937: */
1938: dp_right->db_txt_start -= data_moved;
1939: dp_right->db_free -= total_moved;
1940: vim_memmove((char *)dp_right + dp_right->db_txt_start,
1941: (char *)dp_left + dp_left->db_txt_start,
1942: (size_t)data_moved);
1943: offset = dp_right->db_txt_start - dp_left->db_txt_start;
1944: dp_left->db_txt_start += data_moved;
1945: dp_left->db_free += total_moved;
1946:
1947: /*
1948: * update indexes in the new block
1949: */
1950: for (to = line_count_right, from = db_idx + 1;
1951: from < line_count_left; ++from, ++to)
1952: dp_right->db_index[to] = dp->db_index[from] + offset;
1953: line_count_right += lines_moved;
1954: line_count_left -= lines_moved;
1955: }
1956:
1957: /*
1958: * May move the new line into the left (old or new) block.
1959: */
1960: if (in_left)
1961: {
1962: dp_left->db_txt_start -= len;
1963: dp_left->db_free -= len + INDEX_SIZE;
1964: dp_left->db_index[line_count_left] = dp_left->db_txt_start;
1965: vim_memmove((char *)dp_left + dp_left->db_txt_start,
1966: line, (size_t)len);
1967: ++line_count_left;
1968: }
1969:
1970: if (db_idx < 0) /* left block is new */
1971: {
1972: lnum_left = lnum + 1;
1973: lnum_right = 0;
1974: }
1975: else /* right block is new */
1976: {
1977: lnum_left = 0;
1978: if (in_left)
1979: lnum_right = lnum + 2;
1980: else
1981: lnum_right = lnum + 1;
1982: }
1983: dp_left->db_line_count = line_count_left;
1984: dp_right->db_line_count = line_count_right;
1985:
1986: /*
1987: * release the two data blocks
1988: * The new one (hp_new) already has a correct blocknumber.
1989: * The old one (hp, in ml_locked) gets a positive blocknumber if
1990: * we changed it and we are not editing a new file.
1991: */
1992: if (lines_moved || in_left)
1993: buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
1994: if (!newfile && db_idx >= 0 && in_left)
1995: buf->b_ml.ml_flags |= ML_LOCKED_POS;
1996: mf_put(mfp, hp_new, TRUE, FALSE);
1997:
1998: /*
1999: * flush the old data block
2000: * set ml_locked_lineadd to 0, because the updating of the
2001: * pointer blocks is done below
2002: */
2003: lineadd = buf->b_ml.ml_locked_lineadd;
2004: buf->b_ml.ml_locked_lineadd = 0;
2005: ml_find_line(buf, (linenr_t)0, ML_FLUSH); /* flush data block */
2006:
2007: /*
2008: * update pointer blocks for the new data block
2009: */
2010: for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; --stack_idx)
2011: {
2012: ip = &(buf->b_ml.ml_stack[stack_idx]);
2013: pb_idx = ip->ip_index;
2014: if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
2015: return FAIL;
2016: pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
2017: if (pp->pb_id != PTR_ID)
2018: {
2019: EMSG("pointer block id wrong 3");
2020: mf_put(mfp, hp, FALSE, FALSE);
2021: return FAIL;
2022: }
2023: /*
2024: * TODO: If the pointer block is full and we are adding at the end
2025: * try to insert in front of the next block
2026: */
2027: if (pp->pb_count < pp->pb_count_max) /* block not full, add one entry */
2028: {
2029: if (pb_idx + 1 < (int)pp->pb_count)
2030: vim_memmove(&pp->pb_pointer[pb_idx + 2],
2031: &pp->pb_pointer[pb_idx + 1],
2032: (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
2033: ++pp->pb_count;
2034: pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
2035: pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
2036: pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
2037: pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
2038: pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
2039: pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
2040:
2041: if (lnum_left != 0)
2042: pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
2043: if (lnum_right != 0)
2044: pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
2045:
2046: mf_put(mfp, hp, TRUE, FALSE);
2047: buf->b_ml.ml_stack_top = stack_idx + 1; /* truncate stack */
2048:
2049: if (lineadd)
2050: {
2051: --(buf->b_ml.ml_stack_top);
2052: /* fix line count for rest of blocks in the stack */
2053: ml_lineadd(buf, lineadd);
2054: /* fix stack itself */
2055: buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
2056: lineadd;
2057: ++(buf->b_ml.ml_stack_top);
2058: }
2059:
2060: return OK;
2061: }
2062: else /* pointer block full */
2063: {
2064: /*
2065: * split the pointer block
2066: * allocate a new pointer block
2067: * move some of the pointer into the new block
2068: * prepare for updating the parent block
2069: */
2070: for (;;) /* do this twice when splitting block 1 */
2071: {
2072: hp_new = ml_new_ptr(mfp);
2073: if (hp_new == NULL) /* TODO: try to fix tree */
2074: return FAIL;
2075: pp_new = (PTR_BL *)(hp_new->bh_data);
2076:
2077: if (hp->bh_bnum != 1)
2078: break;
2079:
2080: /*
2081: * if block 1 becomes full the tree is given an extra level
2082: * The pointers from block 1 are moved into the new block.
2083: * block 1 is updated to point to the new block
2084: * then continue to split the new block
2085: */
2086: vim_memmove(pp_new, pp, (size_t)page_size);
2087: pp->pb_count = 1;
2088: pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
2089: pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
2090: pp->pb_pointer[0].pe_old_lnum = 1;
2091: pp->pb_pointer[0].pe_page_count = 1;
2092: mf_put(mfp, hp, TRUE, FALSE); /* release block 1 */
2093: hp = hp_new; /* new block is to be split */
2094: pp = pp_new;
2095: CHECK(stack_idx != 0, "stack_idx should be 0");
2096: ip->ip_index = 0;
2097: ++stack_idx; /* do block 1 again later */
2098: }
2099: /*
2100: * move the pointers after the current one to the new block
2101: * If there are none, the new entry will be in the new block.
2102: */
2103: total_moved = pp->pb_count - pb_idx - 1;
2104: if (total_moved)
2105: {
2106: vim_memmove(&pp_new->pb_pointer[0],
2107: &pp->pb_pointer[pb_idx + 1],
2108: (size_t)(total_moved) * sizeof(PTR_EN));
2109: pp_new->pb_count = total_moved;
2110: pp->pb_count -= total_moved - 1;
2111: pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
2112: pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
2113: pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
2114: if (lnum_right)
2115: pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
2116: }
2117: else
2118: {
2119: pp_new->pb_count = 1;
2120: pp_new->pb_pointer[0].pe_bnum = bnum_right;
2121: pp_new->pb_pointer[0].pe_line_count = line_count_right;
2122: pp_new->pb_pointer[0].pe_page_count = page_count_right;
2123: pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
2124: }
2125: pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
2126: pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
2127: pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
2128: if (lnum_left)
2129: pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
2130: lnum_left = 0;
2131: lnum_right = 0;
2132:
2133: /*
2134: * recompute line counts
2135: */
2136: line_count_right = 0;
2137: for (i = 0; i < (int)pp_new->pb_count; ++i)
2138: line_count_right += pp_new->pb_pointer[i].pe_line_count;
2139: line_count_left = 0;
2140: for (i = 0; i < (int)pp->pb_count; ++i)
2141: line_count_left += pp->pb_pointer[i].pe_line_count;
2142:
2143: bnum_left = hp->bh_bnum;
2144: bnum_right = hp_new->bh_bnum;
2145: page_count_left = 1;
2146: page_count_right = 1;
2147: mf_put(mfp, hp, TRUE, FALSE);
2148: mf_put(mfp, hp_new, TRUE, FALSE);
2149: }
2150: }
2151: EMSG("Updated too many blocks?");
2152: buf->b_ml.ml_stack_top = 0; /* invalidate stack */
2153: }
2154: return OK;
2155: }
2156:
2157: /*
2158: * replace line lnum, with buffering, in current buffer
2159: *
2160: * If copy is TRUE, make a copy of the line, otherwise the line has been
2161: * copied to allocated memory already.
2162: *
2163: * return FAIL for failure, OK otherwise
2164: */
2165: int
2166: ml_replace(lnum, line, copy)
2167: linenr_t lnum;
2168: char_u *line;
2169: int copy;
2170: {
2171: if (line == NULL) /* just checking... */
2172: return FAIL;
2173:
2174: if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
2175: ml_flush_line(curbuf); /* flush it */
2176: else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
2177: vim_free(curbuf->b_ml.ml_line_ptr); /* free it */
2178: if (copy && (line = strsave(line)) == NULL) /* allocate memory */
2179: return FAIL;
2180: curbuf->b_ml.ml_line_ptr = line;
2181: curbuf->b_ml.ml_line_lnum = lnum;
2182: curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
2183:
2184: return OK;
2185: }
2186:
2187: /*
2188: * delete line 'lnum'
2189: *
2190: * return FAIL for failure, OK otherwise
2191: */
2192: int
2193: ml_delete(lnum, message)
2194: linenr_t lnum;
2195: int message;
2196: {
2197: ml_flush_line(curbuf);
2198: return ml_delete_int(curbuf, lnum, message);
2199: }
2200:
2201: static int
2202: ml_delete_int(buf, lnum, message)
2203: BUF *buf;
2204: linenr_t lnum;
2205: int message;
2206: {
2207: BHDR *hp;
2208: MEMFILE *mfp;
2209: DATA_BL *dp;
2210: PTR_BL *pp;
2211: IPTR *ip;
2212: int count; /* number of entries in block */
2213: int idx;
2214: int stack_idx;
2215: int text_start;
2216: int line_start;
2217: int line_size;
2218: int i;
2219:
2220: if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
2221: return FAIL;
2222:
2223: if (lowest_marked && lowest_marked > lnum)
2224: lowest_marked--;
2225:
2226: /*
2227: * If the file becomes empty the last line is replaced by an empty line.
2228: */
2229: if (buf->b_ml.ml_line_count == 1) /* file becomes empty */
2230: {
2231: if (message)
2232: keep_msg = no_lines_msg;
2233: i = ml_replace((linenr_t)1, (char_u *)"", TRUE);
2234: buf->b_ml.ml_flags |= ML_EMPTY;
2235: return i;
2236: }
2237:
2238: /*
2239: * find the data block containing the line
2240: * This also fills the stack with the blocks from the root to the data block
2241: * This also releases any locked block.
2242: */
2243: mfp = buf->b_ml.ml_mfp;
2244: if (mfp == NULL)
2245: return FAIL;
2246:
2247: if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
2248: return FAIL;
2249:
2250: dp = (DATA_BL *)(hp->bh_data);
2251: /* compute line count before the delete */
2252: count = (long)(buf->b_ml.ml_locked_high) - (long)(buf->b_ml.ml_locked_low) + 2;
2253: idx = lnum - buf->b_ml.ml_locked_low;
2254:
2255: --buf->b_ml.ml_line_count;
2256:
2257: /*
2258: * special case: If there is only one line in the data block it becomes empty.
2259: * Then we have to remove the entry, pointing to this data block, from the
2260: * pointer block. If this pointer block also becomes empty, we go up another
2261: * block, and so on, up to the root if necessary.
2262: * The line counts in the pointer blocks have already been adjusted by
2263: * ml_find_line().
2264: */
2265: if (count == 1)
2266: {
2267: mf_free(mfp, hp); /* free the data block */
2268: buf->b_ml.ml_locked = NULL;
2269:
2270: for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0; --stack_idx)
2271: {
2272: buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */
2273: ip = &(buf->b_ml.ml_stack[stack_idx]);
2274: idx = ip->ip_index;
2275: if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
2276: return FAIL;
2277: pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
2278: if (pp->pb_id != PTR_ID)
2279: {
2280: EMSG("pointer block id wrong 4");
2281: mf_put(mfp, hp, FALSE, FALSE);
2282: return FAIL;
2283: }
2284: count = --(pp->pb_count);
2285: if (count == 0) /* the pointer block becomes empty! */
2286: mf_free(mfp, hp);
2287: else
2288: {
2289: if (count != idx) /* move entries after the deleted one */
2290: vim_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
2291: (size_t)(count - idx) * sizeof(PTR_EN));
2292: mf_put(mfp, hp, TRUE, FALSE);
2293:
2294: buf->b_ml.ml_stack_top = stack_idx; /* truncate stack */
2295: /* fix line count for rest of blocks in the stack */
2296: if (buf->b_ml.ml_locked_lineadd)
2297: {
2298: ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
2299: buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
2300: buf->b_ml.ml_locked_lineadd;
2301: }
2302: ++(buf->b_ml.ml_stack_top);
2303:
2304: return OK;
2305: }
2306: }
2307: CHECK(1, "deleted block 1?");
2308:
2309: return OK;
2310: }
2311:
2312: /*
2313: * delete the text by moving the next lines forwards
2314: */
2315: text_start = dp->db_txt_start;
2316: line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
2317: if (idx == 0) /* first line in block, text at the end */
2318: line_size = dp->db_txt_end - line_start;
2319: else
2320: line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
2321: vim_memmove((char *)dp + text_start + line_size, (char *)dp + text_start,
2322: (size_t)(line_start - text_start));
2323:
2324: /*
2325: * delete the index by moving the next indexes backwards
2326: * Adjust the indexes for the text movement.
2327: */
2328: for (i = idx; i < count - 1; ++i)
2329: dp->db_index[i] = dp->db_index[i + 1] + line_size;
2330:
2331: dp->db_free += line_size + INDEX_SIZE;
2332: dp->db_txt_start += line_size;
2333: --(dp->db_line_count);
2334:
2335: /*
2336: * mark the block dirty and make sure it is in the file (for recovery)
2337: */
2338: buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
2339:
2340: return OK;
2341: }
2342:
2343: /*
2344: * set the B_MARKED flag for line 'lnum'
2345: */
2346: void
2347: ml_setmarked(lnum)
2348: linenr_t lnum;
2349: {
2350: BHDR *hp;
2351: DATA_BL *dp;
2352: /* invalid line number */
2353: if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count ||
2354: curbuf->b_ml.ml_mfp == NULL)
2355: return; /* give error message? */
2356:
2357: if (lowest_marked == 0 || lowest_marked > lnum)
2358: lowest_marked = lnum;
2359:
2360: /*
2361: * find the data block containing the line
2362: * This also fills the stack with the blocks from the root to the data block
2363: * This also releases any locked block.
2364: */
2365: if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
2366: return; /* give error message? */
2367:
2368: dp = (DATA_BL *)(hp->bh_data);
2369: dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
2370: curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2371: }
2372:
2373: /*
2374: * find the first line with its B_MARKED flag set
2375: */
2376: linenr_t
2377: ml_firstmarked()
2378: {
2379: BHDR *hp;
2380: DATA_BL *dp;
2381: linenr_t lnum;
2382: int i;
2383:
2384: if (curbuf->b_ml.ml_mfp == NULL)
2385: return (linenr_t) 0;
2386:
2387: /*
2388: * The search starts with lowest_marked line. This is the last line where
2389: * a mark was found, adjusted by inserting/deleting lines.
2390: */
2391: for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
2392: {
2393: /*
2394: * Find the data block containing the line.
2395: * This also fills the stack with the blocks from the root to the data
2396: * block This also releases any locked block.
2397: */
2398: if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
2399: return (linenr_t)0; /* give error message? */
2400:
2401: dp = (DATA_BL *)(hp->bh_data);
2402:
2403: for (i = lnum - curbuf->b_ml.ml_locked_low;
2404: lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
2405: if ((dp->db_index[i]) & DB_MARKED)
2406: {
2407: (dp->db_index[i]) &= DB_INDEX_MASK;
2408: curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2409: lowest_marked = lnum + 1;
2410: return lnum;
2411: }
2412: }
2413:
2414: return (linenr_t) 0;
2415: }
2416:
2417: /*
2418: * return TRUE if line 'lnum' has a mark
2419: */
2420: int
2421: ml_has_mark(lnum)
2422: linenr_t lnum;
2423: {
2424: BHDR *hp;
2425: DATA_BL *dp;
2426:
2427: if (curbuf->b_ml.ml_mfp == NULL ||
2428: (hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
2429: return FALSE;
2430:
2431: dp = (DATA_BL *)(hp->bh_data);
2432: return (int)((dp->db_index[lnum - curbuf->b_ml.ml_locked_low]) & DB_MARKED);
2433: }
2434:
2435: /*
2436: * clear all DB_MARKED flags
2437: */
2438: void
2439: ml_clearmarked()
2440: {
2441: BHDR *hp;
2442: DATA_BL *dp;
2443: linenr_t lnum;
2444: int i;
2445:
2446: if (curbuf->b_ml.ml_mfp == NULL) /* nothing to do */
2447: return;
2448:
2449: /*
2450: * The search starts with line lowest_marked.
2451: */
2452: for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
2453: {
2454: /*
2455: * Find the data block containing the line.
2456: * This also fills the stack with the blocks from the root to the data block
2457: * This also releases any locked block.
2458: */
2459: if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
2460: return; /* give error message? */
2461:
2462: dp = (DATA_BL *)(hp->bh_data);
2463:
2464: for (i = lnum - curbuf->b_ml.ml_locked_low;
2465: lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
2466: if ((dp->db_index[i]) & DB_MARKED)
2467: {
2468: (dp->db_index[i]) &= DB_INDEX_MASK;
2469: curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
2470: }
2471: }
2472:
2473: lowest_marked = 0;
2474: return;
2475: }
2476:
2477: /*
2478: * flush ml_line if necessary
2479: */
2480: static void
2481: ml_flush_line(buf)
2482: BUF *buf;
2483: {
2484: BHDR *hp;
2485: DATA_BL *dp;
2486: linenr_t lnum;
2487: char_u *new_line;
2488: char_u *old_line;
2489: colnr_t new_len;
2490: int old_len;
2491: int extra;
2492: int idx;
2493: int start;
2494: int count;
2495: int i;
2496:
2497: if (buf->b_ml.ml_line_lnum == 0 ||
2498: buf->b_ml.ml_mfp == NULL) /* nothing to do */
2499: return;
2500:
2501: if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
2502: {
2503: lnum = buf->b_ml.ml_line_lnum;
2504: new_line = buf->b_ml.ml_line_ptr;
2505:
2506: hp = ml_find_line(buf, lnum, ML_FIND);
2507: if (hp == NULL)
2508: EMSGN("Cannot find line %ld", lnum);
2509: else
2510: {
2511: dp = (DATA_BL *)(hp->bh_data);
2512: idx = lnum - buf->b_ml.ml_locked_low;
2513: start = ((dp->db_index[idx]) & DB_INDEX_MASK);
2514: old_line = (char_u *)dp + start;
2515: if (idx == 0) /* line is last in block */
2516: old_len = dp->db_txt_end - start;
2517: else /* text of previous line follows */
2518: old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
2519: new_len = STRLEN(new_line) + 1;
2520: extra = new_len - old_len; /* negative if lines gets smaller */
2521:
2522: /*
2523: * if new line fits in data block, replace directly
2524: */
2525: if ((int)dp->db_free >= extra)
2526: {
2527: /* if the length changes and there are following lines */
2528: count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
2529: if (extra != 0 && idx < count - 1)
2530: {
2531: /* move text of following lines */
2532: vim_memmove((char *)dp + dp->db_txt_start - extra,
2533: (char *)dp + dp->db_txt_start,
2534: (size_t)(start - dp->db_txt_start));
2535:
2536: /* adjust pointers of this and following lines */
2537: for (i = idx + 1; i < count; ++i)
2538: dp->db_index[i] -= extra;
2539: }
2540: dp->db_index[idx] -= extra;
2541:
2542: /* adjust free space */
2543: dp->db_free -= extra;
2544: dp->db_txt_start -= extra;
2545:
2546: /* copy new line into the data block */
2547: vim_memmove(old_line - extra, new_line, (size_t)new_len);
2548: buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
2549: }
2550: else
2551: {
2552: /*
2553: * Cannot do it in one data block: delete and append.
2554: */
2555: /* How about handling errors??? */
2556: (void)ml_delete_int(buf, lnum, FALSE);
2557: (void)ml_append_int(buf, lnum - 1, new_line, new_len, FALSE);
2558: }
2559: }
2560: vim_free(new_line);
2561: }
2562:
2563: buf->b_ml.ml_line_lnum = 0;
2564: }
2565:
2566: /*
2567: * create a new, empty, data block
2568: */
2569: static BHDR *
2570: ml_new_data(mfp, negative, page_count)
2571: MEMFILE *mfp;
2572: int negative;
2573: int page_count;
2574: {
2575: BHDR *hp;
2576: DATA_BL *dp;
2577:
2578: if ((hp = mf_new(mfp, negative, page_count)) == NULL)
2579: return NULL;
2580:
2581: dp = (DATA_BL *)(hp->bh_data);
2582: dp->db_id = DATA_ID;
2583: dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
2584: dp->db_free = dp->db_txt_start - HEADER_SIZE;
2585: dp->db_line_count = 0;
2586:
2587: return hp;
2588: }
2589:
2590: /*
2591: * create a new, empty, pointer block
2592: */
2593: static BHDR *
2594: ml_new_ptr(mfp)
2595: MEMFILE *mfp;
2596: {
2597: BHDR *hp;
2598: PTR_BL *pp;
2599:
2600: if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
2601: return NULL;
2602:
2603: pp = (PTR_BL *)(hp->bh_data);
2604: pp->pb_id = PTR_ID;
2605: pp->pb_count = 0;
2606: pp->pb_count_max = (mfp->mf_page_size - sizeof(PTR_BL)) / sizeof(PTR_EN) + 1;
2607:
2608: return hp;
2609: }
2610:
2611: /*
2612: * lookup line 'lnum' in a memline
2613: *
2614: * action: if ML_DELETE or ML_INSERT the line count is updated while searching
2615: * if ML_FLUSH only flush a locked block
2616: * if ML_FIND just find the line
2617: *
2618: * If the block was found it is locked and put in ml_locked.
2619: * The stack is updated to lead to the locked block. The ip_high field in
2620: * the stack is updated to reflect the last line in the block AFTER the
2621: * insert or delete, also if the pointer block has not been updated yet. But
2622: * if if ml_locked != NULL ml_locked_lineadd must be added to ip_high.
2623: *
2624: * return: NULL for failure, pointer to block header otherwise
2625: */
2626: static BHDR *
2627: ml_find_line(buf, lnum, action)
2628: BUF *buf;
2629: linenr_t lnum;
2630: int action;
2631: {
2632: DATA_BL *dp;
2633: PTR_BL *pp;
2634: IPTR *ip;
2635: BHDR *hp;
2636: MEMFILE *mfp;
2637: linenr_t t;
2638: blocknr_t bnum, bnum2;
2639: int dirty;
2640: linenr_t low, high;
2641: int top;
2642: int page_count;
2643: int idx;
2644:
2645: mfp = buf->b_ml.ml_mfp;
2646:
2647: /*
2648: * If there is a locked block check if the wanted line is in it.
2649: * If not, flush and release the locked block.
2650: * Don't do this for ML_INSERT_SAME, because the stack need to be updated.
2651: * Don't do this for ML_FLUSH, because we want to flush the locked block.
2652: */
2653: if (buf->b_ml.ml_locked)
2654: {
2655: if (ML_SIMPLE(action) && buf->b_ml.ml_locked_low <= lnum &&
2656: buf->b_ml.ml_locked_high >= lnum)
2657: {
2658: /* remember to update pointer blocks and stack later */
2659: if (action == ML_INSERT)
2660: {
2661: ++(buf->b_ml.ml_locked_lineadd);
2662: ++(buf->b_ml.ml_locked_high);
2663: }
2664: else if (action == ML_DELETE)
2665: {
2666: --(buf->b_ml.ml_locked_lineadd);
2667: --(buf->b_ml.ml_locked_high);
2668: }
2669: return (buf->b_ml.ml_locked);
2670: }
2671:
2672: mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
2673: buf->b_ml.ml_flags & ML_LOCKED_POS);
2674: buf->b_ml.ml_locked = NULL;
2675:
2676: /*
2677: * if lines have been added or deleted in the locked block, need to
2678: * update the line count in pointer blocks
2679: */
2680: if (buf->b_ml.ml_locked_lineadd)
2681: ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
2682: }
2683:
2684: if (action == ML_FLUSH) /* nothing else to do */
2685: return NULL;
2686:
2687: bnum = 1; /* start at the root of the tree */
2688: page_count = 1;
2689: low = 1;
2690: high = buf->b_ml.ml_line_count;
2691:
2692: if (action == ML_FIND) /* first try stack entries */
2693: {
2694: for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
2695: {
2696: ip = &(buf->b_ml.ml_stack[top]);
2697: if (ip->ip_low <= lnum && ip->ip_high >= lnum)
2698: {
2699: bnum = ip->ip_bnum;
2700: low = ip->ip_low;
2701: high = ip->ip_high;
2702: buf->b_ml.ml_stack_top = top; /* truncate stack at prev entry */
2703: break;
2704: }
2705: }
2706: if (top < 0)
2707: buf->b_ml.ml_stack_top = 0; /* not found, start at the root */
2708: }
2709: else /* ML_DELETE or ML_INSERT */
2710: buf->b_ml.ml_stack_top = 0; /* start at the root */
2711:
2712: /*
2713: * search downwards in the tree until a data block is found
2714: */
2715: for (;;)
2716: {
2717: if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
2718: goto error_noblock;
2719:
2720: /*
2721: * update high for insert/delete
2722: */
2723: if (action == ML_INSERT)
2724: ++high;
2725: else if (action == ML_DELETE)
2726: --high;
2727:
2728: dp = (DATA_BL *)(hp->bh_data);
2729: if (dp->db_id == DATA_ID) /* data block */
2730: {
2731: buf->b_ml.ml_locked = hp;
2732: buf->b_ml.ml_locked_low = low;
2733: buf->b_ml.ml_locked_high = high;
2734: buf->b_ml.ml_locked_lineadd = 0;
2735: buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
2736: return hp;
2737: }
2738:
2739: pp = (PTR_BL *)(dp); /* must be pointer block */
2740: if (pp->pb_id != PTR_ID)
2741: {
2742: EMSG("pointer block id wrong");
2743: goto error_block;
2744: }
2745:
2746: if ((top = ml_add_stack(buf)) < 0) /* add new entry to stack */
2747: goto error_block;
2748: ip = &(buf->b_ml.ml_stack[top]);
2749: ip->ip_bnum = bnum;
2750: ip->ip_low = low;
2751: ip->ip_high = high;
2752: ip->ip_index = -1; /* index not known yet */
2753:
2754: dirty = FALSE;
2755: for (idx = 0; idx < (int)pp->pb_count; ++idx)
2756: {
2757: t = pp->pb_pointer[idx].pe_line_count;
2758: CHECK(t == 0, "pe_line_count is zero");
2759: if ((low += t) > lnum)
2760: {
2761: ip->ip_index = idx;
2762: bnum = pp->pb_pointer[idx].pe_bnum;
2763: page_count = pp->pb_pointer[idx].pe_page_count;
2764: high = low - 1;
2765: low -= t;
2766:
2767: /*
2768: * a negative block number may have been changed
2769: */
2770: if (bnum < 0)
2771: {
2772: bnum2 = mf_trans_del(mfp, bnum);
2773: if (bnum != bnum2)
2774: {
2775: bnum = bnum2;
2776: pp->pb_pointer[idx].pe_bnum = bnum;
2777: dirty = TRUE;
2778: }
2779: }
2780:
2781: break;
2782: }
2783: }
2784: if (idx >= (int)pp->pb_count) /* past the end: something wrong! */
2785: {
2786: if (lnum > buf->b_ml.ml_line_count)
2787: EMSGN("line number out of range: %ld past the end",
2788: lnum - buf->b_ml.ml_line_count);
2789:
2790: else
2791: EMSGN("line count wrong in block %ld", bnum);
2792: goto error_block;
2793: }
2794: if (action == ML_DELETE)
2795: {
2796: pp->pb_pointer[idx].pe_line_count--;
2797: dirty = TRUE;
2798: }
2799: else if (action == ML_INSERT)
2800: {
2801: pp->pb_pointer[idx].pe_line_count++;
2802: dirty = TRUE;
2803: }
2804: mf_put(mfp, hp, dirty, FALSE);
2805: }
2806:
2807: error_block:
2808: mf_put(mfp, hp, FALSE, FALSE);
2809: error_noblock:
2810: /*
2811: * If action is ML_DELETE or ML_INSERT we have to correct the tree for
2812: * the incremented/decremented line counts, because there won't be a line
2813: * inserted/deleted after all.
2814: */
2815: if (action == ML_DELETE)
2816: ml_lineadd(buf, 1);
2817: else if (action == ML_INSERT)
2818: ml_lineadd(buf, -1);
2819: buf->b_ml.ml_stack_top = 0;
2820: return NULL;
2821: }
2822:
2823: /*
2824: * add an entry to the info pointer stack
2825: *
2826: * return -1 for failure, number of the new entry otherwise
2827: */
2828: static int
2829: ml_add_stack(buf)
2830: BUF *buf;
2831: {
2832: int top;
2833: IPTR *newstack;
2834:
2835: top = buf->b_ml.ml_stack_top;
2836:
2837: /* may have to increase the stack size */
2838: if (top == buf->b_ml.ml_stack_size)
2839: {
2840: CHECK(top > 0, "Stack size increases"); /* more than 5 levels??? */
2841:
2842: newstack = (IPTR *)alloc((unsigned)sizeof(IPTR) *
2843: (buf->b_ml.ml_stack_size + STACK_INCR));
2844: if (newstack == NULL)
2845: return -1;
2846: vim_memmove(newstack, buf->b_ml.ml_stack, (size_t)top * sizeof(IPTR));
2847: vim_free(buf->b_ml.ml_stack);
2848: buf->b_ml.ml_stack = newstack;
2849: buf->b_ml.ml_stack_size += STACK_INCR;
2850: }
2851:
2852: buf->b_ml.ml_stack_top++;
2853: return top;
2854: }
2855:
2856: /*
2857: * Update the pointer blocks on the stack for inserted/deleted lines.
2858: * The stack itself is also updated.
2859: *
2860: * When a insert/delete line action fails, the line is not inserted/deleted,
2861: * but the pointer blocks have already been updated. That is fixed here by
2862: * walking through the stack.
2863: *
2864: * Count is the number of lines added, negative if lines have been deleted.
2865: */
2866: static void
2867: ml_lineadd(buf, count)
2868: BUF *buf;
2869: int count;
2870: {
2871: int idx;
2872: IPTR *ip;
2873: PTR_BL *pp;
2874: MEMFILE *mfp = buf->b_ml.ml_mfp;
2875: BHDR *hp;
2876:
2877: for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
2878: {
2879: ip = &(buf->b_ml.ml_stack[idx]);
2880: if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
2881: break;
2882: pp = (PTR_BL *)(hp->bh_data); /* must be pointer block */
2883: if (pp->pb_id != PTR_ID)
2884: {
2885: mf_put(mfp, hp, FALSE, FALSE);
2886: EMSG("pointer block id wrong 2");
2887: break;
2888: }
2889: pp->pb_pointer[ip->ip_index].pe_line_count += count;
2890: ip->ip_high += count;
2891: mf_put(mfp, hp, TRUE, FALSE);
2892: }
2893: }
2894:
2895: /*
2896: * make swap file name out of the filename and a directory name
2897: */
2898: static char_u *
2899: makeswapname(buf, dir_name)
2900: BUF *buf;
2901: char_u *dir_name;
2902: {
2903: char_u *r, *s, *fname;
2904:
2905: #ifdef VMS
2906: r = modname(buf->b_xfilename, (char_u *)"_swp");
2907: #else
2908: r = modname(buf->b_xfilename, (char_u *)".swp");
2909: #endif
2910: /*
2911: * do not use dir_name
2912: * - if dir_name starts with '.' (use current directory)
2913: * - if out of memory
2914: */
2915: if (*dir_name == '.' || r == NULL)
2916: return r;
2917:
2918: fname = gettail(r);
2919: s = concat_fnames(dir_name, fname, TRUE);
2920: vim_free(r);
2921: return s;
2922: }
2923:
2924: /*
2925: * Find out what name to use for the swap file for buffer 'buf'.
2926: *
2927: * Several names are tried to find one that does not exist
2928: *
2929: * Note: if MAXNAMLEN is not correct, you will get error messages for
2930: * not being able to open the swapfile
2931: */
2932: static char_u *
2933: findswapname(buf, dirp, old_fname)
2934: BUF *buf;
2935: char_u **dirp; /* pointer to list of directories */
2936: char_u *old_fname; /* don't give warning for this filename */
2937: {
2938: char_u *fname;
2939: int n;
2940: time_t x;
2941: char_u *dir_name;
2942:
2943: #ifdef AMIGA
2944: BPTR fh;
2945: #endif
2946:
2947: #ifndef SHORT_FNAME
2948: int r;
2949: FILE *dummyfd = NULL;
2950:
2951: /*
2952: * If we start editing a new file, e.g. "test.doc", which resides on an MSDOS
2953: * compatible filesystem, it is possible that the file "test.doc.swp" which we
2954: * create will be exactly the same file. To avoid this problem we temporarily
2955: * create "test.doc".
2956: */
2957: if (!(buf->b_p_sn || buf->b_shortname) && buf->b_xfilename &&
2958: getperm(buf->b_xfilename) < 0)
2959: dummyfd = fopen((char *)buf->b_xfilename, "w");
2960: #endif
2961:
2962: /*
2963: * Isolate a directory name from *dirp and put it in dir_name.
2964: * First allocate some memore to put the directory name in.
2965: */
2966: dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
2967: if (dir_name != NULL)
2968: (void)copy_option_part(dirp, dir_name, 31000, ",");
2969:
2970: /*
2971: * we try different names until we find one that does not exist yet
2972: */
2973: if (dir_name == NULL) /* out of memory */
2974: fname = NULL;
2975: else
2976: fname = makeswapname(buf, dir_name);
2977:
2978: for (;;)
2979: {
2980: if (fname == NULL) /* must be out of memory */
2981: break;
2982: if ((n = STRLEN(fname)) == 0) /* safety check */
2983: {
2984: vim_free(fname);
2985: fname = NULL;
2986: break;
2987: }
2988: #if (defined(UNIX) || defined(OS2)) && !defined(ARCHIE) && !defined(SHORT_FNAME)
2989: /*
2990: * Some systems have a MS-DOS compatible filesystem that use 8.3 character
2991: * file names. If this is the first try and the swap file name does not fit in
2992: * 8.3, detect if this is the case, set shortname and try again.
2993: */
2994: if (fname[n - 1] == 'p' && !(buf->b_p_sn || buf->b_shortname))
2995: {
2996: char_u *tail;
2997: char_u *fname2;
2998: struct stat s1, s2;
2999: int f1, f2;
3000: int created1 = FALSE, created2 = FALSE;
3001: int same = FALSE;
3002:
3003: /*
3004: * Check if swapfilename does not fit in 8.3:
3005: * It either contains two dots or it is longer than 8 chars.
3006: */
3007: tail = gettail(buf->b_xfilename);
3008: if (vim_strchr(tail, '.') != NULL || STRLEN(tail) > (size_t)8)
3009: {
3010: fname2 = alloc(n + 1);
3011: if (fname2 != NULL)
3012: {
3013: STRCPY(fname2, fname);
3014: if (vim_strchr(tail, '.') != NULL)
3015: fname2[n - 1] = 'x'; /* change ".swp" to ".swx" */
3016: else
3017: fname2[n - 5] += 1; /* change "x.swp" to "y.swp" */
3018: /*
3019: * may need to create the files to be able to use stat()
3020: */
3021: f1 = open((char *)fname, O_RDONLY | O_EXTRA);
3022: if (f1 < 0)
3023: {
3024: f1 = open((char *)fname, O_RDWR|O_CREAT|O_EXCL|O_EXTRA
3025: #ifdef AMIGA /* Amiga has no mode argument */
3026: );
3027: #endif
3028: #ifdef UNIX /* open in rw------- mode */
3029: , (mode_t)0600);
3030: #endif
3031: #if defined(MSDOS) || defined(WIN32) || defined(OS2) /* open read/write */
3032: , S_IREAD | S_IWRITE);
3033: #endif
3034: #if defined(OS2)
3035: if (f1 < 0 && errno == ENOENT)
3036: same = TRUE;
3037: #endif
3038: created1 = TRUE;
3039: }
3040: if (f1 >= 0)
3041: {
3042: f2 = open((char *)fname2, O_RDONLY | O_EXTRA);
3043: if (f2 < 0)
3044: {
3045: f2 = open((char *)fname2,
3046: O_RDWR|O_CREAT|O_EXCL|O_EXTRA
3047: #ifdef AMIGA /* Amiga has no mode argument */
3048: );
3049: #endif
3050: #ifdef UNIX /* open in rw------- mode */
3051: , (mode_t)0600);
3052: #endif
3053: #if defined(MSDOS) || defined(WIN32) || defined(OS2) /* open read/write */
3054: , S_IREAD | S_IWRITE);
3055: #endif
3056: created2 = TRUE;
3057: }
3058: if (f2 >= 0)
3059: {
3060: /*
3061: * Both files exist now. If stat() returns the
3062: * same device and inode they are the same file.
3063: */
3064: if (fstat(f1, &s1) != -1 &&
3065: fstat(f2, &s2) != -1 &&
3066: s1.st_dev == s2.st_dev &&
3067: s1.st_ino == s2.st_ino)
3068: same = TRUE;
3069: close(f2);
3070: if (created2)
3071: vim_remove(fname2);
3072: }
3073: close(f1);
3074: if (created1)
3075: vim_remove(fname);
3076: }
3077: vim_free(fname2);
3078: if (same)
3079: {
3080: buf->b_shortname = TRUE;
3081: vim_free(fname);
3082: fname = makeswapname(buf, dir_name);
3083: continue; /* try again with b_shortname set */
3084: }
3085: }
3086: }
3087: }
3088: #endif
3089: /*
3090: * check if the swapfile already exists
3091: */
3092: if (getperm(fname) < 0) /* it does not exist */
3093: {
3094: #ifdef AMIGA
3095: fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
3096: /*
3097: * on the Amiga getperm() will return -1 when the file exists but
3098: * is being used by another program. This happens if you edit
3099: * a file twice.
3100: */
3101: if (fh != (BPTR)NULL) /* can open file, OK */
3102: {
3103: Close(fh);
3104: break;
3105: }
3106: if (IoErr() != ERROR_OBJECT_IN_USE &&
3107: IoErr() != ERROR_OBJECT_EXISTS)
3108: #endif
3109: break;
3110: }
3111: /*
3112: * A file name equal to old_fname is OK to use.
3113: */
3114: if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
3115: break;
3116:
3117: /*
3118: * get here when file already exists
3119: */
3120: if (fname[n - 1] == 'p') /* first try */
3121: {
3122: #ifndef SHORT_FNAME
3123: /*
3124: * on MS-DOS compatible filesystems (e.g. messydos) file.doc.swp
3125: * and file.doc are the same file. To guess if this problem is
3126: * present try if file.doc.swx exists. If it does, we set
3127: * buf->b_shortname and try file_doc.swp (dots replaced by
3128: * underscores for this file), and try again. If it doesn't we
3129: * assume that "file.doc.swp" already exists.
3130: */
3131: if (!(buf->b_p_sn || buf->b_shortname)) /* not tried yet */
3132: {
3133: fname[n - 1] = 'x';
3134: r = getperm(fname); /* try "file.swx" */
3135: fname[n - 1] = 'p';
3136: if (r >= 0) /* "file.swx" seems to exist */
3137: {
3138: buf->b_shortname = TRUE;
3139: vim_free(fname);
3140: fname = makeswapname(buf, dir_name);
3141: continue; /* try again with '.' replaced by '_' */
3142: }
3143: }
3144: #endif
3145: /*
3146: * If we get here the ".swp" file really exists.
3147: * Give an error message, unless recovering, no file name, we are
3148: * viewing a help file or when the path of the file is different
3149: * (happens when all .swp files are in one directory).
3150: */
3151: if (!recoverymode && buf->b_xfilename != NULL && !buf->b_help)
3152: {
3153: int fd;
3154: struct block0 b0;
3155: int differ = FALSE;
3156:
3157: /*
3158: * Try to read block 0 from the swap file to get the original
3159: * file name (and inode number).
3160: */
3161: fd = open((char *)fname, O_RDONLY | O_EXTRA);
3162: if (fd >= 0)
3163: {
3164: if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
3165: {
3166: /*
3167: * The name in the swap file may be "~user/path/file".
3168: * Expand it first.
3169: */
3170: expand_env(b0.b0_fname, NameBuff, MAXPATHL);
3171: #ifdef CHECK_INODE
3172: if (fnamecmp_ino(buf->b_filename, NameBuff,
3173: char_to_long(b0.b0_ino)))
3174: differ = TRUE;
3175: #else
3176: if (fnamecmp(NameBuff, buf->b_filename) != 0)
3177: differ = TRUE;
3178: #endif
3179: }
3180: close(fd);
3181: }
3182: if (differ == FALSE)
3183: {
3184: struct stat st;
3185:
3186: ++no_wait_return;
3187: #ifdef SLEEP_IN_EMSG
3188: ++dont_sleep;
3189: #endif
3190: (void)EMSG("ATTENTION");
3191: #ifdef SLEEP_IN_EMSG
3192: --dont_sleep;
3193: #endif
3194: MSG_OUTSTR("\nFound a swap file by the name \"");
3195: msg_home_replace(fname);
3196: MSG_OUTSTR("\"\n");
3197: swapfile_info(fname);
3198: MSG_OUTSTR("While opening file \"");
3199: msg_outtrans(buf->b_xfilename);
3200: MSG_OUTSTR("\"\n");
3201: if (stat((char *)buf->b_xfilename, &st) != -1)
3202: {
3203: MSG_OUTSTR(" dated: ");
3204: x = st.st_mtime; /* Manx C can't do &st.st_mtime */
3205: MSG_OUTSTR(ctime(&x));
3206: }
3207: MSG_OUTSTR("\n(1) Another program may be editing the same file.\n");
3208: MSG_OUTSTR(" If this is the case, quit this edit session to avoid having\n");
3209: MSG_OUTSTR(" two different instances of the same file when making changes.\n");
3210: MSG_OUTSTR("\n(2) An edit session for this file crashed.\n");
3211: MSG_OUTSTR(" If this is the case, use \":recover\" or \"vim -r ");
3212: msg_outtrans(buf->b_xfilename);
3213: MSG_OUTSTR("\"\n to recover the changes (see \":help recovery)\".\n");
3214: MSG_OUTSTR(" If you did this already, delete the swap file \"");
3215: msg_outtrans(fname);
3216: MSG_OUTSTR("\"\n to avoid this message.\n\n");
3217: cmdline_row = msg_row;
3218: --no_wait_return;
3219: need_wait_return = TRUE; /* call wait_return later */
3220: }
3221: }
3222: }
3223:
3224: if (fname[n - 1] == 'a') /* tried enough names, give up */
3225: {
3226: vim_free(fname);
3227: fname = NULL;
3228: break;
3229: }
3230: --fname[n - 1]; /* change last char of the name */
3231: }
3232:
3233: vim_free(dir_name);
3234: #ifndef SHORT_FNAME
3235: if (dummyfd) /* file has been created temporarily */
3236: {
3237: fclose(dummyfd);
3238: vim_remove(buf->b_xfilename);
3239: }
3240: #endif
3241: return fname;
3242: }
3243:
3244: static int
3245: b0_magic_wrong(b0p)
3246: ZERO_BL *b0p;
3247: {
3248: return (b0p->b0_magic_long != (long)B0_MAGIC_LONG ||
3249: b0p->b0_magic_int != (int)B0_MAGIC_INT ||
3250: b0p->b0_magic_short != (short)B0_MAGIC_SHORT ||
3251: b0p->b0_magic_char != B0_MAGIC_CHAR);
3252: }
3253:
3254: #ifdef CHECK_INODE
3255: /*
3256: * Compare current file name with file name from swap file.
3257: * Try to use inode numbers when possible.
3258: * Return non-zero when files are different.
3259: *
3260: * When comparing file names a few things have to be taken into consideration:
3261: * - When working over a network the full path of a file depends on the host.
3262: * We check the inode number if possible. It is not 100% reliable though,
3263: * because the device number cannot be used over a network.
3264: * - When a file does not exist yet (editing a new file) there is no inode
3265: * number.
3266: * - The file name in a swap file may not be valid on the current host. The
3267: * "~user" form is used whenever possible to avoid this.
3268: *
3269: * This is getting complicated, let's make a table:
3270: *
3271: * ino_c ino_s fname_c fname_s differ =
3272: *
3273: * both files exist -> compare inode numbers:
3274: * != 0 != 0 X X ino_c != ino_s
3275: *
3276: * inode number(s) unknown, file names available -> compare file names
3277: * == 0 X OK OK fname_c != fname_s
3278: * X == 0 OK OK fname_c != fname_s
3279: *
3280: * current file doesn't exist, file for swap file exist, file name(s) not
3281: * available -> probably different
3282: * == 0 != 0 FAIL X TRUE
3283: * == 0 != 0 X FAIL TRUE
3284: *
3285: * current file exists, inode for swap unknown, file name(s) not
3286: * available -> probably different
3287: * != 0 == 0 FAIL X TRUE
3288: * != 0 == 0 X FAIL TRUE
3289: *
3290: * current file doesn't exist, inode for swap unknown, one file name not
3291: * available -> probably different
3292: * == 0 == 0 FAIL OK TRUE
3293: * == 0 == 0 OK FAIL TRUE
3294: *
3295: * current file doesn't exist, inode for swap unknown, both file names not
3296: * available -> probably same file
3297: * == 0 == 0 FAIL FAIL FALSE
3298: */
3299:
3300: static int
3301: fnamecmp_ino(fname_c, fname_s, ino_block0)
3302: char_u *fname_c; /* current file name */
3303: char_u *fname_s; /* file name from swap file */
3304: long ino_block0;
3305: {
3306: struct stat st;
3307: long ino_c = 0; /* ino of current file */
3308: long ino_s; /* ino of file from swap file */
3309: char_u buf_c[MAXPATHL]; /* full path of fname_c */
3310: char_u buf_s[MAXPATHL]; /* full path of fname_s */
3311: int retval_c; /* flag: buf_c valid */
3312: int retval_s; /* flag: buf_s valid */
3313:
3314:
3315: if (stat((char *)fname_c, &st) == 0)
3316: ino_c = st.st_ino;
3317:
3318: /*
3319: * First we try to get the inode from the file name, because the inode in
3320: * the swap file may be outdated. If that fails (e.g. this path is not
3321: * valid on this machine), use the inode from block 0.
3322: */
3323: if (stat((char *)fname_s, &st) == 0)
3324: ino_s = st.st_ino;
3325: else
3326: ino_s = ino_block0;
3327:
3328: if (ino_c && ino_s)
3329: return (ino_c != ino_s);
3330:
3331: /*
3332: * One of the inode numbers is unknown, try a forced FullName() and
3333: * compare the file names.
3334: */
3335: retval_c = FullName(fname_c, buf_c, MAXPATHL, TRUE);
3336: retval_s = FullName(fname_s, buf_s, MAXPATHL, TRUE);
3337: if (retval_c == OK && retval_s == OK)
3338: return (STRCMP(buf_c, buf_s) != 0);
3339:
3340: /*
3341: * Can't compare inodes or filenames, guess that the files are different,
3342: * unless both appear not to exist at all.
3343: */
3344: if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
3345: return FALSE;
3346: return TRUE;
3347: }
3348: #endif /* CHECK_INODE */
3349:
3350: /*
3351: * Move a long integer into a four byte character array.
3352: * Used for machine independency in block zero.
3353: */
3354: static void
3355: long_to_char(n, s)
3356: long n;
3357: char_u *s;
3358: {
3359: s[0] = (n & 0xff);
3360: n >>= 8;
3361: s[1] = (n & 0xff);
3362: n >>= 8;
3363: s[2] = (n & 0xff);
3364: n >>= 8;
3365: s[3] = (n & 0xff);
3366: }
3367:
3368: static long
3369: char_to_long(s)
3370: char_u *s;
3371: {
3372: long retval;
3373:
3374: retval = s[3];
3375: retval <<= 8;
3376: retval += s[2];
3377: retval <<= 8;
3378: retval += s[1];
3379: retval <<= 8;
3380: retval += s[0];
3381:
3382: return retval;
3383: }