diff options
Diffstat (limited to 'src/nvim/fileio.c')
| -rw-r--r-- | src/nvim/fileio.c | 283 |
1 files changed, 166 insertions, 117 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 08a4b76783..55463bdf30 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -11,6 +11,7 @@ #include <fcntl.h> #include "nvim/vim.h" +#include "nvim/api/private/handle.h" #include "nvim/ascii.h" #include "nvim/fileio.h" #include "nvim/buffer.h" @@ -47,6 +48,7 @@ #include "nvim/state.h" #include "nvim/strings.h" #include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/types.h" #include "nvim/undo.h" #include "nvim/window.h" @@ -308,29 +310,30 @@ readfile ( #ifdef UNIX int swap_mode = -1; /* protection bits for swap file */ #endif - int fileformat = 0; /* end-of-line format */ - int keep_fileformat = FALSE; + int fileformat = 0; // end-of-line format + bool keep_fileformat = false; + FileInfo file_info; int file_readonly; linenr_T skip_count = 0; linenr_T read_count = 0; int msg_save = msg_scroll; linenr_T read_no_eol_lnum = 0; // non-zero lnum when last line of // last read was missing the eol - int file_rewind = false; + bool file_rewind = false; int can_retry; - linenr_T conv_error = 0; /* line nr with conversion error */ - linenr_T illegal_byte = 0; /* line nr with illegal byte */ - int keep_dest_enc = FALSE; /* don't retry when char doesn't fit - in destination encoding */ + linenr_T conv_error = 0; // line nr with conversion error + linenr_T illegal_byte = 0; // line nr with illegal byte + bool keep_dest_enc = false; // don't retry when char doesn't fit + // in destination encoding int bad_char_behavior = BAD_REPLACE; /* BAD_KEEP, BAD_DROP or character to * replace with */ char_u *tmpname = NULL; /* name of 'charconvert' output file */ int fio_flags = 0; - char_u *fenc; /* fileencoding to use */ - int fenc_alloced; /* fenc_next is in allocated memory */ - char_u *fenc_next = NULL; /* next item in 'fencs' or NULL */ - int advance_fenc = FALSE; + char_u *fenc; // fileencoding to use + bool fenc_alloced; // fenc_next is in allocated memory + char_u *fenc_next = NULL; // next item in 'fencs' or NULL + bool advance_fenc = false; long real_size = 0; # ifdef USE_ICONV iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */ @@ -481,7 +484,6 @@ readfile ( if (newfile && !read_stdin && !read_buffer && !read_fifo) { // Remember time of file. - FileInfo file_info; if (os_fileinfo((char *)fname, &file_info)) { buf_store_file_info(curbuf, &file_info); curbuf->b_mtime_read = curbuf->b_mtime; @@ -627,13 +629,30 @@ readfile ( // Set swap file protection bits after creating it. if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL && curbuf->b_ml.ml_mfp->mf_fname != NULL) { - (void)os_setperm((const char *)curbuf->b_ml.ml_mfp->mf_fname, - (long)swap_mode); + const char *swap_fname = (const char *)curbuf->b_ml.ml_mfp->mf_fname; + + // If the group-read bit is set but not the world-read bit, then + // the group must be equal to the group of the original file. If + // we can't make that happen then reset the group-read bit. This + // avoids making the swap file readable to more users when the + // primary group of the user is too permissive. + if ((swap_mode & 044) == 040) { + FileInfo swap_info; + + if (os_fileinfo(swap_fname, &swap_info) + && file_info.stat.st_gid != swap_info.stat.st_gid + && os_fchown(curbuf->b_ml.ml_mfp->mf_fd, -1, file_info.stat.st_gid) + == -1) { + swap_mode &= 0600; + } + } + + (void)os_setperm(swap_fname, swap_mode); } #endif } - /* If "Quit" selected at ATTENTION dialog, don't load the file */ + // If "Quit" selected at ATTENTION dialog, don't load the file. if (swap_exists_action == SEA_QUIT) { if (!read_buffer && !read_stdin) close(fd); @@ -747,11 +766,11 @@ readfile ( */ if (eap != NULL && eap->force_enc != 0) { fenc = enc_canonize(eap->cmd + eap->force_enc); - fenc_alloced = TRUE; - keep_dest_enc = TRUE; + fenc_alloced = true; + keep_dest_enc = true; } else if (curbuf->b_p_bin) { - fenc = (char_u *)""; /* binary: don't convert */ - fenc_alloced = FALSE; + fenc = (char_u *)""; // binary: don't convert + fenc_alloced = false; } else if (curbuf->b_help) { // Help files are either utf-8 or latin1. Try utf-8 first, if this // fails it must be latin1. @@ -762,12 +781,12 @@ readfile ( fenc_alloced = false; } else if (*p_fencs == NUL) { - fenc = curbuf->b_p_fenc; /* use format from buffer */ - fenc_alloced = FALSE; + fenc = curbuf->b_p_fenc; // use format from buffer + fenc_alloced = false; } else { fenc_next = p_fencs; /* try items in 'fileencodings' */ fenc = next_fenc(&fenc_next); - fenc_alloced = TRUE; + fenc_alloced = true; } /* @@ -800,10 +819,11 @@ retry: error = true; goto failed; } - /* Delete the previously read lines. */ - while (lnum > from) - ml_delete(lnum--, FALSE); - file_rewind = FALSE; + // Delete the previously read lines. + while (lnum > from) { + ml_delete(lnum--, false); + } + file_rewind = false; if (set_options) { curbuf->b_p_bomb = FALSE; curbuf->b_start_bomb = FALSE; @@ -815,9 +835,9 @@ retry: * When retrying with another "fenc" and the first time "fileformat" * will be reset. */ - if (keep_fileformat) - keep_fileformat = FALSE; - else { + if (keep_fileformat) { + keep_fileformat = false; + } else { if (eap != NULL && eap->force_ff != 0) { fileformat = get_fileformat_force(curbuf, eap); try_unix = try_dos = try_mac = FALSE; @@ -841,7 +861,7 @@ retry: /* * Try the next entry in 'fileencodings'. */ - advance_fenc = FALSE; + advance_fenc = false; if (eap != NULL && eap->force_enc != 0) { /* Conversion given with "++cc=" wasn't possible, read @@ -851,7 +871,7 @@ retry: if (fenc_alloced) xfree(fenc); fenc = (char_u *)""; - fenc_alloced = FALSE; + fenc_alloced = false; } else { if (fenc_alloced) xfree(fenc); @@ -860,7 +880,7 @@ retry: fenc_alloced = (fenc_next != NULL); } else { fenc = (char_u *)""; - fenc_alloced = FALSE; + fenc_alloced = false; } } if (tmpname != NULL) { @@ -926,8 +946,8 @@ retry: if (tmpname == NULL) { tmpname = readfile_charconvert(fname, fenc, &fd); if (tmpname == NULL) { - /* Conversion failed. Try another one. */ - advance_fenc = TRUE; + // Conversion failed. Try another one. + advance_fenc = true; if (fd < 0) { /* Re-opening the original file failed! */ EMSG(_("E202: Conversion made file unreadable!")); @@ -945,7 +965,7 @@ retry: ) { /* Conversion wanted but we can't. * Try the next conversion in 'fileencodings' */ - advance_fenc = TRUE; + advance_fenc = true; goto retry; } } @@ -1180,14 +1200,14 @@ retry: if (fio_flags == FIO_UCSBOM) { if (ccname == NULL) { - /* No BOM detected: retry with next encoding. */ - advance_fenc = TRUE; + // No BOM detected: retry with next encoding. + advance_fenc = true; } else { /* BOM detected: set "fenc" and jump back */ if (fenc_alloced) xfree(fenc); fenc = ccname; - fenc_alloced = FALSE; + fenc_alloced = false; } /* retry reading without getting new bytes or rewinding */ skip_read = TRUE; @@ -1512,9 +1532,9 @@ rewind_retry: did_iconv = TRUE; else # endif - /* use next item from 'fileencodings' */ - advance_fenc = TRUE; - file_rewind = TRUE; + // use next item from 'fileencodings' + advance_fenc = true; + file_rewind = true; goto retry; } } @@ -1648,8 +1668,8 @@ rewind_retry: fileformat = EOL_UNIX; if (set_options) set_fileformat(EOL_UNIX, OPT_LOCAL); - file_rewind = TRUE; - keep_fileformat = TRUE; + file_rewind = true; + keep_fileformat = true; goto retry; } ff_error = EOL_DOS; @@ -1760,8 +1780,8 @@ failed: if (!recoverymode) { /* need to delete the last line, which comes from the empty buffer */ if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY)) { - ml_delete(curbuf->b_ml.ml_line_count, FALSE); - --linecnt; + ml_delete(curbuf->b_ml.ml_line_count, false); + linecnt--; } linecnt = curbuf->b_ml.ml_line_count - linecnt; if (filesize == 0) @@ -2762,7 +2782,7 @@ buf_write ( backup_ext = p_bex; if (backup_copy) { - char_u *wp; + char_u *wp; int some_error = false; char_u *dirp; char_u *rootname; @@ -3456,7 +3476,7 @@ restore_backup: // copy the file. if (os_copy((char *)backup, (char *)fname, UV_FS_COPYFILE_FICLONE) == 0) { - end = 1; + end = 1; // success } } else { if (vim_rename(backup, fname) == 0) { @@ -3591,9 +3611,11 @@ restore_backup: /* * Remove the backup unless 'backup' option is set */ - if (!p_bk && backup != NULL && os_remove((char *)backup) != 0) + if (!p_bk && backup != NULL + && !write_info.bw_conv_error + && os_remove((char *)backup) != 0) { EMSG(_("E207: Can't delete backup file")); - + } goto nofail; @@ -4812,9 +4834,9 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) /* Copy the lines in "frombuf" to "tobuf". */ curbuf = tobuf; - for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; ++lnum) { - p = vim_strsave(ml_get_buf(frombuf, lnum, FALSE)); - if (ml_append(lnum - 1, p, 0, FALSE) == FAIL) { + for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { + p = vim_strsave(ml_get_buf(frombuf, lnum, false)); + if (ml_append(lnum - 1, p, 0, false) == FAIL) { xfree(p); retval = FAIL; break; @@ -4825,13 +4847,14 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) /* Delete all the lines in "frombuf". */ if (retval != FAIL) { curbuf = frombuf; - for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; --lnum) - if (ml_delete(lnum, FALSE) == FAIL) { - /* Oops! We could try putting back the saved lines, but that - * might fail again... */ + for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { + if (ml_delete(lnum, false) == FAIL) { + // Oops! We could try putting back the saved lines, but that + // might fail again... retval = FAIL; break; } + } } curbuf = tbuf; @@ -5509,39 +5532,48 @@ static void au_del_cmd(AutoCmd *ac) au_need_clean = true; } -/* - * Cleanup autocommands and patterns that have been deleted. - * This is only done when not executing autocommands. - */ +/// Cleanup autocommands and patterns that have been deleted. +/// This is only done when not executing autocommands. static void au_cleanup(void) { AutoPat *ap, **prev_ap; AutoCmd *ac, **prev_ac; event_T event; - if (autocmd_busy || !au_need_clean) + if (autocmd_busy || !au_need_clean) { return; + } - /* loop over all events */ + // Loop over all events. for (event = (event_T)0; (int)event < (int)NUM_EVENTS; event = (event_T)((int)event + 1)) { - /* loop over all autocommand patterns */ + // Loop over all autocommand patterns. prev_ap = &(first_autopat[(int)event]); for (ap = *prev_ap; ap != NULL; ap = *prev_ap) { - /* loop over all commands for this pattern */ + // Loop over all commands for this pattern. prev_ac = &(ap->cmds); + bool has_cmd = false; + for (ac = *prev_ac; ac != NULL; ac = *prev_ac) { - /* remove the command if the pattern is to be deleted or when - * the command has been marked for deletion */ + // Remove the command if the pattern is to be deleted or when + // the command has been marked for deletion. if (ap->pat == NULL || ac->cmd == NULL) { *prev_ac = ac->next; xfree(ac->cmd); xfree(ac); - } else + } else { + has_cmd = true; prev_ac = &(ac->next); + } + } + + if (ap->pat != NULL && !has_cmd) { + // Pattern was not marked for deletion, but all of its commands were. + // So mark the pattern for deletion. + au_remove_pat(ap); } - /* remove the pattern if it has been marked for deletion */ + // Remove the pattern if it has been marked for deletion. if (ap->pat == NULL) { if (ap->next == NULL) { if (prev_ap == &(first_autopat[(int)event])) { @@ -5555,12 +5587,13 @@ static void au_cleanup(void) *prev_ap = ap->next; vim_regfree(ap->reg_prog); xfree(ap); - } else + } else { prev_ap = &(ap->next); + } } } - au_need_clean = FALSE; + au_need_clean = false; } /* @@ -5965,20 +5998,36 @@ void do_autocmd(char_u *arg_in, int forceit) } } - // Check for "once" flag. cmd = skipwhite(cmd); - if (*cmd != NUL && STRNCMP(cmd, "once", 4) == 0 - && ascii_iswhite(cmd[4])) { - once = true; - cmd = skipwhite(cmd + 4); - } + for (size_t i = 0; i < 2; i++) { + if (*cmd != NUL) { + // Check for "++once" flag. + if (STRNCMP(cmd, "++once", 6) == 0 && ascii_iswhite(cmd[6])) { + if (once) { + EMSG2(_(e_duparg2), "++once"); + } + once = true; + cmd = skipwhite(cmd + 6); + } - // Check for "nested" flag. - cmd = skipwhite(cmd); - if (*cmd != NUL && STRNCMP(cmd, "nested", 6) == 0 - && ascii_iswhite(cmd[6])) { - nested = true; - cmd = skipwhite(cmd + 6); + // Check for "++nested" flag. + if ((STRNCMP(cmd, "++nested", 8) == 0 && ascii_iswhite(cmd[8]))) { + if (nested) { + EMSG2(_(e_duparg2), "++nested"); + } + nested = true; + cmd = skipwhite(cmd + 8); + } + + // Check for the old (deprecated) "nested" flag. + if (STRNCMP(cmd, "nested", 6) == 0 && ascii_iswhite(cmd[6])) { + if (nested) { + EMSG2(_(e_duparg2), "nested"); + } + nested = true; + cmd = skipwhite(cmd + 6); + } + } } // Find the start of the commands. @@ -6393,21 +6442,17 @@ bool check_nomodeline(char_u **argp) return true; } -/* - * Prepare for executing autocommands for (hidden) buffer "buf". - * Search for a visible window containing the current buffer. If there isn't - * one then use "aucmd_win". - * Set "curbuf" and "curwin" to match "buf". - */ -void -aucmd_prepbuf ( - aco_save_T *aco, /* structure to save values in */ - buf_T *buf /* new curbuf */ -) +/// Prepare for executing autocommands for (hidden) buffer `buf`. +/// If the current buffer is not in any visible window, put it in a temporary +/// floating window `aucmd_win`. +/// Set `curbuf` and `curwin` to match `buf`. +/// +/// @param aco structure to save values in +/// @param buf new curbuf +void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) { - win_T *win; - int save_ea; - int save_acd; + win_T *win; + bool need_append = true; // Append `aucmd_win` to the window list. /* Find a window that is for the new buffer */ if (buf == curbuf) { /* be quick when buf is curbuf */ @@ -6422,9 +6467,10 @@ aucmd_prepbuf ( } } - /* Allocate "aucmd_win" when needed. */ + // Allocate the `aucmd_win` dummy floating window. if (win == NULL && aucmd_win == NULL) { win_alloc_aucmd_win(); + need_append = false; } if (win == NULL && aucmd_win_used) /* Strange recursive autocommand, fall back to using the current @@ -6432,6 +6478,7 @@ aucmd_prepbuf ( win = curwin; aco->save_curwin = curwin; + aco->save_prevwin = prevwin; aco->save_curbuf = curbuf; if (win != NULL) { /* There is a window for "buf" in the current tab page, make it the @@ -6458,21 +6505,16 @@ aucmd_prepbuf ( aco->globaldir = globaldir; globaldir = NULL; - - /* Split the current window, put the aucmd_win in the upper half. - * We don't want the BufEnter or WinEnter autocommands. */ - block_autocmds(); - make_snapshot(SNAP_AUCMD_IDX); - save_ea = p_ea; - p_ea = false; - - /* Prevent chdir() call in win_enter_ext(), through do_autochdir(). */ - save_acd = p_acd; + block_autocmds(); // We don't want BufEnter/WinEnter autocommands. + if (need_append) { + win_append(lastwin, aucmd_win); + handle_register_window(aucmd_win); + win_config_float(aucmd_win, aucmd_win->w_float_config); + } + // Prevent chdir() call in win_enter_ext(), through do_autochdir() + int save_acd = p_acd; p_acd = false; - - (void)win_split_ins(0, WSP_TOP, aucmd_win, 0); - (void)win_comp_pos(); /* recompute window positions */ - p_ea = save_ea; + win_enter(aucmd_win, false); p_acd = save_acd; unblock_autocmds(); curwin = aucmd_win; @@ -6488,8 +6530,6 @@ aucmd_prepbuf ( /// @param aco structure holding saved values void aucmd_restbuf(aco_save_T *aco) { - int dummy; - if (aco->use_aucmd_win) { curbuf->b_nwindows--; // Find "aucmd_win", it can't be closed, but it may be in another tab page. @@ -6508,9 +6548,14 @@ void aucmd_restbuf(aco_save_T *aco) } win_found: - // Remove the window and frame from the tree of frames. - (void)winframe_remove(curwin, &dummy, NULL); win_remove(curwin, NULL); + handle_unregister_window(curwin); + if (curwin->w_grid.chars != NULL) { + ui_comp_remove_grid(&curwin->w_grid); + ui_call_win_hide(curwin->w_grid.handle); + grid_free(&curwin->w_grid); + } + aucmd_win_used = false; last_status(false); // may need to remove last status line @@ -6519,8 +6564,6 @@ win_found: close_tabpage(curtab); } - restore_snapshot(SNAP_AUCMD_IDX, false); - (void)win_comp_pos(); // recompute window positions unblock_autocmds(); if (win_valid(aco->save_curwin)) { @@ -6529,6 +6572,8 @@ win_found: // Hmm, original window disappeared. Just use the first one. curwin = firstwin; } + prevwin = win_valid(aco->save_prevwin) ? aco->save_prevwin + : firstwin; // window disappeared? vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab curbuf = curwin->w_buffer; @@ -6561,6 +6606,8 @@ win_found: } curwin = aco->save_curwin; + prevwin = win_valid(aco->save_prevwin) ? aco->save_prevwin + : firstwin; // window disappeared? curbuf = curwin->w_buffer; // In case the autocommand moves the cursor to a position that does not // exist in curbuf @@ -6956,6 +7003,8 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, do_cmdline(NULL, getnextac, (void *)&patcmd, DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); + reset_lnums(); // restore cursor and topline, unless they were changed + if (eap != NULL) { (void)set_cmdarg(NULL, save_cmdarg); set_vim_var_nr(VV_CMDBANG, save_cmdbang); |
