summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/options.txt22
-rw-r--r--src/Make_all.mak1
-rw-r--r--src/fileio.c50
-rw-r--r--src/memline.c15
-rw-r--r--src/proto/memline.pro1
-rw-r--r--src/testdir/test_alot.vim1
-rw-r--r--src/testdir/test_backup.vim58
-rw-r--r--src/version.c2
8 files changed, 124 insertions, 26 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 8645c4733..eb455fc09 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1054,6 +1054,14 @@ A jump table for the options with a short description can be found at |Q_op|.
name, precede it with a backslash.
- To include a comma in a directory name precede it with a backslash.
- A directory name may end in an '/'.
+ - For Unix and Win32, if a directory ends in two path separators "//",
+ the swap file name will be built from the complete path to the file
+ with all path separators changed to percent '%' signs. This will
+ ensure file name uniqueness in the backup directory.
+ On Win32, it is also possible to end with "\\". However, When a
+ separating comma is following, you must use "//", since "\\" will
+ include the comma in the file name. Therefore it is recommended to
+ use '//', instead of '\\'.
- Environment variables are expanded |:set_env|.
- Careful with '\' characters, type one before a space, type two to
get one in the option (see |option-backslash|), for example: >
@@ -2680,12 +2688,14 @@ A jump table for the options with a short description can be found at |Q_op|.
- A directory starting with "./" (or ".\" for MS-DOS et al.) means to
put the swap file relative to where the edited file is. The leading
"." is replaced with the path name of the edited file.
- - For Unix and Win32, if a directory ends in two path separators "//"
- or "\\", the swap file name will be built from the complete path to
- the file with all path separators substituted to percent '%' signs.
- This will ensure file name uniqueness in the preserve directory.
- On Win32, when a separating comma is following, you must use "//",
- since "\\" will include the comma in the file name.
+ - For Unix and Win32, if a directory ends in two path separators "//",
+ the swap file name will be built from the complete path to the file
+ with all path separators substituted to percent '%' signs. This will
+ ensure file name uniqueness in the preserve directory.
+ On Win32, it is also possible to end with "\\". However, When a
+ separating comma is following, you must use "//", since "\\" will
+ include the comma in the file name. Therefore it is recommended to
+ use '//', instead of '\\'.
- Spaces after the comma are ignored, other spaces are considered part
of the directory name. To have a space at the start of a directory
name, precede it with a backslash.
diff --git a/src/Make_all.mak b/src/Make_all.mak
index 9831f7b04..49ad4f0af 100644
--- a/src/Make_all.mak
+++ b/src/Make_all.mak
@@ -12,6 +12,7 @@ NEW_TESTS = \
test_autocmd \
test_autoload \
test_backspace_opt \
+ test_backup \
test_blockedit \
test_breakindent \
test_bufline \
diff --git a/src/fileio.c b/src/fileio.c
index 281191cfb..42f388a11 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3850,6 +3850,9 @@ buf_write(
stat_T st_new;
char_u *dirp;
char_u *rootname;
+#if defined(UNIX) || defined(WIN3264)
+ char_u *p;
+#endif
#if defined(UNIX)
int did_set_shortname;
mode_t umask_save;
@@ -3887,6 +3890,17 @@ buf_write(
* Isolate one directory name, using an entry in 'bdir'.
*/
(void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
+
+#if defined(UNIX) || defined(WIN3264)
+ p = copybuf + STRLEN(copybuf);
+ if (after_pathsep(copybuf, p) && p[-1] == p[-2])
+ // Ends with '//', use full path
+ if ((p = make_percent_swname(copybuf, fname)) != NULL)
+ {
+ backup = modname(p, backup_ext, FALSE);
+ vim_free(p);
+ }
+#endif
rootname = get_file_in_dir(fname, copybuf);
if (rootname == NULL)
{
@@ -3904,9 +3918,10 @@ buf_write(
for (;;)
{
/*
- * Make backup file name.
+ * Make the backup file name.
*/
- backup = buf_modname((buf->b_p_sn || buf->b_shortname),
+ if (backup == NULL)
+ backup = buf_modname((buf->b_p_sn || buf->b_shortname),
rootname, backup_ext, FALSE);
if (backup == NULL)
{
@@ -4108,14 +4123,29 @@ buf_write(
* Isolate one directory name and make the backup file name.
*/
(void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
- rootname = get_file_in_dir(fname, IObuff);
- if (rootname == NULL)
- backup = NULL;
- else
+
+#if defined(UNIX) || defined(WIN3264)
+ p = IObuff + STRLEN(IObuff);
+ if (after_pathsep(IObuff, p) && p[-1] == p[-2])
+ // path ends with '//', use full path
+ if ((p = make_percent_swname(IObuff, fname)) != NULL)
+ {
+ backup = modname(p, backup_ext, FALSE);
+ vim_free(p);
+ }
+#endif
+ if (backup == NULL)
{
- backup = buf_modname((buf->b_p_sn || buf->b_shortname),
- rootname, backup_ext, FALSE);
- vim_free(rootname);
+ rootname = get_file_in_dir(fname, IObuff);
+ if (rootname == NULL)
+ backup = NULL;
+ else
+ {
+ backup = buf_modname(
+ (buf->b_p_sn || buf->b_shortname),
+ rootname, backup_ext, FALSE);
+ vim_free(rootname);
+ }
}
if (backup != NULL)
@@ -6252,7 +6282,7 @@ shorten_filenames(char_u **fnames, int count)
#endif
/*
- * add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
+ * Add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
* fo_o_h.ext for MSDOS or when shortname option set.
*
* Assumed that fname is a valid name found in the filesystem we assure that
diff --git a/src/memline.c b/src/memline.c
index be395fce6..a2f0b4f62 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -262,9 +262,6 @@ static int fnamecmp_ino(char_u *, char_u *, long);
#endif
static void long_to_char(long, char_u *);
static long char_to_long(char_u *);
-#if defined(UNIX) || defined(WIN3264)
-static char_u *make_percent_swname(char_u *dir, char_u *name);
-#endif
#ifdef FEAT_CRYPT
static cryptstate_T *ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading);
#endif
@@ -2007,18 +2004,18 @@ recover_names(
return file_count;
}
-#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
+#if defined(UNIX) || defined(WIN3264) || defined(PROTO)
/*
+ * Need _very_ long file names.
* Append the full path to name with path separators made into percent
* signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
*/
- static char_u *
+ char_u *
make_percent_swname(char_u *dir, char_u *name)
{
- char_u *d, *s, *f;
+ char_u *d = NULL, *s, *f;
- f = fix_fname(name != NULL ? name : (char_u *) "");
- d = NULL;
+ f = fix_fname(name != NULL ? name : (char_u *)"");
if (f != NULL)
{
s = alloc((unsigned)(STRLEN(f) + 1));
@@ -4070,8 +4067,6 @@ attention_message(
}
#if defined(FEAT_EVAL)
-static int do_swapexists(buf_T *buf, char_u *fname);
-
/*
* Trigger the SwapExists autocommands.
* Returns a value for equivalent to do_dialog() (see below):
diff --git a/src/proto/memline.pro b/src/proto/memline.pro
index bddb902f4..727b24cc3 100644
--- a/src/proto/memline.pro
+++ b/src/proto/memline.pro
@@ -34,4 +34,5 @@ char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned siz
void ml_decrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned size);
long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp);
void goto_byte(long cnt);
+char_u *make_percent_swname (char_u *dir, char_u *name);
/* vim: set ft=c : */
diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim
index 1465a7abf..16a3f7f8a 100644
--- a/src/testdir/test_alot.vim
+++ b/src/testdir/test_alot.vim
@@ -2,6 +2,7 @@
" This makes testing go faster, since Vim doesn't need to restart.
source test_assign.vim
+source test_backup.vim
source test_bufline.vim
source test_cd.vim
source test_changedtick.vim
diff --git a/src/testdir/test_backup.vim b/src/testdir/test_backup.vim
new file mode 100644
index 000000000..3187b5887
--- /dev/null
+++ b/src/testdir/test_backup.vim
@@ -0,0 +1,58 @@
+" Tests for the backup function
+
+func Test_backup()
+ set backup backupdir=.
+ new
+ call setline(1, ['line1', 'line2'])
+ :f Xbackup.txt
+ :w! Xbackup.txt
+ " backup file is only created after
+ " writing a second time (before overwriting)
+ :w! Xbackup.txt
+ let l = readfile('Xbackup.txt~')
+ call assert_equal(['line1', 'line2'], l)
+ bw!
+ set backup&vim backupdir&vim
+ call delete('Xbackup.txt')
+ call delete('Xbackup.txt~')
+endfunc
+
+func Test_backup2()
+ set backup backupdir=.//
+ new
+ call setline(1, ['line1', 'line2', 'line3'])
+ :f Xbackup.txt
+ :w! Xbackup.txt
+ " backup file is only created after
+ " writing a second time (before overwriting)
+ :w! Xbackup.txt
+ sp *Xbackup.txt~
+ call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
+ let f=expand('%')
+ call assert_match('src%testdir%Xbackup.txt\~', f)
+ bw!
+ bw!
+ call delete('Xbackup.txt')
+ call delete(f)
+ set backup&vim backupdir&vim
+endfunc
+
+func Test_backup2_backupcopy()
+ set backup backupdir=.// backupcopy=yes
+ new
+ call setline(1, ['line1', 'line2', 'line3'])
+ :f Xbackup.txt
+ :w! Xbackup.txt
+ " backup file is only created after
+ " writing a second time (before overwriting)
+ :w! Xbackup.txt
+ sp *Xbackup.txt~
+ call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
+ let f=expand('%')
+ call assert_match('src%testdir%Xbackup.txt\~', f)
+ bw!
+ bw!
+ call delete('Xbackup.txt')
+ call delete(f)
+ set backup&vim backupdir&vim backupcopy&vim
+endfunc
diff --git a/src/version.c b/src/version.c
index c9b0ec4dc..432a7ab75 100644
--- a/src/version.c
+++ b/src/version.c
@@ -795,6 +795,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 251,
+/**/
250,
/**/
249,