]> granicus.if.org Git - vim/commitdiff
patch 7.4.1107 v7.4.1107
authorBram Moolenaar <Bram@vim.org>
Sat, 16 Jan 2016 20:27:23 +0000 (21:27 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 16 Jan 2016 20:27:23 +0000 (21:27 +0100)
Problem:    Vim can create a directory but not delete it.
Solution:   Add an argument to delete() to make it possible to delete a
            directory, also recursively.

runtime/doc/eval.txt
src/eval.c
src/fileio.c
src/proto/fileio.pro
src/testdir/test_alot.vim
src/testdir/test_delete.vim [new file with mode: 0644]
src/version.c

index 35a12df6e470b5563bae68fae32c6b96ea33a9c1..6edd3f54118a7bf9a0cad2cc7964e5dbec0eeac7 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*     For Vim version 7.4.  Last change: 2016 Jan 15
+*eval.txt*     For Vim version 7.4.  Last change: 2016 Jan 16
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -919,6 +919,11 @@ just above, except that indexes out of range cause an error.  Examples: >
 Using expr8[expr1] or expr8[expr1a : expr1b] on a |Funcref| results in an
 error.
 
+Watch out for confusion between a namespace and a variable followed by a colon
+for a sublist: >
+       mylist[n:]     " uses variable n
+       mylist[s:]     " uses namespace s:, error!
+
 
 expr8.name             entry in a |Dictionary|         *expr-entry*
 
@@ -1794,7 +1799,7 @@ cursor( {lnum}, {col} [, {off}])
                                Number  move cursor to {lnum}, {col}, {off}
 cursor( {list})                        Number  move cursor to position in {list}
 deepcopy( {expr} [, {noref}])  any     make a full copy of {expr}
-delete( {fname})               Number  delete file {fname}
+delete( {fname} [, {flags}])   Number  delete the file or directory {fname}
 did_filetype()                 Number  TRUE if FileType autocommand event used
 diff_filler( {lnum})           Number  diff filler lines about {lnum}
 diff_hlID( {lnum}, {col})      Number  diff highlighting at {lnum}/{col}
@@ -2748,10 +2753,19 @@ deepcopy({expr}[, {noref}])                             *deepcopy()* *E698*
                {noref} set to 1 will fail.
                Also see |copy()|.
 
-delete({fname})                                                        *delete()*
-               Deletes the file by the name {fname}.  The result is a Number,
-               which is 0 if the file was deleted successfully, and non-zero
-               when the deletion failed.
+delete({fname} [, {flags}])                                    *delete()*
+               Without {flags} or with {flags} empty: Deletes the file by the
+               name {fname}.
+
+               When {flags} is "d": Deletes the directory by the name
+               {fname}.  This fails when {fname} is not empty.
+               
+               When {flags} is "rf": Deletes the directory by the name
+               {fname} and everything in it, recursively.  Be careful!
+               
+               The result is a Number, which is 0 if the delete operation was
+               successful and -1 when the deletion failed or partly failed.
+
                Use |remove()| to delete an item from a |List|.
                To delete a line from the buffer use |:delete|.  Use |:exe|
                when the line number is in a variable.
index d4e3b9ef59512afb8470dfce9fc4c9701155b7f6..c61b64dd600767965a2a61da7d79e5edb45c3714 100644 (file)
@@ -8131,7 +8131,7 @@ static struct fst
     {"cscope_connection",0,3, f_cscope_connection},
     {"cursor",         1, 3, f_cursor},
     {"deepcopy",       1, 2, f_deepcopy},
-    {"delete",         1, 1, f_delete},
+    {"delete",         1, 2, f_delete},
     {"did_filetype",   0, 0, f_did_filetype},
     {"diff_filler",    1, 1, f_diff_filler},
     {"diff_hlID",      2, 2, f_diff_hlID},
@@ -10391,10 +10391,37 @@ f_delete(argvars, rettv)
     typval_T   *argvars;
     typval_T   *rettv;
 {
+    char_u     nbuf[NUMBUFLEN];
+    char_u     *name;
+    char_u     *flags;
+
+    rettv->vval.v_number = -1;
     if (check_restricted() || check_secure())
-       rettv->vval.v_number = -1;
+       return;
+
+    name = get_tv_string(&argvars[0]);
+    if (name == NULL || *name == NUL)
+    {
+       EMSG(_(e_invarg));
+       return;
+    }
+
+    if (argvars[1].v_type != VAR_UNKNOWN)
+       flags = get_tv_string_buf(&argvars[1], nbuf);
+    else
+       flags = (char_u *)"";
+
+    if (*flags == NUL)
+       /* delete a file */
+       rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
+    else if (STRCMP(flags, "d") == 0)
+       /* delete an empty directory */
+       rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
+    else if (STRCMP(flags, "rf") == 0)
+       /* delete an directory recursively */
+       rettv->vval.v_number = delete_recursive(name);
     else
-       rettv->vval.v_number = mch_remove(get_tv_string(&argvars[0]));
+       EMSG2(_(e_invexpr2), flags);
 }
 
 /*
index 75a38764c317798cec75ef624f42162fe77e0093..6dbdea21e660d95c5c8ee6dca8adb51ef4bb39ae 100644 (file)
@@ -7280,39 +7280,65 @@ write_lnum_adjust(offset)
        curbuf->b_no_eol_lnum += offset;
 }
 
-#if defined(TEMPDIRNAMES) || defined(PROTO)
-static long    temp_count = 0;         /* Temp filename counter. */
-
+#if defined(TEMPDIRNAMES) || defined(FEAT_EVAL) || defined(PROTO)
 /*
- * Delete the temp directory and all files it contains.
+ * Delete "name" and everything in it, recursively.
+ * return 0 for succes, -1 if some file was not deleted.
  */
-    void
-vim_deltempdir()
+    int
+delete_recursive(char_u *name)
 {
+    int result = 0;
     char_u     **files;
     int                file_count;
     int                i;
+    char_u     *exp;
 
-    if (vim_tempdir != NULL)
+    if (mch_isdir(name))
     {
-       sprintf((char *)NameBuff, "%s*", vim_tempdir);
-       if (gen_expand_wildcards(1, &NameBuff, &file_count, &files,
+       vim_snprintf((char *)NameBuff, MAXPATHL, "%s/*", name);
+       exp = vim_strsave(NameBuff);
+       if (exp == NULL)
+           return -1;
+       if (gen_expand_wildcards(1, &exp, &file_count, &files,
                                              EW_DIR|EW_FILE|EW_SILENT) == OK)
        {
            for (i = 0; i < file_count; ++i)
-               mch_remove(files[i]);
+               if (delete_recursive(files[i]) != 0)
+                   result = -1;
            FreeWild(file_count, files);
        }
-       gettail(NameBuff)[-1] = NUL;
-       (void)mch_rmdir(NameBuff);
+       else
+           result = -1;
+       vim_free(exp);
+       (void)mch_rmdir(name);
+    }
+    else
+       result = mch_remove(name) == 0 ? 0 : -1;
 
+    return result;
+}
+#endif
+
+#if defined(TEMPDIRNAMES) || defined(PROTO)
+static long    temp_count = 0;         /* Temp filename counter. */
+
+/*
+ * Delete the temp directory and all files it contains.
+ */
+    void
+vim_deltempdir()
+{
+    if (vim_tempdir != NULL)
+    {
+       /* remove the trailing path separator */
+       gettail(vim_tempdir)[-1] = NUL;
+       delete_recursive(vim_tempdir);
        vim_free(vim_tempdir);
        vim_tempdir = NULL;
     }
 }
-#endif
 
-#ifdef TEMPDIRNAMES
 /*
  * Directory "tempdir" was created.  Expand this name to a full path and put
  * it in "vim_tempdir".  This avoids that using ":cd" would confuse us.
index 32d7bce3182ac752a82308c05b6ae1a06826395b..0f68a20c4a247b2528e7dd41f5f5460a1b9c1f3b 100644 (file)
@@ -22,6 +22,7 @@ int buf_check_timestamp __ARGS((buf_T *buf, int focus));
 void buf_reload __ARGS((buf_T *buf, int orig_mode));
 void buf_store_time __ARGS((buf_T *buf, struct stat *st, char_u *fname));
 void write_lnum_adjust __ARGS((linenr_T offset));
+int delete_recursive __ARGS((char_u *name));
 void vim_deltempdir __ARGS((void));
 char_u *vim_tempname __ARGS((int extra_char, int keep));
 void forward_slash __ARGS((char_u *fname));
index 87bd26b45814c28578f4be07820201ae55b4ce0e..3cd1f824ee9412c44f38daf509eaaedffc847872 100644 (file)
@@ -3,6 +3,7 @@
 
 source test_backspace_opt.vim
 source test_cursor_func.vim
+source test_delete.vim
 source test_lispwords.vim
 source test_menu.vim
 source test_searchpos.vim
diff --git a/src/testdir/test_delete.vim b/src/testdir/test_delete.vim
new file mode 100644 (file)
index 0000000..6e2b9c8
--- /dev/null
@@ -0,0 +1,36 @@
+" Test for delete().
+
+func Test_file_delete()
+  split Xfile
+  call setline(1, ['a', 'b'])
+  wq
+  call assert_equal(['a', 'b'], readfile('Xfile'))
+  call assert_equal(0, delete('Xfile'))
+  call assert_fails('call readfile("Xfile")', 'E484:')
+  call assert_equal(-1, delete('Xfile'))
+endfunc
+
+func Test_dir_delete()
+  call mkdir('Xdir1')
+  call assert_true(isdirectory('Xdir1'))
+  call assert_equal(0, delete('Xdir1', 'd'))
+  call assert_false(isdirectory('Xdir1'))
+  call assert_equal(-1, delete('Xdir1', 'd'))
+endfunc
+
+func Test_recursive_delete()
+  call mkdir('Xdir1')
+  call mkdir('Xdir1/subdir')
+  split Xdir1/Xfile
+  call setline(1, ['a', 'b'])
+  w
+  w Xdir1/subdir/Xfile
+  close
+  call assert_true(isdirectory('Xdir1'))
+  call assert_equal(['a', 'b'], readfile('Xdir1/Xfile'))
+  call assert_true(isdirectory('Xdir1/subdir'))
+  call assert_equal(['a', 'b'], readfile('Xdir1/subdir/Xfile'))
+  call assert_equal(0, delete('Xdir1', 'rf'))
+  call assert_false(isdirectory('Xdir1'))
+  call assert_equal(-1, delete('Xdir1', 'd'))
+endfunc
index efc77c0aa8665e69f5f5aebae89664422375868a..9c24efd0df7d226b506d55633e912563745468b8 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1107,
 /**/
     1106,
 /**/