To: vim_dev@googlegroups.com Subject: Patch 8.1.1231 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.1231 Problem: Asking about existing swap file unnecessarily. Solution: When it is safe, delete the swap file. Remove HAS_SWAP_EXISTS_ACTION, it is always defined. (closes #1237) Files: src/memline.c, src/globals.h, src/buffer.c, src/ex_cmds.c, src/fileio.c, src/main.c, src/testdir/test_swap.vim, runtime/doc/usr_11.txt, src/os_win32.c, src/proto/os_win32.pro, src/os_unix.c, src/proto/os_unix.pro *** ../vim-8.1.1230/src/memline.c 2019-04-28 19:46:17.030060105 +0200 --- src/memline.c 2019-04-28 22:22:42.217091959 +0200 *************** *** 2159,2167 **** { msg_puts(_("\n process ID: ")); msg_outnum(char_to_long(b0.b0_pid)); ! #if defined(UNIX) ! /* EMX kill() not working correctly, it seems */ ! if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0) { msg_puts(_(" (STILL RUNNING)")); # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) --- 2159,2166 ---- { msg_puts(_("\n process ID: ")); msg_outnum(char_to_long(b0.b0_pid)); ! #if defined(UNIX) || defined(MSWIN) ! if (mch_process_running((pid_t)char_to_long(b0.b0_pid))) { msg_puts(_(" (STILL RUNNING)")); # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) *************** *** 2193,2198 **** --- 2192,2248 ---- return x; } + /* + * Return TRUE if the swap file looks OK and there are no changes, thus it can + * be safely deleted. + */ + static time_t + swapfile_unchanged(char_u *fname) + { + stat_T st; + int fd; + struct block0 b0; + int ret = TRUE; + #ifdef UNIX + long pid; + #endif + + // must be able to stat the swap file + if (mch_stat((char *)fname, &st) == -1) + return FALSE; + + // must be able to read the first block + fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0); + if (fd < 0) + return FALSE; + if (read_eintr(fd, &b0, sizeof(b0)) != sizeof(b0)) + { + close(fd); + return FALSE; + } + + // the ID and magic number must be correct + if (ml_check_b0_id(&b0) == FAIL|| b0_magic_wrong(&b0)) + ret = FALSE; + + // must be unchanged + if (b0.b0_dirty) + ret = FALSE; + + #if defined(UNIX) || defined(MSWIN) + // process must known and not be running + pid = char_to_long(b0.b0_pid); + if (pid == 0L || mch_process_running((pid_t)pid)) + ret = FALSE; + #endif + + // TODO: Should we check if the swap file was created on the current + // system? And the current user? + + close(fd); + return ret; + } + static int recov_file_names(char_u **names, char_u *path, int prepend_dot) { *************** *** 4757,4765 **** if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED) && vim_strchr(p_shm, SHM_ATTENTION) == NULL) { - #if defined(HAS_SWAP_EXISTS_ACTION) int choice = 0; ! #endif #ifdef CREATE_DUMMY_FILE int did_use_dummy = FALSE; --- 4807,4814 ---- if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED) && vim_strchr(p_shm, SHM_ATTENTION) == NULL) { int choice = 0; ! stat_T st; #ifdef CREATE_DUMMY_FILE int did_use_dummy = FALSE; *************** *** 4779,4791 **** #if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)) process_still_running = FALSE; #endif #if defined(FEAT_EVAL) /* * If there is an SwapExists autocommand and we can handle * the response, trigger it. It may return 0 to ask the * user anyway. */ ! if (swap_exists_action != SEA_NONE && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) choice = do_swapexists(buf, fname); --- 4828,4852 ---- #if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)) process_still_running = FALSE; #endif + // It's safe to delete the swap file if all these are true: + // - the edited file exists + // - the swap file has no changes and looks OK + if (mch_stat((char *)buf->b_fname, &st) == 0 + && swapfile_unchanged(fname)) + { + choice = 4; + if (p_verbose > 0) + verb_msg(_("Found a swap file that is not useful, deleting it")); + } + #if defined(FEAT_EVAL) /* * If there is an SwapExists autocommand and we can handle * the response, trigger it. It may return 0 to ask the * user anyway. */ ! if (choice == 0 ! && swap_exists_action != SEA_NONE && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) choice = do_swapexists(buf, fname); *************** *** 4850,4856 **** } #endif - #if defined(HAS_SWAP_EXISTS_ACTION) if (choice > 0) { switch (choice) --- 4911,4916 ---- *************** *** 4880,4886 **** break; } else - #endif { msg_puts("\n"); if (msg_silent == 0) --- 4940,4945 ---- *** ../vim-8.1.1230/src/globals.h 2019-04-28 19:46:17.026060122 +0200 --- src/globals.h 2019-04-28 22:14:01.975212661 +0200 *************** *** 966,972 **** EXTERN int emsg_noredir INIT(= 0); /* don't redirect error messages */ EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */ - # define HAS_SWAP_EXISTS_ACTION EXTERN int swap_exists_action INIT(= SEA_NONE); /* For dialog when swap file already * exists. */ --- 966,971 ---- *************** *** 1644,1649 **** --- 1643,1651 ---- #endif #ifdef MSWIN + # ifdef PROTO + typedef int HINSTANCE; + # endif EXTERN int ctrl_break_was_pressed INIT(= FALSE); EXTERN HINSTANCE g_hinst INIT(= NULL); #endif *** ../vim-8.1.1230/src/buffer.c 2019-04-28 18:04:56.054492198 +0200 --- src/buffer.c 2019-04-28 20:19:17.859717974 +0200 *************** *** 972,1014 **** int dir, int count) { - #if defined(HAS_SWAP_EXISTS_ACTION) bufref_T old_curbuf; set_bufref(&old_curbuf, curbuf); swap_exists_action = SEA_DIALOG; - #endif (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, eap->forceit); - #if defined(HAS_SWAP_EXISTS_ACTION) if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') { ! # if defined(FEAT_EVAL) cleanup_T cs; /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a window. */ enter_cleanup(&cs); ! # endif /* Quitting means closing the split window, nothing else. */ win_close(curwin, TRUE); swap_exists_action = SEA_NONE; swap_exists_did_quit = TRUE; ! # if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not discarded by a * new aborting error, interrupt, or uncaught exception. */ leave_cleanup(&cs); ! # endif } else handle_swap_exists(&old_curbuf); - #endif } - #if defined(HAS_SWAP_EXISTS_ACTION) || defined(PROTO) /* * Handle the situation of swap_exists_action being set. * It is allowed for "old_curbuf" to be NULL or invalid. --- 972,1009 ---- int dir, int count) { bufref_T old_curbuf; set_bufref(&old_curbuf, curbuf); swap_exists_action = SEA_DIALOG; (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, eap->forceit); if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') { ! #if defined(FEAT_EVAL) cleanup_T cs; /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a window. */ enter_cleanup(&cs); ! #endif /* Quitting means closing the split window, nothing else. */ win_close(curwin, TRUE); swap_exists_action = SEA_NONE; swap_exists_did_quit = TRUE; ! #if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not discarded by a * new aborting error, interrupt, or uncaught exception. */ leave_cleanup(&cs); ! #endif } else handle_swap_exists(&old_curbuf); } /* * Handle the situation of swap_exists_action being set. * It is allowed for "old_curbuf" to be NULL or invalid. *************** *** 1016,1036 **** void handle_swap_exists(bufref_T *old_curbuf) { ! # if defined(FEAT_EVAL) cleanup_T cs; ! # endif ! # ifdef FEAT_SYN_HL long old_tw = curbuf->b_p_tw; ! # endif buf_T *buf; if (swap_exists_action == SEA_QUIT) { ! # if defined(FEAT_EVAL) /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a buffer. */ enter_cleanup(&cs); ! # endif /* User selected Quit at ATTENTION prompt. Go back to previous * buffer. If that buffer is gone or the same as the current one, --- 1011,1031 ---- void handle_swap_exists(bufref_T *old_curbuf) { ! #if defined(FEAT_EVAL) cleanup_T cs; ! #endif ! #ifdef FEAT_SYN_HL long old_tw = curbuf->b_p_tw; ! #endif buf_T *buf; if (swap_exists_action == SEA_QUIT) { ! #if defined(FEAT_EVAL) /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a buffer. */ enter_cleanup(&cs); ! #endif /* User selected Quit at ATTENTION prompt. Go back to previous * buffer. If that buffer is gone or the same as the current one, *************** *** 1053,1078 **** // restore msg_silent, so that the command line will be shown msg_silent = old_msg_silent; ! # ifdef FEAT_SYN_HL if (old_tw != curbuf->b_p_tw) check_colorcolumn(curwin); ! # endif } /* If "old_curbuf" is NULL we are in big trouble here... */ ! # if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not discarded by a * new aborting error, interrupt, or uncaught exception. */ leave_cleanup(&cs); ! # endif } else if (swap_exists_action == SEA_RECOVER) { ! # if defined(FEAT_EVAL) /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a buffer. */ enter_cleanup(&cs); ! # endif /* User selected Recover at ATTENTION prompt. */ msg_scroll = TRUE; --- 1048,1073 ---- // restore msg_silent, so that the command line will be shown msg_silent = old_msg_silent; ! #ifdef FEAT_SYN_HL if (old_tw != curbuf->b_p_tw) check_colorcolumn(curwin); ! #endif } /* If "old_curbuf" is NULL we are in big trouble here... */ ! #if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not discarded by a * new aborting error, interrupt, or uncaught exception. */ leave_cleanup(&cs); ! #endif } else if (swap_exists_action == SEA_RECOVER) { ! #if defined(FEAT_EVAL) /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a buffer. */ enter_cleanup(&cs); ! #endif /* User selected Recover at ATTENTION prompt. */ msg_scroll = TRUE; *************** *** 1081,1095 **** cmdline_row = msg_row; do_modelines(0); ! # if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not discarded by a * new aborting error, interrupt, or uncaught exception. */ leave_cleanup(&cs); ! # endif } swap_exists_action = SEA_NONE; } - #endif /* * do_bufdel() - delete or unload buffer(s) --- 1076,1089 ---- cmdline_row = msg_row; do_modelines(0); ! #if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not discarded by a * new aborting error, interrupt, or uncaught exception. */ leave_cleanup(&cs); ! #endif } swap_exists_action = SEA_NONE; } /* * do_bufdel() - delete or unload buffer(s) *************** *** 5259,5286 **** continue; /* Open the buffer in this window. */ - #if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_action = SEA_DIALOG; - #endif set_curbuf(buf, DOBUF_GOTO); if (!bufref_valid(&bufref)) { /* autocommands deleted the buffer!!! */ - #if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_action = SEA_NONE; - #endif break; } - #if defined(HAS_SWAP_EXISTS_ACTION) if (swap_exists_action == SEA_QUIT) { ! # if defined(FEAT_EVAL) cleanup_T cs; /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a window. */ enter_cleanup(&cs); ! # endif /* User selected Quit at ATTENTION prompt; close this window. */ win_close(curwin, TRUE); --- 5253,5275 ---- continue; /* Open the buffer in this window. */ swap_exists_action = SEA_DIALOG; set_curbuf(buf, DOBUF_GOTO); if (!bufref_valid(&bufref)) { /* autocommands deleted the buffer!!! */ swap_exists_action = SEA_NONE; break; } if (swap_exists_action == SEA_QUIT) { ! #if defined(FEAT_EVAL) cleanup_T cs; /* Reset the error/interrupt/exception state here so that * aborting() returns FALSE when closing a window. */ enter_cleanup(&cs); ! #endif /* User selected Quit at ATTENTION prompt; close this window. */ win_close(curwin, TRUE); *************** *** 5288,5303 **** swap_exists_action = SEA_NONE; swap_exists_did_quit = TRUE; ! # if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not * discarded by a new aborting error, interrupt, or uncaught * exception. */ leave_cleanup(&cs); ! # endif } else handle_swap_exists(NULL); - #endif } ui_breakcheck(); --- 5277,5291 ---- swap_exists_action = SEA_NONE; swap_exists_did_quit = TRUE; ! #if defined(FEAT_EVAL) /* Restore the error/interrupt/exception state if not * discarded by a new aborting error, interrupt, or uncaught * exception. */ leave_cleanup(&cs); ! #endif } else handle_swap_exists(NULL); } ui_breakcheck(); *** ../vim-8.1.1230/src/ex_cmds.c 2019-04-28 19:46:17.022060143 +0200 --- src/ex_cmds.c 2019-04-28 20:19:31.859649114 +0200 *************** *** 4258,4266 **** topline = curwin->w_topline; if (!oldbuf) /* need to read the file */ { - #if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_action = SEA_DIALOG; - #endif curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */ /* --- 4258,4264 ---- *************** *** 4273,4283 **** (void)open_buffer(FALSE, eap, readfile_flags); #endif - #if defined(HAS_SWAP_EXISTS_ACTION) if (swap_exists_action == SEA_QUIT) retval = FAIL; handle_swap_exists(&old_curbuf); - #endif } else { --- 4271,4279 ---- *** ../vim-8.1.1230/src/fileio.c 2019-04-28 19:46:17.026060122 +0200 --- src/fileio.c 2019-04-28 20:19:41.807600177 +0200 *************** *** 684,698 **** #endif } ! #if defined(HAS_SWAP_EXISTS_ACTION) ! /* If "Quit" selected at ATTENTION dialog, don't load the file */ if (swap_exists_action == SEA_QUIT) { if (!read_buffer && !read_stdin) close(fd); return FAIL; } - #endif ++no_wait_return; /* don't wait for return yet */ --- 684,696 ---- #endif } ! // If "Quit" selected at ATTENTION dialog, don't load the file if (swap_exists_action == SEA_QUIT) { if (!read_buffer && !read_stdin) close(fd); return FAIL; } ++no_wait_return; /* don't wait for return yet */ *** ../vim-8.1.1230/src/main.c 2019-04-28 19:46:17.030060105 +0200 --- src/main.c 2019-04-28 20:21:01.743207196 +0200 *************** *** 50,58 **** static void exe_commands(mparm_T *parmp); static void source_startup_scripts(mparm_T *parmp); static void main_start_gui(void); - # if defined(HAS_SWAP_EXISTS_ACTION) static void check_swap_exists_action(void); - # endif # ifdef FEAT_EVAL static void set_progpath(char_u *argv0); # endif --- 50,56 ---- *************** *** 784,802 **** */ if (params.tagname != NULL) { - #if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_did_quit = FALSE; - #endif vim_snprintf((char *)IObuff, IOSIZE, "ta %s", params.tagname); do_cmdline_cmd(IObuff); TIME_MSG("jumping to tag"); - #if defined(HAS_SWAP_EXISTS_ACTION) /* If the user doesn't want to edit the file then we quit here. */ if (swap_exists_did_quit) getout(1); - #endif } /* Execute any "+", "-c" and "-S" arguments. */ --- 782,796 ---- *************** *** 2625,2644 **** { int i; ! #if defined(HAS_SWAP_EXISTS_ACTION) ! /* When getting the ATTENTION prompt here, use a dialog */ swap_exists_action = SEA_DIALOG; ! #endif no_wait_return = TRUE; i = msg_didany; set_buflisted(TRUE); ! (void)open_buffer(TRUE, NULL, 0); /* create memfile and read file */ no_wait_return = FALSE; msg_didany = i; TIME_MSG("reading stdin"); ! #if defined(HAS_SWAP_EXISTS_ACTION) check_swap_exists_action(); - #endif #if !(defined(AMIGA) || defined(MACOS_X)) /* * Close stdin and dup it from stderr. Required for GPM to work --- 2619,2636 ---- { int i; ! // When getting the ATTENTION prompt here, use a dialog swap_exists_action = SEA_DIALOG; ! no_wait_return = TRUE; i = msg_didany; set_buflisted(TRUE); ! (void)open_buffer(TRUE, NULL, 0); // create memfile and read file no_wait_return = FALSE; msg_didany = i; TIME_MSG("reading stdin"); ! check_swap_exists_action(); #if !(defined(AMIGA) || defined(MACOS_X)) /* * Close stdin and dup it from stderr. Required for GPM to work *************** *** 2741,2756 **** if (p_fdls >= 0) curwin->w_p_fdl = p_fdls; #endif ! #if defined(HAS_SWAP_EXISTS_ACTION) ! /* When getting the ATTENTION prompt here, use a dialog */ swap_exists_action = SEA_DIALOG; ! #endif set_buflisted(TRUE); /* create memfile, read file */ (void)open_buffer(FALSE, NULL, 0); - #if defined(HAS_SWAP_EXISTS_ACTION) if (swap_exists_action == SEA_QUIT) { if (got_int || only_one_window()) --- 2733,2746 ---- if (p_fdls >= 0) curwin->w_p_fdl = p_fdls; #endif ! // When getting the ATTENTION prompt here, use a dialog swap_exists_action = SEA_DIALOG; ! set_buflisted(TRUE); /* create memfile, read file */ (void)open_buffer(FALSE, NULL, 0); if (swap_exists_action == SEA_QUIT) { if (got_int || only_one_window()) *************** *** 2768,2774 **** } else handle_swap_exists(NULL); - #endif dorewind = TRUE; /* start again */ } ui_breakcheck(); --- 2758,2763 ---- *************** *** 2865,2877 **** curwin->w_arg_idx = arg_idx; /* Edit file from arg list, if there is one. When "Quit" selected * at the ATTENTION prompt close the window. */ - # ifdef HAS_SWAP_EXISTS_ACTION swap_exists_did_quit = FALSE; - # endif (void)do_ecmd(0, arg_idx < GARGCOUNT ? alist_name(&GARGLIST[arg_idx]) : NULL, NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin); - # ifdef HAS_SWAP_EXISTS_ACTION if (swap_exists_did_quit) { /* abort or quit selected */ --- 2854,2863 ---- *************** *** 2884,2890 **** win_close(curwin, TRUE); advance = FALSE; } - # endif if (arg_idx == GARGCOUNT - 1) arg_had_last = TRUE; ++arg_idx; --- 2870,2875 ---- *************** *** 3485,3491 **** mch_exit(0); } - #if defined(HAS_SWAP_EXISTS_ACTION) /* * Check the result of the ATTENTION dialog: * When "Quit" selected, exit Vim. --- 3470,3475 ---- *************** *** 3498,3504 **** getout(1); handle_swap_exists(NULL); } - #endif #endif /* NO_VIM_MAIN */ --- 3482,3487 ---- *** ../vim-8.1.1230/src/testdir/test_swap.vim 2019-01-27 14:29:20.724544960 +0100 --- src/testdir/test_swap.vim 2019-04-28 21:50:37.397318520 +0200 *************** *** 164,166 **** --- 164,222 ---- call delete('Xtest2') call delete('Xtest3') endfunc + + func Test_swapfile_delete() + autocmd! SwapExists + function s:swap_exists() + let v:swapchoice = s:swap_choice + let s:swapname = v:swapname + let s:filename = expand('') + endfunc + augroup test_swapfile_delete + autocmd! + autocmd SwapExists * call s:swap_exists() + augroup END + + + " Create a valid swapfile by editing a file. + split XswapfileText + call setline(1, ['one', 'two', 'three']) + write " file is written, not modified + " read the swapfile as a Blob + let swapfile_name = swapname('%') + let swapfile_bytes = readfile(swapfile_name, 'B') + + " Close the file and recreate the swap file. + " Now editing the file will run into the process still existing + quit + call writefile(swapfile_bytes, swapfile_name) + let s:swap_choice = 'e' + let s:swapname = '' + split XswapfileText + quit + call assert_equal(swapfile_name, s:swapname) + + " Write the swapfile with a modified PID, now it will be automatically + " deleted. Process one should never be Vim. + let swapfile_bytes[24:27] = 0z01000000 + call writefile(swapfile_bytes, swapfile_name) + let s:swapname = '' + split XswapfileText + quit + call assert_equal('', s:swapname) + + " Now set the modified flag, the swap file will not be deleted + let swapfile_bytes[28 + 80 + 899] = 0x55 + call writefile(swapfile_bytes, swapfile_name) + let s:swapname = '' + split XswapfileText + quit + call assert_equal(swapfile_name, s:swapname) + + call delete('XswapfileText') + call delete(swapfile_name) + augroup test_swapfile_delete + autocmd! + augroup END + augroup! test_swapfile_delete + endfunc *** ../vim-8.1.1230/runtime/doc/usr_11.txt 2018-05-17 13:42:03.000000000 +0200 --- runtime/doc/usr_11.txt 2019-04-28 21:58:09.667057415 +0200 *************** *** 120,126 **** USING A SPECIFIC SWAP FILE If you know which swap file needs to be used, you can recover by giving the ! swap file name. Vim will then finds out the name of the original file from the swap file. Example: > --- 120,126 ---- USING A SPECIFIC SWAP FILE If you know which swap file needs to be used, you can recover by giving the ! swap file name. Vim will then find out the name of the original file from the swap file. Example: > *************** *** 205,210 **** --- 205,217 ---- NEWER than swap file! ~ + NOTE that in the following situation Vim knows the swap file is not useful and + will automatically delete it: + - The file is a valid swap file (Magic number is correct). + - The flag that the file was modified is not set. + - The process is not running. + + UNREADABLE SWAP FILE Sometimes the line *************** *** 284,289 **** --- 291,297 ---- 'shortmess' option. But it's very unusual that you need this. For remarks about encryption and the swap file, see |:recover-crypt|. + For programatic access to the swap file, see |swapinfo()|. ============================================================================== *11.4* Further reading *** ../vim-8.1.1230/src/os_win32.c 2019-04-28 19:46:17.034060084 +0200 --- src/os_win32.c 2019-04-28 22:11:28.811767431 +0200 *************** *** 2903,2908 **** --- 2903,2925 ---- return (long)GetCurrentProcessId(); } + /* + * return TRUE if process "pid" is still running + */ + int + mch_process_running(pid_t pid) + { + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, (DWORD)pid); + DWORD status = 0; + int ret = FALSE; + + if (hProcess == NULL) + return FALSE; // might not have access + if (GetExitCodeProcess(hProcess, &status) ) + ret = status == STILL_ACTIVE; + CloseHandle(hProcess); + return ret; + } /* * Get name of current directory into buffer 'buf' of length 'len' bytes. *** ../vim-8.1.1230/src/proto/os_win32.pro 2019-04-28 19:46:17.034060084 +0200 --- src/proto/os_win32.pro 2019-04-28 22:14:17.599153672 +0200 *************** *** 19,24 **** --- 19,25 ---- int mch_get_user_name(char_u *s, int len); void mch_get_host_name(char_u *s, int len); long mch_get_pid(void); + int mch_process_running(pid_t pid); int mch_dirname(char_u *buf, int len); long mch_getperm(char_u *name); int mch_setperm(char_u *name, long perm); *** ../vim-8.1.1230/src/os_unix.c 2019-04-04 20:13:06.001014760 +0200 --- src/os_unix.c 2019-04-28 22:19:41.013860198 +0200 *************** *** 2393,2398 **** --- 2393,2408 ---- return (long)getpid(); } + /* + * return TRUE if process "pid" is still running + */ + int + mch_process_running(pid_t pid) + { + // EMX kill() not working correctly, it seems + return kill(pid, 0) == 0; + } + #if !defined(HAVE_STRERROR) && defined(USE_GETCWD) static char * strerror(int err) *** ../vim-8.1.1230/src/proto/os_unix.pro 2019-01-20 15:30:36.893328693 +0100 --- src/proto/os_unix.pro 2019-04-28 22:19:14.453970686 +0200 *************** *** 27,32 **** --- 27,33 ---- int mch_get_uname(uid_t uid, char_u *s, int len); void mch_get_host_name(char_u *s, int len); long mch_get_pid(void); + int mch_process_running(pid_t pid); int mch_dirname(char_u *buf, int len); int mch_FullName(char_u *fname, char_u *buf, int len, int force); int mch_isFullName(char_u *fname); *** ../vim-8.1.1230/src/version.c 2019-04-28 19:46:17.034060084 +0200 --- src/version.c 2019-04-28 22:20:54.909549767 +0200 *************** *** 769,770 **** --- 769,772 ---- { /* Add new patch number below this line */ + /**/ + 1231, /**/ -- ARTHUR: What? BLACK KNIGHT: None shall pass. ARTHUR: I have no quarrel with you, good Sir knight, but I must cross this bridge. BLACK KNIGHT: Then you shall die. The Quest for the Holy Grail (Monty Python) /// 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 ///