diff options
Diffstat (limited to 'src/nvim/fileio.c')
| -rw-r--r-- | src/nvim/fileio.c | 2308 |
1 files changed, 251 insertions, 2057 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fbb5c4f1fa..0bb664bcf5 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // fileio.c: read from and write to a file #include <assert.h> @@ -10,13 +7,16 @@ #include <inttypes.h> #include <limits.h> #include <stdbool.h> +#include <stddef.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> +#include <sys/types.h> +#include <time.h> #include <uv.h> #include "auto/config.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" @@ -27,19 +27,20 @@ #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" -#include "nvim/ex_cmds.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_eval.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" +#include "nvim/garray_defs.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/highlight_defs.h" -#include "nvim/iconv.h" -#include "nvim/input.h" +#include "nvim/highlight.h" +#include "nvim/iconv_defs.h" #include "nvim/log.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memfile.h" #include "nvim/memline.h" @@ -47,24 +48,30 @@ #include "nvim/message.h" #include "nvim/move.h" #include "nvim/option.h" +#include "nvim/option_vars.h" #include "nvim/optionstr.h" +#include "nvim/os/fs.h" #include "nvim/os/fs_defs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/time.h" #include "nvim/path.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/regexp.h" -#include "nvim/screen.h" #include "nvim/sha256.h" #include "nvim/shada.h" +#include "nvim/state_defs.h" #include "nvim/strings.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/undo.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" + +#ifdef BACKSLASH_IN_FILENAME +# include "nvim/charset.h" +#endif -#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +#ifdef HAVE_DIRFD_AND_FLOCK # include <dirent.h> # include <sys/file.h> #endif @@ -73,87 +80,48 @@ # include "nvim/charset.h" #endif -#define BUFSIZE 8192 // size of normal write buffer -#define SMBUFSIZE 256 // size of emergency write buffer - // For compatibility with libuv < 1.20.0 (tested on 1.18.0) #ifndef UV_FS_COPYFILE_FICLONE # define UV_FS_COPYFILE_FICLONE 0 #endif -#define HAS_BW_FLAGS -enum { - FIO_LATIN1 = 0x01, // convert Latin1 - FIO_UTF8 = 0x02, // convert UTF-8 - FIO_UCS2 = 0x04, // convert UCS-2 - FIO_UCS4 = 0x08, // convert UCS-4 - FIO_UTF16 = 0x10, // convert UTF-16 - FIO_ENDIAN_L = 0x80, // little endian - FIO_NOCONVERT = 0x2000, // skip encoding conversion - FIO_UCSBOM = 0x4000, // check for BOM at start of file - FIO_ALL = -1, // allow all formats -}; - -// When converting, a read() or write() may leave some bytes to be converted -// for the next call. The value is guessed... -#define CONV_RESTLEN 30 - -// We have to guess how much a sequence of bytes may expand when converting -// with iconv() to be able to allocate a buffer. -#define ICONV_MULT 8 - -// Structure to pass arguments from buf_write() to buf_write_bytes(). -struct bw_info { - int bw_fd; // file descriptor - char *bw_buf; // buffer with data to be written - int bw_len; // length of data -#ifdef HAS_BW_FLAGS - int bw_flags; // FIO_ flags -#endif - char_u bw_rest[CONV_RESTLEN]; // not converted bytes - int bw_restlen; // nr of bytes in bw_rest[] - int bw_first; // first write call - char *bw_conv_buf; // buffer for writing converted chars - size_t bw_conv_buflen; // size of bw_conv_buf - int bw_conv_error; // set for conversion error - linenr_T bw_conv_error_lnum; // first line with error or zero - linenr_T bw_start_lnum; // line number at start of buffer - iconv_t bw_iconv_fd; // descriptor for iconv() or -1 -}; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "fileio.c.generated.h" #endif -static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); -static char e_no_matching_autocommands_for_buftype_str_buffer[] - = N_("E676: No matching autocommands for buftype=%s buffer"); +static const char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); void filemess(buf_T *buf, char *name, char *s, int attr) { - int msg_scroll_save; + int prev_msg_col = msg_col; if (msg_silent != 0) { return; } - add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)name); + + add_quoted_fname(IObuff, IOSIZE - 100, buf, name); + // Avoid an over-long translation to cause trouble. xstrlcat(IObuff, s, IOSIZE); + // For the first message may have to start a new line. // For further ones overwrite the previous one, reset msg_scroll before // calling filemess(). - msg_scroll_save = msg_scroll; - if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) { + int msg_scroll_save = msg_scroll; + if (shortmess(SHM_OVERALL) && !msg_listdo_overwrite && !exiting && p_verbose == 0) { msg_scroll = false; } if (!msg_scroll) { // wait a bit when overwriting an error msg - check_for_delay(false); + msg_check_for_delay(false); } msg_start(); + if (prev_msg_col != 0 && msg_col == 0) { + msg_putchar('\r'); // overwrite any previous message. + } msg_scroll = msg_scroll_save; msg_scrolled_ign = true; // may truncate the message to avoid a hit-return prompt - msg_outtrans_attr(msg_may_trunc(false, IObuff), attr); + msg_outtrans(msg_may_trunc(false, IObuff), attr); msg_clr_eos(); ui_flush(); msg_scrolled_ign = false; @@ -188,6 +156,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap, int flags, bool silent) { + int retval = FAIL; // jump to "theend" instead of returning int fd = stdin_fd >= 0 ? stdin_fd : 0; int newfile = (flags & READ_NEW); int check_readonly; @@ -207,7 +176,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, char *line_start = NULL; // init to shut up gcc int wasempty; // buffer was empty before reading colnr_T len; - long size = 0; + ptrdiff_t size = 0; uint8_t *p = NULL; off_T filesize = 0; bool skip_read = false; @@ -217,7 +186,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T linecnt; bool error = false; // errors encountered int ff_error = EOL_UNKNOWN; // file format with errors - long linerest = 0; // remaining chars in line + ptrdiff_t linerest = 0; // remaining chars in line int perm = 0; #ifdef UNIX int swap_mode = -1; // protection bits for swap file @@ -245,7 +214,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, bool fenc_alloced; // fenc_next is in allocated memory char *fenc_next = NULL; // next item in 'fencs' or NULL bool advance_fenc = false; - long real_size = 0; + int real_size = 0; iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1 bool did_iconv = false; // true when iconv() failed and trying // 'charconvert' next @@ -275,7 +244,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, && vim_strchr(p_cpo, CPO_FNAMER) != NULL && !(flags & READ_DUMMY)) { if (set_rw_fname(fname, sfname) == FAIL) { - return FAIL; + goto theend; } } @@ -319,10 +288,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (newfile) { if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname, false, curbuf, eap)) { - int status = OK; - + retval = OK; if (aborting()) { - status = FAIL; + retval = FAIL; } // The BufReadCmd code usually uses ":read" to get the text and @@ -330,14 +298,15 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // consider this to work like ":edit", thus reset the // BF_NOTEDITED flag. Then ":write" will work to overwrite the // same file. - if (status == OK) { + if (retval == OK) { curbuf->b_flags &= ~BF_NOTEDITED; } - return status; + goto theend; } } else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname, false, NULL, eap)) { - return aborting() ? FAIL : OK; + retval = aborting() ? FAIL : OK; + goto theend; } curbuf->b_op_start = orig_start; @@ -345,11 +314,12 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (flags & READ_NOFILE) { // Return NOTDONE instead of FAIL so that BufEnter can be triggered // and other operations don't fail. - return NOTDONE; + retval = NOTDONE; + goto theend; } } - if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0) { + if (((shortmess(SHM_OVER) && !msg_listdo_overwrite) || curbuf->b_help) && p_verbose == 0) { msg_scroll = false; // overwrite previous file message } else { msg_scroll = true; // don't overwrite previous file message @@ -363,7 +333,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, filemess(curbuf, fname, _("Illegal file name"), 0); msg_end(); msg_scroll = msg_save; - return FAIL; + goto theend; } // If the name ends in a path separator, we can't open it. Check here, @@ -375,7 +345,8 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } msg_end(); msg_scroll = msg_save; - return NOTDONE; + retval = NOTDONE; + goto theend; } } @@ -383,24 +354,30 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, perm = os_getperm(fname); // On Unix it is possible to read a directory, so we have to // check for it before os_open(). + +#ifdef OPEN_CHR_FILES +# define IS_CHR_DEV(perm, fname) S_ISCHR(perm) && is_dev_fd_file(fname) +#else +# define IS_CHR_DEV(perm, fname) false +#endif + if (perm >= 0 && !S_ISREG(perm) // not a regular file ... && !S_ISFIFO(perm) // ... or fifo && !S_ISSOCK(perm) // ... or socket -#ifdef OPEN_CHR_FILES - && !(S_ISCHR(perm) && is_dev_fd_file(fname)) + && !(IS_CHR_DEV(perm, fname)) // ... or a character special file named /dev/fd/<n> -#endif ) { if (S_ISDIR(perm)) { if (!silent) { filemess(curbuf, fname, _(msg_is_a_directory), 0); } + retval = NOTDONE; } else { filemess(curbuf, fname, _("is not a file"), 0); } msg_end(); msg_scroll = msg_save; - return S_ISDIR(perm) ? NOTDONE : FAIL; + goto theend; } } @@ -461,7 +438,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (fd < 0) { // cannot open at all msg_scroll = msg_save; if (!newfile) { - return FAIL; + goto theend; } if (perm == UV_ENOENT) { // check if the file exists // Set the 'new-file' flag, so that when the file has @@ -480,12 +457,12 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, || (using_b_fname && (old_b_fname != curbuf->b_fname))) { emsg(_(e_auchangedbuf)); - return FAIL; + goto theend; } } if (!silent) { if (dir_of_file_exists(fname)) { - filemess(curbuf, sfname, new_file_message(), 0); + filemess(curbuf, sfname, _("[New]"), 0); } else { filemess(curbuf, sfname, _("[New DIRECTORY]"), 0); } @@ -502,23 +479,27 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // remember the current fileformat save_file_ff(curbuf); - if (aborting()) { // autocmds may abort script processing - return FAIL; + if (!aborting()) { // autocmds may abort script processing + retval = OK; // a new file is not an error } - return OK; // a new file is not an error + goto theend; } - filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : #if defined(UNIX) && defined(EOVERFLOW) + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") + : // libuv only returns -errno // in Unix and in Windows // open() does not set // EOVERFLOW - (fd == -EOVERFLOW) ? _("[File too big]") : + (fd == -EOVERFLOW) ? _("[File too big]") + : _("[Permission Denied]")), 0); +#else + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") + : _("[Permission Denied]")), 0); #endif - _("[Permission Denied]")), 0); curbuf->b_p_ro = true; // must use "w!" now - return FAIL; + goto theend; } // Only set the 'ro' flag for readonly files the first time they are @@ -553,13 +534,13 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!read_buffer) { close(fd); } - return FAIL; + goto theend; } #ifdef UNIX // 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) { - const char *swap_fname = (const char *)curbuf->b_ml.ml_mfp->mf_fname; + const char *swap_fname = 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 @@ -588,7 +569,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!read_buffer && !read_stdin) { close(fd); } - return FAIL; + goto theend; } no_wait_return++; // don't wait for return yet @@ -644,7 +625,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, no_wait_return--; msg_scroll = msg_save; curbuf->b_p_ro = true; // must use "w!" now - return FAIL; + goto theend; } // Don't allow the autocommands to change the current buffer. // Try to re-open the file. @@ -663,7 +644,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, emsg(_("E201: *ReadPre autocommands must not change current buffer")); } curbuf->b_p_ro = true; // must use "w!" now - return FAIL; + goto theend; } } @@ -740,7 +721,7 @@ retry: if (read_buffer) { read_buf_lnum = 1; read_buf_col = 0; - } else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0) { + } else if (read_stdin || vim_lseek(fd, 0, SEEK_SET) != 0) { // Can't rewind the file, give up. error = true; goto failed; @@ -902,9 +883,9 @@ retry: // Use buffer >= 64K. Add linerest to double the size if the // line gets very long, to avoid a lot of copying. But don't // read more than 1 Mbyte at a time, so we can be interrupted. - size = 0x10000L + linerest; - if (size > 0x100000L) { - size = 0x100000L; + size = 0x10000 + linerest; + if (size > 0x100000) { + size = 0x100000; } } @@ -957,7 +938,7 @@ retry: if (conv_restlen > 0) { // Insert unconverted bytes from previous line. - memmove(ptr, conv_rest, (size_t)conv_restlen); // -V614 + memmove(ptr, conv_rest, (size_t)conv_restlen); ptr += conv_restlen; size -= conv_restlen; } @@ -969,11 +950,11 @@ retry: size = 0; } else { int ni; - long tlen = 0; - for (;;) { - p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; + int tlen = 0; + while (true) { + p = (uint8_t *)ml_get(read_buf_lnum) + read_buf_col; int n = (int)strlen((char *)p); - if ((int)tlen + n + 1 > size) { + if (tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done // below. @@ -1013,7 +994,8 @@ retry: } } else { // Read bytes from the file. - size = read_eintr(fd, ptr, (size_t)size); + size_t read_size = (size_t)size; + size = read_eintr(fd, ptr, read_size); } if (size <= 0) { @@ -1079,7 +1061,7 @@ retry: if (size < 2 || curbuf->b_p_bin) { ccname = NULL; } else { - ccname = check_for_bom(ptr, size, &blen, + ccname = check_for_bom(ptr, (int)size, &blen, fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc)); } if (ccname != NULL) { @@ -1168,7 +1150,7 @@ retry: } if (fio_flags != 0) { - unsigned int u8c; + unsigned u8c; char *dest; char *tail = NULL; @@ -1347,7 +1329,6 @@ retry: // Reading UTF-8: Check if the bytes are valid UTF-8. for (p = (uint8_t *)ptr;; p++) { int todo = (int)(((uint8_t *)ptr + size) - p); - int l; if (todo <= 0) { break; @@ -1357,7 +1338,7 @@ retry: // an incomplete character at the end though, the next // read() will get the next bytes, we'll check it // then. - l = utf_ptr2len_len((char *)p, todo); + int l = utf_ptr2len_len((char *)p, todo); if (l > todo && !incomplete_tail) { // Avoid retrying with a different encoding when // a truncated file is more likely, or attempting @@ -1552,7 +1533,7 @@ rewind_retry: if (try_unix && !read_stdin && (read_buffer - || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) { + || vim_lseek(fd, 0, SEEK_SET) == 0)) { fileformat = EOL_UNIX; if (set_options) { set_fileformat(EOL_UNIX, OPT_LOCAL); @@ -1711,50 +1692,51 @@ failed: } msg_scroll = msg_save; check_marks_read(); - return OK; // an interrupt isn't really an error + retval = OK; // an interrupt isn't really an error + goto theend; } if (!filtering && !(flags & READ_DUMMY) && !silent) { - add_quoted_fname(IObuff, IOSIZE, curbuf, (const char *)sfname); + add_quoted_fname(IObuff, IOSIZE, curbuf, sfname); c = false; #ifdef UNIX if (S_ISFIFO(perm)) { // fifo - STRCAT(IObuff, _("[fifo]")); + xstrlcat(IObuff, _("[fifo]"), IOSIZE); c = true; } if (S_ISSOCK(perm)) { // or socket - STRCAT(IObuff, _("[socket]")); + xstrlcat(IObuff, _("[socket]"), IOSIZE); c = true; } # ifdef OPEN_CHR_FILES if (S_ISCHR(perm)) { // or character special - STRCAT(IObuff, _("[character special]")); + xstrlcat(IObuff, _("[character special]"), IOSIZE); c = true; } # endif #endif if (curbuf->b_p_ro) { - STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")); + xstrlcat(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"), IOSIZE); c = true; } if (read_no_eol_lnum) { - msg_add_eol(); + xstrlcat(IObuff, _("[noeol]"), IOSIZE); c = true; } if (ff_error == EOL_DOS) { - STRCAT(IObuff, _("[CR missing]")); + xstrlcat(IObuff, _("[CR missing]"), IOSIZE); c = true; } if (split) { - STRCAT(IObuff, _("[long lines split]")); + xstrlcat(IObuff, _("[long lines split]"), IOSIZE); c = true; } if (notconverted) { - STRCAT(IObuff, _("[NOT converted]")); + xstrlcat(IObuff, _("[NOT converted]"), IOSIZE); c = true; } else if (converted) { - STRCAT(IObuff, _("[converted]")); + xstrlcat(IObuff, _("[converted]"), IOSIZE); c = true; } if (conv_error != 0) { @@ -1766,21 +1748,24 @@ failed: _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte); c = true; } else if (error) { - STRCAT(IObuff, _("[READ ERRORS]")); + xstrlcat(IObuff, _("[READ ERRORS]"), IOSIZE); c = true; } if (msg_add_fileformat(fileformat)) { c = true; } - msg_add_lines(c, (long)linecnt, filesize); + msg_add_lines(c, linecnt, filesize); XFREE_CLEAR(keep_msg); p = NULL; msg_scrolled_ign = true; if (!read_stdin && !read_buffer) { - p = (char_u *)msg_trunc_attr(IObuff, false, 0); + if (msg_col > 0) { + msg_putchar('\r'); // overwrite previous message + } + p = (uint8_t *)msg_trunc(IObuff, false, 0); } if (read_stdin || read_buffer || restart_edit != 0 @@ -1802,7 +1787,7 @@ failed: curbuf->b_p_ro = true; } - u_clearline(); // cannot use "U" command after adding lines + u_clearline(curbuf); // cannot use "U" command after adding lines // In Ex mode: cursor at last new line. // Otherwise: cursor at first new line. @@ -1811,7 +1796,7 @@ failed: } else { curwin->w_cursor.lnum = from + 1; } - check_cursor_lnum(); + check_cursor_lnum(curwin); beginline(BL_WHITE | BL_FIX); // on first non-blank if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { @@ -1841,7 +1826,7 @@ failed: // When opening a new file locate undo info and read it. if (read_undo_file) { - char_u hash[UNDO_HASH_SIZE]; + uint8_t hash[UNDO_HASH_SIZE]; sha256_finish(&sha_ctx, hash); u_read_undo(NULL, hash, fname); @@ -1884,10 +1869,18 @@ failed: } } - if (recoverymode && error) { - return FAIL; + if (!(recoverymode && error)) { + retval = OK; } - return OK; + +theend: + if (curbuf->b_ml.ml_mfp != NULL + && curbuf->b_ml.ml_mfp->mf_dirty == MF_DIRTY_YES_NOSYNC) { + // OK to sync the swap file now + curbuf->b_ml.ml_mfp->mf_dirty = MF_DIRTY_YES; + } + + return retval; } #ifdef OPEN_CHR_FILES @@ -1917,11 +1910,8 @@ bool is_dev_fd_file(char *fname) /// @param endp end of more bytes read static linenr_T readfile_linenr(linenr_T linecnt, char *p, const char *endp) { - char *s; - linenr_T lnum; - - lnum = curbuf->b_ml.ml_line_count - linecnt + 1; - for (s = p; s < endp; s++) { + linenr_T lnum = curbuf->b_ml.ml_line_count - linecnt + 1; + for (char *s = p; s < endp; s++) { if (*s == '\n') { lnum++; } @@ -1989,7 +1979,6 @@ void set_forced_fenc(exarg_T *eap) static char *next_fenc(char **pp, bool *alloced) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - char *p; char *r; *alloced = false; @@ -1997,12 +1986,12 @@ static char *next_fenc(char **pp, bool *alloced) *pp = NULL; return ""; } - p = vim_strchr(*pp, ','); + char *p = vim_strchr(*pp, ','); if (p == NULL) { r = enc_canonize(*pp); *pp += strlen(*pp); } else { - r = xstrnsave(*pp, (size_t)(p - *pp)); + r = xmemdupz(*pp, (size_t)(p - *pp)); *pp = p + 1; p = enc_canonize(r); xfree(r); @@ -2024,10 +2013,9 @@ static char *next_fenc(char **pp, bool *alloced) /// Returns NULL if the conversion failed ("*fdp" is not set) . static char *readfile_charconvert(char *fname, char *fenc, int *fdp) { - char *tmpname; char *errmsg = NULL; - tmpname = vim_tempname(); + char *tmpname = vim_tempname(); if (tmpname == NULL) { errmsg = _("Can't find temp file for conversion"); } else { @@ -2045,7 +2033,7 @@ static char *readfile_charconvert(char *fname, char *fenc, int *fdp) if (errmsg != NULL) { // Don't use emsg(), it breaks mappings, the retry with // another type of conversion might still work. - msg(errmsg); + msg(errmsg, 0); if (tmpname != NULL) { os_remove(tmpname); // delete converted file XFREE_CLEAR(tmpname); @@ -2074,1515 +2062,9 @@ static void check_marks_read(void) curbuf->b_marks_read = true; } -char *new_file_message(void) -{ - return shortmess(SHM_NEW) ? _("[New]") : _("[New File]"); -} - -/// buf_write() - write to file "fname" lines "start" through "end" -/// -/// We do our own buffering here because fwrite() is so slow. -/// -/// If "forceit" is true, we don't care for errors when attempting backups. -/// In case of an error everything possible is done to restore the original -/// file. But when "forceit" is true, we risk losing it. -/// -/// When "reset_changed" is true and "append" == false and "start" == 1 and -/// "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed. -/// -/// This function must NOT use NameBuff (because it's called by autowrite()). -/// -/// -/// @param eap for forced 'ff' and 'fenc', can be NULL! -/// @param append append to the file -/// -/// @return FAIL for failure, OK otherwise -int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T end, exarg_T *eap, - int append, int forceit, int reset_changed, int filtering) -{ - int fd; - char *backup = NULL; - int backup_copy = false; // copy the original file? - int dobackup; - char *ffname; - char *wfname = NULL; // name of file to write to - char *s; - char *ptr; - char c; - int len; - linenr_T lnum; - long nchars; -#define SET_ERRMSG_NUM(num, msg) \ - errnum = (num), errmsg = (msg), errmsgarg = 0 -#define SET_ERRMSG_ARG(msg, error) \ - errnum = NULL, errmsg = (msg), errmsgarg = error -#define SET_ERRMSG(msg) \ - errnum = NULL, errmsg = (msg), errmsgarg = 0 - const char *errnum = NULL; - char *errmsg = NULL; - int errmsgarg = 0; - bool errmsg_allocated = false; - char *buffer; - char smallbuf[SMBUFSIZE]; - int bufsize; - long perm; // file permissions - int retval = OK; - int newfile = false; // true if file doesn't exist yet - int msg_save = msg_scroll; - int overwriting; // true if writing over original - int no_eol = false; // no end-of-line written - int device = false; // writing to a device - int prev_got_int = got_int; - int checking_conversion; - bool file_readonly = false; // overwritten file is read-only - static char *err_readonly = - "is read-only (cannot override: \"W\" in 'cpoptions')"; -#if defined(UNIX) - int made_writable = false; // 'w' bit has been set -#endif - // writing everything - int whole = (start == 1 && end == buf->b_ml.ml_line_count); - linenr_T old_line_count = buf->b_ml.ml_line_count; - int fileformat; - int write_bin; - struct bw_info write_info; // info for buf_write_bytes() - int converted = false; - int notconverted = false; - char *fenc; // effective 'fileencoding' - char *fenc_tofree = NULL; // allocated "fenc" -#ifdef HAS_BW_FLAGS - int wb_flags = 0; -#endif -#ifdef HAVE_ACL - vim_acl_T acl = NULL; // ACL copied from original file to - // backup or new file -#endif - int write_undo_file = false; - context_sha256_T sha_ctx; - unsigned int bkc = get_bkc_value(buf); - const pos_T orig_start = buf->b_op_start; - const pos_T orig_end = buf->b_op_end; - - if (fname == NULL || *fname == NUL) { // safety check - return FAIL; - } - if (buf->b_ml.ml_mfp == NULL) { - // This can happen during startup when there is a stray "w" in the - // vimrc file. - emsg(_(e_emptybuf)); - return FAIL; - } - - // Disallow writing in secure mode. - if (check_secure()) { - return FAIL; - } - - // Avoid a crash for a long name. - if (strlen(fname) >= MAXPATHL) { - emsg(_(e_longname)); - return FAIL; - } - - // must init bw_conv_buf and bw_iconv_fd before jumping to "fail" - write_info.bw_conv_buf = NULL; - write_info.bw_conv_error = false; - write_info.bw_conv_error_lnum = 0; - write_info.bw_restlen = 0; - write_info.bw_iconv_fd = (iconv_t)-1; - - // After writing a file changedtick changes but we don't want to display - // the line. - ex_no_reprint = true; - - // If there is no file name yet, use the one for the written file. - // BF_NOTEDITED is set to reflect this (in case the write fails). - // Don't do this when the write is for a filter command. - // Don't do this when appending. - // Only do this when 'cpoptions' contains the 'F' flag. - if (buf->b_ffname == NULL - && reset_changed - && whole - && buf == curbuf - && !bt_nofilename(buf) - && !filtering - && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) - && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) { - if (set_rw_fname(fname, sfname) == FAIL) { - return FAIL; - } - buf = curbuf; // just in case autocmds made "buf" invalid - } - - if (sfname == NULL) { - sfname = fname; - } - - // For Unix: Use the short file name whenever possible. - // Avoids problems with networks and when directory names are changed. - // Don't do this for Windows, a "cd" in a sub-shell may have moved us to - // another directory, which we don't detect. - ffname = fname; // remember full fname -#ifdef UNIX - fname = sfname; -#endif - - if (buf->b_ffname != NULL && path_fnamecmp(ffname, buf->b_ffname) == 0) { - overwriting = true; - } else { - overwriting = false; - } - - no_wait_return++; // don't wait for return yet - - // Set '[ and '] marks to the lines to be written. - buf->b_op_start.lnum = start; - buf->b_op_start.col = 0; - buf->b_op_end.lnum = end; - buf->b_op_end.col = 0; - - { - aco_save_T aco; - int buf_ffname = false; - int buf_sfname = false; - int buf_fname_f = false; - int buf_fname_s = false; - int did_cmd = false; - int nofile_err = false; - int empty_memline = (buf->b_ml.ml_mfp == NULL); - bufref_T bufref; - - // Apply PRE autocommands. - // Set curbuf to the buffer to be written. - // Careful: The autocommands may call buf_write() recursively! - if (ffname == buf->b_ffname) { - buf_ffname = true; - } - if (sfname == buf->b_sfname) { - buf_sfname = true; - } - if (fname == buf->b_ffname) { - buf_fname_f = true; - } - if (fname == buf->b_sfname) { - buf_fname_s = true; - } - - // Set curwin/curbuf to buf and save a few things. - aucmd_prepbuf(&aco, buf); - set_bufref(&bufref, buf); - - if (append) { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, - sfname, sfname, false, curbuf, eap))) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEAPPENDPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else if (filtering) { - apply_autocmds_exarg(EVENT_FILTERWRITEPRE, - NULL, sfname, false, curbuf, eap); - } else if (reset_changed && whole) { - int was_changed = curbufIsChanged(); - - did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, - sfname, sfname, false, curbuf, eap); - if (did_cmd) { - if (was_changed && !curbufIsChanged()) { - // Written everything correctly and BufWriteCmd has reset - // 'modified': Correct the undo information so that an - // undo now sets 'modified'. - u_unchanged(curbuf); - u_update_save_nr(curbuf); - } - } else { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_BUFWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, - sfname, sfname, false, curbuf, eap))) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } - } - - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - - // In three situations we return here and don't write the file: - // 1. the autocommands deleted or unloaded the buffer. - // 2. The autocommands abort script processing. - // 3. If one of the "Cmd" autocommands was executed. - if (!bufref_valid(&bufref)) { - buf = NULL; - } - if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) - || did_cmd || nofile_err - || aborting()) { - if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) { - // restore the original '[ and '] positions - buf->b_op_start = orig_start; - buf->b_op_end = orig_end; - } - - no_wait_return--; - msg_scroll = msg_save; - if (nofile_err) { - semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt); - } - - if (nofile_err - || aborting()) { - // An aborting error, interrupt or exception in the - // autocommands. - return FAIL; - } - if (did_cmd) { - if (buf == NULL) { - // The buffer was deleted. We assume it was written - // (can't retry anyway). - return OK; - } - if (overwriting) { - // Assume the buffer was written, update the timestamp. - ml_timestamp(buf); - if (append) { - buf->b_flags &= ~BF_NEW; - } else { - buf->b_flags &= ~BF_WRITE_MASK; - } - } - if (reset_changed && buf->b_changed && !append - && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { - // Buffer still changed, the autocommands didn't work properly. - return FAIL; - } - return OK; - } - if (!aborting()) { - emsg(_("E203: Autocommands deleted or unloaded buffer to be written")); - } - return FAIL; - } - - |