To: vim_dev@googlegroups.com Subject: Patch 7.4.1107 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1107 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. Files: src/fileio.c, src/eval.c, src/proto/fileio.pro, src/testdir/test_delete.vim, src/testdir/test_alot.vim, runtime/doc/eval.txt *** ../vim-7.4.1106/src/fileio.c 2015-12-31 19:53:16.262087808 +0100 --- src/fileio.c 2016-01-16 21:17:30.167870505 +0100 *************** *** 7280,7318 **** curbuf->b_no_eol_lnum += offset; } ! #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() { char_u **files; int file_count; int i; ! if (vim_tempdir != NULL) { ! sprintf((char *)NameBuff, "%s*", vim_tempdir); ! if (gen_expand_wildcards(1, &NameBuff, &file_count, &files, EW_DIR|EW_FILE|EW_SILENT) == OK) { for (i = 0; i < file_count; ++i) ! mch_remove(files[i]); FreeWild(file_count, files); } ! gettail(NameBuff)[-1] = NUL; ! (void)mch_rmdir(NameBuff); 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. --- 7280,7344 ---- curbuf->b_no_eol_lnum += offset; } ! #if defined(TEMPDIRNAMES) || defined(FEAT_EVAL) || defined(PROTO) /* ! * Delete "name" and everything in it, recursively. ! * return 0 for succes, -1 if some file was not deleted. */ ! int ! delete_recursive(char_u *name) { + int result = 0; char_u **files; int file_count; int i; + char_u *exp; ! if (mch_isdir(name)) { ! 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) ! if (delete_recursive(files[i]) != 0) ! result = -1; FreeWild(file_count, files); } ! 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; } } /* * 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. *** ../vim-7.4.1106/src/eval.c 2016-01-16 16:49:22.678187049 +0100 --- src/eval.c 2016-01-16 21:16:46.112352769 +0100 *************** *** 8131,8137 **** {"cscope_connection",0,3, f_cscope_connection}, {"cursor", 1, 3, f_cursor}, {"deepcopy", 1, 2, f_deepcopy}, ! {"delete", 1, 1, f_delete}, {"did_filetype", 0, 0, f_did_filetype}, {"diff_filler", 1, 1, f_diff_filler}, {"diff_hlID", 2, 2, f_diff_hlID}, --- 8131,8137 ---- {"cscope_connection",0,3, f_cscope_connection}, {"cursor", 1, 3, f_cursor}, {"deepcopy", 1, 2, f_deepcopy}, ! {"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,10400 **** typval_T *argvars; typval_T *rettv; { if (check_restricted() || check_secure()) ! rettv->vval.v_number = -1; else ! rettv->vval.v_number = mch_remove(get_tv_string(&argvars[0])); } /* --- 10391,10427 ---- 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()) ! 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 ! EMSG2(_(e_invexpr2), flags); } /* *** ../vim-7.4.1106/src/proto/fileio.pro 2015-03-31 13:33:00.797524914 +0200 --- src/proto/fileio.pro 2016-01-16 21:12:46.286978324 +0100 *************** *** 22,27 **** --- 22,28 ---- 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)); *** ../vim-7.4.1106/src/testdir/test_delete.vim 2016-01-16 21:25:06.698873635 +0100 --- src/testdir/test_delete.vim 2016-01-16 21:21:51.401011122 +0100 *************** *** 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 *** ../vim-7.4.1106/src/testdir/test_alot.vim 2016-01-15 15:37:16.979521224 +0100 --- src/testdir/test_alot.vim 2016-01-16 20:00:30.214557586 +0100 *************** *** 3,8 **** --- 3,9 ---- 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 *** ../vim-7.4.1106/runtime/doc/eval.txt 2016-01-15 20:48:09.862003231 +0100 --- runtime/doc/eval.txt 2016-01-16 20:34:22.280259614 +0100 *************** *** 1782,1796 **** copy( {expr}) any make a shallow copy of {expr} cos( {expr}) Float cosine of {expr} cosh( {expr}) Float hyperbolic cosine of {expr} ! count( {list}, {expr} [, {start} [, {ic}]]) Number count how many {expr} are in {list} cscope_connection( [{num} , {dbpath} [, {prepend}]]) Number checks existence of cscope connection ! cursor( {lnum}, {col} [, {coladd}]) ! Number move cursor to {lnum}, {col}, {coladd} cursor( {list}) Number move cursor to position in {list} ! deepcopy( {expr}) any make a full copy of {expr} ! delete( {fname}) Number delete file {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} --- 1791,1805 ---- copy( {expr}) any make a shallow copy of {expr} cos( {expr}) Float cosine of {expr} cosh( {expr}) Float hyperbolic cosine of {expr} ! count( {list}, {expr} [, {ic} [, {start}]]) Number count how many {expr} are in {list} cscope_connection( [{num} , {dbpath} [, {prepend}]]) Number checks existence of cscope connection ! 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} [, {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} *************** *** 2739,2748 **** {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. 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. --- 2753,2771 ---- {noref} set to 1 will fail. Also see |copy()|. ! 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. *** ../vim-7.4.1106/src/version.c 2016-01-16 18:05:40.445065341 +0100 --- src/version.c 2016-01-16 21:22:31.716569881 +0100 *************** *** 743,744 **** --- 743,746 ---- { /* Add new patch number below this line */ + /**/ + 1107, /**/ -- BEDEVERE: And that, my lord, is how we know the Earth to be banana-shaped. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///