summaryrefslogtreecommitdiff
path: root/src/memline.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-12-19 22:46:22 +0000
committerBram Moolenaar <Bram@vim.org>2004-12-19 22:46:22 +0000
commit1cd871b5341bf43ee99e136844e3131014880f92 (patch)
tree6bd9573dbc14de3c4ec85e424cbec9c8d1ee0ed8 /src/memline.c
parent46c9c73de8def79baf8f0a34a12549f6c14944f3 (diff)
downloadvim-git-1cd871b5341bf43ee99e136844e3131014880f92.tar.gz
updated for version 7.0023v7.0023
Diffstat (limited to 'src/memline.c')
-rw-r--r--src/memline.c211
1 files changed, 183 insertions, 28 deletions
diff --git a/src/memline.c b/src/memline.c
index a3bd9d7be..13f35c2af 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -125,9 +125,10 @@ struct data_block
#define INDEX_SIZE (sizeof(unsigned)) /* size of one db_index entry */
#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */
-#define B0_FNAME_SIZE 900
-#define B0_UNAME_SIZE 40
-#define B0_HNAME_SIZE 40
+#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
+#define B0_FNAME_SIZE 898
+#define B0_UNAME_SIZE 40
+#define B0_HNAME_SIZE 40
/*
* Restrict the numbers to 32 bits, otherwise most compilers will complain.
* This won't detect a 64 bit machine that only swaps a byte in the top 32
@@ -160,13 +161,39 @@ struct block0
char_u b0_pid[4]; /* process id of creator (or 0) */
char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
- char_u b0_fname[B0_FNAME_SIZE]; /* name of file being edited */
+ char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
long b0_magic_long; /* check for byte order of long */
int b0_magic_int; /* check for byte order of int */
short b0_magic_short; /* check for byte order of short */
char_u b0_magic_char; /* check for last char */
};
-#define b0_dirty b0_fname[B0_FNAME_SIZE-1]
+
+/*
+ * Note: b0_fname and b0_flags are put at the end of the file name. For very
+ * long file names in older versions of Vim they are invalid.
+ * The 'fileencoding' comes before b0_flags, with a NUL in front. But only
+ * when there is room, for very long file names it's omitted.
+ */
+#define B0_DIRTY 0x55
+#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG-1]
+
+/*
+ * The b0_flags field is new in Vim 7.0.
+ */
+#define b0_flags b0_fname[B0_FNAME_SIZE_ORG-2]
+
+/* The lowest two bits contain the fileformat. Zero means it's not set
+ * (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or
+ * EOL_MAC + 1. */
+#define B0_FF_MASK 3
+
+/* Swap file is in directory of edited file. Used to find the file from
+ * different mount points. */
+#define B0_SAME_DIR 4
+
+/* The 'fileencoding' is at the end of b0_fname[], with a NUL in front of it.
+ * When empty there is only the NUL. */
+#define B0_HAS_FENC 8
#define STACK_INCR 5 /* nr of entries added to ml_stack at a time */
@@ -187,7 +214,12 @@ static linenr_T lowest_marked = 0;
#define ML_FLUSH 0x02 /* flush locked block */
#define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */
+static void ml_upd_block0 __ARGS((buf_T *buf, int setfname));
static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf));
+static void set_b0_dir_flag __ARGS((ZERO_BL *b0p, buf_T *buf));
+#ifdef FEAT_MBYTE
+static void add_b0_fenc __ARGS((ZERO_BL *b0p, buf_T *buf));
+#endif
static time_t swapfile_info __ARGS((char_u *));
static int recov_file_names __ARGS((char_u **, char_u *, int prepend_dot));
static int ml_append_int __ARGS((buf_T *, linenr_T, char_u *, colnr_T, int, int));
@@ -282,7 +314,8 @@ ml_open()
b0p->b0_id[0] = BLOCK0_ID0;
b0p->b0_id[1] = BLOCK0_ID1;
- b0p->b0_dirty = curbuf->b_changed ? 0x55 : 0;
+ b0p->b0_dirty = curbuf->b_changed ? B0_DIRTY : 0;
+ b0p->b0_flags = get_fileformat(curbuf) + 1;
b0p->b0_magic_long = (long)B0_MAGIC_LONG;
b0p->b0_magic_int = (int)B0_MAGIC_INT;
b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
@@ -433,6 +466,7 @@ ml_setname(buf)
#else
mf_set_ffname(mfp);
#endif
+ ml_upd_block0(buf, FALSE);
break;
}
vim_free(fname); /* this fname didn't work, try another */
@@ -507,6 +541,8 @@ ml_open_file(buf)
*/
mf_fullname(mfp);
#endif
+ ml_upd_block0(buf, FALSE);
+
/* Flush block zero, so others can read it */
if (mf_sync(mfp, MFS_ZERO) == OK)
break;
@@ -608,19 +644,34 @@ ml_close_notmod()
ml_timestamp(buf)
buf_T *buf;
{
+ ml_upd_block0(buf, TRUE);
+}
+
+/*
+ * Update the timestamp or the B0_SAME_DIR flag of the .swp file.
+ */
+ static void
+ml_upd_block0(buf, setfname)
+ buf_T *buf;
+ int setfname;
+{
memfile_T *mfp;
bhdr_T *hp;
ZERO_BL *b0p;
mfp = buf->b_ml.ml_mfp;
-
if (mfp == NULL || (hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
return;
b0p = (ZERO_BL *)(hp->bh_data);
if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
- EMSG(_("E304: ml_timestamp: Didn't get block 0??"));
+ EMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
else
- set_b0_fname(b0p, buf);
+ {
+ if (setfname)
+ set_b0_fname(b0p, buf);
+ else
+ set_b0_dir_flag(b0p, buf);
+ }
mf_put(mfp, hp, TRUE, FALSE);
}
@@ -641,9 +692,14 @@ set_b0_fname(b0p, buf)
else
{
#if defined(MSDOS) || defined(MSWIN) || defined(AMIGA) || defined(RISCOS)
- /* systems that cannot translate "~user" back into a path: copy the
- * file name unmodified */
+ /* Systems that cannot translate "~user" back into a path: copy the
+ * file name unmodified. Do use slashes instead of backslashes for
+ * portability. */
STRNCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE);
+ b0p->b0_fname[B0_FNAME_SIZE - 1] = NUL;
+# ifdef BACKSLASH_IN_FILENAME
+ forward_slash(b0p->b0_fname);
+# endif
#else
size_t flen, ulen;
char_u uname[B0_UNAME_SIZE];
@@ -662,7 +718,10 @@ set_b0_fname(b0p, buf)
/* If there is no user name or it is too long, don't use "~/" */
if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
|| (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
+ {
STRNCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE);
+ b0p->b0_fname[B0_FNAME_SIZE - 1] = NUL;
+ }
else
{
mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
@@ -691,7 +750,54 @@ set_b0_fname(b0p, buf)
buf->b_orig_mode = 0;
}
}
+
+#ifdef FEAT_MBYTE
+ /* Also add the 'fileencoding' if there is room. */
+ add_b0_fenc(b0p, curbuf);
+#endif
+}
+
+/*
+ * Update the B0_SAME_DIR flag of the swap file. It's set if the file and the
+ * swapfile for "buf" are in the same directory.
+ * This is fail safe: if we are not sure the directories are equal the flag is
+ * not set.
+ */
+ static void
+set_b0_dir_flag(b0p, buf)
+ ZERO_BL *b0p;
+ buf_T *buf;
+{
+ if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
+ b0p->b0_flags |= B0_SAME_DIR;
+ else
+ b0p->b0_flags &= ~B0_SAME_DIR;
+}
+
+#ifdef FEAT_MBYTE
+/*
+ * When there is room, add the 'fileencoding' to block zero.
+ */
+ static void
+add_b0_fenc(b0p, buf)
+ ZERO_BL *b0p;
+ buf_T *buf;
+{
+ int n;
+
+ n = STRLEN(buf->b_p_fenc);
+ if (STRLEN(b0p->b0_fname) + n + 1 > B0_FNAME_SIZE)
+ b0p->b0_flags &= ~B0_HAS_FENC;
+ else
+ {
+ mch_memmove((char *)b0p->b0_fname + B0_FNAME_SIZE - n,
+ (char *)buf->b_p_fenc, (size_t)n);
+ *(b0p->b0_fname + B0_FNAME_SIZE - n - 1) = NUL;
+ b0p->b0_flags |= B0_HAS_FENC;
+ }
}
+#endif
+
/*
* try to recover curbuf from the .swp file
@@ -704,6 +810,8 @@ ml_recover()
char_u *fname;
bhdr_T *hp = NULL;
ZERO_BL *b0p;
+ int b0_ff;
+ char_u *b0_fenc = NULL;
PTR_BL *pp;
DATA_BL *dp;
infoptr_T *ip;
@@ -926,6 +1034,17 @@ ml_recover()
EMSG(_("E308: Warning: Original file may have been changed"));
}
out_flush();
+
+ /* Get the 'fileformat' and 'fileencoding' from block zero. */
+ b0_ff = (b0p->b0_flags & B0_FF_MASK);
+ if (b0p->b0_flags & B0_HAS_FENC)
+ {
+ for (p = b0p->b0_fname + B0_FNAME_SIZE;
+ p > b0p->b0_fname && p[-1] != NUL; --p)
+ ;
+ b0_fenc = vim_strnsave(p, b0p->b0_fname + B0_FNAME_SIZE - p);
+ }
+
mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
hp = NULL;
@@ -948,6 +1067,16 @@ ml_recover()
ml_delete((linenr_T)1, FALSE);
}
+ /* Use the 'fileformat' and 'fileencoding' as stored in the swap file. */
+ if (b0_ff != 0)
+ set_fileformat(b0_ff - 1, OPT_LOCAL);
+ if (b0_fenc != NULL)
+ {
+ set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
+ vim_free(b0_fenc);
+ }
+ unchanged(curbuf, TRUE);
+
bnum = 1; /* start with block 1 */
page_count = 1; /* which is 1 page */
lnum = 0; /* append after line 0 in curbuf */
@@ -1295,7 +1424,7 @@ recover_names(fname, list, nr)
{
#if defined(UNIX) || defined(WIN3264)
p = dir_name + STRLEN(dir_name);
- if (vim_ispathsep(p[-1]) && p[-1] == p[-2])
+ if (after_pathsep(dir_name, p) && p[-1] == p[-2])
{
/* Ends with '//', Use Full path for swap name */
tail = make_percent_swname(dir_name, *fname);
@@ -1441,7 +1570,7 @@ make_percent_swname(dir, name)
char_u *dir;
char_u *name;
{
- char_u *d, *s, *f, *p;
+ char_u *d, *s, *f;
f = fix_fname(name != NULL ? name : (char_u *) "");
d = NULL;
@@ -1450,9 +1579,10 @@ make_percent_swname(dir, name)
s = alloc((unsigned)(STRLEN(f) + 1));
if (s != NULL)
{
- for (d = s, p = f; *p; p++, d++)
- *d = vim_ispathsep(*p) ? '%' : *p;
- *d = 0;
+ STRCPY(s, f);
+ for (d = s; *d != NUL; mb_ptr_adv(d))
+ if (vim_ispathsep(*d))
+ *d = '%';
d = concat_fnames(dir, s, TRUE);
vim_free(s);
}
@@ -3266,7 +3396,7 @@ makeswapname(buf, dir_name)
#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
s = dir_name + STRLEN(dir_name);
- if (vim_ispathsep(s[-1]) && s[-1] == s[-2])
+ if (after_pathsep(dir_name, s) && s[-1] == s[-2])
{ /* Ends with '//', Use Full path */
r = NULL;
if ((s = make_percent_swname(dir_name, buf->b_fname)) != NULL)
@@ -3617,18 +3747,33 @@ findswapname(buf, dirp, old_fname)
if (read(fd, (char *)&b0, sizeof(b0)) == sizeof(b0))
{
/*
- * The name in the swap file may be "~user/path/file".
- * Expand it first.
+ * If the swapfile has the same directory as the
+ * buffer don't compare the directory names, they can
+ * have a different mountpoint.
*/
- expand_env(b0.b0_fname, NameBuff, MAXPATHL);
+ if (b0.b0_flags & B0_SAME_DIR)
+ {
+ if (fnamecmp(gettail(buf->b_ffname),
+ gettail(b0.b0_fname)) != 0
+ || !same_directory(fname, buf->b_ffname))
+ differ = TRUE;
+ }
+ else
+ {
+ /*
+ * The name in the swap file may be
+ * "~user/path/file". Expand it first.
+ */
+ expand_env(b0.b0_fname, NameBuff, MAXPATHL);
#ifdef CHECK_INODE
- if (fnamecmp_ino(buf->b_ffname, NameBuff,
- char_to_long(b0.b0_ino)))
- differ = TRUE;
+ if (fnamecmp_ino(buf->b_ffname, NameBuff,
+ char_to_long(b0.b0_ino)))
+ differ = TRUE;
#else
- if (fnamecmp(NameBuff, buf->b_ffname) != 0)
- differ = TRUE;
+ if (fnamecmp(NameBuff, buf->b_ffname) != 0)
+ differ = TRUE;
#endif
+ }
}
close(fd);
}
@@ -3956,10 +4101,15 @@ char_to_long(s)
return retval;
}
+/*
+ * Set the flags in the first block of the swap file:
+ * - file is modified or not: buf->b_changed
+ * - 'fileformat'
+ * - 'fileencoding'
+ */
void
-ml_setdirty(buf, flag)
+ml_setflags(buf)
buf_T *buf;
- int flag;
{
bhdr_T *hp;
ZERO_BL *b0p;
@@ -3971,7 +4121,12 @@ ml_setdirty(buf, flag)
if (hp->bh_bnum == 0)
{
b0p = (ZERO_BL *)(hp->bh_data);
- b0p->b0_dirty = flag ? 0x55 : 0;
+ b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
+ b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
+ | (get_fileformat(buf) + 1);
+#ifdef FEAT_MBYTE
+ add_b0_fenc(b0p, buf);
+#endif
hp->bh_flags |= BH_DIRTY;
mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
break;