diff options
Diffstat (limited to 'src/nvim/fileio.c')
-rw-r--r-- | src/nvim/fileio.c | 1138 |
1 files changed, 529 insertions, 609 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index d67cd36a85..0ee547d124 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -6,62 +6,72 @@ #include <assert.h> #include <errno.h> #include <fcntl.h> +#include <iconv.h> #include <inttypes.h> +#include <limits.h> #include <stdbool.h> +#include <stdio.h> #include <string.h> +#include <sys/stat.h> +#include <uv.h> -#include "nvim/api/private/helpers.h" +#include "auto/config.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/buffer_updates.h" #include "nvim/change.h" -#include "nvim/charset.h" #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" -#include "nvim/eval/typval.h" -#include "nvim/eval/userfunc.h" #include "nvim/ex_cmds.h" -#include "nvim/ex_docmd.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/getchar.h" -#include "nvim/hashtab.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/highlight_defs.h" #include "nvim/iconv.h" #include "nvim/input.h" +#include "nvim/log.h" +#include "nvim/macros.h" #include "nvim/mbyte.h" #include "nvim/memfile.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/move.h" -#include "nvim/normal.h" #include "nvim/option.h" #include "nvim/optionstr.h" +#include "nvim/os/fs_defs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -#include "nvim/os/os_defs.h" #include "nvim/os/time.h" -#include "nvim/os_unix.h" #include "nvim/path.h" -#include "nvim/quickfix.h" +#include "nvim/pos.h" #include "nvim/regexp.h" -#include "nvim/search.h" +#include "nvim/screen.h" #include "nvim/sha256.h" #include "nvim/shada.h" -#include "nvim/state.h" #include "nvim/strings.h" #include "nvim/types.h" #include "nvim/ui.h" -#include "nvim/ui_compositor.h" #include "nvim/undo.h" #include "nvim/vim.h" -#include "nvim/window.h" + +#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +# include <dirent.h> +# include <sys/file.h> +#endif + +#ifdef OPEN_CHR_FILES +# include "nvim/charset.h" +#endif #define BUFSIZE 8192 // size of normal write buffer #define SMBUFSIZE 256 // size of emergency write buffer @@ -72,27 +82,27 @@ #endif #define HAS_BW_FLAGS -#define FIO_LATIN1 0x01 // convert Latin1 -#define FIO_UTF8 0x02 // convert UTF-8 -#define FIO_UCS2 0x04 // convert UCS-2 -#define FIO_UCS4 0x08 // convert UCS-4 -#define FIO_UTF16 0x10 // convert UTF-16 -#define FIO_ENDIAN_L 0x80 // little endian -#define FIO_NOCONVERT 0x2000 // skip encoding conversion -#define FIO_UCSBOM 0x4000 // check for BOM at start of file -#define 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... */ +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. */ +// 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(). - */ +// Structure to pass arguments from buf_write() to buf_write_bytes(). struct bw_info { int bw_fd; // file descriptor char_u *bw_buf; // buffer with data to be written @@ -118,17 +128,19 @@ struct bw_info { #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"); -void filemess(buf_T *buf, char_u *name, char_u *s, int attr) +void filemess(buf_T *buf, char *name, char *s, int attr) { int msg_scroll_save; if (msg_silent != 0) { return; } - add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)name); + add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)name); // Avoid an over-long translation to cause trouble. - STRLCAT(IObuff, s, IOSIZE); + 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(). @@ -143,7 +155,7 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) msg_scroll = msg_scroll_save; msg_scrolled_ign = true; // may truncate the message to avoid a hit-return prompt - msg_outtrans_attr((char *)msg_may_trunc(false, IObuff), attr); + msg_outtrans_attr(msg_may_trunc(false, IObuff), attr); msg_clr_eos(); ui_flush(); msg_scrolled_ign = false; @@ -257,12 +269,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read - /* - * If there is no file name yet, use the one for the read file. - * BF_NOTEDITED is set to reflect this. - * Don't do this for a read from a filter. - * Only do this when 'cpoptions' contains the 'f' flag. - */ + // If there is no file name yet, use the one for the read file. + // BF_NOTEDITED is set to reflect this. + // Don't do this for a read from a filter. + // Only do this when 'cpoptions' contains the 'f' flag. if (curbuf->b_ffname == NULL && !filtering && fname != NULL @@ -350,11 +360,11 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } // If the name is too long we might crash further on, quit here. if (fname != NULL && *fname != NUL) { - size_t namelen = STRLEN(fname); + size_t namelen = strlen(fname); // If the name is too long we might crash further on, quit here. if (namelen >= MAXPATHL) { - filemess(curbuf, (char_u *)fname, (char_u *)_("Illegal file name"), 0); + filemess(curbuf, fname, _("Illegal file name"), 0); msg_end(); msg_scroll = msg_save; return FAIL; @@ -365,7 +375,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // swap file may destroy it! Reported on MS-DOS and Win 95. if (after_pathsep(fname, fname + namelen)) { if (!silent) { - filemess(curbuf, (char_u *)fname, (char_u *)_(msg_is_a_directory), 0); + filemess(curbuf, fname, _(msg_is_a_directory), 0); } msg_end(); msg_scroll = msg_save; @@ -387,10 +397,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, ) { if (S_ISDIR(perm)) { if (!silent) { - filemess(curbuf, (char_u *)fname, (char_u *)_(msg_is_a_directory), 0); + filemess(curbuf, fname, _(msg_is_a_directory), 0); } } else { - filemess(curbuf, (char_u *)fname, (char_u *)_("is not a file"), 0); + filemess(curbuf, fname, _("is not a file"), 0); } msg_end(); msg_scroll = msg_save; @@ -401,12 +411,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // Set default or forced 'fileformat' and 'binary'. set_file_options(set_options, eap); - /* - * When opening a new file we take the readonly flag from the file. - * Default is r/w, can be set to r/o below. - * Don't reset it when in readonly mode - * Only set/reset b_p_ro when BF_CHECK_RO is set. - */ + // When opening a new file we take the readonly flag from the file. + // Default is r/w, can be set to r/o below. + // Don't reset it when in readonly mode + // Only set/reset b_p_ro when BF_CHECK_RO is set. check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO)); if (check_readonly && !readonlymode) { curbuf->b_p_ro = false; @@ -419,17 +427,15 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_mtime_read = curbuf->b_mtime; curbuf->b_mtime_read_ns = curbuf->b_mtime_ns; #ifdef UNIX - /* - * Use the protection bits of the original file for the swap file. - * This makes it possible for others to read the name of the - * edited file from the swapfile, but only if they can read the - * edited file. - * Remove the "write" and "execute" bits for group and others - * (they must not write the swapfile). - * Add the "read" and "write" bits for the user, otherwise we may - * not be able to write to the file ourselves. - * Setting the bits is done below, after creating the swap file. - */ + // Use the protection bits of the original file for the swap file. + // This makes it possible for others to read the name of the + // edited file from the swapfile, but only if they can read the + // edited file. + // Remove the "write" and "execute" bits for group and others + // (they must not write the swapfile). + // Add the "read" and "write" bits for the user, otherwise we may + // not be able to write to the file ourselves. + // Setting the bits is done below, after creating the swap file. swap_mode = ((int)file_info.stat.st_mode & 0644) | 0600; #endif } else { @@ -482,10 +488,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } } if (!silent) { - if (dir_of_file_exists((char_u *)fname)) { - filemess(curbuf, (char_u *)sfname, (char_u *)new_file_message(), 0); + if (dir_of_file_exists(fname)) { + filemess(curbuf, sfname, new_file_message(), 0); } else { - filemess(curbuf, (char_u *)sfname, (char_u *)_("[New DIRECTORY]"), 0); + filemess(curbuf, sfname, _("[New DIRECTORY]"), 0); } } // Even though this is a new file, it might have been @@ -504,26 +510,23 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, return FAIL; } return OK; // a new file is not an error - } else { - filemess(curbuf, (char_u *)sfname, (char_u *)((fd == UV_EFBIG) ? _("[File too big]") : + } + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : #if defined(UNIX) && defined(EOVERFLOW) - // libuv only returns -errno - // in Unix and in Windows - // open() does not set - // EOVERFLOW - (fd == -EOVERFLOW) ? _("[File too big]") : + // libuv only returns -errno + // in Unix and in Windows + // open() does not set + // EOVERFLOW + (fd == -EOVERFLOW) ? _("[File too big]") : #endif - _("[Permission Denied]")), 0); - curbuf->b_p_ro = true; // must use "w!" now - } + _("[Permission Denied]")), 0); + curbuf->b_p_ro = true; // must use "w!" now return FAIL; } - /* - * Only set the 'ro' flag for readonly files the first time they are - * loaded. Help files always get readonly mode - */ + // Only set the 'ro' flag for readonly files the first time they are + // loaded. Help files always get readonly mode if ((check_readonly && file_readonly) || curbuf->b_help) { curbuf->b_p_ro = true; } @@ -532,6 +535,8 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // Don't change 'eol' if reading from buffer as it will already be // correctly set when reading stdin. if (!read_buffer) { + curbuf->b_p_eof = false; + curbuf->b_start_eof = false; curbuf->b_p_eol = true; curbuf->b_start_eol = true; } @@ -645,13 +650,11 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_p_ro = true; // must use "w!" now return FAIL; } - /* - * Don't allow the autocommands to change the current buffer. - * Try to re-open the file. - * - * Don't allow the autocommands to change the buffer name either - * (cd for example) if it invalidates fname or sfname. - */ + // Don't allow the autocommands to change the current buffer. + // Try to re-open the file. + // + // Don't allow the autocommands to change the buffer name either + // (cd for example) if it invalidates fname or sfname. if (!read_stdin && (curbuf != old_curbuf || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) || (using_b_fname && (old_b_fname != curbuf->b_fname)) @@ -673,16 +676,14 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!recoverymode && !filtering && !(flags & READ_DUMMY) && !silent) { if (!read_stdin && !read_buffer) { - filemess(curbuf, (char_u *)sfname, (char_u *)"", 0); + filemess(curbuf, sfname, "", 0); } } msg_scroll = false; // overwrite the file message - /* - * Set linecnt now, before the "retry" caused by a wrong guess for - * fileformat, and after the autocommands, which may change them. - */ + // Set linecnt now, before the "retry" caused by a wrong guess for + // fileformat, and after the autocommands, which may change them. linecnt = curbuf->b_ml.ml_line_count; // "++bad=" argument. @@ -695,9 +696,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, curbuf->b_bad_char = 0; } - /* - * Decide which 'encoding' to use or use first. - */ + // Decide which 'encoding' to use or use first. if (eap != NULL && eap->force_enc != 0) { fenc = enc_canonize(eap->cmd + eap->force_enc); fenc_alloced = true; @@ -719,28 +718,26 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, fenc_alloced = false; } else { fenc_next = p_fencs; // try items in 'fileencodings' - fenc = (char *)next_fenc(&fenc_next, &fenc_alloced); - } - - /* - * Jump back here to retry reading the file in different ways. - * Reasons to retry: - * - encoding conversion failed: try another one from "fenc_next" - * - BOM detected and fenc was set, need to setup conversion - * - "fileformat" check failed: try another - * - * Variables set for special retry actions: - * "file_rewind" Rewind the file to start reading it again. - * "advance_fenc" Advance "fenc" using "fenc_next". - * "skip_read" Re-use already read bytes (BOM detected). - * "did_iconv" iconv() conversion failed, try 'charconvert'. - * "keep_fileformat" Don't reset "fileformat". - * - * Other status indicators: - * "tmpname" When != NULL did conversion with 'charconvert'. - * Output file has to be deleted afterwards. - * "iconv_fd" When != -1 did conversion with iconv(). - */ + fenc = next_fenc(&fenc_next, &fenc_alloced); + } + + // Jump back here to retry reading the file in different ways. + // Reasons to retry: + // - encoding conversion failed: try another one from "fenc_next" + // - BOM detected and fenc was set, need to setup conversion + // - "fileformat" check failed: try another + // + // Variables set for special retry actions: + // "file_rewind" Rewind the file to start reading it again. + // "advance_fenc" Advance "fenc" using "fenc_next". + // "skip_read" Re-use already read bytes (BOM detected). + // "did_iconv" iconv() conversion failed, try 'charconvert'. + // "keep_fileformat" Don't reset "fileformat". + // + // Other status indicators: + // "tmpname" When != NULL did conversion with 'charconvert'. + // Output file has to be deleted afterwards. + // "iconv_fd" When != -1 did conversion with iconv(). retry: if (file_rewind) { @@ -764,10 +761,8 @@ retry: conv_error = 0; } - /* - * When retrying with another "fenc" and the first time "fileformat" - * will be reset. - */ + // When retrying with another "fenc" and the first time "fileformat" + // will be reset. if (keep_fileformat) { keep_fileformat = false; } else { @@ -793,9 +788,7 @@ retry: #endif if (advance_fenc) { - /* - * Try the next entry in 'fileencodings'. - */ + // Try the next entry in 'fileencodings'. advance_fenc = false; if (eap != NULL && eap->force_enc != 0) { @@ -813,7 +806,7 @@ retry: xfree(fenc); } if (fenc_next != NULL) { - fenc = (char *)next_fenc(&fenc_next, &fenc_alloced); + fenc = next_fenc(&fenc_next, &fenc_alloced); } else { fenc = ""; fenc_alloced = false; @@ -825,16 +818,14 @@ retry: } } - /* - * Conversion may be required when the encoding of the file is different - * from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4. - */ + // Conversion may be required when the encoding of the file is different + // from 'encoding' or 'encoding' is UTF-16, UCS-2 or UCS-4. fio_flags = 0; - converted = need_conversion((char_u *)fenc); + converted = need_conversion(fenc); if (converted) { // "ucs-bom" means we need to check the first bytes of the file // for a BOM. - if (STRCMP(fenc, ENC_UCSBOM) == 0) { + if (strcmp(fenc, ENC_UCSBOM) == 0) { fio_flags = FIO_UCSBOM; } else { // Check if UCS-2/4 or Latin1 to UTF-8 conversion needs to be @@ -855,10 +846,8 @@ retry: } #endif - /* - * Use the 'charconvert' expression when conversion is required - * and we can't do it internally or with iconv(). - */ + // Use the 'charconvert' expression when conversion is required + // and we can't do it internally or with iconv(). if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL && !read_fifo #ifdef HAVE_ICONV @@ -922,12 +911,10 @@ retry: } while (!error && !got_int) { - /* - * We allocate as much space for the file as we can get, plus - * space for the old line plus room for one terminating NUL. - * The amount is limited by the fact that read() only can read - * up to max_unsigned characters (and other things). - */ + // We allocate as much space for the file as we can get, plus + // space for the old line plus room for one terminating NUL. + // The amount is limited by the fact that read() only can read + // up to max_unsigned characters (and other things). { if (!skip_read) { // Use buffer >= 64K. Add linerest to double the size if the @@ -999,10 +986,8 @@ retry: } if (read_buffer) { - /* - * Read bytes from curbuf. Used for converting text read - * from stdin. - */ + // Read bytes from curbuf. Used for converting text read + // from stdin. if (read_buf_lnum > from) { size = 0; } else { @@ -1011,8 +996,8 @@ retry: tlen = 0; for (;;) { - p = ml_get(read_buf_lnum) + read_buf_col; - n = (int)STRLEN(p); + p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; + n = (int)strlen((char *)p); if ((int)tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done @@ -1052,9 +1037,7 @@ retry: } } } else { - /* - * Read bytes from the file. - */ + // Read bytes from the file. size = read_eintr(fd, ptr, (size_t)size); } @@ -1062,10 +1045,8 @@ retry: if (size < 0) { // read error error = true; } else if (conv_restlen > 0) { - /* - * Reached end-of-file but some trailing bytes could - * not be converted. Truncated file? - */ + // Reached end-of-file but some trailing bytes could + // not be converted. Truncated file? // When we did a conversion report an error. if (fio_flags != 0 @@ -1080,9 +1061,8 @@ retry: conv_error = curbuf->b_ml.ml_line_count - linecnt + 1; } - } - // Remember the first linenr with an illegal byte - else if (illegal_byte == 0) { + } else if (illegal_byte == 0) { + // Remember the first linenr with an illegal byte illegal_byte = curbuf->b_ml.ml_line_count - linecnt + 1; } @@ -1098,7 +1078,7 @@ retry: #ifdef HAVE_ICONV || iconv_fd != (iconv_t)-1 #endif - )) { + )) { // NOLINT(whitespace/parens) while (conv_restlen > 0) { *(--ptr) = (char)bad_char_behavior; conv_restlen--; @@ -1118,12 +1098,10 @@ retry: skip_read = false; - /* - * At start of file: Check for BOM. - * Also check for a BOM for other Unicode encodings, but not after - * converting with 'charconvert' or when a BOM has already been - * found. - */ + // At start of file: Check for BOM. + // Also check for a BOM for other Unicode encodings, but not after + // converting with 'charconvert' or when a BOM has already been + // found. if ((filesize == 0) && (fio_flags == FIO_UCSBOM || (!curbuf->b_p_bomb @@ -1172,9 +1150,7 @@ retry: ptr -= conv_restlen; size += conv_restlen; conv_restlen = 0; - /* - * Break here for a read error or end-of-file. - */ + // Break here for a read error or end-of-file. if (size <= 0) { break; } @@ -1188,11 +1164,9 @@ retry: char *top = ptr; size_t to_size = (size_t)(real_size - size); - /* - * If there is conversion error or not enough room try using - * another conversion. Except for when there is no - * alternative (help files). - */ + // If there is conversion error or not enough room try using + // another conversion. Except for when there is no + // alternative (help files). while ((iconv(iconv_fd, (void *)&fromp, &from_size, &top, &to_size) == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) @@ -1371,7 +1345,7 @@ retry: if (*--p < 0x80) { u8c = *p; } else { - len = utf_head_off((char_u *)ptr, p); + len = utf_head_off(ptr, (char *)p); p -= len; u8c = (unsigned)utf_ptr2char((char *)p); if (len == 0) { @@ -1493,9 +1467,7 @@ rewind_retry: // count the number of characters (after conversion!) filesize += size; - /* - * when reading the first part of a file: guess EOL type - */ + // when reading the first part of a file: guess EOL type if (fileformat == EOL_UNKNOWN) { // First try finding a NL, for Dos and Unix if (try_dos || try_unix) { @@ -1560,10 +1532,8 @@ rewind_retry: } } - /* - * This loop is executed once for every character read. - * Keep it fast! - */ + // This loop is executed once for every character read. + // Keep it fast! if (fileformat == EOL_MAC) { ptr--; while (++ptr, --size >= 0) { @@ -1665,18 +1635,28 @@ failed: error = false; } - /* - * If we get EOF in the middle of a line, note the fact and - * complete the line ourselves. - * In Dos format ignore a trailing CTRL-Z, unless 'binary' set. - */ + // In Dos format ignore a trailing CTRL-Z, unless 'binary' is set. + // In old days the file length was in sector count and the CTRL-Z the + // marker where the file really ended. Assuming we write it to a file + // system that keeps file length properly the CTRL-Z should be dropped. + // Set the 'endoffile' option so the user can decide what to write later. + // In Unix format the CTRL-Z is just another character. + if (linerest != 0 + && !curbuf->b_p_bin + && fileformat == EOL_DOS + && ptr[-1] == Ctrl_Z) { + ptr--; + linerest--; + if (set_options) { + curbuf->b_p_eof = true; + } + } + + // If we get EOF in the middle of a line, note the fact and + // complete the line ourselves. if (!error && !got_int - && linerest != 0 - && !(!curbuf->b_p_bin - && fileformat == EOL_DOS - && *line_start == Ctrl_Z - && ptr == line_start + 1)) { + && linerest != 0) { // remember for when writing if (set_options) { curbuf->b_p_eol = false; @@ -1719,7 +1699,7 @@ failed: if (read_stdin) { close(fd); if (stdin_fd < 0) { -#ifndef WIN32 +#ifndef MSWIN // On Unix, use stderr for stdin, makes shell commands work. vim_ignored = dup(2); #else @@ -1727,7 +1707,7 @@ failed: HANDLE conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, 0, (HANDLE)NULL); - vim_ignored = _open_osfhandle(conin, _O_RDONLY); + vim_ignored = _open_osfhandle((intptr_t)conin, _O_RDONLY); #endif } } @@ -1738,9 +1718,7 @@ failed: } no_wait_return--; // may wait for return now - /* - * In recovery mode everything but autocommands is skipped. - */ + // In recovery mode everything but autocommands is skipped. if (!recoverymode) { // need to delete the last line, which comes from the empty buffer if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY)) { @@ -1767,18 +1745,9 @@ failed: appended_lines_mark(from, linecnt); } - /* - * If we were reading from the same terminal as where messages go, - * the screen will have been messed up. - * Switch on raw mode now and clear the screen. - */ - if (read_stdin) { - screenclear(); - } - if (got_int) { if (!(flags & READ_DUMMY)) { - filemess(curbuf, (char_u *)sfname, (char_u *)_(e_interr), 0); + filemess(curbuf, sfname, _(e_interr), 0); if (newfile) { curbuf->b_p_ro = true; // must use "w!" now } @@ -1789,7 +1758,7 @@ failed: } if (!filtering && !(flags & READ_DUMMY) && !silent) { - add_quoted_fname((char *)IObuff, IOSIZE, curbuf, (const char *)sfname); + add_quoted_fname(IObuff, IOSIZE, curbuf, (const char *)sfname); c = false; #ifdef UNIX @@ -1832,12 +1801,12 @@ failed: c = true; } if (conv_error != 0) { - sprintf((char *)IObuff + STRLEN(IObuff), - _("[CONVERSION ERROR in line %" PRId64 "]"), (int64_t)conv_error); + snprintf(IObuff + strlen(IObuff), IOSIZE - strlen(IObuff), + _("[CONVERSION ERROR in line %" PRId64 "]"), (int64_t)conv_error); c = true; } else if (illegal_byte > 0) { - sprintf((char *)IObuff + STRLEN(IObuff), - _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte); + snprintf(IObuff + strlen(IObuff), IOSIZE - strlen(IObuff), + _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte); c = true; } else if (error) { STRCAT(IObuff, _("[READ ERRORS]")); @@ -1854,7 +1823,7 @@ failed: msg_scrolled_ign = true; if (!read_stdin && !read_buffer) { - p = (char_u *)msg_trunc_attr((char *)IObuff, false, 0); + p = (char_u *)msg_trunc_attr(IObuff, false, 0); } if (read_stdin || read_buffer || restart_edit != 0 @@ -1878,10 +1847,8 @@ failed: u_clearline(); // cannot use "U" command after adding lines - /* - * In Ex mode: cursor at last new line. - * Otherwise: cursor at first new line. - */ + // In Ex mode: cursor at last new line. + // Otherwise: cursor at first new line. if (exmode_active) { curwin->w_cursor.lnum = from + linecnt; } else { @@ -1900,17 +1867,13 @@ failed: } msg_scroll = msg_save; - /* - * Get the marks before executing autocommands, so they can be used there. - */ + // Get the marks before executing autocommands, so they can be used there. check_marks_read(); - /* - * We remember if the last line of the read didn't have - * an eol even when 'binary' is off, to support turning 'fixeol' off, - * or writing the read again with 'binary' on. The latter is required - * for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work. - */ + // We remember if the last line of the read didn't have + // an eol even when 'binary' is off, to support turning 'fixeol' off, + // or writing the read again with 'binary' on. The latter is required + // for ":autocmd FileReadPost *.gz set bin|'[,']!gunzip" to work. curbuf->b_no_eol_lnum = read_no_eol_lnum; // When reloading a buffer put the cursor at the first line that is @@ -1919,9 +1882,7 @@ failed: u_find_first_changed(); } - /* - * When opening a new file locate undo info and read it. - */ + // When opening a new file locate undo info and read it. if (read_undo_file) { char_u hash[UNDO_HASH_SIZE]; @@ -1939,11 +1900,9 @@ failed: save_file_ff(curbuf); } - /* - * The output from the autocommands should not overwrite anything and - * should not be overwritten: Set msg_scroll, restore its value if no - * output was done. - */ + // The output from the autocommands should not overwrite anything and + // should not be overwritten: Set msg_scroll, restore its value if no + // output was done. msg_scroll = true; if (filtering) { apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname, @@ -1984,7 +1943,7 @@ failed: bool is_dev_fd_file(char *fname) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - return STRNCMP(fname, "/dev/fd/", 8) == 0 + return strncmp(fname, "/dev/fd/", 8) == 0 && ascii_isdigit((uint8_t)fname[8]) && *skipdigits(fname + 9) == NUL && (fname[9] != NUL @@ -1999,7 +1958,7 @@ bool is_dev_fd_file(char *fname) /// @param linecnt line count before reading more bytes /// @param p start of more bytes read /// @param endp end of more bytes read -static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp) +static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, const char_u *endp) { char_u *s; linenr_T lnum; @@ -2018,7 +1977,7 @@ static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp) void prep_exarg(exarg_T *eap, const buf_T *buf) FUNC_ATTR_NONNULL_ALL { - const size_t cmd_len = 15 + STRLEN(buf->b_p_fenc); + const size_t cmd_len = 15 + strlen(buf->b_p_fenc); eap->cmd = xmalloc(cmd_len); snprintf(eap->cmd, cmd_len, "e ++enc=%s", buf->b_p_fenc); @@ -2055,11 +2014,13 @@ void set_file_options(int set_options, exarg_T *eap) /// Set forced 'fileencoding'. void set_forced_fenc(exarg_T *eap) { - if (eap->force_enc != 0) { - char *fenc = enc_canonize(eap->cmd + eap->force_enc); - set_string_option_direct("fenc", -1, fenc, OPT_FREE|OPT_LOCAL, 0); - xfree(fenc); + if (eap->force_enc == 0) { + return; } + + char *fenc = enc_canonize(eap->cmd + eap->force_enc); + set_string_option_direct("fenc", -1, fenc, OPT_FREE|OPT_LOCAL, 0); + xfree(fenc); } /// Find next fileencoding to use from 'fileencodings'. @@ -2068,25 +2029,25 @@ void set_forced_fenc(exarg_T *eap) /// NULL. /// When *pp is not set to NULL, the result is in allocated memory and "alloced" /// is set to true. -static char_u *next_fenc(char **pp, bool *alloced) +static char *next_fenc(char **pp, bool *alloced) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - char_u *p; - char_u *r; + char *p; + char *r; *alloced = false; if (**pp == NUL) { *pp = NULL; - return (char_u *)""; + return ""; } - p = (char_u *)vim_strchr((*pp), ','); + p = vim_strchr((*pp), ','); if (p == NULL) { - r = (char_u *)enc_canonize(*pp); - *pp += STRLEN(*pp); + r = enc_canonize(*pp); + *pp += strlen(*pp); } else { - r = vim_strnsave((char_u *)(*pp), (size_t)(p - (char_u *)(*pp))); - *pp = (char *)p + 1; - p = (char_u *)enc_canonize((char *)r); + r = xstrnsave(*pp, (size_t)(p - *pp)); + *pp = p + 1; + p = enc_canonize(r); xfree(r); r = p; } @@ -2109,7 +2070,7 @@ static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp) char_u *tmpname; char *errmsg = NULL; - tmpname = vim_tempname(); + tmpname = (char_u *)vim_tempname(); if (tmpname == NULL) { errmsg = _("Can't find temp file for conversion"); } else { @@ -2151,8 +2112,8 @@ static void check_marks_read(void) shada_read_marks(); } - /* Always set b_marks_read; needed when 'shada' is changed to include - * the ' parameter after opening a buffer. */ + // Always set b_marks_read; needed when 'shada' is changed to include + // the ' parameter after opening a buffer. curbuf->b_marks_read = true; } @@ -2237,8 +2198,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en int wb_flags = 0; #endif #ifdef HAVE_ACL - vim_acl_T acl = NULL; /* ACL copied from original file to - backup or new file */ + 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; @@ -2250,22 +2211,19 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en return FAIL; } if (buf->b_ml.ml_mfp == NULL) { - /* This can happen during startup when there is a stray "w" in the - * vimrc file. */ + // This can happen during startup when there is a stray "w" in the + // vimrc file. emsg(_(e_emptybuf)); return FAIL; } - /* - * Disallow writing from .exrc and .vimrc in current directory for - * security reasons. - */ + // Disallow writing in secure mode. if (check_secure()) { return FAIL; } // Avoid a crash for a long name. - if (STRLEN(fname) >= MAXPATHL) { + if (strlen(fname) >= MAXPATHL) { emsg(_(e_longname)); return FAIL; } @@ -2279,17 +2237,15 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en write_info.bw_iconv_fd = (iconv_t)-1; #endif - /* After writing a file changedtick changes but we don't want to display - * the line. */ + // 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 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 @@ -2317,7 +2273,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en fname = sfname; #endif - if (buf->b_ffname != NULL && FNAMECMP(ffname, buf->b_ffname) == 0) { + if (buf->b_ffname != NULL && path_fnamecmp(ffname, buf->b_ffname) == 0) { overwriting = true; } else { overwriting = false; @@ -2325,9 +2281,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en no_wait_return++; // don't wait for return yet - /* - * Set '[ and '] marks to the lines to be written. - */ + // 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; @@ -2344,11 +2298,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en 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! - */ + // 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; } @@ -2386,9 +2338,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en 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'. */ + // 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); } @@ -2434,19 +2386,19 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en no_wait_return--; msg_scroll = msg_save; if (nofile_err) { - emsg(_("E676: No matching autocommands for acwrite buffer")); + 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. */ + // 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). */ + // The buffer was deleted. We assume it was written + // (can't retry anyway). return OK; } if (overwriting) { @@ -2471,12 +2423,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en return FAIL; } - /* - * The autocommands may have changed the number of lines in the file. - * When writing the whole file, adjust the end. - * When writing part of the file, assume that the autocommands only - * changed the number of lines that are to be written (tricky!). - */ + // The autocommands may have changed the number of lines in the file. + // When writing the whole file, adjust the end. + // When writing part of the file, assume that the autocommands only + // changed the number of lines that are to be written (tricky!). if (buf->b_ml.ml_line_count != old_line_count) { if (whole) { // write all end = buf->b_ml.ml_line_count; @@ -2493,10 +2443,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } } - /* - * The autocommands may have changed the name of the buffer, which may - * be kept in fname, ffname and sfname. - */ + // The autocommands may have changed the name of the buffer, which may + // be kept in fname, ffname and sfname. if (buf_ffname) { ffname = buf->b_ffname; } @@ -2527,9 +2475,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #ifndef UNIX (char_u *)sfname, #else - (char_u *)fname, + fname, #endif - (char_u *)"", 0); // show that we are busy + "", 0); // show that we are busy } msg_scroll = false; // always overwrite the file message now @@ -2543,9 +2491,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bufsize = BUFSIZE; } - /* - * Get information about original file (if there is one). - */ + // Get information about original file (if there is one). FileInfo file_info_old; #if defined(UNIX) perm = -1; @@ -2562,8 +2508,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en SET_ERRMSG_NUM("E503", _("is not a file or writable device")); goto fail; } - /* It's a device of some kind (or a fifo) which we can write to - * but for which we can't make a backup. */ + // It's a device of some kind (or a fifo) which we can write to + // but for which we can't make a backup. device = true; newfile = true; perm = -1; @@ -2595,10 +2541,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #endif // !UNIX if (!device && !newfile) { - /* - * Check if the file is really writable (when renaming the file to - * make a backup we won't discover it later). - */ + // Check if the file is really writable (when renaming the file to + // make a backup we won't discover it later). file_readonly = !os_file_is_writable(fname); if (!forceit && file_readonly) { @@ -2610,10 +2554,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en goto fail; } - /* - * Check if the timestamp hasn't changed since reading the file. - */ - if (overwriting) { + // If 'forceit' is false, check if the timestamp hasn't changed since reading the file. + if (overwriting && !forceit) { retval = check_mtime(buf, &file_info_old); if (retval == FAIL) { goto fail; @@ -2622,41 +2564,33 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } #ifdef HAVE_ACL - /* - * For systems that support ACL: get the ACL from the original file. - */ + // For systems that support ACL: get the ACL from the original file. if (!newfile) { - acl = mch_get_acl((char_u *)fname); + acl = os_get_acl((char_u *)fname); } #endif - /* - * If 'backupskip' is not empty, don't make a backup for some files. - */ + // If 'backupskip' is not empty, don't make a backup for some files. dobackup = (p_wb || p_bk || *p_pm != NUL); if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, (char_u *)sfname, (char_u *)ffname)) { dobackup = false; } - /* - * Save the value of got_int and reset it. We don't want a previous - * interruption cancel writing, only hitting CTRL-C while writing should - * abort it. - */ + // Save the value of got_int and reset it. We don't want a previous + // interruption cancel writing, only hitting CTRL-C while writing should + // abort it. prev_got_int = got_int; got_int = false; // Mark the buffer as 'being saved' to prevent changed buffer warnings buf->b_saving = true; - /* - * If we are not appending or filtering, the file exists, and the - * 'writebackup', 'backup' or 'patchmode' option is set, need a backup. - * When 'patchmode' is set also make a backup when appending. - * - * Do not make any backup, if 'writebackup' and 'backup' are both switched - * off. This helps when editing large files on almost-full disks. - */ + // If we are not appending or filtering, the file exists, and the + // 'writebackup', 'backup' or 'patchmode' option is set, need a backup. + // When 'patchmode' is set also make a backup when appending. + // + // Do not make any backup, if 'writebackup' and 'backup' are both switched + // off. This helps when editing large files on almost-full disks. if (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) { FileInfo file_info; const bool no_prepend_dot = false; @@ -2666,57 +2600,51 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } else if ((bkc & BKC_AUTO)) { // "auto" int i; - /* - * Don't rename the file when: - * - it's a hard link - * - it's a symbolic link - * - we don't have write permission in the directory - */ + // Don't rename the file when: + // - it's a hard link + // - it's a symbolic link + // - we don't have write permission in the directory if (os_fileinfo_hardlinks(&file_info_old) > 1 || !os_fileinfo_link(fname, &file_info) || !os_fileinfo_id_equal(&file_info, &file_info_old)) { backup_copy = true; } else { - /* - * Check if we can create a file and set the owner/group to - * the ones from the original file. - * First find a file name that doesn't exist yet (use some - * arbitrary numbers). - */ + // Check if we can create a file and set the owner/group to + // the ones from the original file. + // First find a file name that doesn't exist yet (use some + // arbitrary numbers). STRCPY(IObuff, fname); for (i = 4913;; i += 123) { - char *tail = path_tail((char *)IObuff); - size_t size = (size_t)((char_u *)tail - IObuff); + char *tail = path_tail(IObuff); + size_t size = (size_t)(tail - IObuff); snprintf(tail, IOSIZE - size, "%d", i); - if (!os_fileinfo_link((char *)IObuff, &file_info)) { + if (!os_fileinfo_link(IObuff, &file_info)) { break; } } - fd = os_open((char *)IObuff, + fd = os_open(IObuff, O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, (int)perm); if (fd < 0) { // can't write in directory backup_copy = true; } else { #ifdef UNIX os_fchown(fd, (uv_uid_t)file_info_old.stat.st_uid, (uv_gid_t)file_info_old.stat.st_gid); - if (!os_fileinfo((char *)IObuff, &file_info) + if (!os_fileinfo(IObuff, &file_info) || file_info.stat.st_uid != file_info_old.stat.st_uid || file_info.stat.st_gid != file_info_old.stat.st_gid || (long)file_info.stat.st_mode != perm) { backup_copy = true; } #endif - /* Close the file before removing it, on MS-Windows we - * can't delete an open file. */ + // Close the file before removing it, on MS-Windows we + // can't delete an open file. close(fd); - os_remove((char *)IObuff); + os_remove(IObuff); } } } - /* - * Break symlinks and/or hardlinks if we've been asked to. - */ + // Break symlinks and/or hardlinks if we've been asked to. if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK)) { #ifdef UNIX bool file_info_link_ok = os_fileinfo_link(fname, &file_info); @@ -2752,33 +2680,29 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en char *rootname; char *p; - /* - * Try to make the backup in each directory in the 'bdir' option. - * - * Unix semantics has it, that we may have a writable file, - * that cannot be recreated with a simple open(..., O_CREAT, ) e.g: - * - the directory is not writable, - * - the file may be a symbolic link, - * - the file may belong to another user/group, etc. - * - * For these reasons, the existing writable file must be truncated - * and reused. Creation of a backup COPY will be attempted. - */ + // Try to make the backup in each directory in the 'bdir' option. + // + // Unix semantics has it, that we may have a writable file, + // that cannot be recreated with a simple open(..., O_CREAT, ) e.g: + // - the directory is not writable, + // - the file may be a symbolic link, + // - the file may belong to another user/group, etc. + // + // For these reasons, the existing writable file must be truncated + // and reused. Creation of a backup COPY will be attempted. dirp = p_bdir; while (*dirp) { - /* - * Isolate one directory name, using an entry in 'bdir'. - */ - size_t dir_len = copy_option_part(&dirp, (char *)IObuff, IOSIZE, ","); - p = (char *)IObuff + dir_len; - bool trailing_pathseps = after_pathsep((char *)IObuff, p) && p[-1] == p[-2]; + // Isolate one directory name, using an entry in 'bdir'. + size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); + p = IObuff + dir_len; + bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; } - if (*dirp == NUL && !os_isdir((char *)IObuff)) { + if (*dirp == NUL && !os_isdir(IObuff)) { int ret; char *failed_dir; - if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) { + if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir)) != 0) { semsg(_("E303: Unable to create directory \"%s\" for backup file: %s"), failed_dir, os_strerror(ret)); xfree(failed_dir); @@ -2786,14 +2710,14 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } if (trailing_pathseps) { // Ends with '//', Use Full path - if ((p = make_percent_swname((char *)IObuff, fname)) + if ((p = make_percent_swname(IObuff, fname)) != NULL) { backup = modname(p, backup_ext, no_prepend_dot); xfree(p); } } - rootname = (char *)get_file_in_dir((char_u *)fname, IObuff); + rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { some_error = true; // out of memory goto nobackup; @@ -2814,9 +2738,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en goto nobackup; } - /* - * Check if backup file already exists. - */ + // Check if backup file already exists. if (os_fileinfo(backup, &file_info_new)) { if (os_fileinfo_id_equal(&file_info_new, &file_info_old)) { // @@ -2831,7 +2753,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // delete an existing one, and try to use another name instead. // Change one character, just before the extension. // - wp = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); + wp = backup + strlen(backup) - 1 - strlen(backup_ext); if (wp < backup) { // empty file name ??? wp = backup; } @@ -2848,9 +2770,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } xfree(rootname); - /* - * Try to create the backup file - */ + // Try to create the backup file if (backup != NULL) { // remove old backup, if present os_remove(backup); @@ -2873,10 +2793,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #endif // copy the file - if (os_copy(fname, backup, UV_FS_COPYFILE_FICLONE) - != 0) { - SET_ERRMSG(_("E506: Can't write to backup file " - "(add ! to override)")); + if (os_copy(fname, backup, UV_FS_COPYFILE_FICLONE) != 0) { + SET_ERRMSG(_("E509: Cannot create backup file (add ! to override)")); + XFREE_CLEAR(backup); + backup = NULL; + continue; } #ifdef UNIX @@ -2885,8 +2806,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en (double)file_info_old.stat.st_mtim.tv_sec); #endif #ifdef HAVE_ACL - mch_set_acl((char_u *)backup, acl); + os_set_acl((char_u *)backup, acl); #endif + SET_ERRMSG(NULL); break; } } @@ -2906,40 +2828,32 @@ nobackup: char *p; char *rootname; - /* - * Make a backup by renaming the original file. - */ - /* - * If 'cpoptions' includes the "W" flag, we don't want to - * overwrite a read-only file. But rename may be possible - * anyway, thus we need an extra check here. - */ + // Make a backup by renaming the original file. + + // If 'cpoptions' includes the "W" flag, we don't want to + // overwrite a read-only file. But rename may be possible + // anyway, thus we need an extra check here. if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) { SET_ERRMSG_NUM("E504", _(err_readonly)); goto fail; } - /* - * - * Form the backup file name - change path/fo.o.h to - * path/fo.o.h.bak Try all directories in 'backupdir', first one - * that works is used. - */ + // Form the backup file name - change path/fo.o.h to + // path/fo.o.h.bak Try all directories in 'backupdir', first one + // that works is used. dirp = p_bdir; while (*dirp) { - /* - * Isolate one directory name and make the backup file name. - */ - size_t dir_len = copy_option_part(&dirp, (char *)IObuff, IOSIZE, ","); - p = (char *)IObuff + dir_len; - bool trailing_pathseps = after_pathsep((char *)IObuff, p) && p[-1] == p[-2]; + // Isolate one directory name and make the backup file name. + size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); + p = IObuff + dir_len; + bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; } - if (*dirp == NUL && !os_isdir((char *)IObuff)) { + if (*dirp == NUL && !os_isdir(IObuff)) { int ret; char *failed_dir; - if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) { + if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir)) != 0) { semsg(_("E303: Unable to create directory \"%s\" for backup file: %s"), failed_dir, os_strerror(ret)); xfree(failed_dir); @@ -2947,7 +2861,7 @@ nobackup: } if (trailing_pathseps) { // path ends with '//', use full path - if ((p = make_percent_swname((char *)IObuff, fname)) + if ((p = make_percent_swname(IObuff, fname)) != NULL) { backup = modname(p, backup_ext, no_prepend_dot); xfree(p); @@ -2955,7 +2869,7 @@ nobackup: } if (backup == NULL) { - rootname = (char *)get_file_in_dir((char_u *)fname, IObuff); + rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { backup = NULL; } else { @@ -2965,18 +2879,16 @@ nobackup: } if (backup != NULL) { - /* - * If we are not going to keep the backup file, don't - * delete an existing one, try to use another name. - * Change one character, just before the extension. - */ - if (!p_bk && os_path_exists((char_u *)backup)) { - p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext); + // If we are not going to keep the backup file, don't + // delete an existing one, try to use another name. + // Change one character, just before the extension. + if (!p_bk && os_path_exists(backup)) { + p = backup + strlen(backup) - 1 - strlen(backup_ext); if (p < backup) { // empty file name ??? p = backup; } *p = 'z'; - while (*p > 'a' && os_path_exists((char_u *)backup)) { + while (*p > 'a' && os_path_exists(backup)) { (*p)--; } // They all exist??? Must be something wrong! @@ -2994,7 +2906,7 @@ nobackup: // If the renaming of the original file to the backup file // works, quit here. /// - if (vim_rename((char_u *)fname, (char_u *)backup) == 0) { + if (vim_rename(fname, backup) == 0) { break; } @@ -3062,7 +2974,7 @@ nobackup: } // Check if the file needs to be converted. - converted = need_conversion((char_u *)fenc); + converted = need_conversion(fenc); // Check if UTF-8 to UCS-2/4 or Latin1 conversion needs to be done. Or // Latin1 to Unicode conversion. This is handled in buf_write_bytes(). @@ -3099,13 +3011,11 @@ nobackup: } else { #endif - /* - * When the file needs to be converted with 'charconvert' after - * writing, write to a temp file instead and let the conversion - * overwrite the original file. - */ + // When the file needs to be converted with 'charconvert' after + // writing, write to a temp file instead and let the conversion + // overwrite the original file. if (*p_ccv != NUL) { - wfname = (char *)vim_tempname(); + wfname = vim_tempname(); if (wfname == NULL) { // Can't write without a tempfile! SET_ERRMSG(_("E214: Can't find temp file for writing")); goto restore_backup; @@ -3156,9 +3066,11 @@ nobackup: // false. while ((fd = os_open(wfname, O_WRONLY | - (append ? - (forceit ? (O_APPEND | O_CREAT) : O_APPEND) - : (O_CREAT | O_TRUNC)), + (append + ? (forceit + ? (O_APPEND | O_CREAT) + : O_APPEND) + : (O_CREAT | O_TRUNC)), perm < 0 ? 0666 : (perm & 0777))) < 0) { // A forced write will try to create a new file if the old one // is still readonly. This may also happen when the directory @@ -3211,21 +3123,21 @@ restore_backup: // This may not work if the vim_rename() fails. // In that case we leave the copy around. // If file does not exist, put the copy in its place - if (!os_path_exists((char_u *)fname)) { - vim_rename((char_u *)backup, (char_u *)fname); + if (!os_path_exists(fname)) { + vim_rename(backup, fname); } // if original file does exist throw away the copy - if (os_path_exists((char_u *)fname)) { + if (os_path_exists(fname)) { os_remove(backup); } } else { // try to put the original file back - vim_rename((char_u *)backup, (char_u *)fname); + vim_rename(backup, fname); } } // if original file no longer exists give an extra warning - if (!newfile && !os_path_exists((char_u *)fname)) { + if (!newfile && !os_path_exists(fname)) { end = 0; } } @@ -3282,9 +3194,9 @@ restore_backup: for (lnum = start; lnum <= end; lnum++) { // The next while loop is done once for each character written. // Keep it fast! - ptr = (char *)ml_get_buf(buf, lnum, false) - 1; + ptr = ml_get_buf(buf, lnum, false) - 1; if (write_undo_file) { - sha256_update(&sha_ctx, (char_u *)ptr + 1, (uint32_t)(STRLEN(ptr + 1) + 1)); + sha256_update(&sha_ctx, (char_u *)ptr + 1, (uint32_t)(strlen(ptr + 1) + 1)); } while ((c = *++ptr) != NUL) { if (c == NL) { @@ -3358,6 +3270,11 @@ restore_backup: nchars += len; } + if (!buf->b_p_fixeol && buf->b_p_eof) { + // write trailing CTRL-Z + (void)write_eintr(write_info.bw_fd, "\x1a", 1); + } + // Stop when writing done or an error was encountered. if (!checking_conversion || end == 0) { break; @@ -3425,7 +3342,7 @@ restore_backup: // Probably need to set the ACL before changing the user (can't set the // ACL on a file the user doesn't own). if (!backup_copy) { - mch_set_acl((char_u *)wfname, acl); + os_set_acl((char_u *)wfname, acl); } #endif @@ -3453,7 +3370,7 @@ restore_backup: } else { errmsg_allocated = true; SET_ERRMSG(xmalloc(300)); - vim_snprintf(errmsg, 300, + vim_snprintf(errmsg, 300, // NOLINT(runtime/printf) _("E513: write error, conversion failed in line %" PRIdLINENR " (make 'fenc' empty to override)"), write_info.bw_conv_error_lnum); @@ -3487,7 +3404,7 @@ restore_backup: end = 1; // success } } else { - if (vim_rename((char_u *)backup, (char_u *)fname) == 0) { + if (vim_rename(backup, fname) == 0) { end = 1; } } @@ -3502,13 +3419,13 @@ restore_backup: fname = sfname; // use shortname now, for the messages #endif if (!filtering) { - add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname); + add_quoted_fname(IObuff, IOSIZE, buf, (const char *)fname); c = false; if (write_info.bw_conv_error) { STRCAT(IObuff, _(" CONVERSION ERROR")); c = true; if (write_info.bw_conv_error_lnum != 0) { - vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %" PRId64 ";"), + vim_snprintf_add(IObuff, IOSIZE, _(" in line %" PRId64 ";"), (int64_t)write_info.bw_conv_error_lnum); } } else if (notconverted) { @@ -3542,11 +3459,11 @@ restore_backup: } } - set_keep_msg(msg_trunc_attr((char *)IObuff, false, 0), 0); + set_keep_msg(msg_trunc_attr(IObuff, false, 0), 0); } - /* When written everything correctly: reset 'modified'. Unless not - * writing to the original file and '+' is not in 'cpoptions'. */ + // When written everything correctly: reset 'modified'. Unless not + // writing to the original file and '+' is not in 'cpoptions'. if (reset_changed && whole && !append && !write_info.bw_conv_error && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { @@ -3561,10 +3478,8 @@ restore_backup: u_update_save_nr(buf); } - /* - * If written to the current file, update the timestamp of the swap file - * and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime. - */ + // If written to the current file, update the timestamp of the swap file + // and reset the BF_WRITE_MASK flags. Also sets buf->b_mtime. if (overwriting) { ml_timestamp(buf); if (append) { @@ -3574,22 +3489,18 @@ restore_backup: } } - /* - * If we kept a backup until now, and we are in patch mode, then we make - * the backup file our 'original' file. - */ + // If we kept a backup until now, and we are in patch mode, then we make + // the backup file our 'original' file. if (*p_pm && dobackup) { char *const org = modname(fname, p_pm, false); if (backup != NULL) { - /* - * If the original file does not exist yet - * the current backup file becomes the original file - */ + // If the original file does not exist yet + // the current backup file becomes the original file if (org == NULL) { emsg(_("E205: Patchmode: can't save original file")); - } else if (!os_path_exists((char_u *)org)) { - vim_rename((char_u *)backup, (char_u *)org); + } else if (!os_path_exists(org)) { + vim_rename(backup, org); XFREE_CLEAR(backup); // don't delete the file #ifdef UNIX os_file_settime(org, @@ -3597,12 +3508,9 @@ restore_backup: (double)file_info_old.stat.st_mtim.tv_sec); #endif } - } - /* - * If there is no backup file, remember that a (new) file was - * created. - */ - else { + } else { + // If there is no backup file, remember that a (new) file was + // created. int empty_fd; if (org == NULL @@ -3620,9 +3528,7 @@ restore_backup: } } - /* - * Remove the backup unless 'backup' option is set - */ + // Remove the backup unless 'backup' option is set if (!p_bk && backup != NULL && !write_info.bw_conv_error && os_remove(backup) != 0) { @@ -3631,9 +3537,7 @@ restore_backup: goto nofail; - /* - * Finish up. We get here either after failure or success. - */ + // Finish up. We get here either after failure or success. fail: no_wait_return--; // may wait for return now nofail: @@ -3654,15 +3558,15 @@ nofail: } #endif #ifdef HAVE_ACL - mch_free_acl(acl); + os_free_acl(acl); #endif if (errmsg != NULL) { // - 100 to save some space for further error message #ifndef UNIX - add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)sfname); + add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)sfname); #else - add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)fname); + add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)fname); #endif if (errnum != NULL) { if (errmsgarg != 0) { @@ -3698,10 +3602,8 @@ nofail: } msg_scroll = msg_save; - /* - * When writing the whole file and 'undofile' is set, also write the undo - * file. - */ + // When writing the whole file and 'undofile' is set, also write the undo + // file. if (retval == OK && write_undo_file) { char hash[UNDO_HASH_SIZE]; @@ -3714,10 +3616,8 @@ nofail: curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read - /* - * Apply POST autocommands. - * Careful: The autocommands may call buf_write() recursively! - */ + // Apply POST autocommands. + // Careful: The autocommands may call buf_write() recursively! aucmd_prepbuf(&aco, buf); if (append) { @@ -3843,22 +3743,22 @@ static bool msg_add_fileformat(int eol_type) /// Append line and character count to IObuff. void msg_add_lines(int insert_space, long lnum, off_T nchars) { - char_u *p; + char *p; - p = IObuff + STRLEN(IObuff); + p = IObuff + strlen(IObuff); if (insert_space) { *p++ = ' '; } if (shortmess(SHM_LINES)) { - vim_snprintf((char *)p, (size_t)(IOSIZE - (p - IObuff)), "%" PRId64 "L, %" PRId64 "B", + vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), "%" PRId64 "L, %" PRId64 "B", (int64_t)lnum, (int64_t)nchars); } else { - vim_snprintf((char *)p, (size_t)(IOSIZE - (p - IObuff)), + vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), NGETTEXT("%" PRId64 " line, ", "%" PRId64 " lines, ", lnum), (int64_t)lnum); - p += STRLEN(p); - vim_snprintf((char *)p, (size_t)(IOSIZE - (p - IObuff)), + p += strlen(p); + vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), NGETTEXT("%" PRId64 " byte", "%" PRId64 " bytes", nchars), (int64_t)nchars); } @@ -3918,18 +3818,14 @@ static int buf_write_bytes(struct bw_info *ip) int flags = ip->bw_flags; // extra flags #endif - /* - * Skip conversion when writing the BOM. - */ + // Skip conversion when writing the BOM. if (!(flags & FIO_NOCONVERT)) { char_u *p; unsigned c; int n; if (flags & FIO_UTF8) { - /* - * Convert latin1 in the buffer to UTF-8 in the file. - */ + // Convert latin1 in the buffer to UTF-8 in the file. p = ip->bw_conv_buf; // translate to buffer for (wlen = 0; wlen < len; wlen++) { p += utf_char2bytes(buf[wlen], (char *)p); @@ -3937,10 +3833,8 @@ static int buf_write_bytes(struct bw_info *ip) buf = ip->bw_conv_buf; len = (int)(p - ip->bw_conv_buf); } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { - /* - * Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or - * Latin1 chars in the file. - */ + // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or + // Latin1 chars in the file. if (flags & FIO_LATIN1) { p = buf; // translate in-place (can only get shorter) } else { @@ -3950,9 +3844,9 @@ static int buf_write_bytes(struct bw_info *ip) if (wlen == 0 && ip->bw_restlen != 0) { int l; - /* Use remainder of previous call. Append the start of - * buf[] to get a full sequence. Might still be too - * short! */ + // Use remainder of previous call. Append the start of + // buf[] to get a full sequence. Might still be too + // short! l = CONV_RESTLEN - ip->bw_restlen; if (l > len) { l = len; @@ -3960,9 +3854,9 @@ static int buf_write_bytes(struct bw_info *ip) memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l); if (n > ip->bw_restlen + len) { - /* We have an incomplete byte sequence at the end to - * be written. We can't convert it without the - * remaining bytes. Keep them for the next call. */ + // We have an incomplete byte sequence at the end to + // be written. We can't convert it without the + // remaining bytes. Keep them for the next call. if (ip->bw_restlen + len > CONV_RESTLEN) { return FAIL; } @@ -3986,9 +3880,9 @@ static int buf_write_bytes(struct bw_info *ip) } else { n = utf_ptr2len_len(buf + wlen, len - wlen); if (n > len - wlen) { - /* We have an incomplete byte sequence at the end to - * be written. We can't convert it without the - * remaining bytes. Keep them for the next call. */ + // We have an incomplete byte sequence at the end to + // be written. We can't convert it without the + // remaining bytes. Keep them for the next call. if (len - wlen > CONV_RESTLEN) { return FAIL; } @@ -4031,9 +3925,9 @@ static int buf_write_bytes(struct bw_info *ip) if (ip->bw_restlen > 0) { char *fp; - /* Need to concatenate the remainder of the previous call and - * the bytes of the current call. Use the end of the - * conversion buffer for this. */ + // Need to concatenate the remainder of the previous call and + // the bytes of the current call. Use the end of the + // conversion buffer for this. fromlen = (size_t)len + (size_t)ip->bw_restlen; fp = (char *)ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); @@ -4053,9 +3947,8 @@ static int buf_write_bytes(struct bw_info *ip) // output the initial shift state sequence (void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen); - /* There is a bug in iconv() on Linux (which appears to be - * wide-spread) which sets "to" to NULL and messes up "tolen". - */ + // There is a bug in iconv() on Linux (which appears to be + // wide-spread) which sets "to" to NULL and messes up "tolen". if (to == NULL) { to = (char *)ip->bw_conv_buf; tolen = save_len; @@ -4063,9 +3956,7 @@ static int buf_write_bytes(struct bw_info *ip) ip->bw_first = false; } - /* - * If iconv() has an error or there is not enough room, fail. - */ + // If iconv() has an error or there is not enough room, fail. if ((iconv(ip->bw_iconv_fd, (void *)&from, &fromlen, &to, &tolen) == (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL) || fromlen > CONV_RESTLEN) { @@ -4121,8 +4012,8 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL } else if (flags & (FIO_UCS2 | FIO_UTF16)) { if (c >= 0x10000) { if (flags & FIO_UTF16) { - /* Make two words, ten bits of the character in each. First - * word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */ + // Make two words, ten bits of the character in each. First + // word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff c -= 0x10000; if (c >= 0x100000) { error = true; @@ -4166,21 +4057,21 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL /// @param fenc file encoding to check /// /// @return true if conversion is required -static bool need_conversion(const char_u *fenc) +static bool need_conversion(const char *fenc) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { int same_encoding; int enc_flags; int fenc_flags; - if (*fenc == NUL || STRCMP(p_enc, fenc) == 0) { + if (*fenc == NUL || strcmp(p_enc, fenc) == 0) { same_encoding = true; fenc_flags = 0; } else { // Ignore difference between "ansi" and "latin1", "ucs-4" and // "ucs-4be", etc. enc_flags = get_fio_flags((char_u *)p_enc); - fenc_flags = get_fio_flags(fenc); + fenc_flags = get_fio_flags((char_u *)fenc); same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); } if (same_encoding) { @@ -4205,7 +4096,7 @@ static int get_fio_flags(const char_u *name) if (*name == NUL) { name = (char_u *)p_enc; } - prop = enc_canon_props(name); + prop = enc_canon_props((char *)name); if (prop & ENC_UNICODE) { if (prop & ENC_2BYTE) { if (prop & ENC_ENDIAN_L) { @@ -4239,7 +4130,7 @@ static int get_fio_flags(const char_u *name) /// /// @return the name of the encoding and set "*lenp" to the length or, /// NULL when no BOM found. -static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags) +static char_u *check_for_bom(const char_u *p, long size, int *lenp, int flags) { char *name = NULL; int len = 2; @@ -4327,7 +4218,7 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } - p = (char *)path_shorten_fname((char_u *)buf->b_ffname, dirname); + p = path_shorten_fname(buf->b_ffname, (char *)dirname); if (p != NULL) { buf->b_sfname = xstrdup(p); buf->b_fname = buf->b_sfname; @@ -4343,7 +4234,7 @@ void shorten_fnames(int force) { char_u dirname[MAXPATHL]; - os_dirname(dirname, MAXPATHL); + os_dirname((char *)dirname, MAXPATHL); FOR_ALL_BUFFERS(buf) { shorten_buf_fname(buf, dirname, force); @@ -4390,7 +4281,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) // (we need the full path in case :cd is used). if (fname == NULL || *fname == NUL) { retval = xmalloc(MAXPATHL + extlen + 3); // +3 for PATHSEP, "_" (Win), NUL - if (os_dirname((char_u *)retval, MAXPATHL) == FAIL + if (os_dirname(retval, MAXPATHL) == FAIL || strlen(retval) == 0) { xfree(retval); return NULL; @@ -4401,7 +4292,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) } else { fnamelen = strlen(fname); retval = xmalloc(fnamelen + extlen + 3); - strcpy(retval, fname); + strcpy(retval, fname); // NOLINT(runtime/printf) } // Search backwards until we hit a '/', '\' or ':'. @@ -4419,12 +4310,11 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) ptr[BASENAMELEN] = '\0'; } - char *s; - s = ptr + strlen(ptr); + char *s = ptr + strlen(ptr); // Append the extension. // ext can start with '.' and cannot exceed 3 more characters. - strcpy(s, ext); + strcpy(s, ext); // NOLINT(runtime/printf) char *e; // Prepend the dot if needed. @@ -4458,7 +4348,8 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) /// @param fp file to read from /// /// @return true for EOF or error -bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL +bool vim_fgets(char *buf, int size, FILE *fp) + FUNC_ATTR_NONNULL_ALL { char *retval; @@ -4467,7 +4358,7 @@ bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL do { errno = 0; - retval = fgets((char *)buf, size, fp); + retval = fgets(buf, size, fp); } while (retval == NULL && errno == EINTR && ferror(fp)); if (buf[size - 2] != NUL && buf[size - 2] != '\n') { @@ -4619,7 +4510,7 @@ int put_time(FILE *fd, time_t time_) /// function will (attempts to?) copy the file across if rename fails -- webb /// /// @return -1 for failure, 0 for success -int vim_rename(const char_u *from, const char_u *to) +int vim_rename(const char *from, const char *to) FUNC_ATTR_NONNULL_ALL { int fd_in; @@ -4633,13 +4524,11 @@ int vim_rename(const char_u *from, const char_u *to) #endif bool use_tmp_file = false; - /* - * When the names are identical, there is nothing to do. When they refer - * to the same file (ignoring case and slash/backslash differences) but - * the file name differs we need to go through a temp file. - */ - if (FNAMECMP(from, to) == 0) { - if (p_fic && (STRCMP(path_tail((char *)from), path_tail((char *)to)) + // When the names are identical, there is nothing to do. When they refer + // to the same file (ignoring case and slash/backslash differences) but + // the file name differs we need to go through a temp file. + if (path_fnamecmp(from, to) == 0) { + if (p_fic && (strcmp(path_tail((char *)from), path_tail((char *)to)) != 0)) { use_tmp_file = true; } else { @@ -4665,11 +4554,9 @@ int vim_rename(const char_u *from, const char_u *to) if (use_tmp_file) { char_u tempname[MAXPATHL + 1]; - /* - * Find a name that doesn't exist and is in the same directory. - * Rename "from" to "tempname" and then rename "tempname" to "to". - */ - if (STRLEN(from) >= MAXPATHL - 5) { + // Find a name that doesn't exist and is in the same directory. + // Rename "from" to "tempname" and then rename "tempname" to "to". + if (strlen(from) >= MAXPATHL - 5) { return -1; } STRCPY(tempname, from); @@ -4677,14 +4564,14 @@ int vim_rename(const char_u *from, const char_u *to) char *tail = path_tail((char *)tempname); snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - (char *)tempname - 1)), "%d", n); - if (!os_path_exists(tempname)) { - if (os_rename(from, tempname) == OK) { - if (os_rename(tempname, to) == OK) { + if (!os_path_exists((char *)tempname)) { + if (os_rename((char_u *)from, tempname) == OK) { + if (os_rename(tempname, (char_u *)to) == OK) { return 0; } // Strange, the second step failed. Try moving the // file back and return failure. - (void)os_rename(tempname, from); + (void)os_rename(tempname, (char_u *)from); return -1; } // If it fails for one temp name it will most likely fail @@ -4695,33 +4582,27 @@ int vim_rename(const char_u *from, const char_u *to) return -1; } - /* - * Delete the "to" file, this is required on some systems to make the - * os_rename() work, on other systems it makes sure that we don't have - * two files when the os_rename() fails. - */ + // Delete the "to" file, this is required on some systems to make the + // os_rename() work, on other systems it makes sure that we don't have + // two files when the os_rename() fails. os_remove((char *)to); - /* - * First try a normal rename, return if it works. - */ - if (os_rename(from, to) == OK) { + // First try a normal rename, return if it works. + if (os_rename((char_u *)from, (char_u *)to) == OK) { return 0; } - /* - * Rename() failed, try copying the file. - */ - perm = os_getperm((const char *)from); + // Rename() failed, try copying the file. + perm = os_getperm(from); #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. - acl = mch_get_acl(from); + acl = os_get_acl((char_u *)from); #endif fd_in = os_open((char *)from, O_RDONLY, 0); if (fd_in < 0) { #ifdef HAVE_ACL - mch_free_acl(acl); + os_free_acl(acl); #endif return -1; } @@ -4732,7 +4613,7 @@ int vim_rename(const char_u *from, const char_u *to) if (fd_out < 0) { close(fd_in); #ifdef HAVE_ACL - mch_free_acl(acl); + os_free_acl(acl); #endif return -1; } @@ -4744,7 +4625,7 @@ int vim_rename(const char_u *from, const char_u *to) close(fd_out); close(fd_in); #ifdef HAVE_ACL - mch_free_acl(acl); + os_free_acl(acl); #endif return -1; } @@ -4769,8 +4650,8 @@ int vim_rename(const char_u *from, const char_u *to) os_setperm((const char *)to, perm); #endif #ifdef HAVE_ACL - mch_set_acl(to, acl); - mch_free_acl(acl); + os_set_acl((char_u *)to, acl); + os_free_acl(acl); #endif if (errmsg != NULL) { semsg(errmsg, to); @@ -4852,13 +4733,13 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) buf_T *tbuf = curbuf; int retval = OK; linenr_T lnum; - char_u *p; + char *p; // 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, (char *)p, 0, false) == FAIL) { + p = xstrdup(ml_get_buf(frombuf, lnum, false)); + if (ml_append(lnum - 1, p, 0, false) == FAIL) { xfree(p); retval = FAIL; break; @@ -4893,7 +4774,7 @@ int buf_check_timestamp(buf_T *buf) FUNC_ATTR_NONNULL_ALL { int retval = 0; - char_u *path; + char *path; char *mesg = NULL; char *mesg2 = ""; bool helpmesg = false; @@ -4908,7 +4789,7 @@ int buf_check_timestamp(buf_T *buf) uint64_t orig_size = buf->b_orig_size; int orig_mode = buf->b_orig_mode; static bool busy = false; - char_u *s; + char *s; char *reason; bufref_T bufref; @@ -4983,12 +4864,12 @@ int buf_check_timestamp(buf_T *buf) if (!bufref_valid(&bufref)) { emsg(_("E246: FileChangedShell autocommand deleted buffer")); } - s = (char_u *)get_vim_var_str(VV_FCS_CHOICE); - if (STRCMP(s, "reload") == 0 && *reason != 'd') { + s = get_vim_var_str(VV_FCS_CHOICE); + if (strcmp(s, "reload") == 0 && *reason != 'd') { reload = RELOAD_NORMAL; - } else if (STRCMP(s, "edit") == 0) { + } else if (strcmp(s, "edit") == 0) { reload = RELOAD_DETECT; - } else if (STRCMP(s, "ask") == 0) { + } else if (strcmp(s, "ask") == 0) { n = false; } else { return 2; @@ -5028,7 +4909,7 @@ int buf_check_timestamp(buf_T *buf) } } } else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W) - && os_path_exists((char_u *)buf->b_ffname)) { + && os_path_exists(buf->b_ffname)) { retval = 1; mesg = _("W13: Warning: File \"%s\" has been created after editing started"); buf->b_flags |= BF_NEW_W; @@ -5036,11 +4917,11 @@ int buf_check_timestamp(buf_T *buf) } if (mesg != NULL) { - path = (char_u *)home_replace_save(buf, buf->b_fname); + path = home_replace_save(buf, buf->b_fname); if (!helpmesg) { mesg2 = ""; } - const size_t tbuf_len = STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2; + const size_t tbuf_len = strlen(path) + strlen(mesg) + strlen(mesg2) + 2; char *const tbuf = xmalloc(tbuf_len); snprintf(tbuf, tbuf_len, mesg, path); // Set warningmsg here, before the unimportant and output-specific @@ -5051,8 +4932,8 @@ int buf_check_timestamp(buf_T *buf) xstrlcat(tbuf, "\n", tbuf_len - 1); xstrlcat(tbuf, mesg2, tbuf_len - 1); } - switch (do_dialog(VIM_WARNING, (char_u *)_("Warning"), (char_u *)tbuf, - (char_u *)_("&OK\n&Load File\nLoad File &and Options"), + switch (do_dialog(VIM_WARNING, _("Warning"), tbuf, + _("&OK\n&Load File\nLoad File &and Options"), 1, NULL, true)) { case 2: reload = RELOAD_NORMAL; @@ -5077,7 +4958,7 @@ int buf_check_timestamp(buf_T *buf) } msg_clr_eos(); (void)msg_end(); - if (emsg_silent == 0) { + if (emsg_silent == 0 && !in_assert_fails) { ui_flush(); // give the user some time to think about it os_delay(1004L, true); @@ -5128,7 +5009,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) aco_save_T aco; int flags = READ_NEW; - // set curwin/curbuf for "buf" and save some things + // Set curwin/curbuf for "buf" and save some things. aucmd_prepbuf(&aco, buf); // Unless reload_options is set, we only want to read the text from the @@ -5292,6 +5173,9 @@ void forward_slash(char_u *fname) /// Path to Nvim's own temp dir. Ends in a slash. static char *vim_tempdir = NULL; +#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +DIR *vim_tempdir_dp = NULL; ///< File descriptor of temp dir +#endif /// Creates a directory for private use by this instance of Nvim, trying each of /// `TEMP_DIR_NAMES` until one succeeds. @@ -5364,10 +5248,9 @@ static void vim_mktempdir(void) if (vim_settempdir(path)) { // Successfully created and set temporary directory so stop trying. break; - } else { - // Couldn't set `vim_tempdir` to `path` so remove created directory. - os_rmdir(path); } + // Couldn't set `vim_tempdir` to `path` so remove created directory. + os_rmdir(path); } (void)umask(umask_save); } @@ -5434,7 +5317,7 @@ int delete_recursive(const char *name) garray_T ga; if (readdir_core(&ga, exp, NULL, NULL) == OK) { for (int i = 0; i < ga.ga_len; i++) { - vim_snprintf((char *)NameBuff, MAXPATHL, "%s/%s", exp, ((char_u **)ga.ga_data)[i]); + vim_snprintf(NameBuff, MAXPATHL, "%s/%s", exp, ((char_u **)ga.ga_data)[i]); if (delete_recursive((const char *)NameBuff) != 0) { // Remember the failure but continue deleting any further // entries. @@ -5457,15 +5340,50 @@ int delete_recursive(const char *name) return result; } +#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +/// Open temporary directory and take file lock to prevent +/// to be auto-cleaned. +static void vim_opentempdir(void) +{ + if (vim_tempdir_dp != NULL) { + return; + } + + DIR *dp = opendir(vim_tempdir); + if (dp == NULL) { + return; + } + + vim_tempdir_dp = dp; + flock(dirfd(vim_tempdir_dp), LOCK_SH); +} + +/// Close temporary directory - it automatically release file lock. +static void vim_closetempdir(void) +{ + if (vim_tempdir_dp == NULL) { + return; + } + + closedir(vim_tempdir_dp); + vim_tempdir_dp = NULL; +} +#endif + /// Delete the temp directory and all files it contains. void vim_deltempdir(void) { - if (vim_tempdir != NULL) { - // remove the trailing path separator - path_tail(vim_tempdir)[-1] = NUL; - delete_recursive(vim_tempdir); - XFREE_CLEAR(vim_tempdir); + if (vim_tempdir == NULL) { + return; } + +#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) + vim_closetempdir(); +#endif + // remove the trailing path separator + path_tail(vim_tempdir)[-1] = NUL; + delete_recursive(vim_tempdir); + XFREE_CLEAR(vim_tempdir); } /// Gets path to Nvim's own temp dir (ending with slash). @@ -5490,12 +5408,16 @@ char *vim_gettempdir(void) static bool vim_settempdir(char *tempdir) { char *buf = verbose_try_malloc(MAXPATHL + 2); - if (!buf) { + if (buf == NULL) { return false; } + vim_FullName(tempdir, buf, MAXPATHL, false); add_pathsep(buf); vim_tempdir = xstrdup(buf); +#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) + vim_opentempdir(); +#endif xfree(buf); return true; } @@ -5506,7 +5428,7 @@ static bool vim_settempdir(char *tempdir) /// /// @return pointer to the temp file name or NULL if Nvim can't create /// temporary directory for its own temporary files. -char_u *vim_tempname(void) +char *vim_tempname(void) { // Temp filename counter. static uint64_t temp_count; @@ -5518,10 +5440,10 @@ char_u *vim_tempname(void) // There is no need to check if the file exists, because we own the directory // and nobody else creates a file in it. - char_u template[TEMP_FILE_PATH_MAXLEN]; - snprintf((char *)template, TEMP_FILE_PATH_MAXLEN, + char template[TEMP_FILE_PATH_MAXLEN]; + snprintf(template, TEMP_FILE_PATH_MAXLEN, "%s%" PRIu64, tempdir, temp_count++); - return vim_strsave(template); + return xstrdup(template); } /// Tries matching a filename with a "pattern" ("prog" is NULL), or use the @@ -5553,12 +5475,10 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, } } - /* - * Try for a match with the pattern with: - * 1. the full file name, when the pattern has a '/'. - * 2. the short file name, when the pattern has a '/'. - * 3. the tail of the file name, when the pattern has no '/'. - */ + // Try for a match with the pattern with: + // 1. the full file name, when the pattern has a '/'. + // 2. the short file name, when the pattern has a '/'. + // 3. the tail of the file name, when the pattern has no '/'. if (regmatch.regprog != NULL && ((allow_dirs && (vim_regexec(®match, fname, (colnr_T)0) @@ -5639,7 +5559,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs *allow_dirs = false; } if (pat_end == NULL) { - pat_end = pat + STRLEN(pat); + pat_end = pat + strlen(pat); } if (pat_end == pat) { @@ -5715,7 +5635,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs // "\*" to "\\.*" e.g., "dir\*.c" // "\?" to "\\." e.g., "dir\??.c" // "\+" to "\+" e.g., "fileX\+.c" - if ((vim_isfilec(p[1]) || p[1] == '*' || p[1] == '?') + if ((vim_isfilec((uint8_t)p[1]) || p[1] == '*' || p[1] == '?') && p[1] != '+') { reg_pat[i++] = '['; reg_pat[i++] = '\\'; |