diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:23:01 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:23:01 +0000 |
commit | 142d9041391780ac15b89886a54015fdc5c73995 (patch) | |
tree | 0f6b5cac1a60810a03f52826c9e67c9e2780b033 /src/nvim/fileio.c | |
parent | ad86b5db74922285699ab2a1dbb2ff20e6268a33 (diff) | |
parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
download | rneovim-142d9041391780ac15b89886a54015fdc5c73995.tar.gz rneovim-142d9041391780ac15b89886a54015fdc5c73995.tar.bz2 rneovim-142d9041391780ac15b89886a54015fdc5c73995.zip |
Merge remote-tracking branch 'upstream/master' into userreg
Diffstat (limited to 'src/nvim/fileio.c')
-rw-r--r-- | src/nvim/fileio.c | 618 |
1 files changed, 319 insertions, 299 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 30898981de..9da9d6199e 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,15 +82,17 @@ #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 +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... @@ -93,7 +105,7 @@ // 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 + char *bw_buf; // buffer with data to be written int bw_len; // length of data #ifdef HAS_BW_FLAGS int bw_flags; // FIO_ flags @@ -101,14 +113,12 @@ struct bw_info { 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_u *bw_conv_buf; // buffer for writing converted chars + 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 -#ifdef HAVE_ICONV iconv_t bw_iconv_fd; // descriptor for iconv() or -1 -#endif }; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -126,7 +136,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) 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. xstrlcat(IObuff, s, IOSIZE); // For the first message may have to start a new line. @@ -143,7 +153,7 @@ void filemess(buf_T *buf, char *name, char *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(msg_may_trunc(false, (char *)IObuff), attr); + msg_outtrans_attr(msg_may_trunc(false, IObuff), attr); msg_clr_eos(); ui_flush(); msg_scrolled_ign = false; @@ -236,11 +246,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, char *fenc_next = NULL; // next item in 'fencs' or NULL bool advance_fenc = false; long real_size = 0; -#ifdef HAVE_ICONV iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1 bool did_iconv = false; // true when iconv() failed and trying // 'charconvert' next -#endif bool converted = false; // true if conversion done bool notconverted = false; // true if conversion wanted but it wasn't possible char conv_rest[CONV_RESTLEN]; @@ -266,7 +274,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, && fname != NULL && vim_strchr(p_cpo, CPO_FNAMER) != NULL && !(flags & READ_DUMMY)) { - if (set_rw_fname((char_u *)fname, (char_u *)sfname) == FAIL) { + if (set_rw_fname(fname, sfname) == FAIL) { return FAIL; } } @@ -476,7 +484,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } } if (!silent) { - if (dir_of_file_exists((char_u *)fname)) { + if (dir_of_file_exists(fname)) { filemess(curbuf, sfname, new_file_message(), 0); } else { filemess(curbuf, sfname, _("[New DIRECTORY]"), 0); @@ -498,18 +506,17 @@ 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, sfname, ((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; } @@ -524,6 +531,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; } @@ -766,13 +775,11 @@ retry: } } -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { // aborted conversion with iconv(), close the descriptor iconv_close(iconv_fd); iconv_fd = (iconv_t)-1; } -#endif if (advance_fenc) { // Try the next entry in 'fileencodings'. @@ -822,32 +829,24 @@ retry: // appears not to handle this correctly. This works just like // conversion to UTF-8 except how the resulting character is put in // the buffer. - fio_flags = get_fio_flags((char_u *)fenc); + fio_flags = get_fio_flags(fenc); } -#ifdef HAVE_ICONV // Try using iconv() if we can't convert internally. if (fio_flags == 0 && !did_iconv) { - iconv_fd = (iconv_t)my_iconv_open((char_u *)"utf-8", (char_u *)fenc); + iconv_fd = (iconv_t)my_iconv_open("utf-8", fenc); } -#endif // 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 - && iconv_fd == (iconv_t)-1 -#endif - ) { -#ifdef HAVE_ICONV + && !read_fifo && iconv_fd == (iconv_t)-1) { did_iconv = false; -#endif // Skip conversion when it's already done (retry for wrong // "fileformat"). if (tmpname == NULL) { - tmpname = (char *)readfile_charconvert((char_u *)fname, (char_u *)fenc, &fd); + tmpname = readfile_charconvert(fname, fenc, &fd); if (tmpname == NULL) { // Conversion failed. Try another one. advance_fenc = true; @@ -861,11 +860,7 @@ retry: } } } else { - if (fio_flags == 0 -#ifdef HAVE_ICONV - && iconv_fd == (iconv_t)-1 -#endif - ) { + if (fio_flags == 0 && iconv_fd == (iconv_t)-1) { // Conversion wanted but we can't. // Try the next conversion in 'fileencodings' advance_fenc = true; @@ -948,12 +943,9 @@ retry: // ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be // multiple of 4 real_size = (int)size; -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { size = size / ICONV_MULT; - } else { -#endif - if (fio_flags & FIO_LATIN1) { + } else if (fio_flags & FIO_LATIN1) { size = size / 2; } else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) { size = (size * 2 / 3) & ~1; @@ -962,9 +954,7 @@ retry: } else if (fio_flags == FIO_UCSBOM) { size = size / ICONV_MULT; // worst case } -#ifdef HAVE_ICONV - } -#endif + if (conv_restlen > 0) { // Insert unconverted bytes from previous line. memmove(ptr, conv_rest, (size_t)conv_restlen); // -V614 @@ -984,7 +974,7 @@ retry: tlen = 0; for (;;) { p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; - n = (int)STRLEN(p); + 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 @@ -1036,11 +1026,7 @@ retry: // not be converted. Truncated file? // When we did a conversion report an error. - if (fio_flags != 0 -#ifdef HAVE_ICONV - || iconv_fd != (iconv_t)-1 -#endif - ) { + if (fio_flags != 0 || iconv_fd != (iconv_t)-1) { if (can_retry) { goto rewind_retry; } @@ -1048,9 +1034,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; } @@ -1062,23 +1047,17 @@ retry: // character if we were converting; if we weren't, // leave the UTF8 checking code to do it, as it // works slightly differently. - if (bad_char_behavior != BAD_KEEP && (fio_flags != 0 -#ifdef HAVE_ICONV - || iconv_fd != (iconv_t)-1 -#endif - )) { + if (bad_char_behavior != BAD_KEEP && (fio_flags != 0 || iconv_fd != (iconv_t)-1)) { while (conv_restlen > 0) { *(--ptr) = (char)bad_char_behavior; conv_restlen--; } } fio_flags = 0; // don't convert this -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { iconv_close(iconv_fd); iconv_fd = (iconv_t)-1; } -#endif } } } @@ -1095,15 +1074,15 @@ retry: || (!curbuf->b_p_bomb && tmpname == NULL && (*fenc == 'u' || *fenc == NUL)))) { - char_u *ccname; + char *ccname; int blen = 0; // no BOM detection in a short file or in binary mode if (size < 2 || curbuf->b_p_bin) { ccname = NULL; } else { - ccname = check_for_bom((char_u *)ptr, size, &blen, - fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags((char_u *)fenc)); + ccname = check_for_bom(ptr, size, &blen, + fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc)); } if (ccname != NULL) { // Remove BOM from the text @@ -1125,7 +1104,7 @@ retry: if (fenc_alloced) { xfree(fenc); } - fenc = (char *)ccname; + fenc = ccname; fenc_alloced = false; } // retry reading without getting new bytes or rewinding @@ -1143,7 +1122,6 @@ retry: break; } -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { // Attempt conversion of the read bytes to 'encoding' using iconv(). const char *fromp = ptr; @@ -1163,7 +1141,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, (char_u *)top); + conv_error = readfile_linenr(linecnt, ptr, top); } // Deal with a bad byte and continue with the next. @@ -1181,7 +1159,7 @@ retry: if (from_size > 0) { // Some remaining characters, keep them for the next // round. - memmove(conv_rest, (char_u *)fromp, from_size); + memmove(conv_rest, fromp, from_size); conv_restlen = (int)from_size; } @@ -1190,7 +1168,6 @@ retry: memmove(line_start, buffer, (size_t)linerest); size = (top - ptr); } -#endif if (fio_flags != 0) { unsigned int u8c; @@ -1275,7 +1252,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } if (bad_char_behavior == BAD_DROP) { continue; @@ -1303,7 +1280,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } if (bad_char_behavior == BAD_DROP) { continue; @@ -1344,7 +1321,7 @@ retry: goto rewind_retry; } if (conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } if (bad_char_behavior == BAD_DROP) { continue; @@ -1382,7 +1359,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(p, todo); + 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 @@ -1408,15 +1385,15 @@ retry: if (can_retry && !incomplete_tail) { break; } -#ifdef HAVE_ICONV + // When we did a conversion report an error. if (iconv_fd != (iconv_t)-1 && conv_error == 0) { - conv_error = readfile_linenr(linecnt, (char_u *)ptr, p); + conv_error = readfile_linenr(linecnt, ptr, (char *)p); } -#endif + // Remember the first linenr with an illegal byte if (conv_error == 0 && illegal_byte == 0) { - illegal_byte = readfile_linenr(linecnt, (char_u *)ptr, p); + illegal_byte = readfile_linenr(linecnt, ptr, (char *)p); } // Drop, keep or replace the bad byte. @@ -1436,17 +1413,13 @@ retry: // Detected a UTF-8 error. rewind_retry: // Retry reading with another conversion. -#ifdef HAVE_ICONV if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) { // iconv() failed, try 'charconvert' did_iconv = true; } else { -#endif - // use next item from 'fileencodings' - advance_fenc = true; -#ifdef HAVE_ICONV - } -#endif + // use next item from 'fileencodings' + advance_fenc = true; + } file_rewind = true; goto retry; } @@ -1542,7 +1515,7 @@ rewind_retry: break; } if (read_undo_file) { - sha256_update(&sha_ctx, (char_u *)line_start, (size_t)len); + sha256_update(&sha_ctx, (uint8_t *)line_start, (size_t)len); } lnum++; if (--read_count == 0) { @@ -1598,7 +1571,7 @@ rewind_retry: break; } if (read_undo_file) { - sha256_update(&sha_ctx, (char_u *)line_start, (size_t)len); + sha256_update(&sha_ctx, (uint8_t *)line_start, (size_t)len); } lnum++; if (--read_count == 0) { @@ -1623,16 +1596,28 @@ failed: error = false; } + // 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. - // In Dos format ignore a trailing CTRL-Z, unless 'binary' set. 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; @@ -1643,7 +1628,7 @@ failed: error = true; } else { if (read_undo_file) { - sha256_update(&sha_ctx, (char_u *)line_start, (size_t)len); + sha256_update(&sha_ctx, (uint8_t *)line_start, (size_t)len); } read_no_eol_lnum = ++lnum; } @@ -1659,11 +1644,9 @@ failed: if (fenc_alloced) { xfree(fenc); } -#ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { iconv_close(iconv_fd); } -#endif if (!read_buffer && !read_stdin) { close(fd); // errors are ignored @@ -1734,7 +1717,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 @@ -1799,7 +1782,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 @@ -1863,7 +1846,7 @@ failed: char_u hash[UNDO_HASH_SIZE]; sha256_finish(&sha_ctx, hash); - u_read_undo(NULL, hash, (char_u *)fname); + u_read_undo(NULL, hash, fname); } if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL)) { @@ -1919,7 +1902,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 @@ -1934,9 +1917,9 @@ 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 *p, const char *endp) { - char_u *s; + char *s; linenr_T lnum; lnum = curbuf->b_ml.ml_line_count - linecnt + 1; @@ -1990,11 +1973,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'. @@ -2014,7 +1999,7 @@ static char *next_fenc(char **pp, bool *alloced) *pp = NULL; return ""; } - p = vim_strchr((*pp), ','); + p = vim_strchr(*pp, ','); if (p == NULL) { r = enc_canonize(*pp); *pp += strlen(*pp); @@ -2039,22 +2024,22 @@ static char *next_fenc(char **pp, bool *alloced) /// /// @return name of the resulting converted file (the caller should delete it after reading it). /// Returns NULL if the conversion failed ("*fdp" is not set) . -static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp) +static char *readfile_charconvert(char *fname, char *fenc, int *fdp) { - char_u *tmpname; + char *tmpname; char *errmsg = NULL; - tmpname = (char_u *)vim_tempname(); + tmpname = vim_tempname(); if (tmpname == NULL) { errmsg = _("Can't find temp file for conversion"); } else { close(*fdp); // close the input file, ignore errors *fdp = -1; - if (eval_charconvert((char *)fenc, "utf-8", - (char *)fname, (char *)tmpname) == FAIL) { + if (eval_charconvert(fenc, "utf-8", + fname, tmpname) == FAIL) { errmsg = _("Conversion with 'charconvert' failed"); } - if (errmsg == NULL && (*fdp = os_open((char *)tmpname, O_RDONLY, 0)) < 0) { + if (errmsg == NULL && (*fdp = os_open(tmpname, O_RDONLY, 0)) < 0) { errmsg = _("can't read output of 'charconvert'"); } } @@ -2064,14 +2049,14 @@ static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp) // another type of conversion might still work. msg(errmsg); if (tmpname != NULL) { - os_remove((char *)tmpname); // delete converted file + os_remove(tmpname); // delete converted file XFREE_CLEAR(tmpname); } } // If the input file is closed, open it (caller should check for error). if (*fdp < 0) { - *fdp = os_open((char *)fname, O_RDONLY, 0); + *fdp = os_open(fname, O_RDONLY, 0); } return tmpname; @@ -2191,8 +2176,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en return FAIL; } - // Disallow writing from .exrc and .vimrc in current directory for - // security reasons. + // Disallow writing in secure mode. if (check_secure()) { return FAIL; } @@ -2208,9 +2192,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en write_info.bw_conv_error = false; write_info.bw_conv_error_lnum = 0; write_info.bw_restlen = 0; -#ifdef HAVE_ICONV write_info.bw_iconv_fd = (iconv_t)-1; -#endif // After writing a file changedtick changes but we don't want to display // the line. @@ -2229,7 +2211,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en && !filtering && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) { - if (set_rw_fname((char_u *)fname, (char_u *)sfname) == FAIL) { + if (set_rw_fname(fname, sfname) == FAIL) { return FAIL; } buf = curbuf; // just in case autocmds made "buf" invalid @@ -2448,7 +2430,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if (!filtering) { filemess(buf, #ifndef UNIX - (char_u *)sfname, + sfname, #else fname, #endif @@ -2492,7 +2474,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } #else // win32 // Check for a writable device name. - c = fname == NULL ? NODE_OTHER : os_nodetype((char *)fname); + c = fname == NULL ? NODE_OTHER : os_nodetype(fname); if (c == NODE_OTHER) { SET_ERRMSG_NUM("E503", _("is not a file or writable device")); goto fail; @@ -2510,7 +2492,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en goto fail; } if (overwriting) { - os_fileinfo((char *)fname, &file_info_old); + os_fileinfo(fname, &file_info_old); } } #endif // !UNIX @@ -2541,13 +2523,13 @@ 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. if (!newfile) { - acl = mch_get_acl((char_u *)fname); + acl = os_get_acl(fname); } #endif // 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)) { + if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) { dobackup = false; } @@ -2590,21 +2572,21 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // arbitrary numbers). STRCPY(IObuff, fname); for (i = 4913;; i += 123) { - char *tail = path_tail((char *)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) { @@ -2614,7 +2596,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // 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); } } } @@ -2668,16 +2650,16 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en 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]; + 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); @@ -2685,14 +2667,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 = get_file_in_dir(fname, (char *)IObuff); + rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { some_error = true; // out of memory goto nobackup; @@ -2768,10 +2750,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 @@ -2780,8 +2763,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(backup, acl); #endif + SET_ERRMSG(NULL); break; } } @@ -2817,16 +2801,16 @@ nobackup: 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]; + 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); @@ -2834,7 +2818,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); @@ -2842,7 +2826,7 @@ nobackup: } if (backup == NULL) { - rootname = get_file_in_dir(fname, (char *)IObuff); + rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { backup = NULL; } else { @@ -2953,7 +2937,7 @@ nobackup: // Latin1 to Unicode conversion. This is handled in buf_write_bytes(). // Prepare the flags for it and allocate bw_conv_buf when needed. if (converted) { - wb_flags = get_fio_flags((char_u *)fenc); + wb_flags = get_fio_flags(fenc); if (wb_flags & (FIO_UCS2 | FIO_UCS4 | FIO_UTF16 | FIO_UTF8)) { // Need to allocate a buffer to translate into. if (wb_flags & (FIO_UCS2 | FIO_UTF16 | FIO_UTF8)) { @@ -2969,10 +2953,9 @@ nobackup: } if (converted && wb_flags == 0) { -#ifdef HAVE_ICONV // Use iconv() conversion when conversion is needed and it's not done // internally. - write_info.bw_iconv_fd = (iconv_t)my_iconv_open((char_u *)fenc, (char_u *)"utf-8"); + write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, "utf-8"); if (write_info.bw_iconv_fd != (iconv_t)-1) { // We're going to use iconv(), allocate a buffer to convert in. write_info.bw_conv_buflen = (size_t)bufsize * ICONV_MULT; @@ -2982,28 +2965,21 @@ nobackup: } write_info.bw_first = true; } 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. - if (*p_ccv != NUL) { - 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; + // 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 = vim_tempname(); + if (wfname == NULL) { // Can't write without a tempfile! + SET_ERRMSG(_("E214: Can't find temp file for writing")); + goto restore_backup; + } } } } -#ifdef HAVE_ICONV -} -#endif - if (converted && wb_flags == 0 -#ifdef HAVE_ICONV && write_info.bw_iconv_fd == (iconv_t)-1 -#endif && wfname == fname) { if (!forceit) { SET_ERRMSG(_("E213: Cannot convert (add ! to write without conversion)")); @@ -3039,9 +3015,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 @@ -3122,7 +3100,7 @@ restore_backup: } SET_ERRMSG(NULL); - write_info.bw_buf = (char_u *)buffer; + write_info.bw_buf = buffer; nchars = 0; // use "++bin", "++nobin" or 'binary' @@ -3135,7 +3113,7 @@ restore_backup: // Skip the BOM when appending and the file already existed, the BOM // only makes sense at the start of the file. if (buf->b_p_bomb && !write_bin && (!append || perm < 0)) { - write_info.bw_len = make_bom((char_u *)buffer, (char_u *)fenc); + write_info.bw_len = make_bom((char_u *)buffer, fenc); if (write_info.bw_len > 0) { // don't convert write_info.bw_flags = FIO_NOCONVERT | wb_flags; @@ -3167,7 +3145,7 @@ restore_backup: // Keep it fast! 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, (uint8_t *)ptr + 1, (uint32_t)(strlen(ptr + 1) + 1)); } while ((c = *++ptr) != NUL) { if (c == NL) { @@ -3241,6 +3219,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; @@ -3308,7 +3291,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(wfname, acl); } #endif @@ -3336,7 +3319,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); @@ -3385,13 +3368,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) { @@ -3425,7 +3408,7 @@ 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 @@ -3517,22 +3500,20 @@ nofail: } xfree(fenc_tofree); xfree(write_info.bw_conv_buf); -#ifdef HAVE_ICONV if (write_info.bw_iconv_fd != (iconv_t)-1) { iconv_close(write_info.bw_iconv_fd); write_info.bw_iconv_fd = (iconv_t)-1; } -#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) { @@ -3571,10 +3552,10 @@ nofail: // 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]; + uint8_t hash[UNDO_HASH_SIZE]; - sha256_finish(&sha_ctx, (char_u *)hash); - u_write_undo(NULL, false, buf, (char_u *)hash); + sha256_finish(&sha_ctx, hash); + u_write_undo(NULL, false, buf, hash); } if (!should_abort(retval)) { @@ -3618,7 +3599,7 @@ nofail: /// Set the name of the current buffer. Use when the buffer doesn't have a /// name and a ":r" or ":w" command with a file name is used. -static int set_rw_fname(char_u *fname, char_u *sfname) +static int set_rw_fname(char *fname, char *sfname) { buf_T *buf = curbuf; @@ -3636,7 +3617,7 @@ static int set_rw_fname(char_u *fname, char_u *sfname) return FAIL; } - if (setfname(curbuf, (char *)fname, (char *)sfname, false) == OK) { + if (setfname(curbuf, fname, sfname, false) == OK) { curbuf->b_flags |= BF_NOTEDITED; } @@ -3709,22 +3690,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 = (char_u *)IObuff + STRLEN(IObuff); + p = IObuff + strlen(IObuff); if (insert_space) { *p++ = ' '; } if (shortmess(SHM_LINES)) { - vim_snprintf((char *)p, (size_t)(IOSIZE - (p - (char_u *)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 - (char_u *)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 - (char_u *)IObuff)), + p += strlen(p); + vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), NGETTEXT("%" PRId64 " byte", "%" PRId64 " bytes", nchars), (int64_t)nchars); } @@ -3767,7 +3748,7 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F || file_info->stat.st_mtim.tv_sec - mtime > 1 || mtime - file_info->stat.st_mtim.tv_sec > 1; #else - || (long)file_info->stat.st_mtim.tv_sec != mtime; + || file_info->stat.st_mtim.tv_sec != mtime; #endif } @@ -3778,7 +3759,7 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F static int buf_write_bytes(struct bw_info *ip) { int wlen; - char_u *buf = ip->bw_buf; // data to write + char *buf = ip->bw_buf; // data to write int len = ip->bw_len; // length of data #ifdef HAS_BW_FLAGS int flags = ip->bw_flags; // extra flags @@ -3786,7 +3767,7 @@ static int buf_write_bytes(struct bw_info *ip) // Skip conversion when writing the BOM. if (!(flags & FIO_NOCONVERT)) { - char_u *p; + char *p; unsigned c; int n; @@ -3794,7 +3775,7 @@ static int buf_write_bytes(struct bw_info *ip) // 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); + p += utf_char2bytes((uint8_t)buf[wlen], p); } buf = ip->bw_conv_buf; len = (int)(p - ip->bw_conv_buf); @@ -3818,7 +3799,7 @@ static int buf_write_bytes(struct bw_info *ip) l = len; } memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); - n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l); + n = utf_ptr2len_len((char *)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 @@ -3858,9 +3839,9 @@ static int buf_write_bytes(struct bw_info *ip) break; } if (n > 1) { - c = (unsigned)utf_ptr2char((char *)buf + wlen); + c = (unsigned)utf_ptr2char(buf + wlen); } else { - c = buf[wlen]; + c = (uint8_t)buf[wlen]; } } @@ -3880,7 +3861,6 @@ static int buf_write_bytes(struct bw_info *ip) } } -#ifdef HAVE_ICONV if (ip->bw_iconv_fd != (iconv_t)-1) { const char *from; size_t fromlen; @@ -3895,17 +3875,17 @@ static int buf_write_bytes(struct bw_info *ip) // 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; + fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen); memmove(fp + ip->bw_restlen, buf, (size_t)len); from = fp; tolen = ip->bw_conv_buflen - fromlen; } else { - from = (const char *)buf; + from = buf; fromlen = (size_t)len; tolen = ip->bw_conv_buflen; } - to = (char *)ip->bw_conv_buf; + to = ip->bw_conv_buf; if (ip->bw_first) { size_t save_len = tolen; @@ -3916,7 +3896,7 @@ static int buf_write_bytes(struct bw_info *ip) // 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; + to = ip->bw_conv_buf; tolen = save_len; } ip->bw_first = false; @@ -3937,9 +3917,8 @@ static int buf_write_bytes(struct bw_info *ip) ip->bw_restlen = (int)fromlen; buf = ip->bw_conv_buf; - len = (int)((char_u *)to - ip->bw_conv_buf); + len = (int)(to - ip->bw_conv_buf); } -#endif } if (ip->bw_fd < 0) { @@ -3957,9 +3936,9 @@ static int buf_write_bytes(struct bw_info *ip) /// @param flags FIO_ flags that specify which encoding to use /// /// @return true for an error, false when it's OK. -static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL +static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL { - char_u *p = *pp; + char_u *p = (char_u *)(*pp); bool error = false; int cc; @@ -4013,7 +3992,7 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL } } - *pp = p; + *pp = (char *)p; return error; } @@ -4036,8 +4015,8 @@ static bool need_conversion(const char *fenc) } 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((char_u *)fenc); + enc_flags = get_fio_flags(p_enc); + fenc_flags = get_fio_flags(fenc); same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); } if (same_encoding) { @@ -4055,12 +4034,12 @@ static bool need_conversion(const char *fenc) /// use 'encoding'. /// /// @param name string to check for encoding -static int get_fio_flags(const char_u *name) +static int get_fio_flags(const char *name) { int prop; if (*name == NUL) { - name = (char_u *)p_enc; + name = p_enc; } prop = enc_canon_props(name); if (prop & ENC_UNICODE) { @@ -4096,8 +4075,9 @@ 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 *check_for_bom(const char *p_in, long size, int *lenp, int flags) { + const uint8_t *p = (const uint8_t *)p_in; char *name = NULL; int len = 2; @@ -4133,16 +4113,16 @@ static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags) } *lenp = len; - return (char_u *)name; + return name; } /// Generate a BOM in "buf[4]" for encoding "name". /// /// @return the length of the BOM (zero when no BOM). -static int make_bom(char_u *buf, char_u *name) +static int make_bom(char_u *buf, char *name) { int flags; - char_u *p; + char *p; flags = get_fio_flags(name); @@ -4157,9 +4137,9 @@ static int make_bom(char_u *buf, char_u *name) buf[2] = 0xbf; return 3; } - p = buf; + p = (char *)buf; (void)ucs2bytes(0xfeff, &p, flags); - return (int)(p - buf); + return (int)((char_u *)p - buf); } /// Shorten filename of a buffer. @@ -4171,7 +4151,7 @@ static int make_bom(char_u *buf, char_u *name) /// /// For buffers that have buftype "nofile" or "scratch": never change the file /// name. -void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) +void shorten_buf_fname(buf_T *buf, char *dirname, int force) { char *p; @@ -4180,11 +4160,11 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) && !path_with_url(buf->b_fname) && (force || buf->b_sfname == NULL - || path_is_absolute((char_u *)buf->b_sfname))) { + || path_is_absolute(buf->b_sfname))) { if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } - p = path_shorten_fname(buf->b_ffname, (char *)dirname); + p = path_shorten_fname(buf->b_ffname, dirname); if (p != NULL) { buf->b_sfname = xstrdup(p); buf->b_fname = buf->b_sfname; @@ -4198,11 +4178,11 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) /// Shorten filenames for all buffers. void shorten_fnames(int force) { - char_u dirname[MAXPATHL]; + char dirname[MAXPATHL]; os_dirname(dirname, MAXPATHL); FOR_ALL_BUFFERS(buf) { - shorten_buf_fname(buf, dirname, force); + shorten_buf_fname(buf, (char *)dirname, force); // Always make the swap file name a full path, a "nofile" buffer may // also have a swap file. @@ -4247,7 +4227,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; @@ -4258,7 +4238,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 ':'. @@ -4276,12 +4256,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. @@ -4315,7 +4294,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; @@ -4324,7 +4304,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') { @@ -4518,7 +4498,7 @@ int vim_rename(const char *from, const char *to) } if (use_tmp_file) { - char_u tempname[MAXPATHL + 1]; + char 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". @@ -4527,17 +4507,17 @@ int vim_rename(const char *from, const char *to) } STRCPY(tempname, from); for (n = 123; n < 99999; n++) { - char *tail = path_tail((char *)tempname); - snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - (char *)tempname - 1)), "%d", n); + char *tail = path_tail(tempname); + snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n); - if (!os_path_exists((char *)tempname)) { - if (os_rename((char_u *)from, tempname) == OK) { - if (os_rename(tempname, (char_u *)to) == OK) { + if (!os_path_exists(tempname)) { + if (os_rename(from, tempname) == OK) { + if (os_rename(tempname, to) == OK) { return 0; } // Strange, the second step failed. Try moving the // file back and return failure. - (void)os_rename(tempname, (char_u *)from); + (void)os_rename(tempname, from); return -1; } // If it fails for one temp name it will most likely fail @@ -4555,7 +4535,7 @@ int vim_rename(const char *from, const char *to) os_remove((char *)to); // First try a normal rename, return if it works. - if (os_rename((char_u *)from, (char_u *)to) == OK) { + if (os_rename(from, to) == OK) { return 0; } @@ -4563,12 +4543,12 @@ int vim_rename(const char *from, const char *to) perm = os_getperm(from); #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. - acl = mch_get_acl((char_u *)from); + acl = os_get_acl(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; } @@ -4579,7 +4559,7 @@ int vim_rename(const char *from, const char *to) if (fd_out < 0) { close(fd_in); #ifdef HAVE_ACL - mch_free_acl(acl); + os_free_acl(acl); #endif return -1; } @@ -4591,7 +4571,7 @@ int vim_rename(const char *from, const char *to) close(fd_out); close(fd_in); #ifdef HAVE_ACL - mch_free_acl(acl); + os_free_acl(acl); #endif return -1; } @@ -4613,11 +4593,11 @@ int vim_rename(const char *from, const char *to) to = from; } #ifndef UNIX // For Unix os_open() already set the permission. - os_setperm((const char *)to, perm); + os_setperm(to, perm); #endif #ifdef HAVE_ACL - mch_set_acl((char_u *)to, acl); - mch_free_acl(acl); + os_set_acl(to, acl); + os_free_acl(acl); #endif if (errmsg != NULL) { semsg(errmsg, to); @@ -4924,7 +4904,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); @@ -4975,7 +4955,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 @@ -5122,11 +5102,11 @@ void write_lnum_adjust(linenr_T offset) #if defined(BACKSLASH_IN_FILENAME) /// Convert all backslashes in fname to forward slashes in-place, /// unless when it looks like a URL. -void forward_slash(char_u *fname) +void forward_slash(char *fname) { - char_u *p; + char *p; - if (path_with_url((const char *)fname)) { + if (path_with_url(fname)) { return; } for (p = fname; *p != NUL; p++) { @@ -5139,6 +5119,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. @@ -5211,10 +5194,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); } @@ -5281,7 +5263,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 **)ga.ga_data)[i]); if (delete_recursive((const char *)NameBuff) != 0) { // Remember the failure but continue deleting any further // entries. @@ -5304,15 +5286,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). @@ -5337,12 +5354,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; } @@ -5430,28 +5451,27 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, /// @param ffname full file name /// /// @return true if there was a match -bool match_file_list(char_u *list, char_u *sfname, char_u *ffname) +bool match_file_list(char *list, char *sfname, char *ffname) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) { - char_u buf[100]; - char_u *tail; - char_u *regpat; + char buf[100]; + char *tail; + char *regpat; char allow_dirs; bool match; char *p; - tail = (char_u *)path_tail((char *)sfname); + tail = path_tail(sfname); // try all patterns in 'wildignore' - p = (char *)list; + p = list; while (*p) { - copy_option_part(&p, (char *)buf, ARRAY_SIZE(buf), ","); - regpat = (char_u *)file_pat_to_reg_pat((char *)buf, NULL, &allow_dirs, false); + copy_option_part(&p, buf, ARRAY_SIZE(buf), ","); + regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); if (regpat == NULL) { break; } - match = match_file_pat((char *)regpat, NULL, (char *)ffname, (char *)sfname, (char *)tail, - (int)allow_dirs); + match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs); xfree(regpat); if (match) { return true; @@ -5560,7 +5580,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++] = '\\'; |