From 3c2bb1b2bec993cbcd6d65572c531aafbefa25a1 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 26 Jan 2023 15:17:23 +0000 Subject: refactor(fileio.c): reduce scope of locals --- src/nvim/fileio.c | 184 +++++++++++++++++++----------------------------------- 1 file changed, 63 insertions(+), 121 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 9da9d6199e..6b3e7dddb5 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -968,13 +968,11 @@ retry: if (read_buf_lnum > from) { size = 0; } else { - int n, ni; - long tlen; - - tlen = 0; + int ni; + long tlen = 0; for (;;) { p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; - n = (int)strlen((char *)p); + int 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 @@ -2126,7 +2124,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bool errmsg_allocated = false; char *buffer; char smallbuf[SMBUFSIZE]; - char *backup_ext; int bufsize; long perm; // file permissions int retval = OK; @@ -2555,8 +2552,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if ((bkc & BKC_YES) || append) { // "yes" backup_copy = true; } else if ((bkc & BKC_AUTO)) { // "auto" - int i; - // Don't rename the file when: // - it's a hard link // - it's a symbolic link @@ -2571,7 +2566,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // First find a file name that doesn't exist yet (use some // arbitrary numbers). STRCPY(IObuff, fname); - for (i = 4913;; i += 123) { + for (int i = 4913;; i += 123) { char *tail = path_tail(IObuff); size_t size = (size_t)(tail - IObuff); snprintf(tail, IOSIZE - size, "%d", i); @@ -2624,18 +2619,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } // make sure we have a valid backup extension to use - if (*p_bex == NUL) { - backup_ext = ".bak"; - } else { - backup_ext = p_bex; - } + char *backup_ext = *p_bex == NUL ? ".bak" : p_bex; if (backup_copy) { - char *wp; int some_error = false; - char *dirp; - char *rootname; - char *p; // Try to make the backup in each directory in the 'bdir' option. // @@ -2647,11 +2634,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // // For these reasons, the existing writable file must be truncated // and reused. Creation of a backup COPY will be attempted. - dirp = p_bdir; + char *dirp = p_bdir; while (*dirp) { // Isolate one directory name, using an entry in 'bdir'. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - p = IObuff + dir_len; + char *p = IObuff + dir_len; bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; @@ -2674,7 +2661,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } } - rootname = get_file_in_dir(fname, IObuff); + char *rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { some_error = true; // out of memory goto nobackup; @@ -2710,7 +2697,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); + char *wp = backup + strlen(backup) - 1 - strlen(backup_ext); if (wp < backup) { // empty file name ??? wp = backup; } @@ -2781,10 +2768,6 @@ nobackup: } SET_ERRMSG(NULL); } else { - char *dirp; - char *p; - char *rootname; - // Make a backup by renaming the original file. // If 'cpoptions' includes the "W" flag, we don't want to @@ -2798,11 +2781,11 @@ nobackup: // 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; + char *dirp = p_bdir; while (*dirp) { // Isolate one directory name and make the backup file name. size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - p = IObuff + dir_len; + char *p = IObuff + dir_len; bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2]; if (trailing_pathseps) { IObuff[dir_len - 2] = NUL; @@ -2826,7 +2809,7 @@ nobackup: } if (backup == NULL) { - rootname = get_file_in_dir(fname, IObuff); + char *rootname = get_file_in_dir(fname, IObuff); if (rootname == NULL) { backup = NULL; } else { @@ -3690,9 +3673,7 @@ 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 *p; - - p = IObuff + strlen(IObuff); + char *p = IObuff + strlen(IObuff); if (insert_space) { *p++ = ' '; @@ -3758,46 +3739,35 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F /// @return FAIL for failure, OK otherwise. static int buf_write_bytes(struct bw_info *ip) { - int wlen; - char *buf = ip->bw_buf; // data to write - int len = ip->bw_len; // length of data + 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 + int flags = ip->bw_flags; // extra flags #endif // Skip conversion when writing the BOM. if (!(flags & FIO_NOCONVERT)) { - char *p; - unsigned c; - int n; - if (flags & FIO_UTF8) { // 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++) { + char *p = ip->bw_conv_buf; // translate to buffer + for (int wlen = 0; wlen < len; wlen++) { p += utf_char2bytes((uint8_t)buf[wlen], p); } buf = ip->bw_conv_buf; len = (int)(p - ip->bw_conv_buf); } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { + unsigned c; + int n = 0; // 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 { - p = ip->bw_conv_buf; // translate to buffer - } - for (wlen = 0; wlen < len; wlen += n) { + // translate in-place (can only get shorter) or to buffer + char *p = flags & FIO_LATIN1 ? buf : ip->bw_conv_buf; + for (int wlen = 0; wlen < len; wlen += n) { 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! - l = CONV_RESTLEN - ip->bw_restlen; - if (l > len) { - l = len; - } + int l = MIN(len, CONV_RESTLEN - ip->bw_restlen); memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l); n = utf_ptr2len_len((char *)ip->bw_rest, ip->bw_restlen + l); if (n > ip->bw_restlen + len) { @@ -3864,18 +3834,15 @@ static int buf_write_bytes(struct bw_info *ip) if (ip->bw_iconv_fd != (iconv_t)-1) { const char *from; size_t fromlen; - char *to; size_t tolen; // Convert with iconv(). 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. fromlen = (size_t)len + (size_t)ip->bw_restlen; - fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen; + char *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; @@ -3885,7 +3852,7 @@ static int buf_write_bytes(struct bw_info *ip) fromlen = (size_t)len; tolen = ip->bw_conv_buflen; } - to = ip->bw_conv_buf; + char *to = ip->bw_conv_buf; if (ip->bw_first) { size_t save_len = tolen; @@ -3925,7 +3892,7 @@ static int buf_write_bytes(struct bw_info *ip) // Only checking conversion, which is OK if we get here. return OK; } - wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len); + int wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len); return (wlen < len) ? FAIL : OK; } @@ -3940,7 +3907,6 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL { char_u *p = (char_u *)(*pp); bool error = false; - int cc; if (flags & FIO_UCS4) { if (flags & FIO_ENDIAN_L) { @@ -3963,7 +3929,7 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL if (c >= 0x100000) { error = true; } - cc = (int)(((c >> 10) & 0x3ff) + 0xd800); + int cc = (int)(((c >> 10) & 0x3ff) + 0xd800); if (flags & FIO_ENDIAN_L) { *p++ = (uint8_t)cc; *p++ = (uint8_t)(cc >> 8); @@ -4006,7 +3972,6 @@ 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) { @@ -4015,7 +3980,7 @@ 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(p_enc); + int enc_flags = get_fio_flags(p_enc); fenc_flags = get_fio_flags(fenc); same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); } @@ -4036,12 +4001,10 @@ static bool need_conversion(const char *fenc) /// @param name string to check for encoding static int get_fio_flags(const char *name) { - int prop; - if (*name == NUL) { name = p_enc; } - prop = enc_canon_props(name); + int prop = enc_canon_props(name); if (prop & ENC_UNICODE) { if (prop & ENC_2BYTE) { if (prop & ENC_ENDIAN_L) { @@ -4121,10 +4084,7 @@ static char *check_for_bom(const char *p_in, long size, int *lenp, int flags) /// @return the length of the BOM (zero when no BOM). static int make_bom(char_u *buf, char *name) { - int flags; - char *p; - - flags = get_fio_flags(name); + int flags = get_fio_flags(name); // Can't put a BOM in a non-Unicode file. if (flags == FIO_LATIN1 || flags == 0) { @@ -4137,7 +4097,7 @@ static int make_bom(char_u *buf, char *name) buf[2] = 0xbf; return 3; } - p = (char *)buf; + char *p = (char *)buf; (void)ucs2bytes(0xfeff, &p, flags); return (int)((char_u *)p - buf); } @@ -4153,8 +4113,6 @@ static int make_bom(char_u *buf, char *name) /// name. void shorten_buf_fname(buf_T *buf, char *dirname, int force) { - char *p; - if (buf->b_fname != NULL && !bt_nofilename(buf) && !path_with_url(buf->b_fname) @@ -4164,7 +4122,7 @@ void shorten_buf_fname(buf_T *buf, char *dirname, int force) if (buf->b_sfname != buf->b_ffname) { XFREE_CLEAR(buf->b_sfname); } - p = path_shorten_fname(buf->b_ffname, dirname); + char *p = path_shorten_fname(buf->b_ffname, dirname); if (p != NULL) { buf->b_sfname = xstrdup(p); buf->b_fname = buf->b_sfname; @@ -4461,10 +4419,7 @@ int vim_rename(const char *from, const char *to) { int fd_in; int fd_out; - int n; char *errmsg = NULL; - char *buffer; - long perm; #ifdef HAVE_ACL vim_acl_T acl; // ACL from original file #endif @@ -4506,7 +4461,7 @@ int vim_rename(const char *from, const char *to) return -1; } STRCPY(tempname, from); - for (n = 123; n < 99999; n++) { + for (int n = 123; n < 99999; n++) { char *tail = path_tail(tempname); snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n); @@ -4540,7 +4495,7 @@ int vim_rename(const char *from, const char *to) } // Rename() failed, try copying the file. - perm = os_getperm(from); + long perm = os_getperm(from); #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. acl = os_get_acl(from); @@ -4566,7 +4521,7 @@ int vim_rename(const char *from, const char *to) // Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim // is `preserve_exit()`ing. - buffer = try_malloc(BUFSIZE); + char *buffer = try_malloc(BUFSIZE); if (buffer == NULL) { close(fd_out); close(fd_in); @@ -4576,6 +4531,7 @@ int vim_rename(const char *from, const char *to) return -1; } + int n; while ((n = (int)read_eintr(fd_in, buffer, BUFSIZE)) > 0) { if (write_eintr(fd_out, buffer, (size_t)n) != n) { errmsg = _("E208: Error writing to \"%s\""); @@ -4619,8 +4575,6 @@ static int already_warned = false; /// @return true if some message was written (screen should be redrawn and cursor positioned). int check_timestamps(int focus) { - int didit = 0; - // Don't check timestamps while system() or another low-level function may // cause us to lose and gain focus. if (no_check_timestamps > 0) { @@ -4635,6 +4589,8 @@ int check_timestamps(int focus) return false; } + int didit = 0; + if (!stuff_empty() || global_busy || !typebuf_typed() || autocmd_busy || curbuf->b_ro_locked > 0 || allbuf_lock > 0) { @@ -4678,13 +4634,11 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) { buf_T *tbuf = curbuf; int retval = OK; - linenr_T lnum; - char *p; // Copy the lines in "frombuf" to "tobuf". curbuf = tobuf; - for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { - p = xstrdup(ml_get_buf(frombuf, lnum, false)); + for (linenr_T lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { + char *p = xstrdup(ml_get_buf(frombuf, lnum, false)); if (ml_append(lnum - 1, p, 0, false) == FAIL) { xfree(p); retval = FAIL; @@ -4696,7 +4650,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) // Delete all the lines in "frombuf". if (retval != FAIL) { curbuf = frombuf; - for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { + for (linenr_T lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { if (ml_delete(lnum, false) == FAIL) { // Oops! We could try putting back the saved lines, but that // might fail again... @@ -4720,7 +4674,6 @@ int buf_check_timestamp(buf_T *buf) FUNC_ATTR_NONNULL_ALL { int retval = 0; - char *path; char *mesg = NULL; char *mesg2 = ""; bool helpmesg = false; @@ -4735,8 +4688,6 @@ 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 *s; - char *reason; bufref_T bufref; set_bufref(&bufref, buf); @@ -4784,6 +4735,7 @@ int buf_check_timestamp(buf_T *buf) // was set, the global option value otherwise. reload = RELOAD_NORMAL; } else { + char *reason; if (!file_info_ok) { reason = "deleted"; } else if (bufIsChanged(buf)) { @@ -4810,7 +4762,7 @@ int buf_check_timestamp(buf_T *buf) if (!bufref_valid(&bufref)) { emsg(_("E246: FileChangedShell autocommand deleted buffer")); } - s = get_vim_var_str(VV_FCS_CHOICE); + char *s = get_vim_var_str(VV_FCS_CHOICE); if (strcmp(s, "reload") == 0 && *reason != 'd') { reload = RELOAD_NORMAL; } else if (strcmp(s, "edit") == 0) { @@ -4863,7 +4815,7 @@ int buf_check_timestamp(buf_T *buf) } if (mesg != NULL) { - path = home_replace_save(buf, buf->b_fname); + char *path = home_replace_save(buf, buf->b_fname); if (!helpmesg) { mesg2 = ""; } @@ -4946,8 +4898,6 @@ int buf_check_timestamp(buf_T *buf) void buf_reload(buf_T *buf, int orig_mode, bool reload_options) { exarg_T ea; - pos_T old_cursor; - linenr_T old_topline; int old_ro = buf->b_p_ro; buf_T *savebuf; bufref_T bufref; @@ -4967,8 +4917,8 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) prep_exarg(&ea, buf); } - old_cursor = curwin->w_cursor; - old_topline = curwin->w_topline; + pos_T old_cursor = curwin->w_cursor; + linenr_T old_topline = curwin->w_topline; if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) { // Save all the text, so that the reload can be undone. @@ -5454,24 +5404,19 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, bool match_file_list(char *list, char *sfname, char *ffname) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3) { - char buf[100]; - char *tail; - char *regpat; - char allow_dirs; - bool match; - char *p; - - tail = path_tail(sfname); + char *tail = path_tail(sfname); // try all patterns in 'wildignore' - p = list; + char *p = list; while (*p) { + char buf[100]; copy_option_part(&p, buf, ARRAY_SIZE(buf), ","); - regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); + char allow_dirs; + char *regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); if (regpat == NULL) { break; } - match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs); + bool match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs); xfree(regpat); if (match) { return true; @@ -5494,15 +5439,6 @@ bool match_file_list(char *list, char *sfname, char *ffname) char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash) FUNC_ATTR_NONNULL_ARG(1) { - const char *endp; - char *reg_pat; - const char *p; - int nested = 0; - bool add_dollar = true; - - if (allow_dirs != NULL) { - *allow_dirs = false; - } if (pat_end == NULL) { pat_end = pat + strlen(pat); } @@ -5511,9 +5447,13 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs return xstrdup("^$"); } + if (allow_dirs != NULL) { + *allow_dirs = false; + } + size_t size = 2; // '^' at start, '$' at end. - for (p = pat; p < pat_end; p++) { + for (const char *p = pat; p < pat_end; p++) { switch (*p) { case '*': case '.': @@ -5534,7 +5474,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs break; } } - reg_pat = xmalloc(size + 1); + char *reg_pat = xmalloc(size + 1); size_t i = 0; @@ -5545,14 +5485,16 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs } else { reg_pat[i++] = '^'; } - endp = pat_end - 1; + const char *endp = pat_end - 1; + bool add_dollar = true; if (endp >= pat && *endp == '*') { while (endp - pat > 0 && *endp == '*') { endp--; } add_dollar = false; } - for (p = pat; *p && nested >= 0 && p <= endp; p++) { + int nested = 0; + for (const char *p = pat; *p && nested >= 0 && p <= endp; p++) { switch (*p) { case '*': reg_pat[i++] = '.'; -- cgit From b4c4c232ba6fe3df5c6f12faff4405a16e4d40df Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 28 Jan 2023 13:06:45 +0800 Subject: fix(fileio.c): don't use uninitialized memory (#22031) --- src/nvim/fileio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 6b3e7dddb5..fbb5c4f1fa 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -5439,6 +5439,10 @@ bool match_file_list(char *list, char *sfname, char *ffname) char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash) FUNC_ATTR_NONNULL_ARG(1) { + if (allow_dirs != NULL) { + *allow_dirs = false; + } + if (pat_end == NULL) { pat_end = pat + strlen(pat); } @@ -5447,10 +5451,6 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs return xstrdup("^$"); } - if (allow_dirs != NULL) { - *allow_dirs = false; - } - size_t size = 2; // '^' at start, '$' at end. for (const char *p = pat; p < pat_end; p++) { -- cgit From b7d09695c4107bfbe03e9755f22e65027a8b18c2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 13:02:50 +0000 Subject: refactor(fileio.c): refactor match_file_path() --- src/nvim/fileio.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fbb5c4f1fa..6bd1655ebc 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -5363,13 +5363,7 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, bool result = false; regmatch.rm_ic = p_fic; // ignore case if 'fileignorecase' is set - { - if (prog != NULL) { - regmatch.regprog = *prog; - } else { - regmatch.regprog = vim_regcomp(pattern, RE_MAGIC); - } - } + regmatch.regprog = prog != NULL ? *prog : vim_regcomp(pattern, RE_MAGIC); // Try for a match with the pattern with: // 1. the full file name, when the pattern has a '/'. -- cgit From 99149153c40725859ca7f4db17ff9018f29c3529 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 13:03:10 +0000 Subject: refactor(fileio.c): refactor vim_rename() --- src/nvim/fileio.c | 73 +++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 37 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 6bd1655ebc..7826071424 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -4410,6 +4410,38 @@ int put_time(FILE *fd, time_t time_) return fwrite(buf, sizeof(uint8_t), ARRAY_SIZE(buf), fd) == 1 ? OK : FAIL; } +static int rename_with_tmp(const char *const from, const char *const to) +{ + // 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; + } + + char tempname[MAXPATHL + 1]; + STRCPY(tempname, from); + for (int n = 123; n < 99999; n++) { + char *tail = path_tail(tempname); + snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n); + + 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, from); + return -1; + } + // If it fails for one temp name it will most likely fail + // for any temp name, give up. + return -1; + } + } + return -1; +} + /// os_rename() only works if both files are on the same file system, this /// function will (attempts to?) copy the file across if rename fails -- webb /// @@ -4417,12 +4449,7 @@ int put_time(FILE *fd, time_t time_) int vim_rename(const char *from, const char *to) FUNC_ATTR_NONNULL_ALL { - int fd_in; - int fd_out; char *errmsg = NULL; -#ifdef HAVE_ACL - vim_acl_T acl; // ACL from original file -#endif bool use_tmp_file = false; // When the names are identical, there is nothing to do. When they refer @@ -4453,34 +4480,7 @@ int vim_rename(const char *from, const char *to) } if (use_tmp_file) { - 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". - if (strlen(from) >= MAXPATHL - 5) { - return -1; - } - STRCPY(tempname, from); - for (int n = 123; n < 99999; n++) { - char *tail = path_tail(tempname); - snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n); - - 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, from); - return -1; - } - // If it fails for one temp name it will most likely fail - // for any temp name, give up. - return -1; - } - } - return -1; + return rename_with_tmp(from, to); } // Delete the "to" file, this is required on some systems to make the @@ -4498,9 +4498,9 @@ int vim_rename(const char *from, const char *to) long perm = os_getperm(from); #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. - acl = os_get_acl(from); + vim_acl_T acl = os_get_acl(from); #endif - fd_in = os_open((char *)from, O_RDONLY, 0); + int fd_in = os_open((char *)from, O_RDONLY, 0); if (fd_in < 0) { #ifdef HAVE_ACL os_free_acl(acl); @@ -4509,8 +4509,7 @@ int vim_rename(const char *from, const char *to) } // Create the new file with same permissions as the original. - fd_out = os_open((char *)to, - O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm); + int fd_out = os_open((char *)to, O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm); if (fd_out < 0) { close(fd_in); #ifdef HAVE_ACL -- cgit From f770e05c8718bc885f93585a211c5dd1c621ed01 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 13:11:53 +0000 Subject: refactor(fileio.c): refactor buf_write_bytes --- src/nvim/fileio.c | 113 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 51 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 7826071424..27ae622172 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3733,6 +3733,67 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F #endif } +static int buf_write_convert_with_iconv(struct bw_info *ip, char **bufp, int *lenp) +{ + const char *from; + size_t fromlen; + size_t tolen; + + int len = *lenp; + + // Convert with iconv(). + if (ip->bw_restlen > 0) { + // 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; + char *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, *bufp, (size_t)len); + from = fp; + tolen = ip->bw_conv_buflen - fromlen; + } else { + from = *bufp; + fromlen = (size_t)len; + tolen = ip->bw_conv_buflen; + } + char *to = ip->bw_conv_buf; + + if (ip->bw_first) { + size_t save_len = tolen; + + // 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". + if (to == NULL) { + to = ip->bw_conv_buf; + tolen = save_len; + } + ip->bw_first = false; + } + + // 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) { + ip->bw_conv_error = true; + return FAIL; + } + + // copy remainder to ip->bw_rest[] to be used for the next call. + if (fromlen > 0) { + memmove(ip->bw_rest, (void *)from, fromlen); + } + ip->bw_restlen = (int)fromlen; + + *bufp = ip->bw_conv_buf; + *lenp = (int)(to - ip->bw_conv_buf); + + return OK; +} + /// Call write() to write a number of bytes to the file. /// Handles 'encoding' conversion. /// @@ -3832,59 +3893,9 @@ static int buf_write_bytes(struct bw_info *ip) } if (ip->bw_iconv_fd != (iconv_t)-1) { - const char *from; - size_t fromlen; - size_t tolen; - - // Convert with iconv(). - if (ip->bw_restlen > 0) { - // 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; - char *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 = buf; - fromlen = (size_t)len; - tolen = ip->bw_conv_buflen; - } - char *to = ip->bw_conv_buf; - - if (ip->bw_first) { - size_t save_len = tolen; - - // 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". - if (to == NULL) { - to = ip->bw_conv_buf; - tolen = save_len; - } - ip->bw_first = false; - } - - // 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) { - ip->bw_conv_error = true; + if (buf_write_convert_with_iconv(ip, &buf, &len) == FAIL) { return FAIL; } - - // copy remainder to ip->bw_rest[] to be used for the next call. - if (fromlen > 0) { - memmove(ip->bw_rest, (void *)from, fromlen); - } - ip->bw_restlen = (int)fromlen; - - buf = ip->bw_conv_buf; - len = (int)(to - ip->bw_conv_buf); } } -- cgit From 740f6ae168bf845360ee01442837237b717d53c6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 13:18:00 +0000 Subject: refactor(fileio.c): refactor buf_write_bytes (2) --- src/nvim/fileio.c | 187 +++++++++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 88 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 27ae622172..e2138485e9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3794,6 +3794,103 @@ static int buf_write_convert_with_iconv(struct bw_info *ip, char **bufp, int *le return OK; } +static int buf_write_convert(struct bw_info *ip, char **bufp, int *lenp) +{ + int flags = ip->bw_flags; // extra flags + + if (flags & FIO_UTF8) { + // Convert latin1 in the buffer to UTF-8 in the file. + char *p = ip->bw_conv_buf; // translate to buffer + for (int wlen = 0; wlen < *lenp; wlen++) { + p += utf_char2bytes((uint8_t)(*bufp)[wlen], p); + } + *bufp = ip->bw_conv_buf; + *lenp = (int)(p - ip->bw_conv_buf); + } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { + unsigned c; + int n = 0; + // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or + // Latin1 chars in the file. + // translate in-place (can only get shorter) or to buffer + char *p = flags & FIO_LATIN1 ? *bufp : ip->bw_conv_buf; + for (int wlen = 0; wlen < *lenp; wlen += n) { + if (wlen == 0 && ip->bw_restlen != 0) { + // Use remainder of previous call. Append the start of + // buf[] to get a full sequence. Might still be too + // short! + int l = MIN(*lenp, CONV_RESTLEN - ip->bw_restlen); + memmove(ip->bw_rest + ip->bw_restlen, *bufp, (size_t)l); + n = utf_ptr2len_len((char *)ip->bw_rest, ip->bw_restlen + l); + if (n > ip->bw_restlen + *lenp) { + // 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 + *lenp > CONV_RESTLEN) { + return FAIL; + } + ip->bw_restlen += *lenp; + break; + } + if (n > 1) { + c = (unsigned)utf_ptr2char((char *)ip->bw_rest); + } else { + c = ip->bw_rest[0]; + } + if (n >= ip->bw_restlen) { + n -= ip->bw_restlen; + ip->bw_restlen = 0; + } else { + ip->bw_restlen -= n; + memmove(ip->bw_rest, ip->bw_rest + n, + (size_t)ip->bw_restlen); + n = 0; + } + } else { + n = utf_ptr2len_len(*bufp + wlen, *lenp - wlen); + if (n > *lenp - 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. + if (*lenp - wlen > CONV_RESTLEN) { + return FAIL; + } + ip->bw_restlen = *lenp - wlen; + memmove(ip->bw_rest, *bufp + wlen, + (size_t)ip->bw_restlen); + break; + } + if (n > 1) { + c = (unsigned)utf_ptr2char(*bufp + wlen); + } else { + c = (uint8_t)(*bufp)[wlen]; + } + } + + if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) { + ip->bw_conv_error = true; + ip->bw_conv_error_lnum = ip->bw_start_lnum; + } + if (c == NL) { + ip->bw_start_lnum++; + } + } + if (flags & FIO_LATIN1) { + *lenp = (int)(p - *bufp); + } else { + *bufp = ip->bw_conv_buf; + *lenp = (int)(p - ip->bw_conv_buf); + } + } + + if (ip->bw_iconv_fd != (iconv_t)-1) { + if (buf_write_convert_with_iconv(ip, bufp, lenp) == FAIL) { + return FAIL; + } + } + + return OK; +} + /// Call write() to write a number of bytes to the file. /// Handles 'encoding' conversion. /// @@ -3808,94 +3905,8 @@ static int buf_write_bytes(struct bw_info *ip) // Skip conversion when writing the BOM. if (!(flags & FIO_NOCONVERT)) { - if (flags & FIO_UTF8) { - // Convert latin1 in the buffer to UTF-8 in the file. - char *p = ip->bw_conv_buf; // translate to buffer - for (int wlen = 0; wlen < len; wlen++) { - p += utf_char2bytes((uint8_t)buf[wlen], p); - } - buf = ip->bw_conv_buf; - len = (int)(p - ip->bw_conv_buf); - } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { - unsigned c; - int n = 0; - // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or - // Latin1 chars in the file. - // translate in-place (can only get shorter) or to buffer - char *p = flags & FIO_LATIN1 ? buf : ip->bw_conv_buf; - for (int wlen = 0; wlen < len; wlen += n) { - if (wlen == 0 && ip->bw_restlen != 0) { - // Use remainder of previous call. Append the start of - // buf[] to get a full sequence. Might still be too - // short! - int l = MIN(len, CONV_RESTLEN - ip->bw_restlen); - memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)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 - // remaining bytes. Keep them for the next call. - if (ip->bw_restlen + len > CONV_RESTLEN) { - return FAIL; - } - ip->bw_restlen += len; - break; - } - if (n > 1) { - c = (unsigned)utf_ptr2char((char *)ip->bw_rest); - } else { - c = ip->bw_rest[0]; - } - if (n >= ip->bw_restlen) { - n -= ip->bw_restlen; - ip->bw_restlen = 0; - } else { - ip->bw_restlen -= n; - memmove(ip->bw_rest, ip->bw_rest + n, - (size_t)ip->bw_restlen); - n = 0; - } - } 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. - if (len - wlen > CONV_RESTLEN) { - return FAIL; - } - ip->bw_restlen = len - wlen; - memmove(ip->bw_rest, buf + wlen, - (size_t)ip->bw_restlen); - break; - } - if (n > 1) { - c = (unsigned)utf_ptr2char(buf + wlen); - } else { - c = (uint8_t)buf[wlen]; - } - } - - if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) { - ip->bw_conv_error = true; - ip->bw_conv_error_lnum = ip->bw_start_lnum; - } - if (c == NL) { - ip->bw_start_lnum++; - } - } - if (flags & FIO_LATIN1) { - len = (int)(p - buf); - } else { - buf = ip->bw_conv_buf; - len = (int)(p - ip->bw_conv_buf); - } - } - - if (ip->bw_iconv_fd != (iconv_t)-1) { - if (buf_write_convert_with_iconv(ip, &buf, &len) == FAIL) { - return FAIL; - } + if (buf_write_convert(ip, &buf, &len) == FAIL) { + return FAIL; } } -- cgit From f4b1f0d042a910f069cde9f336bb4d2a8443713c Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 13:18:46 +0000 Subject: refactor(fileio.c): remove HAS_BW_FLAGS --- src/nvim/fileio.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index e2138485e9..826b25cd3e 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -81,7 +81,6 @@ # define UV_FS_COPYFILE_FICLONE 0 #endif -#define HAS_BW_FLAGS enum { FIO_LATIN1 = 0x01, // convert Latin1 FIO_UTF8 = 0x02, // convert UTF-8 @@ -107,9 +106,7 @@ struct bw_info { int bw_fd; // file descriptor char *bw_buf; // buffer with data to be written int bw_len; // length of data -#ifdef HAS_BW_FLAGS int bw_flags; // FIO_ flags -#endif char_u bw_rest[CONV_RESTLEN]; // not converted bytes int bw_restlen; // nr of bytes in bw_rest[] int bw_first; // first write call @@ -2150,9 +2147,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en int notconverted = false; char *fenc; // effective 'fileencoding' char *fenc_tofree = NULL; // allocated "fenc" -#ifdef HAS_BW_FLAGS int wb_flags = 0; -#endif #ifdef HAVE_ACL vim_acl_T acl = NULL; // ACL copied from original file to // backup or new file @@ -3117,9 +3112,7 @@ restore_backup: } write_info.bw_len = bufsize; -#ifdef HAS_BW_FLAGS write_info.bw_flags = wb_flags; -#endif fileformat = get_fileformat_force(buf, eap); s = buffer; len = 0; @@ -3899,9 +3892,7 @@ static int buf_write_bytes(struct bw_info *ip) { 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 -#endif // Skip conversion when writing the BOM. if (!(flags & FIO_NOCONVERT)) { -- cgit From b001f25204042ada6459d13f21ff29dfa0ba494c Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 13:39:15 +0000 Subject: refactor(fileio.c): factor out autocmd handling from buf_write() --- src/nvim/fileio.c | 363 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 190 insertions(+), 173 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 826b25cd3e..e81d5f614f 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2076,6 +2076,188 @@ char *new_file_message(void) return shortmess(SHM_NEW) ? _("[New]") : _("[New File]"); } +static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char **ffnamep, + linenr_T start, linenr_T *endp, exarg_T *eap, bool append, + bool filtering, bool reset_changed, bool overwriting, bool whole, + const pos_T orig_start, const pos_T orig_end) +{ + linenr_T old_line_count = buf->b_ml.ml_line_count; + int msg_save = msg_scroll; + + aco_save_T aco; + int buf_ffname = false; + int buf_sfname = false; + int buf_fname_f = false; + int buf_fname_s = false; + int did_cmd = false; + int nofile_err = false; + int empty_memline = (buf->b_ml.ml_mfp == NULL); + bufref_T bufref; + + char *sfname = *sfnamep; + + // Apply PRE autocommands. + // Set curbuf to the buffer to be written. + // Careful: The autocommands may call buf_write() recursively! + if (*ffnamep == buf->b_ffname) { + buf_ffname = true; + } + if (sfname == buf->b_sfname) { + buf_sfname = true; + } + if (*fnamep == buf->b_ffname) { + buf_fname_f = true; + } + if (*fnamep == buf->b_sfname) { + buf_fname_s = true; + } + + // Set curwin/curbuf to buf and save a few things. + aucmd_prepbuf(&aco, buf); + set_bufref(&bufref, buf); + + if (append) { + if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, + sfname, sfname, false, curbuf, eap))) { + if (overwriting && bt_nofilename(curbuf)) { + nofile_err = true; + } else { + apply_autocmds_exarg(EVENT_FILEAPPENDPRE, + sfname, sfname, false, curbuf, eap); + } + } + } else if (filtering) { + apply_autocmds_exarg(EVENT_FILTERWRITEPRE, + NULL, sfname, false, curbuf, eap); + } else if (reset_changed && whole) { + int was_changed = curbufIsChanged(); + + did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, + sfname, sfname, false, curbuf, eap); + if (did_cmd) { + if (was_changed && !curbufIsChanged()) { + // Written everything correctly and BufWriteCmd has reset + // 'modified': Correct the undo information so that an + // undo now sets 'modified'. + u_unchanged(curbuf); + u_update_save_nr(curbuf); + } + } else { + if (overwriting && bt_nofilename(curbuf)) { + nofile_err = true; + } else { + apply_autocmds_exarg(EVENT_BUFWRITEPRE, + sfname, sfname, false, curbuf, eap); + } + } + } else { + if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, + sfname, sfname, false, curbuf, eap))) { + if (overwriting && bt_nofilename(curbuf)) { + nofile_err = true; + } else { + apply_autocmds_exarg(EVENT_FILEWRITEPRE, + sfname, sfname, false, curbuf, eap); + } + } + } + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + + // In three situations we return here and don't write the file: + // 1. the autocommands deleted or unloaded the buffer. + // 2. The autocommands abort script processing. + // 3. If one of the "Cmd" autocommands was executed. + if (!bufref_valid(&bufref)) { + buf = NULL; + } + if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) + || did_cmd || nofile_err + || aborting()) { + if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) { + // restore the original '[ and '] positions + buf->b_op_start = orig_start; + buf->b_op_end = orig_end; + } + + no_wait_return--; + msg_scroll = msg_save; + if (nofile_err) { + semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt); + } + + if (nofile_err + || aborting()) { + // An aborting error, interrupt or exception in the + // autocommands. + return FAIL; + } + if (did_cmd) { + if (buf == NULL) { + // The buffer was deleted. We assume it was written + // (can't retry anyway). + return OK; + } + if (overwriting) { + // Assume the buffer was written, update the timestamp. + ml_timestamp(buf); + if (append) { + buf->b_flags &= ~BF_NEW; + } else { + buf->b_flags &= ~BF_WRITE_MASK; + } + } + if (reset_changed && buf->b_changed && !append + && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { + // Buffer still changed, the autocommands didn't work properly. + return FAIL; + } + return OK; + } + if (!aborting()) { + emsg(_("E203: Autocommands deleted or unloaded buffer to be written")); + } + return FAIL; + } + + // 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 + *endp = buf->b_ml.ml_line_count; + } else if (buf->b_ml.ml_line_count > old_line_count) { // more lines + *endp += buf->b_ml.ml_line_count - old_line_count; + } else { // less lines + *endp -= old_line_count - buf->b_ml.ml_line_count; + if (*endp < start) { + no_wait_return--; + msg_scroll = msg_save; + emsg(_("E204: Autocommand changed number of lines in unexpected way")); + return FAIL; + } + } + } + + // The autocommands may have changed the name of the buffer, which may + // be kept in fname, ffname and sfname. + if (buf_ffname) { + *ffnamep = buf->b_ffname; + } + if (buf_sfname) { + *sfnamep = buf->b_sfname; + } + if (buf_fname_f) { + *fnamep = buf->b_ffname; + } + if (buf_fname_s) { + *fnamep = buf->b_sfname; + } + return NOTDONE; +} + /// buf_write() - write to file "fname" lines "start" through "end" /// /// We do our own buffering here because fwrite() is so slow. @@ -2139,7 +2321,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #endif // writing everything int whole = (start == 1 && end == buf->b_ml.ml_line_count); - linenr_T old_line_count = buf->b_ml.ml_line_count; int fileformat; int write_bin; struct bw_info write_info; // info for buf_write_bytes() @@ -2155,8 +2336,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en int write_undo_file = false; context_sha256_T sha_ctx; unsigned int bkc = get_bkc_value(buf); - const pos_T orig_start = buf->b_op_start; - const pos_T orig_end = buf->b_op_end; if (fname == NULL || *fname == NUL) { // safety check return FAIL; @@ -2230,182 +2409,20 @@ 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 + const pos_T orig_start = buf->b_op_start; + const pos_T orig_end = buf->b_op_end; + // Set '[ and '] marks to the lines to be written. buf->b_op_start.lnum = start; buf->b_op_start.col = 0; buf->b_op_end.lnum = end; buf->b_op_end.col = 0; - { - aco_save_T aco; - int buf_ffname = false; - int buf_sfname = false; - int buf_fname_f = false; - int buf_fname_s = false; - int did_cmd = false; - int nofile_err = false; - int empty_memline = (buf->b_ml.ml_mfp == NULL); - bufref_T bufref; - - // Apply PRE autocommands. - // Set curbuf to the buffer to be written. - // Careful: The autocommands may call buf_write() recursively! - if (ffname == buf->b_ffname) { - buf_ffname = true; - } - if (sfname == buf->b_sfname) { - buf_sfname = true; - } - if (fname == buf->b_ffname) { - buf_fname_f = true; - } - if (fname == buf->b_sfname) { - buf_fname_s = true; - } - - // Set curwin/curbuf to buf and save a few things. - aucmd_prepbuf(&aco, buf); - set_bufref(&bufref, buf); - - if (append) { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, - sfname, sfname, false, curbuf, eap))) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEAPPENDPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else if (filtering) { - apply_autocmds_exarg(EVENT_FILTERWRITEPRE, - NULL, sfname, false, curbuf, eap); - } else if (reset_changed && whole) { - int was_changed = curbufIsChanged(); - - did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, - sfname, sfname, false, curbuf, eap); - if (did_cmd) { - if (was_changed && !curbufIsChanged()) { - // Written everything correctly and BufWriteCmd has reset - // 'modified': Correct the undo information so that an - // undo now sets 'modified'. - u_unchanged(curbuf); - u_update_save_nr(curbuf); - } - } else { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_BUFWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, - sfname, sfname, false, curbuf, eap))) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } - } - - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - - // In three situations we return here and don't write the file: - // 1. the autocommands deleted or unloaded the buffer. - // 2. The autocommands abort script processing. - // 3. If one of the "Cmd" autocommands was executed. - if (!bufref_valid(&bufref)) { - buf = NULL; - } - if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) - || did_cmd || nofile_err - || aborting()) { - if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) { - // restore the original '[ and '] positions - buf->b_op_start = orig_start; - buf->b_op_end = orig_end; - } - - no_wait_return--; - msg_scroll = msg_save; - if (nofile_err) { - semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt); - } - - if (nofile_err - || aborting()) { - // An aborting error, interrupt or exception in the - // autocommands. - return FAIL; - } - if (did_cmd) { - if (buf == NULL) { - // The buffer was deleted. We assume it was written - // (can't retry anyway). - return OK; - } - if (overwriting) { - // Assume the buffer was written, update the timestamp. - ml_timestamp(buf); - if (append) { - buf->b_flags &= ~BF_NEW; - } else { - buf->b_flags &= ~BF_WRITE_MASK; - } - } - if (reset_changed && buf->b_changed && !append - && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { - // Buffer still changed, the autocommands didn't work properly. - return FAIL; - } - return OK; - } - if (!aborting()) { - emsg(_("E203: Autocommands deleted or unloaded buffer to be written")); - } - return FAIL; - } - - // 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; - } else if (buf->b_ml.ml_line_count > old_line_count) { // more lines - end += buf->b_ml.ml_line_count - old_line_count; - } else { // less lines - end -= old_line_count - buf->b_ml.ml_line_count; - if (end < start) { - no_wait_return--; - msg_scroll = msg_save; - emsg(_("E204: Autocommand changed number of lines in unexpected way")); - return FAIL; - } - } - } - - // 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; - } - if (buf_sfname) { - sfname = buf->b_sfname; - } - if (buf_fname_f) { - fname = buf->b_ffname; - } - if (buf_fname_s) { - fname = buf->b_sfname; - } + int res = buf_write_do_autocmds(buf, &fname, &sfname, &ffname, start, &end, eap, append, + filtering, reset_changed, overwriting, whole, orig_start, + orig_end); + if (res != NOTDONE) { + return res; } if (cmdmod.cmod_flags & CMOD_LOCKMARKS) { -- cgit From 253a4d7074bd2ed31e26ed663aedda66e8dca833 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 13:58:07 +0000 Subject: refactor(fileio.c): more bools --- src/nvim/fileio.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index e81d5f614f..c7fcd85c7e 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2085,13 +2085,9 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char int msg_save = msg_scroll; aco_save_T aco; - int buf_ffname = false; - int buf_sfname = false; - int buf_fname_f = false; - int buf_fname_s = false; - int did_cmd = false; - int nofile_err = false; - int empty_memline = (buf->b_ml.ml_mfp == NULL); + bool did_cmd = false; + bool nofile_err = false; + bool empty_memline = buf->b_ml.ml_mfp == NULL; bufref_T bufref; char *sfname = *sfnamep; @@ -2099,26 +2095,18 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char // Apply PRE autocommands. // Set curbuf to the buffer to be written. // Careful: The autocommands may call buf_write() recursively! - if (*ffnamep == buf->b_ffname) { - buf_ffname = true; - } - if (sfname == buf->b_sfname) { - buf_sfname = true; - } - if (*fnamep == buf->b_ffname) { - buf_fname_f = true; - } - if (*fnamep == buf->b_sfname) { - buf_fname_s = true; - } + bool buf_ffname = *ffnamep == buf->b_ffname; + bool buf_sfname = sfname == buf->b_sfname; + bool buf_fname_f = *fnamep == buf->b_ffname; + bool buf_fname_s = *fnamep == buf->b_sfname; // Set curwin/curbuf to buf and save a few things. aucmd_prepbuf(&aco, buf); set_bufref(&bufref, buf); if (append) { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, - sfname, sfname, false, curbuf, eap))) { + did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, sfname, sfname, false, curbuf, eap); + if (!did_cmd) { if (overwriting && bt_nofilename(curbuf)) { nofile_err = true; } else { @@ -2130,10 +2118,9 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char apply_autocmds_exarg(EVENT_FILTERWRITEPRE, NULL, sfname, false, curbuf, eap); } else if (reset_changed && whole) { - int was_changed = curbufIsChanged(); + bool was_changed = curbufIsChanged(); - did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, - sfname, sfname, false, curbuf, eap); + did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, sfname, sfname, false, curbuf, eap); if (did_cmd) { if (was_changed && !curbufIsChanged()) { // Written everything correctly and BufWriteCmd has reset @@ -2151,8 +2138,8 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char } } } else { - if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, - sfname, sfname, false, curbuf, eap))) { + did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, sfname, sfname, false, curbuf, eap); + if (!did_cmd) { if (overwriting && bt_nofilename(curbuf)) { nofile_err = true; } else { -- cgit From 9417a3d98a10265fe4265e40ad204ead00a7e0a2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 15:30:05 +0000 Subject: refactor(fileio.c): reduce scope of locals --- src/nvim/fileio.c | 108 +++++++++++++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 55 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index c7fcd85c7e..88d92b7dfa 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2266,18 +2266,6 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering) { - int fd; - char *backup = NULL; - int backup_copy = false; // copy the original file? - int dobackup; - char *ffname; - char *wfname = NULL; // name of file to write to - char *s; - char *ptr; - char c; - int len; - linenr_T lnum; - long nchars; #define SET_ERRMSG_NUM(num, msg) \ errnum = (num), errmsg = (msg), errmsgarg = 0 #define SET_ERRMSG_ARG(msg, error) \ @@ -2288,38 +2276,13 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en char *errmsg = NULL; int errmsgarg = 0; bool errmsg_allocated = false; - char *buffer; - char smallbuf[SMBUFSIZE]; - int bufsize; - long perm; // file permissions int retval = OK; - int newfile = false; // true if file doesn't exist yet int msg_save = msg_scroll; - int overwriting; // true if writing over original - int no_eol = false; // no end-of-line written - int device = false; // writing to a device int prev_got_int = got_int; - int checking_conversion; - bool file_readonly = false; // overwritten file is read-only static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')"; -#if defined(UNIX) - int made_writable = false; // 'w' bit has been set -#endif // writing everything int whole = (start == 1 && end == buf->b_ml.ml_line_count); - int fileformat; - int write_bin; - struct bw_info write_info; // info for buf_write_bytes() - int converted = false; - int notconverted = false; - char *fenc; // effective 'fileencoding' - char *fenc_tofree = NULL; // allocated "fenc" - int wb_flags = 0; -#ifdef HAVE_ACL - vim_acl_T acl = NULL; // ACL copied from original file to - // backup or new file -#endif int write_undo_file = false; context_sha256_T sha_ctx; unsigned int bkc = get_bkc_value(buf); @@ -2346,6 +2309,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } // must init bw_conv_buf and bw_iconv_fd before jumping to "fail" + struct bw_info write_info; // info for buf_write_bytes() write_info.bw_conv_buf = NULL; write_info.bw_conv_error = false; write_info.bw_conv_error_lnum = 0; @@ -2383,16 +2347,13 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // Avoids problems with networks and when directory names are changed. // Don't do this for Windows, a "cd" in a sub-shell may have moved us to // another directory, which we don't detect. - ffname = fname; // remember full fname + char *ffname = fname; // remember full fname #ifdef UNIX fname = sfname; #endif - if (buf->b_ffname != NULL && path_fnamecmp(ffname, buf->b_ffname) == 0) { - overwriting = true; - } else { - overwriting = false; - } +// true if writing over original + int overwriting = buf->b_ffname != NULL && path_fnamecmp(ffname, buf->b_ffname) == 0; no_wait_return++; // don't wait for return yet @@ -2434,7 +2395,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } msg_scroll = false; // always overwrite the file message now - buffer = verbose_try_malloc(BUFSIZE); + char *buffer = verbose_try_malloc(BUFSIZE); + int bufsize; + char smallbuf[SMBUFSIZE]; // can't allocate big buffer, use small one (to be able to write when out of // memory) if (buffer == NULL) { @@ -2444,8 +2407,20 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bufsize = BUFSIZE; } + int newfile = false; // true if file doesn't exist yet + int device = false; // writing to a device + char *backup = NULL; + char *fenc_tofree = NULL; // allocated "fenc" + // Get information about original file (if there is one). FileInfo file_info_old; + +#ifdef HAVE_ACL + vim_acl_T acl = NULL; // ACL copied from original file to + // backup or new file +#endif + + long perm; // file permissions #if defined(UNIX) perm = -1; if (!os_fileinfo(fname, &file_info_old)) { @@ -2470,12 +2445,12 @@ 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(fname); - if (c == NODE_OTHER) { + char nodetype = fname == NULL ? NODE_OTHER : os_nodetype(fname); + if (nodetype == NODE_OTHER) { SET_ERRMSG_NUM("E503", _("is not a file or writable device")); goto fail; } - if (c == NODE_WRITABLE) { + if (nodetype == NODE_WRITABLE) { device = true; newfile = true; perm = -1; @@ -2493,6 +2468,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } #endif // !UNIX + bool file_readonly = false; // overwritten file is read-only + if (!device && !newfile) { // Check if the file is really writable (when renaming the file to // make a backup we won't discover it later). @@ -2524,11 +2501,13 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #endif // If 'backupskip' is not empty, don't make a backup for some files. - dobackup = (p_wb || p_bk || *p_pm != NUL); + bool dobackup = (p_wb || p_bk || *p_pm != NUL); if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) { dobackup = false; } + int backup_copy = false; // copy the original file? + // 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. @@ -2573,8 +2552,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en break; } } - fd = os_open(IObuff, - O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, (int)perm); + int 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 { @@ -2860,6 +2839,8 @@ nobackup: } #if defined(UNIX) + int made_writable = false; // 'w' bit has been set + // When using ":w!" and the file was read-only: make it writable if (forceit && perm >= 0 && !(perm & 0200) && file_info_old.stat.st_uid == getuid() @@ -2885,6 +2866,8 @@ nobackup: start = end + 1; } + char *wfname = NULL; // name of file to write to + // If the original file is being overwritten, there is a small chance that // we crash in the middle of writing. Therefore the file is preserved now. // This makes all block numbers positive so that recovery does not need @@ -2903,6 +2886,8 @@ nobackup: // multi-byte conversion. wfname = fname; + char *fenc; // effective 'fileencoding' + // Check for forced 'fileencoding' from "++opt=val" argument. if (eap != NULL && eap->force_enc != 0) { fenc = eap->cmd + eap->force_enc; @@ -2913,7 +2898,8 @@ nobackup: } // Check if the file needs to be converted. - converted = need_conversion(fenc); + int converted = need_conversion(fenc); + int wb_flags = 0; // 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(). @@ -2960,6 +2946,8 @@ nobackup: } } + int notconverted = false; + if (converted && wb_flags == 0 && write_info.bw_iconv_fd == (iconv_t)-1 && wfname == fname) { @@ -2970,6 +2958,14 @@ nobackup: notconverted = true; } + int no_eol = false; // no end-of-line written + long nchars; + linenr_T lnum; + int fileformat; + int checking_conversion; + + int fd; + // If conversion is taking place, we may first pretend to write and check // for conversion errors. Then loop again to write for real. // When not doing conversion this writes for real right away. @@ -3086,6 +3082,7 @@ restore_backup: nchars = 0; // use "++bin", "++nobin" or 'binary' + int write_bin; if (eap != NULL && eap->force_bin != 0) { write_bin = (eap->force_bin == FORCE_BIN); } else { @@ -3118,15 +3115,16 @@ restore_backup: write_info.bw_len = bufsize; write_info.bw_flags = wb_flags; fileformat = get_fileformat_force(buf, eap); - s = buffer; - len = 0; + char *s = buffer; + int len = 0; for (lnum = start; lnum <= end; lnum++) { // The next while loop is done once for each character written. // Keep it fast! - ptr = ml_get_buf(buf, lnum, false) - 1; + char *ptr = ml_get_buf(buf, lnum, false) - 1; if (write_undo_file) { sha256_update(&sha_ctx, (uint8_t *)ptr + 1, (uint32_t)(strlen(ptr + 1) + 1)); } + char c; while ((c = *++ptr) != NUL) { if (c == NL) { *s = NUL; // replace newlines with NULs @@ -3349,7 +3347,7 @@ restore_backup: #endif if (!filtering) { add_quoted_fname(IObuff, IOSIZE, buf, (const char *)fname); - c = false; + char c = false; if (write_info.bw_conv_error) { STRCAT(IObuff, _(" CONVERSION ERROR")); c = true; -- cgit From 842cf780a6aa11df0411b41573f263bc5c151405 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 30 Jan 2023 17:20:25 +0000 Subject: refactor(fileio.c): do not use macros for error handling --- src/nvim/fileio.c | 133 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 74 insertions(+), 59 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 88d92b7dfa..c5c5a26d9d 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -118,6 +118,13 @@ struct bw_info { iconv_t bw_iconv_fd; // descriptor for iconv() or -1 }; +typedef struct { + const char *num; + char *msg; + int arg; + bool alloc; +} Error_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "fileio.c.generated.h" #endif @@ -2245,6 +2252,39 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char return NOTDONE; } +static inline Error_T set_err_num(const char *num, const char *msg) +{ + return (Error_T){ .num = num, .msg = (char *)msg, .arg = 0 }; +} + +static inline Error_T set_err_arg(const char *msg, int arg) +{ + return (Error_T){ .num = NULL, .msg = (char *)msg, .arg = arg }; +} + +static inline Error_T set_err(const char *msg) +{ + return (Error_T){ .num = NULL, .msg = (char *)msg, .arg = 0 }; +} + +static void emit_err(Error_T *e) +{ + if (e->num != NULL) { + if (e->arg != 0) { + semsg("%s: %s%s: %s", e->num, IObuff, e->msg, os_strerror(e->arg)); + } else { + semsg("%s: %s%s", e->num, IObuff, e->msg); + } + } else if (e->arg != 0) { + semsg(e->msg, os_strerror(e->arg)); + } else { + emsg(e->msg); + } + if (e->alloc) { + xfree(e->msg); + } +} + /// buf_write() - write to file "fname" lines "start" through "end" /// /// We do our own buffering here because fwrite() is so slow. @@ -2266,16 +2306,6 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering) { -#define SET_ERRMSG_NUM(num, msg) \ - errnum = (num), errmsg = (msg), errmsgarg = 0 -#define SET_ERRMSG_ARG(msg, error) \ - errnum = NULL, errmsg = (msg), errmsgarg = error -#define SET_ERRMSG(msg) \ - errnum = NULL, errmsg = (msg), errmsgarg = 0 - const char *errnum = NULL; - char *errmsg = NULL; - int errmsgarg = 0; - bool errmsg_allocated = false; int retval = OK; int msg_save = msg_scroll; int prev_got_int = got_int; @@ -2407,6 +2437,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en bufsize = BUFSIZE; } + Error_T err = { 0 }; int newfile = false; // true if file doesn't exist yet int device = false; // writing to a device char *backup = NULL; @@ -2429,11 +2460,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en perm = (long)file_info_old.stat.st_mode; if (!S_ISREG(file_info_old.stat.st_mode)) { // not a file if (S_ISDIR(file_info_old.stat.st_mode)) { - SET_ERRMSG_NUM("E502", _("is a directory")); + err = set_err_num("E502", _("is a directory")); goto fail; } if (os_nodetype(fname) != NODE_WRITABLE) { - SET_ERRMSG_NUM("E503", _("is not a file or writable device")); + err = set_err_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 @@ -2447,7 +2478,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // Check for a writable device name. char nodetype = fname == NULL ? NODE_OTHER : os_nodetype(fname); if (nodetype == NODE_OTHER) { - SET_ERRMSG_NUM("E503", _("is not a file or writable device")); + err = set_err_num("E503", _("is not a file or writable device")); goto fail; } if (nodetype == NODE_WRITABLE) { @@ -2459,7 +2490,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if (perm < 0) { newfile = true; } else if (os_isdir(fname)) { - SET_ERRMSG_NUM("E502", _("is a directory")); + err = set_err_num("E502", _("is a directory")); goto fail; } if (overwriting) { @@ -2477,9 +2508,9 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en if (!forceit && file_readonly) { if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { - SET_ERRMSG_NUM("E504", _(err_readonly)); + err = set_err_num("E504", _(err_readonly)); } else { - SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)")); + err = set_err_num("E505", _("is read-only (add ! to override)")); } goto fail; } @@ -2716,7 +2747,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // copy the file if (os_copy(fname, backup, UV_FS_COPYFILE_FICLONE) != 0) { - SET_ERRMSG(_("E509: Cannot create backup file (add ! to override)")); + err = set_err(_("E509: Cannot create backup file (add ! to override)")); XFREE_CLEAR(backup); backup = NULL; continue; @@ -2730,21 +2761,21 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en #ifdef HAVE_ACL os_set_acl(backup, acl); #endif - SET_ERRMSG(NULL); + err = set_err(NULL); break; } } nobackup: - if (backup == NULL && errmsg == NULL) { - SET_ERRMSG(_("E509: Cannot create backup file (add ! to override)")); + if (backup == NULL && err.msg == NULL) { + err = set_err(_("E509: Cannot create backup file (add ! to override)")); } // Ignore errors when forceit is true. - if ((some_error || errmsg != NULL) && !forceit) { + if ((some_error || err.msg != NULL) && !forceit) { retval = FAIL; goto fail; } - SET_ERRMSG(NULL); + err = set_err(NULL); } else { // Make a backup by renaming the original file. @@ -2752,7 +2783,7 @@ nobackup: // 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)); + err = set_err_num("E504", _(err_readonly)); goto fail; } @@ -2832,7 +2863,7 @@ nobackup: } } if (backup == NULL && !forceit) { - SET_ERRMSG(_("E510: Can't make backup file (add ! to override)")); + err = set_err(_("E510: Can't make backup file (add ! to override)")); goto fail; } } @@ -2877,7 +2908,7 @@ nobackup: && !(exiting && backup != NULL)) { ml_preserve(buf, false, !!p_fs); if (got_int) { - SET_ERRMSG(_(e_interr)); + err = set_err(_(e_interr)); goto restore_backup; } } @@ -2939,7 +2970,7 @@ nobackup: 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")); + err = set_err(_("E214: Can't find temp file for writing")); goto restore_backup; } } @@ -2952,7 +2983,7 @@ nobackup: && write_info.bw_iconv_fd == (iconv_t)-1 && wfname == fname) { if (!forceit) { - SET_ERRMSG(_("E213: Cannot convert (add ! to write without conversion)")); + err = set_err(_("E213: Cannot convert (add ! to write without conversion)")); goto restore_backup; } notconverted = true; @@ -3002,7 +3033,7 @@ nobackup: // A forced write will try to create a new file if the old one // is still readonly. This may also happen when the directory // is read-only. In that case the mch_remove() will fail. - if (errmsg == NULL) { + if (err.msg == NULL) { #ifdef UNIX FileInfo file_info; @@ -3010,10 +3041,10 @@ nobackup: if ((!newfile && os_fileinfo_hardlinks(&file_info_old) > 1) || (os_fileinfo_link(fname, &file_info) && !os_fileinfo_id_equal(&file_info, &file_info_old))) { - SET_ERRMSG(_("E166: Can't open linked file for writing")); + err = set_err(_("E166: Can't open linked file for writing")); } else { #endif - SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd); + err = set_err_arg(_("E212: Can't open file for writing: %s"), fd); if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) { #ifdef UNIX @@ -3076,7 +3107,7 @@ restore_backup: } write_info.bw_fd = fd; } - SET_ERRMSG(NULL); + err = set_err(NULL); write_info.bw_buf = buffer; nchars = 0; @@ -3226,7 +3257,7 @@ restore_backup: if (p_fs && (error = os_fsync(fd)) != 0 && !device // fsync not supported on this storage. && error != UV_ENOTSUP) { - SET_ERRMSG_ARG(e_fsync, error); + err = set_err_arg(e_fsync, error); end = 0; } @@ -3253,7 +3284,7 @@ restore_backup: #endif if ((error = os_close(fd)) != 0) { - SET_ERRMSG_ARG(_("E512: Close failed: %s"), error); + err = set_err_arg(_("E512: Close failed: %s"), error); end = 0; } @@ -3289,23 +3320,23 @@ restore_backup: if (end == 0) { // Error encountered. - if (errmsg == NULL) { + if (err.msg == NULL) { if (write_info.bw_conv_error) { if (write_info.bw_conv_error_lnum == 0) { - SET_ERRMSG(_("E513: write error, conversion failed " - "(make 'fenc' empty to override)")); + err = set_err(_("E513: write error, conversion failed " + "(make 'fenc' empty to override)")); } else { - errmsg_allocated = true; - SET_ERRMSG(xmalloc(300)); - vim_snprintf(errmsg, 300, // NOLINT(runtime/printf) + err = set_err(xmalloc(300)); + err.alloc = true; + vim_snprintf(err.msg, 300, // NOLINT(runtime/printf) _("E513: write error, conversion failed in line %" PRIdLINENR " (make 'fenc' empty to override)"), write_info.bw_conv_error_lnum); } } else if (got_int) { - SET_ERRMSG(_(e_interr)); + err = set_err(_(e_interr)); } else { - SET_ERRMSG(_("E514: write error (file system full?)")); + err = set_err(_("E514: write error (file system full?)")); } } @@ -3486,27 +3517,14 @@ nofail: os_free_acl(acl); #endif - if (errmsg != NULL) { + if (err.msg != NULL) { // - 100 to save some space for further error message #ifndef UNIX add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)sfname); #else add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)fname); #endif - if (errnum != NULL) { - if (errmsgarg != 0) { - semsg("%s: %s%s: %s", errnum, IObuff, errmsg, os_strerror(errmsgarg)); - } else { - semsg("%s: %s%s", errnum, IObuff, errmsg); - } - } else if (errmsgarg != 0) { - semsg(errmsg, os_strerror(errmsgarg)); - } else { - emsg(errmsg); - } - if (errmsg_allocated) { - xfree(errmsg); - } + emit_err(&err); retval = FAIL; if (end == 0) { @@ -3570,9 +3588,6 @@ nofail: got_int |= prev_got_int; return retval; -#undef SET_ERRMSG -#undef SET_ERRMSG_ARG -#undef SET_ERRMSG_NUM } /// Set the name of the current buffer. Use when the buffer doesn't have a -- cgit From cb3be2c766b79cf7a9ba642a565fa87aab76d2ab Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 31 Jan 2023 09:27:22 +0000 Subject: refactor(fileio.c): factor out buf_write post autocmds --- src/nvim/fileio.c | 55 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index c5c5a26d9d..047abebde0 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2252,6 +2252,35 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char return NOTDONE; } +static void buf_write_do_post_autocmds(buf_T *buf, char *fname, exarg_T *eap, bool append, + bool filtering, bool reset_changed, bool whole) +{ + aco_save_T aco; + + 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! + aucmd_prepbuf(&aco, buf); + + if (append) { + apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, + false, curbuf, eap); + } else if (filtering) { + apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, + false, curbuf, eap); + } else if (reset_changed && whole) { + apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, + false, curbuf, eap); + } else { + apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, + false, curbuf, eap); + } + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); +} + static inline Error_T set_err_num(const char *num, const char *msg) { return (Error_T){ .num = num, .msg = (char *)msg, .arg = 0 }; @@ -3555,31 +3584,7 @@ nofail: } if (!should_abort(retval)) { - aco_save_T aco; - - 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! - aucmd_prepbuf(&aco, buf); - - if (append) { - apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, - false, curbuf, eap); - } else if (filtering) { - apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, - false, curbuf, eap); - } else if (reset_changed && whole) { - apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, - false, curbuf, eap); - } else { - apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, - false, curbuf, eap); - } - - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - + buf_write_do_post_autocmds(buf, fname, eap, append, filtering, reset_changed, whole); if (aborting()) { // autocmds may abort script processing retval = false; } -- cgit From eacdece35426ce6e929fdd44d4ea331dc8317ea4 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 31 Jan 2023 09:24:41 +0000 Subject: refactor(fileio.c): factor out file info calc --- src/nvim/fileio.c | 205 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 122 insertions(+), 83 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 047abebde0..cad48aee52 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -125,6 +125,8 @@ typedef struct { bool alloc; } Error_T; +static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')"; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "fileio.c.generated.h" #endif @@ -2314,6 +2316,111 @@ static void emit_err(Error_T *e) } } +#if defined(UNIX) + +static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, long *perm, + bool *device, bool *newfile, Error_T *err) +{ + *perm = -1; + if (!os_fileinfo(fname, file_info_old)) { + *newfile = true; + } else { + *perm = (long)file_info_old->stat.st_mode; + if (!S_ISREG(file_info_old->stat.st_mode)) { // not a file + if (S_ISDIR(file_info_old->stat.st_mode)) { + *err = set_err_num("E502", _("is a directory")); + return FAIL; + } + if (os_nodetype(fname) != NODE_WRITABLE) { + *err = set_err_num("E503", _("is not a file or writable device")); + return 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. + *device = true; + *newfile = true; + *perm = -1; + } + } + return OK; +} + +#else + +static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, long *perm, + bool *device, bool *newfile, Error_T *err) +{ + // Check for a writable device name. + char nodetype = fname == NULL ? NODE_OTHER : (char)os_nodetype(fname); + if (nodetype == NODE_OTHER) { + *err = set_err_num("E503", _("is not a file or writable device")); + return FAIL; + } + if (nodetype == NODE_WRITABLE) { + *device = true; + *newfile = true; + *perm = -1; + } else { + *perm = os_getperm((const char *)fname); + if (*perm < 0) { + *newfile = true; + } else if (os_isdir(fname)) { + *err = set_err_num("E502", _("is a directory")); + return FAIL; + } + if (overwriting) { + os_fileinfo(fname, file_info_old); + } + } + return OK; +} + +#endif + +/// @param buf +/// @param fname File name +/// @param overwriting +/// @param forceit +/// @param[out] file_info_old +/// @param[out] perm +/// @param[out] device +/// @param[out] newfile +/// @param[out] readonly +static int get_fileinfo(buf_T *buf, char *fname, bool overwriting, bool forceit, + FileInfo *file_info_old, long *perm, bool *device, bool *newfile, + bool *readonly, Error_T *err) +{ + if (get_fileinfo_os(fname, file_info_old, overwriting, perm, device, newfile, err) == FAIL) { + return FAIL; + } + + *readonly = false; // overwritten file is read-only + + if (!*device && !*newfile) { + // Check if the file is really writable (when renaming the file to + // make a backup we won't discover it later). + *readonly = !os_file_is_writable(fname); + + if (!forceit && *readonly) { + if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { + *err = set_err_num("E504", _(err_readonly)); + } else { + *err = set_err_num("E505", _("is read-only (add ! to override)")); + } + return FAIL; + } + + // If 'forceit' is false, check if the timestamp hasn't changed since reading the file. + if (overwriting && !forceit) { + int retval = check_mtime(buf, file_info_old); + if (retval == FAIL) { + return FAIL; + } + } + } + return OK; +} + /// buf_write() - write to file "fname" lines "start" through "end" /// /// We do our own buffering here because fwrite() is so slow. @@ -2338,8 +2445,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en int retval = OK; int msg_save = msg_scroll; int prev_got_int = got_int; - static char *err_readonly = - "is read-only (cannot override: \"W\" in 'cpoptions')"; // writing everything int whole = (start == 1 && end == buf->b_ml.ml_line_count); int write_undo_file = false; @@ -2467,8 +2572,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en } Error_T err = { 0 }; - int newfile = false; // true if file doesn't exist yet - int device = false; // writing to a device + long perm; // file permissions + bool newfile = false; // true if file doesn't exist yet + bool device = false; // writing to a device + bool file_readonly = false; // overwritten file is read-only char *backup = NULL; char *fenc_tofree = NULL; // allocated "fenc" @@ -2480,78 +2587,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // backup or new file #endif - long perm; // file permissions -#if defined(UNIX) - perm = -1; - if (!os_fileinfo(fname, &file_info_old)) { - newfile = true; - } else { - perm = (long)file_info_old.stat.st_mode; - if (!S_ISREG(file_info_old.stat.st_mode)) { // not a file - if (S_ISDIR(file_info_old.stat.st_mode)) { - err = set_err_num("E502", _("is a directory")); - goto fail; - } - if (os_nodetype(fname) != NODE_WRITABLE) { - err = set_err_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. - device = true; - newfile = true; - perm = -1; - } - } -#else // win32 - // Check for a writable device name. - char nodetype = fname == NULL ? NODE_OTHER : os_nodetype(fname); - if (nodetype == NODE_OTHER) { - err = set_err_num("E503", _("is not a file or writable device")); + if (get_fileinfo(buf, fname, overwriting, forceit, &file_info_old, &perm, &device, &newfile, + &file_readonly, &err) == FAIL) { goto fail; } - if (nodetype == NODE_WRITABLE) { - device = true; - newfile = true; - perm = -1; - } else { - perm = os_getperm((const char *)fname); - if (perm < 0) { - newfile = true; - } else if (os_isdir(fname)) { - err = set_err_num("E502", _("is a directory")); - goto fail; - } - if (overwriting) { - os_fileinfo(fname, &file_info_old); - } - } -#endif // !UNIX - - bool file_readonly = false; // overwritten file is read-only - - if (!device && !newfile) { - // 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) { - if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { - err = set_err_num("E504", _(err_readonly)); - } else { - err = set_err_num("E505", _("is read-only (add ! to override)")); - } - goto fail; - } - - // 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; - } - } - } #ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. @@ -3407,37 +3446,37 @@ restore_backup: #endif if (!filtering) { add_quoted_fname(IObuff, IOSIZE, buf, (const char *)fname); - char c = false; + bool insert_space = false; if (write_info.bw_conv_error) { STRCAT(IObuff, _(" CONVERSION ERROR")); - c = true; + insert_space = true; if (write_info.bw_conv_error_lnum != 0) { vim_snprintf_add(IObuff, IOSIZE, _(" in line %" PRId64 ";"), (int64_t)write_info.bw_conv_error_lnum); } } else if (notconverted) { STRCAT(IObuff, _("[NOT converted]")); - c = true; + insert_space = true; } else if (converted) { STRCAT(IObuff, _("[converted]")); - c = true; + insert_space = true; } if (device) { STRCAT(IObuff, _("[Device]")); - c = true; + insert_space = true; } else if (newfile) { STRCAT(IObuff, new_file_message()); - c = true; + insert_space = true; } if (no_eol) { msg_add_eol(); - c = true; + insert_space = true; } // may add [unix/dos/mac] if (msg_add_fileformat(fileformat)) { - c = true; + insert_space = true; } - msg_add_lines(c, (long)lnum, nchars); // add line/char count + msg_add_lines(insert_space, (long)lnum, nchars); // add line/char count if (!shortmess(SHM_WRITE)) { if (append) { STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended")); -- cgit From 33a183e8981de7894968a0d2aef836d9296786a7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 31 Jan 2023 10:04:44 +0000 Subject: refactor(fileio.c): make unreadable expression readable --- src/nvim/fileio.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index cad48aee52..098db6b4af 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3090,14 +3090,12 @@ nobackup: // quotum for number of files). // Appending will fail if the file does not exist and forceit is // false. - while ((fd = os_open(wfname, - O_WRONLY | - (append - ? (forceit - ? (O_APPEND | O_CREAT) - : O_APPEND) - : (O_CREAT | O_TRUNC)), - perm < 0 ? 0666 : (perm & 0777))) < 0) { + const int fflags = O_WRONLY | (append + ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND) + : (O_CREAT | O_TRUNC)); + const int mode = perm < 0 ? 0666 : (perm & 0777); + + while ((fd = os_open(wfname, fflags, mode)) < 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 // is read-only. In that case the mch_remove() will fail. -- cgit From c1a3865c476844e1b30200e2e7f3f9f2fa682329 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 31 Jan 2023 11:26:43 +0000 Subject: refactor(fileio.c): factor out backup creation --- src/nvim/fileio.c | 635 +++++++++++++++++++++++++++--------------------------- 1 file changed, 322 insertions(+), 313 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 098db6b4af..4b3a52759d 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2421,6 +2421,324 @@ static int get_fileinfo(buf_T *buf, char *fname, bool overwriting, bool forceit, return OK; } +static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_old, vim_acl_T acl, + long perm, unsigned int bkc, bool file_readonly, bool forceit, + int *backup_copyp, char **backupp, Error_T *err) +{ + FileInfo file_info; + const bool no_prepend_dot = false; + + if ((bkc & BKC_YES) || append) { // "yes" + *backup_copyp = true; + } else if ((bkc & BKC_AUTO)) { // "auto" + // 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_copyp = 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). + STRCPY(IObuff, fname); + for (int i = 4913;; i += 123) { + char *tail = path_tail(IObuff); + size_t size = (size_t)(tail - IObuff); + snprintf(tail, IOSIZE - size, "%d", i); + if (!os_fileinfo_link(IObuff, &file_info)) { + break; + } + } + int fd = os_open(IObuff, + O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, (int)perm); + if (fd < 0) { // can't write in directory + *backup_copyp = 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(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_copyp = true; + } +#endif + // Close the file before removing it, on MS-Windows we + // can't delete an open file. + close(fd); + os_remove(IObuff); + } + } + } + + // 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); + + // Symlinks. + if ((bkc & BKC_BREAKSYMLINK) + && file_info_link_ok + && !os_fileinfo_id_equal(&file_info, file_info_old)) { + *backup_copyp = false; + } + + // Hardlinks. + if ((bkc & BKC_BREAKHARDLINK) + && os_fileinfo_hardlinks(file_info_old) > 1 + && (!file_info_link_ok + || os_fileinfo_id_equal(&file_info, file_info_old))) { + *backup_copyp = false; + } +#endif + } + + // make sure we have a valid backup extension to use + char *backup_ext = *p_bex == NUL ? ".bak" : p_bex; + + if (*backup_copyp) { + int some_error = false; + + // 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. + char *dirp = p_bdir; + while (*dirp) { + // Isolate one directory name, using an entry in 'bdir'. + size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); + char *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(IObuff)) { + int ret; + char *failed_dir; + 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); + } + } + if (trailing_pathseps) { + // Ends with '//', Use Full path + if ((p = make_percent_swname(IObuff, fname)) + != NULL) { + *backupp = modname(p, backup_ext, no_prepend_dot); + xfree(p); + } + } + + char *rootname = get_file_in_dir(fname, IObuff); + if (rootname == NULL) { + some_error = true; // out of memory + goto nobackup; + } + + FileInfo file_info_new; + { + // + // Make the backup file name. + // + if (*backupp == NULL) { + *backupp = modname(rootname, backup_ext, no_prepend_dot); + } + + if (*backupp == NULL) { + xfree(rootname); + some_error = true; // out of memory + goto nobackup; + } + + // Check if backup file already exists. + if (os_fileinfo(*backupp, &file_info_new)) { + if (os_fileinfo_id_equal(&file_info_new, file_info_old)) { + // + // Backup file is same as original file. + // May happen when modname() gave the same file back (e.g. silly + // link). If we don't check here, we either ruin the file when + // copying or erase it after writing. + // + XFREE_CLEAR(*backupp); // no backup file to delete + } else if (!p_bk) { + // We are not going to keep the backup file, so don't + // delete an existing one, and try to use another name instead. + // Change one character, just before the extension. + // + char *wp = *backupp + strlen(*backupp) - 1 - strlen(backup_ext); + if (wp < *backupp) { // empty file name ??? + wp = *backupp; + } + *wp = 'z'; + while (*wp > 'a' && os_fileinfo(*backupp, &file_info_new)) { + (*wp)--; + } + // They all exist??? Must be something wrong. + if (*wp == 'a') { + XFREE_CLEAR(*backupp); + } + } + } + } + xfree(rootname); + + // Try to create the backup file + if (*backupp != NULL) { + // remove old backup, if present + os_remove(*backupp); + + // set file protection same as original file, but + // strip s-bit. + (void)os_setperm((const char *)(*backupp), perm & 0777); + +#ifdef UNIX + // + // Try to set the group of the backup same as the original file. If + // this fails, set the protection bits for the group same as the + // protection bits for others. + // + if (file_info_new.stat.st_gid != file_info_old->stat.st_gid + && os_chown(*backupp, (uv_uid_t)-1, (uv_gid_t)file_info_old->stat.st_gid) != 0) { + os_setperm((const char *)(*backupp), + ((int)perm & 0707) | (((int)perm & 07) << 3)); + } +#endif + + // copy the file + if (os_copy(fname, *backupp, UV_FS_COPYFILE_FICLONE) != 0) { + *err = set_err(_("E509: Cannot create backup file (add ! to override)")); + XFREE_CLEAR(*backupp); + *backupp = NULL; + continue; + } + +#ifdef UNIX + os_file_settime(*backupp, + (double)file_info_old->stat.st_atim.tv_sec, + (double)file_info_old->stat.st_mtim.tv_sec); +#endif +#ifdef HAVE_ACL + os_set_acl(*backupp, acl); +#endif + *err = set_err(NULL); + break; + } + } + +nobackup: + if (*backupp == NULL && err->msg == NULL) { + *err = set_err(_("E509: Cannot create backup file (add ! to override)")); + } + // Ignore errors when forceit is true. + if ((some_error || err->msg != NULL) && !forceit) { + return FAIL; + } + *err = set_err(NULL); + } else { + // 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) { + *err = set_err_num("E504", _(err_readonly)); + return 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. + char *dirp = p_bdir; + while (*dirp) { + // Isolate one directory name and make the backup file name. + size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); + char *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(IObuff)) { + int ret; + char *failed_dir; + 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); + } + } + if (trailing_pathseps) { + // path ends with '//', use full path + if ((p = make_percent_swname(IObuff, fname)) + != NULL) { + *backupp = modname(p, backup_ext, no_prepend_dot); + xfree(p); + } + } + + if (*backupp == NULL) { + char *rootname = get_file_in_dir(fname, IObuff); + if (rootname == NULL) { + *backupp = NULL; + } else { + *backupp = modname(rootname, backup_ext, no_prepend_dot); + xfree(rootname); + } + } + + if (*backupp != 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(*backupp)) { + p = *backupp + strlen(*backupp) - 1 - strlen(backup_ext); + if (p < *backupp) { // empty file name ??? + p = *backupp; + } + *p = 'z'; + while (*p > 'a' && os_path_exists(*backupp)) { + (*p)--; + } + // They all exist??? Must be something wrong! + if (*p == 'a') { + XFREE_CLEAR(*backupp); + } + } + } + if (*backupp != NULL) { + // Delete any existing backup and move the current version + // to the backup. For safety, we don't remove the backup + // until the write has finished successfully. And if the + // 'backup' option is set, leave it around. + + // If the renaming of the original file to the backup file + // works, quit here. + /// + if (vim_rename(fname, *backupp) == 0) { + break; + } + + XFREE_CLEAR(*backupp); // don't do the rename below + } + } + if (*backupp == NULL && !forceit) { + *err = set_err(_("E510: Can't make backup file (add ! to override)")); + return FAIL; + } + } + return OK; +} + /// buf_write() - write to file "fname" lines "start" through "end" /// /// We do our own buffering here because fwrite() is so slow. @@ -2582,10 +2900,8 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // Get information about original file (if there is one). FileInfo file_info_old; -#ifdef HAVE_ACL vim_acl_T acl = NULL; // ACL copied from original file to // backup or new file -#endif if (get_fileinfo(buf, fname, overwriting, forceit, &file_info_old, &perm, &device, &newfile, &file_readonly, &err) == FAIL) { @@ -2623,317 +2939,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en // 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; - - if ((bkc & BKC_YES) || append) { // "yes" - backup_copy = true; - } else if ((bkc & BKC_AUTO)) { // "auto" - // 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). - STRCPY(IObuff, fname); - for (int i = 4913;; i += 123) { - char *tail = path_tail(IObuff); - size_t size = (size_t)(tail - IObuff); - snprintf(tail, IOSIZE - size, "%d", i); - if (!os_fileinfo_link(IObuff, &file_info)) { - break; - } - } - int 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(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(fd); - os_remove(IObuff); - } - } - } - - // 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); - - // Symlinks. - if ((bkc & BKC_BREAKSYMLINK) - && file_info_link_ok - && !os_fileinfo_id_equal(&file_info, &file_info_old)) { - backup_copy = false; - } - - // Hardlinks. - if ((bkc & BKC_BREAKHARDLINK) - && os_fileinfo_hardlinks(&file_info_old) > 1 - && (!file_info_link_ok - || os_fileinfo_id_equal(&file_info, &file_info_old))) { - backup_copy = false; - } -#endif - } - - // make sure we have a valid backup extension to use - char *backup_ext = *p_bex == NUL ? ".bak" : p_bex; - - if (backup_copy) { - int some_error = false; - - // 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. - char *dirp = p_bdir; - while (*dirp) { - // Isolate one directory name, using an entry in 'bdir'. - size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - char *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(IObuff)) { - int ret; - char *failed_dir; - 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); - } - } - if (trailing_pathseps) { - // Ends with '//', Use Full path - if ((p = make_percent_swname(IObuff, fname)) - != NULL) { - backup = modname(p, backup_ext, no_prepend_dot); - xfree(p); - } - } - - char *rootname = get_file_in_dir(fname, IObuff); - if (rootname == NULL) { - some_error = true; // out of memory - goto nobackup; - } - - FileInfo file_info_new; - { - // - // Make the backup file name. - // - if (backup == NULL) { - backup = modname(rootname, backup_ext, no_prepend_dot); - } - - if (backup == NULL) { - xfree(rootname); - some_error = true; // out of memory - goto nobackup; - } - - // Check if backup file already exists. - if (os_fileinfo(backup, &file_info_new)) { - if (os_fileinfo_id_equal(&file_info_new, &file_info_old)) { - // - // Backup file is same as original file. - // May happen when modname() gave the same file back (e.g. silly - // link). If we don't check here, we either ruin the file when - // copying or erase it after writing. - // - XFREE_CLEAR(backup); // no backup file to delete - } else if (!p_bk) { - // We are not going to keep the backup file, so don't - // delete an existing one, and try to use another name instead. - // Change one character, just before the extension. - // - char *wp = backup + strlen(backup) - 1 - strlen(backup_ext); - if (wp < backup) { // empty file name ??? - wp = backup; - } - *wp = 'z'; - while (*wp > 'a' && os_fileinfo(backup, &file_info_new)) { - (*wp)--; - } - // They all exist??? Must be something wrong. - if (*wp == 'a') { - XFREE_CLEAR(backup); - } - } - } - } - xfree(rootname); - - // Try to create the backup file - if (backup != NULL) { - // remove old backup, if present - os_remove(backup); - - // set file protection same as original file, but - // strip s-bit. - (void)os_setperm((const char *)backup, perm & 0777); - -#ifdef UNIX - // - // Try to set the group of the backup same as the original file. If - // this fails, set the protection bits for the group same as the - // protection bits for others. - // - if (file_info_new.stat.st_gid != file_info_old.stat.st_gid - && os_chown(backup, (uv_uid_t)-1, (uv_gid_t)file_info_old.stat.st_gid) != 0) { - os_setperm((const char *)backup, - ((int)perm & 0707) | (((int)perm & 07) << 3)); - } -#endif - - // copy the file - if (os_copy(fname, backup, UV_FS_COPYFILE_FICLONE) != 0) { - err = set_err(_("E509: Cannot create backup file (add ! to override)")); - XFREE_CLEAR(backup); - backup = NULL; - continue; - } - -#ifdef UNIX - os_file_settime(backup, - (double)file_info_old.stat.st_atim.tv_sec, - (double)file_info_old.stat.st_mtim.tv_sec); -#endif -#ifdef HAVE_ACL - os_set_acl(backup, acl); -#endif - err = set_err(NULL); - break; - } - } - -nobackup: - if (backup == NULL && err.msg == NULL) { - err = set_err(_("E509: Cannot create backup file (add ! to override)")); - } - // Ignore errors when forceit is true. - if ((some_error || err.msg != NULL) && !forceit) { - retval = FAIL; - goto fail; - } - err = set_err(NULL); - } else { - // 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) { - err = set_err_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. - char *dirp = p_bdir; - while (*dirp) { - // Isolate one directory name and make the backup file name. - size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - char *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(IObuff)) { - int ret; - char *failed_dir; - 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); - } - } - if (trailing_pathseps) { - // path ends with '//', use full path - if ((p = make_percent_swname(IObuff, fname)) - != NULL) { - backup = modname(p, backup_ext, no_prepend_dot); - xfree(p); - } - } - - if (backup == NULL) { - char *rootname = get_file_in_dir(fname, IObuff); - if (rootname == NULL) { - backup = NULL; - } else { - backup = modname(rootname, backup_ext, no_prepend_dot); - xfree(rootname); - } - } - - 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(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(backup)) { - (*p)--; - } - // They all exist??? Must be something wrong! - if (*p == 'a') { - XFREE_CLEAR(backup); - } - } - } - if (backup != NULL) { - // Delete any existing backup and move the current version - // to the backup. For safety, we don't remove the backup - // until the write has finished successfully. And if the - // 'backup' option is set, leave it around. - - // If the renaming of the original file to the backup file - // works, quit here. - /// - if (vim_rename(fname, backup) == 0) { - break; - } - - XFREE_CLEAR(backup); // don't do the rename below - } - } - if (backup == NULL && !forceit) { - err = set_err(_("E510: Can't make backup file (add ! to override)")); - goto fail; - } + if (buf_write_make_backup(fname, append, &file_info_old, acl, perm, bkc, file_readonly, forceit, + &backup_copy, &backup, &err) == FAIL) { + retval = FAIL; + goto fail; } } -- cgit From b3d304df93347ef3f585ae91ae9ff6f5f28651af Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 31 Jan 2023 11:47:02 +0000 Subject: refactor(fileio.c): remove HAVE_ACL ifdefs --- src/nvim/fileio.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 4b3a52759d..77b8cc833f 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2628,9 +2628,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o (double)file_info_old->stat.st_atim.tv_sec, (double)file_info_old->stat.st_mtim.tv_sec); #endif -#ifdef HAVE_ACL os_set_acl(*backupp, acl); -#endif *err = set_err(NULL); break; } @@ -2908,12 +2906,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en goto fail; } -#ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. if (!newfile) { acl = os_get_acl(fname); } -#endif // If 'backupskip' is not empty, don't make a backup for some files. bool dobackup = (p_wb || p_bk || *p_pm != NUL); @@ -3371,13 +3367,11 @@ restore_backup: if (perm >= 0) { // Set perm. of new file same as old file. (void)os_setperm((const char *)wfname, (int)perm); } -#ifdef HAVE_ACL // 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) { os_set_acl(wfname, acl); } -#endif if (wfname != fname) { // The file was written to a temp file, now it needs to be converted @@ -3588,9 +3582,7 @@ nofail: iconv_close(write_info.bw_iconv_fd); write_info.bw_iconv_fd = (iconv_t)-1; } -#ifdef HAVE_ACL os_free_acl(acl); -#endif if (err.msg != NULL) { // - 100 to save some space for further error message @@ -4577,15 +4569,11 @@ int vim_rename(const char *from, const char *to) // Rename() failed, try copying the file. long perm = os_getperm(from); -#ifdef HAVE_ACL // For systems that support ACL: get the ACL from the original file. vim_acl_T acl = os_get_acl(from); -#endif int fd_in = os_open((char *)from, O_RDONLY, 0); if (fd_in < 0) { -#ifdef HAVE_ACL os_free_acl(acl); -#endif return -1; } @@ -4593,9 +4581,7 @@ int vim_rename(const char *from, const char *to) int fd_out = os_open((char *)to, O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm); if (fd_out < 0) { close(fd_in); -#ifdef HAVE_ACL os_free_acl(acl); -#endif return -1; } @@ -4605,9 +4591,7 @@ int vim_rename(const char *from, const char *to) if (buffer == NULL) { close(fd_out); close(fd_in); -#ifdef HAVE_ACL os_free_acl(acl); -#endif return -1; } @@ -4631,10 +4615,8 @@ int vim_rename(const char *from, const char *to) #ifndef UNIX // For Unix os_open() already set the permission. os_setperm(to, perm); #endif -#ifdef HAVE_ACL os_set_acl(to, acl); os_free_acl(acl); -#endif if (errmsg != NULL) { semsg(errmsg, to); return -1; -- cgit From 6aee2336ca75301bd4db6b99c2392f63f8304335 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 31 Jan 2023 12:00:33 +0000 Subject: refactor(fileio.c): normalize ifdefs As well as improving readbability, this also avoids all Treesitter parsing errors which cannot handle elaborate use of the preprocessor. --- src/nvim/fileio.c | 76 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 36 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 77b8cc833f..716d7af149 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -389,13 +389,18 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, perm = os_getperm(fname); // On Unix it is possible to read a directory, so we have to // check for it before os_open(). + +#ifdef OPEN_CHR_FILES +# define IS_CHR_DEV(perm, fname) S_ISCHR(perm) && is_dev_fd_file(fname) +#else +# define IS_CHR_DEV(perm, fname) false +#endif + if (perm >= 0 && !S_ISREG(perm) // not a regular file ... && !S_ISFIFO(perm) // ... or fifo && !S_ISSOCK(perm) // ... or socket -#ifdef OPEN_CHR_FILES - && !(S_ISCHR(perm) && is_dev_fd_file(fname)) + && !(IS_CHR_DEV(perm, fname)) // ... or a character special file named /dev/fd/ -#endif ) { if (S_ISDIR(perm)) { if (!silent) { @@ -513,15 +518,18 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } return OK; // a new file is not an error } - filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : #if defined(UNIX) && defined(EOVERFLOW) + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : // libuv only returns -errno // in Unix and in Windows // open() does not set // EOVERFLOW (fd == -EOVERFLOW) ? _("[File too big]") : -#endif _("[Permission Denied]")), 0); +#else + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : + _("[Permission Denied]")), 0); +#endif curbuf->b_p_ro = true; // must use "w!" now return FAIL; @@ -2865,13 +2873,12 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en msg_scroll = true; // don't overwrite previous file message } if (!filtering) { - filemess(buf, + // show that we are busy #ifndef UNIX - sfname, + filemess(buf, sfname, "", 0); #else - fname, + filemess(buf, fname, "", 0); #endif - "", 0); // show that we are busy } msg_scroll = false; // always overwrite the file message now @@ -3114,29 +3121,32 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en && !os_fileinfo_id_equal(&file_info, &file_info_old))) { err = set_err(_("E166: Can't open linked file for writing")); } else { -#endif - err = set_err_arg(_("E212: Can't open file for writing: %s"), fd); - if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL - && perm >= 0) { -#ifdef UNIX - // we write to the file, thus it should be marked - // writable after all - if (!(perm & 0200)) { - made_writable = true; - } - perm |= 0200; - if (file_info_old.stat.st_uid != getuid() - || file_info_old.stat.st_gid != getgid()) { - perm &= 0777; + err = set_err_arg(_("E212: Can't open file for writing: %s"), fd); + if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) { + // we write to the file, thus it should be marked + // writable after all + if (!(perm & 0200)) { + made_writable = true; + } + perm |= 0200; + if (file_info_old.stat.st_uid != getuid() + || file_info_old.stat.st_gid != getgid()) { + perm &= 0777; + } + if (!append) { // don't remove when appending + os_remove(wfname); + } + continue; } -#endif + } +#else + err = set_err_arg(_("E212: Can't open file for writing: %s"), fd); + if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) { if (!append) { // don't remove when appending os_remove(wfname); } continue; } -#ifdef UNIX - } #endif } @@ -3774,14 +3784,15 @@ static int check_mtime(buf_T *buf, FileInfo *file_info) static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST { - return file_info->stat.st_mtim.tv_nsec != mtime_ns #if defined(__linux__) || defined(MSWIN) + return file_info->stat.st_mtim.tv_nsec != mtime_ns // On a FAT filesystem, esp. under Linux, there are only 5 bits to store // the seconds. Since the roundoff is done when flushing the inode, the // time may change unexpectedly by one second!!! || file_info->stat.st_mtim.tv_sec - mtime > 1 || mtime - file_info->stat.st_mtim.tv_sec > 1; #else + return file_info->stat.st_mtim.tv_nsec != mtime_ns || file_info->stat.st_mtim.tv_sec != mtime; #endif } @@ -5600,11 +5611,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs // regexp. // An escaped { must be unescaped since we use magic not // verymagic. Use "\\\{n,m\}"" to get "\{n,m}". - if (*++p == '?' -#ifdef BACKSLASH_IN_FILENAME - && no_bslash -#endif - ) { + if (*++p == '?' && (!BACKSLASH_IN_FILENAME_BOOL || no_bslash)) { reg_pat[i++] = '?'; } else if (*p == ',' || *p == '%' || *p == '#' || ascii_isspace(*p) || *p == '{' || *p == '}') { @@ -5615,10 +5622,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs p += 2; } else { if (allow_dirs != NULL && vim_ispathsep(*p) -#ifdef BACKSLASH_IN_FILENAME - && (!no_bslash || *p != '\\') -#endif - ) { + && (!BACKSLASH_IN_FILENAME_BOOL || (!no_bslash || *p != '\\'))) { *allow_dirs = true; } reg_pat[i++] = '\\'; -- cgit From 7224c889e0d5d70b99ae377036baa6377c33a568 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:25:24 +0100 Subject: build: enable MSVC level 3 warnings (#21934) MSVC has 4 different warning levels: 1 (severe), 2 (significant), 3 (production quality) and 4 (informational). Enabling level 3 warnings mostly revealed conversion problems, similar to GCC/clang -Wconversion flag. --- src/nvim/fileio.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fbb5c4f1fa..8c904f0c0a 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -64,6 +64,10 @@ #include "nvim/undo.h" #include "nvim/vim.h" +#ifdef BACKSLASH_IN_FILENAME +# include "nvim/charset.h" +#endif + #if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) # include # include @@ -207,7 +211,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, char *line_start = NULL; // init to shut up gcc int wasempty; // buffer was empty before reading colnr_T len; - long size = 0; + ptrdiff_t size = 0; uint8_t *p = NULL; off_T filesize = 0; bool skip_read = false; @@ -217,7 +221,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T linecnt; bool error = false; // errors encountered int ff_error = EOL_UNKNOWN; // file format with errors - long linerest = 0; // remaining chars in line + ptrdiff_t linerest = 0; // remaining chars in line int perm = 0; #ifdef UNIX int swap_mode = -1; // protection bits for swap file @@ -1079,7 +1083,7 @@ retry: if (size < 2 || curbuf->b_p_bin) { ccname = NULL; } else { - ccname = check_for_bom(ptr, size, &blen, + ccname = check_for_bom(ptr, (int)size, &blen, fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc)); } if (ccname != NULL) { @@ -4038,7 +4042,7 @@ static int get_fio_flags(const char *name) /// /// @return the name of the encoding and set "*lenp" to the length or, /// NULL when no BOM found. -static char *check_for_bom(const char *p_in, long size, int *lenp, int flags) +static char *check_for_bom(const char *p_in, int size, int *lenp, int flags) { const uint8_t *p = (const uint8_t *)p_in; char *name = NULL; @@ -5630,7 +5634,7 @@ long read_eintr(int fd, void *buf, size_t bufsize) long ret; for (;;) { - ret = read(fd, buf, bufsize); + ret = read(fd, buf, (unsigned int)bufsize); if (ret >= 0 || errno != EINTR) { break; } @@ -5647,7 +5651,7 @@ long write_eintr(int fd, void *buf, size_t bufsize) // Repeat the write() so long it didn't fail, other than being interrupted // by a signal. while (ret < (long)bufsize) { - long wlen = write(fd, (char *)buf + ret, bufsize - (size_t)ret); + long wlen = write(fd, (char *)buf + ret, (unsigned int)(bufsize - (size_t)ret)); if (wlen < 0) { if (errno != EINTR) { break; -- cgit From d34c64e342dfba9248d1055e702d02620a1b31a8 Mon Sep 17 00:00:00 2001 From: Ghjuvan Lacambre Date: Thu, 16 Feb 2023 13:15:02 +0100 Subject: feat: $NVIM_APPNAME #22128 This commit implements the ability to control all of the XDG paths Neovim should use. This is done by setting an environment variable named NVIM_APPNAME. For example, setting $NVIM_APPNAME makes Neovim look for its configuration directory in $XDG_CONFIG_HOME/$NVIM_APPNAME instead of $XDG_CONFIG_HOME/nvim. If NVIM_APPNAME is not set or is an empty string, "nvim" will be used as default. The usecase for this feature is to enable an easy way to switch from configuration to configuration. One might argue that the various $XDG environment variables can already be used for this usecase. However, setting $XDG environment variables also affects tools spawned by Neovim. For example, while setting $XDG_CONFIG_HOME will enable Neovim to use a different configuration directory, it will also prevent Git from finding its "default" configuration. Closes https://github.com/neovim/neovim/issues/21691 --- src/nvim/fileio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index a3cdd2bb23..755b8e0834 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -5181,7 +5181,10 @@ static void vim_mktempdir(void) // "/tmp/" exists, now try to create "/tmp/nvim./". add_pathsep(tmp); - xstrlcat(tmp, "nvim.", sizeof(tmp)); + + const char *appname = get_appname(); + xstrlcat(tmp, appname, sizeof(tmp)); + xstrlcat(tmp, ".", sizeof(tmp)); xstrlcat(tmp, user, sizeof(tmp)); (void)os_mkdir(tmp, 0700); // Always create, to avoid a race. bool owned = os_file_owned(tmp); -- cgit From 166b149d5b473f277c63e64ced03c40df44ac3c9 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 27 Feb 2023 16:30:32 +0100 Subject: refactor(build): remove unused stdlib function and include checks In addition: merge some checks for the same feature into one test_compile. This reduces the total number of test compiles which speeds up the cmake configure stage. --- src/nvim/fileio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 755b8e0834..c93df43cff 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -68,7 +68,7 @@ # include "nvim/charset.h" #endif -#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +#ifdef HAVE_DIRFD_AND_FLOCK # include # include #endif @@ -5146,7 +5146,7 @@ void forward_slash(char *fname) /// Path to Nvim's own temp dir. Ends in a slash. static char *vim_tempdir = NULL; -#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +#ifdef HAVE_DIRFD_AND_FLOCK DIR *vim_tempdir_dp = NULL; ///< File descriptor of temp dir #endif @@ -5316,7 +5316,7 @@ int delete_recursive(const char *name) return result; } -#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +#ifdef HAVE_DIRFD_AND_FLOCK /// Open temporary directory and take file lock to prevent /// to be auto-cleaned. static void vim_opentempdir(void) @@ -5353,7 +5353,7 @@ void vim_deltempdir(void) return; } -#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +#ifdef HAVE_DIRFD_AND_FLOCK vim_closetempdir(); #endif // remove the trailing path separator @@ -5391,7 +5391,7 @@ static bool vim_settempdir(char *tempdir) vim_FullName(tempdir, buf, MAXPATHL, false); add_pathsep(buf); vim_tempdir = xstrdup(buf); -#if defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +#ifdef HAVE_DIRFD_AND_FLOCK vim_opentempdir(); #endif xfree(buf); -- cgit From 6cab36e5b7b0d741abe6c5a7c0e20bad30361034 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 4 Mar 2023 13:10:00 +0100 Subject: refactor: replace char_u with char or uint8_t (#22400) Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/fileio.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index c93df43cff..6a13548027 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -107,19 +107,19 @@ enum { // Structure to pass arguments from buf_write() to buf_write_bytes(). struct bw_info { - int bw_fd; // file descriptor - char *bw_buf; // buffer with data to be written - int bw_len; // length of data - int bw_flags; // FIO_ flags - char_u bw_rest[CONV_RESTLEN]; // not converted bytes - int bw_restlen; // nr of bytes in bw_rest[] - int bw_first; // first write call - char *bw_conv_buf; // buffer for writing converted chars - size_t bw_conv_buflen; // size of bw_conv_buf - int bw_conv_error; // set for conversion error - linenr_T bw_conv_error_lnum; // first line with error or zero - linenr_T bw_start_lnum; // line number at start of buffer - iconv_t bw_iconv_fd; // descriptor for iconv() or -1 + int bw_fd; // file descriptor + char *bw_buf; // buffer with data to be written + int bw_len; // length of data + int bw_flags; // FIO_ flags + uint8_t bw_rest[CONV_RESTLEN]; // not converted bytes + int bw_restlen; // nr of bytes in bw_rest[] + int bw_first; // first write call + char *bw_conv_buf; // buffer for writing converted chars + size_t bw_conv_buflen; // size of bw_conv_buf + int bw_conv_error; // set for conversion error + linenr_T bw_conv_error_lnum; // first line with error or zero + linenr_T bw_start_lnum; // line number at start of buffer + iconv_t bw_iconv_fd; // descriptor for iconv() or -1 }; typedef struct { @@ -989,7 +989,7 @@ retry: int ni; long tlen = 0; for (;;) { - p = (char_u *)ml_get(read_buf_lnum) + read_buf_col; + p = (uint8_t *)ml_get(read_buf_lnum) + read_buf_col; int n = (int)strlen((char *)p); if ((int)tlen + n + 1 > size) { // Filled up to "size", append partial line. @@ -1798,7 +1798,7 @@ failed: msg_scrolled_ign = true; if (!read_stdin && !read_buffer) { - p = (char_u *)msg_trunc_attr(IObuff, false, 0); + p = (uint8_t *)msg_trunc_attr(IObuff, false, 0); } if (read_stdin || read_buffer || restart_edit != 0 @@ -1859,7 +1859,7 @@ failed: // When opening a new file locate undo info and read it. if (read_undo_file) { - char_u hash[UNDO_HASH_SIZE]; + uint8_t hash[UNDO_HASH_SIZE]; sha256_finish(&sha_ctx, hash); u_read_undo(NULL, hash, fname); @@ -3208,7 +3208,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, fenc); + write_info.bw_len = make_bom(buffer, fenc); if (write_info.bw_len > 0) { // don't convert write_info.bw_flags = FIO_NOCONVERT | wb_flags; @@ -3991,9 +3991,10 @@ 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 **pp, int flags) FUNC_ATTR_NONNULL_ALL +static bool ucs2bytes(unsigned c, char **pp, int flags) + FUNC_ATTR_NONNULL_ALL { - char_u *p = (char_u *)(*pp); + uint8_t *p = (uint8_t *)(*pp); bool error = false; if (flags & FIO_UCS4) { @@ -4170,8 +4171,9 @@ static char *check_for_bom(const char *p_in, int size, int *lenp, int flags) /// 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 *name) +static int make_bom(char *buf_in, char *name) { + uint8_t *buf = (uint8_t *)buf_in; int flags = get_fio_flags(name); // Can't put a BOM in a non-Unicode file. @@ -4187,7 +4189,7 @@ static int make_bom(char_u *buf, char *name) } char *p = (char *)buf; (void)ucs2bytes(0xfeff, &p, flags); - return (int)((char_u *)p - buf); + return (int)((uint8_t *)p - buf); } /// Shorten filename of a buffer. @@ -4953,7 +4955,7 @@ int buf_check_timestamp(buf_T *buf) // Reload the buffer. buf_reload(buf, orig_mode, reload == RELOAD_DETECT); if (buf->b_p_udf && buf->b_ffname != NULL) { - char_u hash[UNDO_HASH_SIZE]; + uint8_t hash[UNDO_HASH_SIZE]; // Any existing undo file is unusable, write it now. u_compute_hash(buf, hash); -- cgit From ce0fddf5ae334f0c79dcd95b379999e11df1486b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 9 Mar 2023 08:07:36 -0500 Subject: feat: try to recover from missing tempdir #22573 Problem: If vim_tempdir mysteriously goes missing (typically by "antivirus" on Windows), any plugins using tempname() will be broken for the rest of the session. #1432 #9833 https://groups.google.com/g/vim_use/c/ef55jNm5czI Steps: mkdir foo TMPDIR=./foo nvim :echo tempname() !rm -r foo :echo tempname() tempname() still uses the foo path even though it was deleted. Solution: - Don't assume that vim_tempdir exists. - If it goes missing once, retry vim_mktempdir and log (silently) an error. - If it goes missing again, retry vim_mktempdir and show an error. Rejected in Vim for performance reasons: https://groups.google.com/g/vim_use/c/qgRob9SWDv8/m/FAOFVVcDTv0J https://groups.google.com/g/vim_dev/c/cogp-Vye4oo/m/d_SVFXBbnnoJ But, logging shows that `vim_gettempdir` is not called frequently. Fixes #1432 Fixes #9833 Fixes #11250 Related: stdpath("run") f50135a32e11c535e1dc3a8e9460c5b4e640ee86 --- src/nvim/fileio.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 6a13548027..115d34c3ea 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -5369,10 +5369,21 @@ void vim_deltempdir(void) /// Creates the directory on the first call. char *vim_gettempdir(void) { - if (vim_tempdir == NULL) { + static int notfound = 0; + bool exists = false; + if (vim_tempdir == NULL || !(exists = os_isdir(vim_tempdir))) { + if (vim_tempdir != NULL && !exists) { + notfound++; + if (notfound == 1) { + ELOG("tempdir disappeared (antivirus or broken cleanup job?): %s", vim_tempdir); + } + if (notfound > 1) { + msg_schedule_semsg("E5431: tempdir disappeared (%d times)", notfound); + } + XFREE_CLEAR(vim_tempdir); + } vim_mktempdir(); } - return vim_tempdir; } -- cgit From d6ecead36406233cc56353dd05f3380f0497630f Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 14 Mar 2023 11:49:46 +0100 Subject: refactor(screen): screen.c delenda est drawscreen.c vs screen.c makes absolutely no sense. The screen exists only to draw upon it, therefore helper functions are distributed randomly between screen.c and the file that does the redrawing. In addition screen.c does a lot of drawing on the screen. It made more sense for vim/vim as our grid.c is their screen.c Not sure if we want to dump all the code for option chars into optionstr.c, so keep these in a optionchar.c for now. --- src/nvim/fileio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 115d34c3ea..684658b4e3 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -55,7 +55,6 @@ #include "nvim/path.h" #include "nvim/pos.h" #include "nvim/regexp.h" -#include "nvim/screen.h" #include "nvim/sha256.h" #include "nvim/shada.h" #include "nvim/strings.h" @@ -157,7 +156,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) msg_scroll = false; } if (!msg_scroll) { // wait a bit when overwriting an error msg - check_for_delay(false); + msg_check_for_delay(false); } msg_start(); msg_scroll = msg_scroll_save; -- cgit From 371823d407d7d7519735131bcad4670c62a731a7 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:13:53 +0200 Subject: refactor: make error message definitions const message.c functions now take const char * as a format. Error message definitions can be made const. --- src/nvim/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 684658b4e3..cbb378b4b6 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -134,8 +134,8 @@ static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions' # include "fileio.c.generated.h" #endif -static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); -static char e_no_matching_autocommands_for_buftype_str_buffer[] +static const char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); +static const char e_no_matching_autocommands_for_buftype_str_buffer[] = N_("E676: No matching autocommands for buftype=%s buffer"); void filemess(buf_T *buf, char *name, char *s, int attr) -- cgit From 7190dba017e3aac0409c73ff1c954d18858cb3c9 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Thu, 6 Apr 2023 22:39:50 +0200 Subject: refactor: remove use of reserved c++ keywords libnvim couldn't be easily used in C++ due to the use of reserved keywords. Additionally, add explicit casts to *alloc function calls used in inline functions, as C++ doesn't allow implicit casts from void pointers. --- src/nvim/fileio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index cbb378b4b6..d76b22f65c 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -5428,10 +5428,9 @@ char *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 template[TEMP_FILE_PATH_MAXLEN]; - snprintf(template, TEMP_FILE_PATH_MAXLEN, - "%s%" PRIu64, tempdir, temp_count++); - return xstrdup(template); + char templ[TEMP_FILE_PATH_MAXLEN]; + snprintf(templ, TEMP_FILE_PATH_MAXLEN, "%s%" PRIu64, tempdir, temp_count++); + return xstrdup(templ); } /// Tries matching a filename with a "pattern" ("prog" is NULL), or use the -- cgit From 9408f2dcf7cade2631688300e9b58eed6bc5219a Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:40:57 +0200 Subject: refactor: remove redundant const char * casts --- src/nvim/fileio.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index d76b22f65c..143ec988c9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -145,7 +145,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) if (msg_silent != 0) { return; } - add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)name); + add_quoted_fname(IObuff, IOSIZE - 100, buf, name); // Avoid an over-long translation to cause trouble. xstrlcat(IObuff, s, IOSIZE); // For the first message may have to start a new line. @@ -576,7 +576,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // Set swap file protection bits after creating it. if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL && curbuf->b_ml.ml_mfp->mf_fname != NULL) { - const char *swap_fname = (const char *)curbuf->b_ml.ml_mfp->mf_fname; + const char *swap_fname = curbuf->b_ml.ml_mfp->mf_fname; // If the group-read bit is set but not the world-read bit, then // the group must be equal to the group of the original file. If @@ -1732,7 +1732,7 @@ failed: } if (!filtering && !(flags & READ_DUMMY) && !silent) { - add_quoted_fname(IObuff, IOSIZE, curbuf, (const char *)sfname); + add_quoted_fname(IObuff, IOSIZE, curbuf, sfname); c = false; #ifdef UNIX @@ -2372,7 +2372,7 @@ static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwritin *newfile = true; *perm = -1; } else { - *perm = os_getperm((const char *)fname); + *perm = os_getperm(fname); if (*perm < 0) { *newfile = true; } else if (os_isdir(fname)) { @@ -2611,7 +2611,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o // set file protection same as original file, but // strip s-bit. - (void)os_setperm((const char *)(*backupp), perm & 0777); + (void)os_setperm(*backupp, perm & 0777); #ifdef UNIX // @@ -2621,8 +2621,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o // if (file_info_new.stat.st_gid != file_info_old->stat.st_gid && os_chown(*backupp, (uv_uid_t)-1, (uv_gid_t)file_info_old->stat.st_gid) != 0) { - os_setperm((const char *)(*backupp), - ((int)perm & 0707) | (((int)perm & 07) << 3)); + os_setperm(*backupp, ((int)perm & 0707) | (((int)perm & 07) << 3)); } #endif @@ -2960,7 +2959,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en && file_info_old.stat.st_uid == getuid() && vim_strchr(p_cpo, CPO_FWRITE) == NULL) { perm |= 0200; - (void)os_setperm((const char *)fname, (int)perm); + (void)os_setperm(fname, (int)perm); made_writable = true; } #endif @@ -3378,7 +3377,7 @@ restore_backup: } #endif if (perm >= 0) { // Set perm. of new file same as old file. - (void)os_setperm((const char *)wfname, (int)perm); + (void)os_setperm(wfname, (int)perm); } // Probably need to set the ACL before changing the user (can't set the // ACL on a file the user doesn't own). @@ -3459,7 +3458,7 @@ restore_backup: fname = sfname; // use shortname now, for the messages #endif if (!filtering) { - add_quoted_fname(IObuff, IOSIZE, buf, (const char *)fname); + add_quoted_fname(IObuff, IOSIZE, buf, fname); bool insert_space = false; if (write_info.bw_conv_error) { STRCAT(IObuff, _(" CONVERSION ERROR")); @@ -3563,7 +3562,7 @@ restore_backup: } } if (org != NULL) { - os_setperm(org, os_getperm((const char *)fname) & 0777); + os_setperm(org, os_getperm(fname) & 0777); xfree(org); } } @@ -3600,9 +3599,9 @@ nofail: if (err.msg != NULL) { // - 100 to save some space for further error message #ifndef UNIX - add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)sfname); + add_quoted_fname(IObuff, IOSIZE - 100, buf, sfname); #else - add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)fname); + add_quoted_fname(IObuff, IOSIZE - 100, buf, fname); #endif emit_err(&err); @@ -5295,7 +5294,7 @@ int delete_recursive(const char *name) if (readdir_core(&ga, exp, NULL, NULL) == OK) { for (int i = 0; i < ga.ga_len; i++) { vim_snprintf(NameBuff, MAXPATHL, "%s/%s", exp, ((char **)ga.ga_data)[i]); - if (delete_recursive((const char *)NameBuff) != 0) { + if (delete_recursive(NameBuff) != 0) { // Remember the failure but continue deleting any further // entries. result = -1; -- cgit From 04933b1ea968f958d2541dd65fd33ebb503caac3 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:08:16 +0200 Subject: refactor: remove redundant casts --- src/nvim/fileio.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 143ec988c9..d4725ccd86 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -4228,7 +4228,7 @@ void shorten_fnames(int force) os_dirname(dirname, MAXPATHL); FOR_ALL_BUFFERS(buf) { - shorten_buf_fname(buf, (char *)dirname, force); + shorten_buf_fname(buf, dirname, force); // Always make the swap file name a full path, a "nofile" buffer may // also have a swap file. @@ -4362,7 +4362,7 @@ bool vim_fgets(char *buf, int size, FILE *fp) do { tbuf[sizeof(tbuf) - 2] = NUL; errno = 0; - retval = fgets((char *)tbuf, sizeof(tbuf), fp); + retval = fgets(tbuf, sizeof(tbuf), fp); if (retval == NULL && (feof(fp) || errno != EINTR)) { break; } @@ -4544,8 +4544,7 @@ int vim_rename(const char *from, const char *to) // 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)) { + if (p_fic && (strcmp(path_tail(from), path_tail(to)) != 0)) { use_tmp_file = true; } else { return 0; @@ -4554,7 +4553,7 @@ int vim_rename(const char *from, const char *to) // Fail if the "from" file doesn't exist. Avoids that "to" is deleted. FileInfo from_info; - if (!os_fileinfo((char *)from, &from_info)) { + if (!os_fileinfo(from, &from_info)) { return -1; } @@ -4562,8 +4561,7 @@ int vim_rename(const char *from, const char *to) // This happens when "from" and "to" differ in case and are on a FAT32 // filesystem. In that case go through a temp file name. FileInfo to_info; - if (os_fileinfo((char *)to, &to_info) - && os_fileinfo_id_equal(&from_info, &to_info)) { + if (os_fileinfo(to, &to_info) && os_fileinfo_id_equal(&from_info, &to_info)) { use_tmp_file = true; } @@ -4575,7 +4573,7 @@ int vim_rename(const char *from, const char *to) // 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); + os_remove(to); // First try a normal rename, return if it works. if (os_rename(from, to) == OK) { @@ -4586,14 +4584,14 @@ int vim_rename(const char *from, const char *to) long perm = os_getperm(from); // For systems that support ACL: get the ACL from the original file. vim_acl_T acl = os_get_acl(from); - int fd_in = os_open((char *)from, O_RDONLY, 0); + int fd_in = os_open(from, O_RDONLY, 0); if (fd_in < 0) { os_free_acl(acl); return -1; } // Create the new file with same permissions as the original. - int fd_out = os_open((char *)to, O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm); + int fd_out = os_open(to, O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm); if (fd_out < 0) { close(fd_in); os_free_acl(acl); @@ -4636,7 +4634,7 @@ int vim_rename(const char *from, const char *to) semsg(errmsg, to); return -1; } - os_remove((char *)from); + os_remove(from); return 0; } -- cgit From f39b33ee491a4a8d4b08425e582dd0dd53617edf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 11:46:17 +0800 Subject: vim-patch:9.0.0411: only created files can be cleaned up with one call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Only created files can be cleaned up with one call. Solution: Add flags to mkdir() to delete with a deferred function. Expand the writefile() name to a full path to handle changing directory. https://github.com/vim/vim/commit/6f14da15ac900589f2f413d77898b9bff3b31ece vim-patch:8.2.3742: dec mouse test fails without gnome terminfo entry Problem: Dec mouse test fails without gnome terminfo entry. Solution: Check if there is a gnome entry. Also fix 'acd' test on MS-Windows. (Dominique Pellé, closes vim/vim#9282) https://github.com/vim/vim/commit/f589fd3e1047cdf90566b68aaf9a13389e54d26a Cherry-pick test_autochdir.vim changes from patch 9.0.0313. Cherry-pick test_autocmd.vim changes from patch 9.0.0323. Co-authored-by: Bram Moolenaar --- src/nvim/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index d4725ccd86..fa2f72932f 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2536,7 +2536,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o if (*dirp == NUL && !os_isdir(IObuff)) { int ret; char *failed_dir; - if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir)) != 0) { + if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir, NULL)) != 0) { semsg(_("E303: Unable to create directory \"%s\" for backup file: %s"), failed_dir, os_strerror(ret)); xfree(failed_dir); @@ -2679,7 +2679,7 @@ nobackup: if (*dirp == NUL && !os_isdir(IObuff)) { int ret; char *failed_dir; - if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir)) != 0) { + if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir, NULL)) != 0) { semsg(_("E303: Unable to create directory \"%s\" for backup file: %s"), failed_dir, os_strerror(ret)); xfree(failed_dir); -- cgit From 7bf1a917b78ebc622b6691af9196b95b4a9d3142 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 19 Apr 2023 13:15:29 +0100 Subject: vim-patch:8.1.2094: the fileio.c file is too big Problem: The fileio.c file is too big. Solution: Move buf_write() to bufwrite.c. (Yegappan Lakshmanan, closes vim/vim#4990) https://github.com/vim/vim/commit/c079f0fed1c16495d726d616c5362edc04742a0d Co-authored-by: Yegappan Lakshmanan Co-authored-by: zeertzjq --- src/nvim/fileio.c | 2238 +++++------------------------------------------------ 1 file changed, 177 insertions(+), 2061 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fa2f72932f..52fafa6a21 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ #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" @@ -76,78 +76,31 @@ # include "nvim/charset.h" #endif -#define BUFSIZE 8192 // size of normal write buffer -#define SMBUFSIZE 256 // size of emergency write buffer - // For compatibility with libuv < 1.20.0 (tested on 1.18.0) #ifndef UV_FS_COPYFILE_FICLONE # define UV_FS_COPYFILE_FICLONE 0 #endif -enum { - FIO_LATIN1 = 0x01, // convert Latin1 - FIO_UTF8 = 0x02, // convert UTF-8 - FIO_UCS2 = 0x04, // convert UCS-2 - FIO_UCS4 = 0x08, // convert UCS-4 - FIO_UTF16 = 0x10, // convert UTF-16 - FIO_ENDIAN_L = 0x80, // little endian - FIO_NOCONVERT = 0x2000, // skip encoding conversion - FIO_UCSBOM = 0x4000, // check for BOM at start of file - FIO_ALL = -1, // allow all formats -}; - -// When converting, a read() or write() may leave some bytes to be converted -// for the next call. The value is guessed... -#define CONV_RESTLEN 30 - -// We have to guess how much a sequence of bytes may expand when converting -// with iconv() to be able to allocate a buffer. -#define ICONV_MULT 8 - -// Structure to pass arguments from buf_write() to buf_write_bytes(). -struct bw_info { - int bw_fd; // file descriptor - char *bw_buf; // buffer with data to be written - int bw_len; // length of data - int bw_flags; // FIO_ flags - uint8_t bw_rest[CONV_RESTLEN]; // not converted bytes - int bw_restlen; // nr of bytes in bw_rest[] - int bw_first; // first write call - char *bw_conv_buf; // buffer for writing converted chars - size_t bw_conv_buflen; // size of bw_conv_buf - int bw_conv_error; // set for conversion error - linenr_T bw_conv_error_lnum; // first line with error or zero - linenr_T bw_start_lnum; // line number at start of buffer - iconv_t bw_iconv_fd; // descriptor for iconv() or -1 -}; - -typedef struct { - const char *num; - char *msg; - int arg; - bool alloc; -} Error_T; - -static char *err_readonly = "is read-only (cannot override: \"W\" in 'cpoptions')"; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "fileio.c.generated.h" #endif static const char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name"); -static const char e_no_matching_autocommands_for_buftype_str_buffer[] - = N_("E676: No matching autocommands for buftype=%s buffer"); void filemess(buf_T *buf, char *name, char *s, int attr) { int msg_scroll_save; + int prev_msg_col = msg_col; if (msg_silent != 0) { return; } + add_quoted_fname(IObuff, IOSIZE - 100, buf, name); + // Avoid an over-long translation to cause trouble. xstrlcat(IObuff, s, IOSIZE); + // For the first message may have to start a new line. // For further ones overwrite the previous one, reset msg_scroll before // calling filemess(). @@ -159,6 +112,9 @@ void filemess(buf_T *buf, char *name, char *s, int attr) msg_check_for_delay(false); } msg_start(); + if (prev_msg_col != 0 && msg_col == 0) { + msg_putchar('\r'); // overwrite any previous message. + } msg_scroll = msg_scroll_save; msg_scrolled_ign = true; // may truncate the message to avoid a hit-return prompt @@ -1797,6 +1753,9 @@ failed: msg_scrolled_ign = true; if (!read_stdin && !read_buffer) { + if (msg_col > 0) { + msg_putchar('\r'); // overwrite previous message + } p = (uint8_t *)msg_trunc_attr(IObuff, false, 0); } @@ -2096,2036 +2055,217 @@ char *new_file_message(void) return shortmess(SHM_NEW) ? _("[New]") : _("[New File]"); } -static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char **ffnamep, - linenr_T start, linenr_T *endp, exarg_T *eap, bool append, - bool filtering, bool reset_changed, bool overwriting, bool whole, - const pos_T orig_start, const pos_T orig_end) +/// 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. +int set_rw_fname(char *fname, char *sfname) { - linenr_T old_line_count = buf->b_ml.ml_line_count; - int msg_save = msg_scroll; - - aco_save_T aco; - bool did_cmd = false; - bool nofile_err = false; - bool empty_memline = buf->b_ml.ml_mfp == NULL; - bufref_T bufref; - - char *sfname = *sfnamep; - - // Apply PRE autocommands. - // Set curbuf to the buffer to be written. - // Careful: The autocommands may call buf_write() recursively! - bool buf_ffname = *ffnamep == buf->b_ffname; - bool buf_sfname = sfname == buf->b_sfname; - bool buf_fname_f = *fnamep == buf->b_ffname; - bool buf_fname_s = *fnamep == buf->b_sfname; - - // Set curwin/curbuf to buf and save a few things. - aucmd_prepbuf(&aco, buf); - set_bufref(&bufref, buf); + buf_T *buf = curbuf; - if (append) { - did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD, sfname, sfname, false, curbuf, eap); - if (!did_cmd) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEAPPENDPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else if (filtering) { - apply_autocmds_exarg(EVENT_FILTERWRITEPRE, - NULL, sfname, false, curbuf, eap); - } else if (reset_changed && whole) { - bool was_changed = curbufIsChanged(); - - did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD, sfname, sfname, false, curbuf, eap); - if (did_cmd) { - if (was_changed && !curbufIsChanged()) { - // Written everything correctly and BufWriteCmd has reset - // 'modified': Correct the undo information so that an - // undo now sets 'modified'. - u_unchanged(curbuf); - u_update_save_nr(curbuf); - } - } else { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_BUFWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } - } else { - did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD, sfname, sfname, false, curbuf, eap); - if (!did_cmd) { - if (overwriting && bt_nofilename(curbuf)) { - nofile_err = true; - } else { - apply_autocmds_exarg(EVENT_FILEWRITEPRE, - sfname, sfname, false, curbuf, eap); - } - } + // It's like the unnamed buffer is deleted.... + if (curbuf->b_p_bl) { + apply_autocmds(EVENT_BUFDELETE, NULL, NULL, false, curbuf); + } + apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, false, curbuf); + if (aborting()) { // autocmds may abort script processing + return FAIL; + } + if (curbuf != buf) { + // We are in another buffer now, don't do the renaming. + emsg(_(e_auchangedbuf)); + return FAIL; } - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); - - // In three situations we return here and don't write the file: - // 1. the autocommands deleted or unloaded the buffer. - // 2. The autocommands abort script processing. - // 3. If one of the "Cmd" autocommands was executed. - if (!bufref_valid(&bufref)) { - buf = NULL; - } - if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline) - || did_cmd || nofile_err - || aborting()) { - if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS)) { - // restore the original '[ and '] positions - buf->b_op_start = orig_start; - buf->b_op_end = orig_end; - } - - no_wait_return--; - msg_scroll = msg_save; - if (nofile_err) { - semsg(_(e_no_matching_autocommands_for_buftype_str_buffer), curbuf->b_p_bt); - } + if (setfname(curbuf, fname, sfname, false) == OK) { + curbuf->b_flags |= BF_NOTEDITED; + } - if (nofile_err - || aborting()) { - // An aborting error, interrupt or exception in the - // autocommands. - return FAIL; - } - if (did_cmd) { - if (buf == NULL) { - // The buffer was deleted. We assume it was written - // (can't retry anyway). - return OK; - } - if (overwriting) { - // Assume the buffer was written, update the timestamp. - ml_timestamp(buf); - if (append) { - buf->b_flags &= ~BF_NEW; - } else { - buf->b_flags &= ~BF_WRITE_MASK; - } - } - if (reset_changed && buf->b_changed && !append - && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { - // Buffer still changed, the autocommands didn't work properly. - return FAIL; - } - return OK; - } - if (!aborting()) { - emsg(_("E203: Autocommands deleted or unloaded buffer to be written")); - } + // ....and a new named one is created + apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, curbuf); + if (curbuf->b_p_bl) { + apply_autocmds(EVENT_BUFADD, NULL, NULL, false, curbuf); + } + if (aborting()) { // autocmds may abort script processing 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!). - if (buf->b_ml.ml_line_count != old_line_count) { - if (whole) { // write all - *endp = buf->b_ml.ml_line_count; - } else if (buf->b_ml.ml_line_count > old_line_count) { // more lines - *endp += buf->b_ml.ml_line_count - old_line_count; - } else { // less lines - *endp -= old_line_count - buf->b_ml.ml_line_count; - if (*endp < start) { - no_wait_return--; - msg_scroll = msg_save; - emsg(_("E204: Autocommand changed number of lines in unexpected way")); - return FAIL; - } + // Do filetype detection now if 'filetype' is empty. + if (*curbuf->b_p_ft == NUL) { + if (augroup_exists("filetypedetect")) { + (void)do_doautocmd("filetypedetect BufRead", false, NULL); } + do_modelines(0); } - // The autocommands may have changed the name of the buffer, which may - // be kept in fname, ffname and sfname. - if (buf_ffname) { - *ffnamep = buf->b_ffname; + return OK; +} + +/// Put file name into the specified buffer with quotes +/// +/// Replaces home directory at the start with `~`. +/// +/// @param[out] ret_buf Buffer to save results to. +/// @param[in] buf_len ret_buf length. +/// @param[in] buf buf_T file name is coming from. +/// @param[in] fname File name to write. +void add_quoted_fname(char *const ret_buf, const size_t buf_len, const buf_T *const buf, + const char *fname) + FUNC_ATTR_NONNULL_ARG(1) +{ + if (fname == NULL) { + fname = "-stdin-"; } - if (buf_sfname) { - *sfnamep = buf->b_sfname; + ret_buf[0] = '"'; + home_replace(buf, fname, ret_buf + 1, buf_len - 4, true); + xstrlcat(ret_buf, "\" ", buf_len); +} + +/// Append message for text mode to IObuff. +/// +/// @param eol_type line ending type +/// +/// @return true if something was appended. +bool msg_add_fileformat(int eol_type) +{ +#ifndef USE_CRNL + if (eol_type == EOL_DOS) { + STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]")); + return true; } - if (buf_fname_f) { - *fnamep = buf->b_ffname; +#endif + if (eol_type == EOL_MAC) { + STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]")); + return true; } - if (buf_fname_s) { - *fnamep = buf->b_sfname; +#ifdef USE_CRNL + if (eol_type == EOL_UNIX) { + STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]")); + return true; } - return NOTDONE; +#endif + return false; } -static void buf_write_do_post_autocmds(buf_T *buf, char *fname, exarg_T *eap, bool append, - bool filtering, bool reset_changed, bool whole) +/// Append line and character count to IObuff. +void msg_add_lines(int insert_space, long lnum, off_T nchars) { - aco_save_T aco; - - 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! - aucmd_prepbuf(&aco, buf); + char *p = IObuff + strlen(IObuff); - if (append) { - apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname, - false, curbuf, eap); - } else if (filtering) { - apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname, - false, curbuf, eap); - } else if (reset_changed && whole) { - apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname, - false, curbuf, eap); + if (insert_space) { + *p++ = ' '; + } + if (shortmess(SHM_LINES)) { + vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), "%" PRId64 "L, %" PRId64 "B", + (int64_t)lnum, (int64_t)nchars); } else { - apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname, - false, curbuf, eap); + vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), + NGETTEXT("%" PRId64 " line, ", "%" PRId64 " lines, ", lnum), + (int64_t)lnum); + p += strlen(p); + vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), + NGETTEXT("%" PRId64 " byte", "%" PRId64 " bytes", nchars), + (int64_t)nchars); } - - // restore curwin/curbuf and a few other things - aucmd_restbuf(&aco); } -static inline Error_T set_err_num(const char *num, const char *msg) +/// Append message for missing line separator to IObuff. +void msg_add_eol(void) { - return (Error_T){ .num = num, .msg = (char *)msg, .arg = 0 }; + STRCAT(IObuff, + shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]")); } -static inline Error_T set_err_arg(const char *msg, int arg) +bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST { - return (Error_T){ .num = NULL, .msg = (char *)msg, .arg = arg }; +#if defined(__linux__) || defined(MSWIN) + return file_info->stat.st_mtim.tv_nsec != mtime_ns + // On a FAT filesystem, esp. under Linux, there are only 5 bits to store + // the seconds. Since the roundoff is done when flushing the inode, the + // time may change unexpectedly by one second!!! + || file_info->stat.st_mtim.tv_sec - mtime > 1 + || mtime - file_info->stat.st_mtim.tv_sec > 1; +#else + return file_info->stat.st_mtim.tv_nsec != mtime_ns + || file_info->stat.st_mtim.tv_sec != mtime; +#endif } -static inline Error_T set_err(const char *msg) +/// Return true if file encoding "fenc" requires conversion from or to +/// 'encoding'. +/// +/// @param fenc file encoding to check +/// +/// @return true if conversion is required +bool need_conversion(const char *fenc) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - return (Error_T){ .num = NULL, .msg = (char *)msg, .arg = 0 }; -} + int same_encoding; + int fenc_flags; -static void emit_err(Error_T *e) -{ - if (e->num != NULL) { - if (e->arg != 0) { - semsg("%s: %s%s: %s", e->num, IObuff, e->msg, os_strerror(e->arg)); - } else { - semsg("%s: %s%s", e->num, IObuff, e->msg); - } - } else if (e->arg != 0) { - semsg(e->msg, os_strerror(e->arg)); + if (*fenc == NUL || strcmp(p_enc, fenc) == 0) { + same_encoding = true; + fenc_flags = 0; } else { - emsg(e->msg); + // Ignore difference between "ansi" and "latin1", "ucs-4" and + // "ucs-4be", etc. + int enc_flags = get_fio_flags(p_enc); + fenc_flags = get_fio_flags(fenc); + same_encoding = (enc_flags != 0 && fenc_flags == enc_flags); } - if (e->alloc) { - xfree(e->msg); + if (same_encoding) { + // Specified file encoding matches UTF-8. + return false; } -} - -#if defined(UNIX) -static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, long *perm, - bool *device, bool *newfile, Error_T *err) -{ - *perm = -1; - if (!os_fileinfo(fname, file_info_old)) { - *newfile = true; - } else { - *perm = (long)file_info_old->stat.st_mode; - if (!S_ISREG(file_info_old->stat.st_mode)) { // not a file - if (S_ISDIR(file_info_old->stat.st_mode)) { - *err = set_err_num("E502", _("is a directory")); - return FAIL; - } - if (os_nodetype(fname) != NODE_WRITABLE) { - *err = set_err_num("E503", _("is not a file or writable device")); - return 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. - *device = true; - *newfile = true; - *perm = -1; - } - } - return OK; + // Encodings differ. However, conversion is not needed when 'enc' is any + // Unicode encoding and the file is UTF-8. + return !(fenc_flags == FIO_UTF8); } -#else - -static int get_fileinfo_os(char *fname, FileInfo *file_info_old, bool overwriting, long *perm, - bool *device, bool *newfile, Error_T *err) +/// Return the FIO_ flags needed for the internal conversion if 'name' was +/// unicode or latin1, otherwise 0. If "name" is an empty string, +/// use 'encoding'. +/// +/// @param name string to check for encoding +int get_fio_flags(const char *name) { - // Check for a writable device name. - char nodetype = fname == NULL ? NODE_OTHER : (char)os_nodetype(fname); - if (nodetype == NODE_OTHER) { - *err = set_err_num("E503", _("is not a file or writable device")); - return FAIL; + if (*name == NUL) { + name = p_enc; } - if (nodetype == NODE_WRITABLE) { - *device = true; - *newfile = true; - *perm = -1; - } else { - *perm = os_getperm(fname); - if (*perm < 0) { - *newfile = true; - } else if (os_isdir(fname)) { - *err = set_err_num("E502", _("is a directory")); - return FAIL; - } - if (overwriting) { - os_fileinfo(fname, file_info_old); + int prop = enc_canon_props(name); + if (prop & ENC_UNICODE) { + if (prop & ENC_2BYTE) { + if (prop & ENC_ENDIAN_L) { + return FIO_UCS2 | FIO_ENDIAN_L; + } + return FIO_UCS2; } - } - return OK; -} - -#endif - -/// @param buf -/// @param fname File name -/// @param overwriting -/// @param forceit -/// @param[out] file_info_old -/// @param[out] perm -/// @param[out] device -/// @param[out] newfile -/// @param[out] readonly -static int get_fileinfo(buf_T *buf, char *fname, bool overwriting, bool forceit, - FileInfo *file_info_old, long *perm, bool *device, bool *newfile, - bool *readonly, Error_T *err) -{ - if (get_fileinfo_os(fname, file_info_old, overwriting, perm, device, newfile, err) == FAIL) { - return FAIL; - } - - *readonly = false; // overwritten file is read-only - - if (!*device && !*newfile) { - // Check if the file is really writable (when renaming the file to - // make a backup we won't discover it later). - *readonly = !os_file_is_writable(fname); - - if (!forceit && *readonly) { - if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { - *err = set_err_num("E504", _(err_readonly)); - } else { - *err = set_err_num("E505", _("is read-only (add ! to override)")); + if (prop & ENC_4BYTE) { + if (prop & ENC_ENDIAN_L) { + return FIO_UCS4 | FIO_ENDIAN_L; } - return FAIL; + return FIO_UCS4; } - - // If 'forceit' is false, check if the timestamp hasn't changed since reading the file. - if (overwriting && !forceit) { - int retval = check_mtime(buf, file_info_old); - if (retval == FAIL) { - return FAIL; + if (prop & ENC_2WORD) { + if (prop & ENC_ENDIAN_L) { + return FIO_UTF16 | FIO_ENDIAN_L; } + return FIO_UTF16; } + return FIO_UTF8; } - return OK; + if (prop & ENC_LATIN1) { + return FIO_LATIN1; + } + // must be ENC_DBCS, requires iconv() + return 0; } -static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_old, vim_acl_T acl, - long perm, unsigned int bkc, bool file_readonly, bool forceit, - int *backup_copyp, char **backupp, Error_T *err) -{ - FileInfo file_info; - const bool no_prepend_dot = false; - - if ((bkc & BKC_YES) || append) { // "yes" - *backup_copyp = true; - } else if ((bkc & BKC_AUTO)) { // "auto" - // 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_copyp = 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). - STRCPY(IObuff, fname); - for (int i = 4913;; i += 123) { - char *tail = path_tail(IObuff); - size_t size = (size_t)(tail - IObuff); - snprintf(tail, IOSIZE - size, "%d", i); - if (!os_fileinfo_link(IObuff, &file_info)) { - break; - } - } - int fd = os_open(IObuff, - O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, (int)perm); - if (fd < 0) { // can't write in directory - *backup_copyp = 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(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_copyp = true; - } -#endif - // Close the file before removing it, on MS-Windows we - // can't delete an open file. - close(fd); - os_remove(IObuff); - } - } - } - - // 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); - - // Symlinks. - if ((bkc & BKC_BREAKSYMLINK) - && file_info_link_ok - && !os_fileinfo_id_equal(&file_info, file_info_old)) { - *backup_copyp = false; - } - - // Hardlinks. - if ((bkc & BKC_BREAKHARDLINK) - && os_fileinfo_hardlinks(file_info_old) > 1 - && (!file_info_link_ok - || os_fileinfo_id_equal(&file_info, file_info_old))) { - *backup_copyp = false; - } -#endif - } - - // make sure we have a valid backup extension to use - char *backup_ext = *p_bex == NUL ? ".bak" : p_bex; - - if (*backup_copyp) { - int some_error = false; - - // 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. - char *dirp = p_bdir; - while (*dirp) { - // Isolate one directory name, using an entry in 'bdir'. - size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - char *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(IObuff)) { - int ret; - char *failed_dir; - if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir, NULL)) != 0) { - semsg(_("E303: Unable to create directory \"%s\" for backup file: %s"), - failed_dir, os_strerror(ret)); - xfree(failed_dir); - } - } - if (trailing_pathseps) { - // Ends with '//', Use Full path - if ((p = make_percent_swname(IObuff, fname)) - != NULL) { - *backupp = modname(p, backup_ext, no_prepend_dot); - xfree(p); - } - } - - char *rootname = get_file_in_dir(fname, IObuff); - if (rootname == NULL) { - some_error = true; // out of memory - goto nobackup; - } - - FileInfo file_info_new; - { - // - // Make the backup file name. - // - if (*backupp == NULL) { - *backupp = modname(rootname, backup_ext, no_prepend_dot); - } - - if (*backupp == NULL) { - xfree(rootname); - some_error = true; // out of memory - goto nobackup; - } - - // Check if backup file already exists. - if (os_fileinfo(*backupp, &file_info_new)) { - if (os_fileinfo_id_equal(&file_info_new, file_info_old)) { - // - // Backup file is same as original file. - // May happen when modname() gave the same file back (e.g. silly - // link). If we don't check here, we either ruin the file when - // copying or erase it after writing. - // - XFREE_CLEAR(*backupp); // no backup file to delete - } else if (!p_bk) { - // We are not going to keep the backup file, so don't - // delete an existing one, and try to use another name instead. - // Change one character, just before the extension. - // - char *wp = *backupp + strlen(*backupp) - 1 - strlen(backup_ext); - if (wp < *backupp) { // empty file name ??? - wp = *backupp; - } - *wp = 'z'; - while (*wp > 'a' && os_fileinfo(*backupp, &file_info_new)) { - (*wp)--; - } - // They all exist??? Must be something wrong. - if (*wp == 'a') { - XFREE_CLEAR(*backupp); - } - } - } - } - xfree(rootname); - - // Try to create the backup file - if (*backupp != NULL) { - // remove old backup, if present - os_remove(*backupp); - - // set file protection same as original file, but - // strip s-bit. - (void)os_setperm(*backupp, perm & 0777); - -#ifdef UNIX - // - // Try to set the group of the backup same as the original file. If - // this fails, set the protection bits for the group same as the - // protection bits for others. - // - if (file_info_new.stat.st_gid != file_info_old->stat.st_gid - && os_chown(*backupp, (uv_uid_t)-1, (uv_gid_t)file_info_old->stat.st_gid) != 0) { - os_setperm(*backupp, ((int)perm & 0707) | (((int)perm & 07) << 3)); - } -#endif - - // copy the file - if (os_copy(fname, *backupp, UV_FS_COPYFILE_FICLONE) != 0) { - *err = set_err(_("E509: Cannot create backup file (add ! to override)")); - XFREE_CLEAR(*backupp); - *backupp = NULL; - continue; - } - -#ifdef UNIX - os_file_settime(*backupp, - (double)file_info_old->stat.st_atim.tv_sec, - (double)file_info_old->stat.st_mtim.tv_sec); -#endif - os_set_acl(*backupp, acl); - *err = set_err(NULL); - break; - } - } - -nobackup: - if (*backupp == NULL && err->msg == NULL) { - *err = set_err(_("E509: Cannot create backup file (add ! to override)")); - } - // Ignore errors when forceit is true. - if ((some_error || err->msg != NULL) && !forceit) { - return FAIL; - } - *err = set_err(NULL); - } else { - // 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) { - *err = set_err_num("E504", _(err_readonly)); - return 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. - char *dirp = p_bdir; - while (*dirp) { - // Isolate one directory name and make the backup file name. - size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ","); - char *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(IObuff)) { - int ret; - char *failed_dir; - if ((ret = os_mkdir_recurse(IObuff, 0755, &failed_dir, NULL)) != 0) { - semsg(_("E303: Unable to create directory \"%s\" for backup file: %s"), - failed_dir, os_strerror(ret)); - xfree(failed_dir); - } - } - if (trailing_pathseps) { - // path ends with '//', use full path - if ((p = make_percent_swname(IObuff, fname)) - != NULL) { - *backupp = modname(p, backup_ext, no_prepend_dot); - xfree(p); - } - } - - if (*backupp == NULL) { - char *rootname = get_file_in_dir(fname, IObuff); - if (rootname == NULL) { - *backupp = NULL; - } else { - *backupp = modname(rootname, backup_ext, no_prepend_dot); - xfree(rootname); - } - } - - if (*backupp != 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(*backupp)) { - p = *backupp + strlen(*backupp) - 1 - strlen(backup_ext); - if (p < *backupp) { // empty file name ??? - p = *backupp; - } - *p = 'z'; - while (*p > 'a' && os_path_exists(*backupp)) { - (*p)--; - } - // They all exist??? Must be something wrong! - if (*p == 'a') { - XFREE_CLEAR(*backupp); - } - } - } - if (*backupp != NULL) { - // Delete any existing backup and move the current version - // to the backup. For safety, we don't remove the backup - // until the write has finished successfully. And if the - // 'backup' option is set, leave it around. - - // If the renaming of the original file to the backup file - // works, quit here. - /// - if (vim_rename(fname, *backupp) == 0) { - break; - } - - XFREE_CLEAR(*backupp); // don't do the rename below - } - } - if (*backupp == NULL && !forceit) { - *err = set_err(_("E510: Can't make backup file (add ! to override)")); - return FAIL; - } - } - return OK; -} - -/// buf_write() - write to file "fname" lines "start" through "end" -/// -/// We do our own buffering here because fwrite() is so slow. -/// -/// If "forceit" is true, we don't care for errors when attempting backups. -/// In case of an error everything possible is done to restore the original -/// file. But when "forceit" is true, we risk losing it. -/// -/// When "reset_changed" is true and "append" == false and "start" == 1 and -/// "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed. -/// -/// This function must NOT use NameBuff (because it's called by autowrite()). -/// -/// -/// @param eap for forced 'ff' and 'fenc', can be NULL! -/// @param append append to the file -/// -/// @return FAIL for failure, OK otherwise -int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T end, exarg_T *eap, - int append, int forceit, int reset_changed, int filtering) -{ - int retval = OK; - int msg_save = msg_scroll; - int prev_got_int = got_int; - // writing everything - int whole = (start == 1 && end == buf->b_ml.ml_line_count); - int write_undo_file = false; - context_sha256_T sha_ctx; - unsigned int bkc = get_bkc_value(buf); - - if (fname == NULL || *fname == NUL) { // safety check - return FAIL; - } - if (buf->b_ml.ml_mfp == NULL) { - // This can happen during startup when there is a stray "w" in the - // vimrc file. - emsg(_(e_emptybuf)); - return FAIL; - } - - // Disallow writing in secure mode. - if (check_secure()) { - return FAIL; - } - - // Avoid a crash for a long name. - if (strlen(fname) >= MAXPATHL) { - emsg(_(e_longname)); - return FAIL; - } - - // must init bw_conv_buf and bw_iconv_fd before jumping to "fail" - struct bw_info write_info; // info for buf_write_bytes() - write_info.bw_conv_buf = NULL; - write_info.bw_conv_error = false; - write_info.bw_conv_error_lnum = 0; - write_info.bw_restlen = 0; - write_info.bw_iconv_fd = (iconv_t)-1; - - // After writing a file changedtick changes but we don't want to display - // the line. - ex_no_reprint = true; - - // If there is no file name yet, use the one for the written file. - // BF_NOTEDITED is set to reflect this (in case the write fails). - // Don't do this when the write is for a filter command. - // Don't do this when appending. - // Only do this when 'cpoptions' contains the 'F' flag. - if (buf->b_ffname == NULL - && reset_changed - && whole - && buf == curbuf - && !bt_nofilename(buf) - && !filtering - && (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL) - && vim_strchr(p_cpo, CPO_FNAMEW) != NULL) { - if (set_rw_fname(fname, sfname) == FAIL) { - return FAIL; - } - buf = curbuf; // just in case autocmds made "buf" invalid - } - - if (sfname == NULL) { - sfname = fname; - } - - // For Unix: Use the short file name whenever possible. - // Avoids problems with networks and when directory names are changed. - // Don't do this for Windows, a "cd" in a sub-shell may have moved us to - // another directory, which we don't detect. - char *ffname = fname; // remember full fname -#ifdef UNIX - fname = sfname; -#endif - -// true if writing over original - int overwriting = buf->b_ffname != NULL && path_fnamecmp(ffname, buf->b_ffname) == 0; - - no_wait_return++; // don't wait for return yet - - const pos_T orig_start = buf->b_op_start; - const pos_T orig_end = buf->b_op_end; - - // Set '[ and '] marks to the lines to be written. - buf->b_op_start.lnum = start; - buf->b_op_start.col = 0; - buf->b_op_end.lnum = end; - buf->b_op_end.col = 0; - - int res = buf_write_do_autocmds(buf, &fname, &sfname, &ffname, start, &end, eap, append, - filtering, reset_changed, overwriting, whole, orig_start, - orig_end); - if (res != NOTDONE) { - return res; - } - - if (cmdmod.cmod_flags & CMOD_LOCKMARKS) { - // restore the original '[ and '] positions - buf->b_op_start = orig_start; - buf->b_op_end = orig_end; - } - - if (shortmess(SHM_OVER) && !exiting) { - msg_scroll = false; // overwrite previous file message - } else { - msg_scroll = true; // don't overwrite previous file message - } - if (!filtering) { - // show that we are busy -#ifndef UNIX - filemess(buf, sfname, "", 0); -#else - filemess(buf, fname, "", 0); -#endif - } - msg_scroll = false; // always overwrite the file message now - - char *buffer = verbose_try_malloc(BUFSIZE); - int bufsize; - char smallbuf[SMBUFSIZE]; - // can't allocate big buffer, use small one (to be able to write when out of - // memory) - if (buffer == NULL) { - buffer = smallbuf; - bufsize = SMBUFSIZE; - } else { - bufsize = BUFSIZE; - } - - Error_T err = { 0 }; - long perm; // file permissions - bool newfile = false; // true if file doesn't exist yet - bool device = false; // writing to a device - bool file_readonly = false; // overwritten file is read-only - char *backup = NULL; - char *fenc_tofree = NULL; // allocated "fenc" - - // Get information about original file (if there is one). - FileInfo file_info_old; - - vim_acl_T acl = NULL; // ACL copied from original file to - // backup or new file - - if (get_fileinfo(buf, fname, overwriting, forceit, &file_info_old, &perm, &device, &newfile, - &file_readonly, &err) == FAIL) { - goto fail; - } - - // For systems that support ACL: get the ACL from the original file. - if (!newfile) { - acl = os_get_acl(fname); - } - - // If 'backupskip' is not empty, don't make a backup for some files. - bool dobackup = (p_wb || p_bk || *p_pm != NUL); - if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) { - dobackup = false; - } - - int backup_copy = false; // copy the original file? - - // 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 (!(append && *p_pm == NUL) && !filtering && perm >= 0 && dobackup) { - if (buf_write_make_backup(fname, append, &file_info_old, acl, perm, bkc, file_readonly, forceit, - &backup_copy, &backup, &err) == FAIL) { - retval = FAIL; - goto fail; - } - } - -#if defined(UNIX) - int made_writable = false; // 'w' bit has been set - - // When using ":w!" and the file was read-only: make it writable - if (forceit && perm >= 0 && !(perm & 0200) - && file_info_old.stat.st_uid == getuid() - && vim_strchr(p_cpo, CPO_FWRITE) == NULL) { - perm |= 0200; - (void)os_setperm(fname, (int)perm); - made_writable = true; - } -#endif - - // When using ":w!" and writing to the current file, 'readonly' makes no - // sense, reset it, unless 'Z' appears in 'cpoptions'. - if (forceit && overwriting && vim_strchr(p_cpo, CPO_KEEPRO) == NULL) { - buf->b_p_ro = false; - need_maketitle = true; // set window title later - status_redraw_all(); // redraw status lines later - } - - if (end > buf->b_ml.ml_line_count) { - end = buf->b_ml.ml_line_count; - } - if (buf->b_ml.ml_flags & ML_EMPTY) { - start = end + 1; - } - - char *wfname = NULL; // name of file to write to - - // If the original file is being overwritten, there is a small chance that - // we crash in the middle of writing. Therefore the file is preserved now. - // This makes all block numbers positive so that recovery does not need - // the original file. - // Don't do this if there is a backup file and we are exiting. - if (reset_changed && !newfile && overwriting - && !(exiting && backup != NULL)) { - ml_preserve(buf, false, !!p_fs); - if (got_int) { - err = set_err(_(e_interr)); - goto restore_backup; - } - } - - // Default: write the file directly. May write to a temp file for - // multi-byte conversion. - wfname = fname; - - char *fenc; // effective 'fileencoding' - - // Check for forced 'fileencoding' from "++opt=val" argument. - if (eap != NULL && eap->force_enc != 0) { - fenc = eap->cmd + eap->force_enc; - fenc = enc_canonize(fenc); - fenc_tofree = fenc; - } else { - fenc = buf->b_p_fenc; - } - - // Check if the file needs to be converted. - int converted = need_conversion(fenc); - int wb_flags = 0; - - // 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(). - // Prepare the flags for it and allocate bw_conv_buf when needed. - if (converted) { - 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)) { - write_info.bw_conv_buflen = (size_t)bufsize * 2; - } else { // FIO_UCS4 - write_info.bw_conv_buflen = (size_t)bufsize * 4; - } - write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen); - if (!write_info.bw_conv_buf) { - end = 0; - } - } - } - - if (converted && wb_flags == 0) { - // Use iconv() conversion when conversion is needed and it's not done - // internally. - 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; - write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen); - if (!write_info.bw_conv_buf) { - end = 0; - } - write_info.bw_first = true; - } else { - // 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! - err = set_err(_("E214: Can't find temp file for writing")); - goto restore_backup; - } - } - } - } - - int notconverted = false; - - if (converted && wb_flags == 0 - && write_info.bw_iconv_fd == (iconv_t)-1 - && wfname == fname) { - if (!forceit) { - err = set_err(_("E213: Cannot convert (add ! to write without conversion)")); - goto restore_backup; - } - notconverted = true; - } - - int no_eol = false; // no end-of-line written - long nchars; - linenr_T lnum; - int fileformat; - int checking_conversion; - - int fd; - - // If conversion is taking place, we may first pretend to write and check - // for conversion errors. Then loop again to write for real. - // When not doing conversion this writes for real right away. - for (checking_conversion = true;; checking_conversion = false) { - // There is no need to check conversion when: - // - there is no conversion - // - we make a backup file, that can be restored in case of conversion - // failure. - if (!converted || dobackup) { - checking_conversion = false; - } - - if (checking_conversion) { - // Make sure we don't write anything. - fd = -1; - write_info.bw_fd = fd; - } else { - // Open the file "wfname" for writing. - // We may try to open the file twice: If we can't write to the file - // and forceit is true we delete the existing file and try to - // create a new one. If this still fails we may have lost the - // original file! (this may happen when the user reached his - // quotum for number of files). - // Appending will fail if the file does not exist and forceit is - // false. - const int fflags = O_WRONLY | (append - ? (forceit ? (O_APPEND | O_CREAT) : O_APPEND) - : (O_CREAT | O_TRUNC)); - const int mode = perm < 0 ? 0666 : (perm & 0777); - - while ((fd = os_open(wfname, fflags, mode)) < 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 - // is read-only. In that case the mch_remove() will fail. - if (err.msg == NULL) { -#ifdef UNIX - FileInfo file_info; - - // Don't delete the file when it's a hard or symbolic link. - if ((!newfile && os_fileinfo_hardlinks(&file_info_old) > 1) - || (os_fileinfo_link(fname, &file_info) - && !os_fileinfo_id_equal(&file_info, &file_info_old))) { - err = set_err(_("E166: Can't open linked file for writing")); - } else { - err = set_err_arg(_("E212: Can't open file for writing: %s"), fd); - if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) { - // we write to the file, thus it should be marked - // writable after all - if (!(perm & 0200)) { - made_writable = true; - } - perm |= 0200; - if (file_info_old.stat.st_uid != getuid() - || file_info_old.stat.st_gid != getgid()) { - perm &= 0777; - } - if (!append) { // don't remove when appending - os_remove(wfname); - } - continue; - } - } -#else - err = set_err_arg(_("E212: Can't open file for writing: %s"), fd); - if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL && perm >= 0) { - if (!append) { // don't remove when appending - os_remove(wfname); - } - continue; - } -#endif - } - -restore_backup: - { - // If we failed to open the file, we don't need a backup. Throw it - // away. If we moved or removed the original file try to put the - // backup in its place. - if (backup != NULL && wfname == fname) { - if (backup_copy) { - // There is a small chance that we removed the original, - // try to move the copy in its place. - // 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(fname)) { - vim_rename(backup, fname); - } - // if original file does exist throw away the copy - if (os_path_exists(fname)) { - os_remove(backup); - } - } else { - // try to put the original file back - vim_rename(backup, fname); - } - } - - // if original file no longer exists give an extra warning - if (!newfile && !os_path_exists(fname)) { - end = 0; - } - } - - if (wfname != fname) { - xfree(wfname); - } - goto fail; - } - write_info.bw_fd = fd; - } - err = set_err(NULL); - - write_info.bw_buf = buffer; - nchars = 0; - - // use "++bin", "++nobin" or 'binary' - int write_bin; - if (eap != NULL && eap->force_bin != 0) { - write_bin = (eap->force_bin == FORCE_BIN); - } else { - write_bin = buf->b_p_bin; - } - - // 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(buffer, fenc); - if (write_info.bw_len > 0) { - // don't convert - write_info.bw_flags = FIO_NOCONVERT | wb_flags; - if (buf_write_bytes(&write_info) == FAIL) { - end = 0; - } else { - nchars += write_info.bw_len; - } - } - } - write_info.bw_start_lnum = start; - - write_undo_file = (buf->b_p_udf && overwriting && !append - && !filtering && reset_changed && !checking_conversion); - if (write_undo_file) { - // Prepare for computing the hash value of the text. - sha256_start(&sha_ctx); - } - - write_info.bw_len = bufsize; - write_info.bw_flags = wb_flags; - fileformat = get_fileformat_force(buf, eap); - char *s = buffer; - int len = 0; - for (lnum = start; lnum <= end; lnum++) { - // The next while loop is done once for each character written. - // Keep it fast! - char *ptr = ml_get_buf(buf, lnum, false) - 1; - if (write_undo_file) { - sha256_update(&sha_ctx, (uint8_t *)ptr + 1, (uint32_t)(strlen(ptr + 1) + 1)); - } - char c; - while ((c = *++ptr) != NUL) { - if (c == NL) { - *s = NUL; // replace newlines with NULs - } else if (c == CAR && fileformat == EOL_MAC) { - *s = NL; // Mac: replace CRs with NLs - } else { - *s = c; - } - s++; - if (++len != bufsize) { - continue; - } - if (buf_write_bytes(&write_info) == FAIL) { - end = 0; // write error: break loop - break; - } - nchars += bufsize; - s = buffer; - len = 0; - write_info.bw_start_lnum = lnum; - } - // write failed or last line has no EOL: stop here - if (end == 0 - || (lnum == end - && (write_bin || !buf->b_p_fixeol) - && ((write_bin && lnum == buf->b_no_eol_lnum) - || (lnum == buf->b_ml.ml_line_count && !buf->b_p_eol)))) { - lnum++; // written the line, count it - no_eol = true; - break; - } - if (fileformat == EOL_UNIX) { - *s++ = NL; - } else { - *s++ = CAR; // EOL_MAC or EOL_DOS: write CR - if (fileformat == EOL_DOS) { // write CR-NL - if (++len == bufsize) { - if (buf_write_bytes(&write_info) == FAIL) { - end = 0; // write error: break loop - break; - } - nchars += bufsize; - s = buffer; - len = 0; - } - *s++ = NL; - } - } - if (++len == bufsize) { - if (buf_write_bytes(&write_info) == FAIL) { - end = 0; // Write error: break loop. - break; - } - nchars += bufsize; - s = buffer; - len = 0; - - os_breakcheck(); - if (got_int) { - end = 0; // Interrupted, break loop. - break; - } - } - } - if (len > 0 && end > 0) { - write_info.bw_len = len; - if (buf_write_bytes(&write_info) == FAIL) { - end = 0; // write error - } - 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; - } - - // If no error happened until now, writing should be ok, so loop to - // really write the buffer. - } - - // If we started writing, finish writing. Also when an error was - // encountered. - if (!checking_conversion) { - // On many journalling file systems there is a bug that causes both the - // original and the backup file to be lost when halting the system right - // after writing the file. That's because only the meta-data is - // journalled. Syncing the file slows down the system, but assures it has - // been written to disk and we don't lose it. - // For a device do try the fsync() but don't complain if it does not work - // (could be a pipe). - // If the 'fsync' option is false, don't fsync(). Useful for laptops. - int error; - if (p_fs && (error = os_fsync(fd)) != 0 && !device - // fsync not supported on this storage. - && error != UV_ENOTSUP) { - err = set_err_arg(e_fsync, error); - end = 0; - } - -#ifdef UNIX - // When creating a new file, set its owner/group to that of the original - // file. Get the new device and inode number. - if (backup != NULL && !backup_copy) { - // don't change the owner when it's already OK, some systems remove - // permission or ACL stuff - FileInfo file_info; - if (!os_fileinfo(wfname, &file_info) - || file_info.stat.st_uid != file_info_old.stat.st_uid - || file_info.stat.st_gid != file_info_old.stat.st_gid) { - os_fchown(fd, (uv_uid_t)file_info_old.stat.st_uid, (uv_gid_t)file_info_old.stat.st_gid); - if (perm >= 0) { // Set permission again, may have changed. - (void)os_setperm(wfname, (int)perm); - } - } - buf_set_file_id(buf); - } else if (!buf->file_id_valid) { - // Set the file_id when creating a new file. - buf_set_file_id(buf); - } -#endif - - if ((error = os_close(fd)) != 0) { - err = set_err_arg(_("E512: Close failed: %s"), error); - end = 0; - } - -#ifdef UNIX - if (made_writable) { - perm &= ~0200; // reset 'w' bit for security reasons - } -#endif - if (perm >= 0) { // Set perm. of new file same as old file. - (void)os_setperm(wfname, (int)perm); - } - // 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) { - os_set_acl(wfname, acl); - } - - if (wfname != fname) { - // The file was written to a temp file, now it needs to be converted - // with 'charconvert' to (overwrite) the output file. - if (end != 0) { - if (eval_charconvert("utf-8", fenc, wfname, fname) == FAIL) { - write_info.bw_conv_error = true; - end = 0; - } - } - os_remove(wfname); - xfree(wfname); - } - } - - if (end == 0) { - // Error encountered. - if (err.msg == NULL) { - if (write_info.bw_conv_error) { - if (write_info.bw_conv_error_lnum == 0) { - err = set_err(_("E513: write error, conversion failed " - "(make 'fenc' empty to override)")); - } else { - err = set_err(xmalloc(300)); - err.alloc = true; - vim_snprintf(err.msg, 300, // NOLINT(runtime/printf) - _("E513: write error, conversion failed in line %" PRIdLINENR - " (make 'fenc' empty to override)"), - write_info.bw_conv_error_lnum); - } - } else if (got_int) { - err = set_err(_(e_interr)); - } else { - err = set_err(_("E514: write error (file system full?)")); - } - } - - // If we have a backup file, try to put it in place of the new file, - // because the new file is probably corrupt. This avoids losing the - // original file when trying to make a backup when writing the file a - // second time. - // When "backup_copy" is set we need to copy the backup over the new - // file. Otherwise rename the backup file. - // If this is OK, don't give the extra warning message. - if (backup != NULL) { - if (backup_copy) { - // This may take a while, if we were interrupted let the user - // know we got the message. - if (got_int) { - msg(_(e_interr)); - ui_flush(); - } - - // copy the file. - if (os_copy(backup, fname, UV_FS_COPYFILE_FICLONE) - == 0) { - end = 1; // success - } - } else { - if (vim_rename(backup, fname) == 0) { - end = 1; - } - } - } - goto fail; - } - - lnum -= start; // compute number of written lines - no_wait_return--; // may wait for return now - -#if !defined(UNIX) - fname = sfname; // use shortname now, for the messages -#endif - if (!filtering) { - add_quoted_fname(IObuff, IOSIZE, buf, fname); - bool insert_space = false; - if (write_info.bw_conv_error) { - STRCAT(IObuff, _(" CONVERSION ERROR")); - insert_space = true; - if (write_info.bw_conv_error_lnum != 0) { - vim_snprintf_add(IObuff, IOSIZE, _(" in line %" PRId64 ";"), - (int64_t)write_info.bw_conv_error_lnum); - } - } else if (notconverted) { - STRCAT(IObuff, _("[NOT converted]")); - insert_space = true; - } else if (converted) { - STRCAT(IObuff, _("[converted]")); - insert_space = true; - } - if (device) { - STRCAT(IObuff, _("[Device]")); - insert_space = true; - } else if (newfile) { - STRCAT(IObuff, new_file_message()); - insert_space = true; - } - if (no_eol) { - msg_add_eol(); - insert_space = true; - } - // may add [unix/dos/mac] - if (msg_add_fileformat(fileformat)) { - insert_space = true; - } - msg_add_lines(insert_space, (long)lnum, nchars); // add line/char count - if (!shortmess(SHM_WRITE)) { - if (append) { - STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended")); - } else { - STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written")); - } - } - - 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'. - if (reset_changed && whole && !append - && !write_info.bw_conv_error - && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) { - unchanged(buf, true, false); - const varnumber_T changedtick = buf_get_changedtick(buf); - if (buf->b_last_changedtick + 1 == changedtick) { - // b:changedtick may be incremented in unchanged() but that - // should not trigger a TextChanged event. - buf->b_last_changedtick = changedtick; - } - u_unchanged(buf); - 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 (overwriting) { - ml_timestamp(buf); - if (append) { - buf->b_flags &= ~BF_NEW; - } else { - buf->b_flags &= ~BF_WRITE_MASK; - } - } - - // 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 (org == NULL) { - emsg(_("E205: Patchmode: can't save original file")); - } else if (!os_path_exists(org)) { - vim_rename(backup, org); - XFREE_CLEAR(backup); // don't delete the file -#ifdef UNIX - os_file_settime(org, - (double)file_info_old.stat.st_atim.tv_sec, - (double)file_info_old.stat.st_mtim.tv_sec); -#endif - } - } else { - // If there is no backup file, remember that a (new) file was - // created. - int empty_fd; - - if (org == NULL - || (empty_fd = os_open(org, - O_CREAT | O_EXCL | O_NOFOLLOW, - perm < 0 ? 0666 : (perm & 0777))) < 0) { - emsg(_("E206: patchmode: can't touch empty original file")); - } else { - close(empty_fd); - } - } - if (org != NULL) { - os_setperm(org, os_getperm(fname) & 0777); - xfree(org); - } - } - - // Remove the backup unless 'backup' option is set - if (!p_bk && backup != NULL - && !write_info.bw_conv_error - && os_remove(backup) != 0) { - emsg(_("E207: Can't delete backup file")); - } - - goto nofail; - - // Finish up. We get here either after failure or success. -fail: - no_wait_return--; // may wait for return now -nofail: - - // Done saving, we accept changed buffer warnings again - buf->b_saving = false; - - xfree(backup); - if (buffer != smallbuf) { - xfree(buffer); - } - xfree(fenc_tofree); - xfree(write_info.bw_conv_buf); - if (write_info.bw_iconv_fd != (iconv_t)-1) { - iconv_close(write_info.bw_iconv_fd); - write_info.bw_iconv_fd = (iconv_t)-1; - } - os_free_acl(acl); - - if (err.msg != NULL) { - // - 100 to save some space for further error message -#ifndef UNIX - add_quoted_fname(IObuff, IOSIZE - 100, buf, sfname); -#else - add_quoted_fname(IObuff, IOSIZE - 100, buf, fname); -#endif - emit_err(&err); - - retval = FAIL; - if (end == 0) { - const int attr = HL_ATTR(HLF_E); // Set highlight for error messages. - msg_puts_attr(_("\nWARNING: Original file may be lost or damaged\n"), - attr | MSG_HIST); - msg_puts_attr(_("don't quit the editor until the file is successfully written!"), - attr | MSG_HIST); - - // Update the timestamp to avoid an "overwrite changed file" - // prompt when writing again. - if (os_fileinfo(fname, &file_info_old)) { - buf_store_file_info(buf, &file_info_old); - buf->b_mtime_read = buf->b_mtime; - buf->b_mtime_read_ns = buf->b_mtime_ns; - } - } - } - msg_scroll = msg_save; - - // When writing the whole file and 'undofile' is set, also write the undo - // file. - if (retval == OK && write_undo_file) { - uint8_t hash[UNDO_HASH_SIZE]; - - sha256_finish(&sha_ctx, hash); - u_write_undo(NULL, false, buf, hash); - } - - if (!should_abort(retval)) { - buf_write_do_post_autocmds(buf, fname, eap, append, filtering, reset_changed, whole); - if (aborting()) { // autocmds may abort script processing - retval = false; - } - } - - got_int |= prev_got_int; - - return retval; -} - -/// 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 *fname, char *sfname) -{ - buf_T *buf = curbuf; - - // It's like the unnamed buffer is deleted.... - if (curbuf->b_p_bl) { - apply_autocmds(EVENT_BUFDELETE, NULL, NULL, false, curbuf); - } - apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, false, curbuf); - if (aborting()) { // autocmds may abort script processing - return FAIL; - } - if (curbuf != buf) { - // We are in another buffer now, don't do the renaming. - emsg(_(e_auchangedbuf)); - return FAIL; - } - - if (setfname(curbuf, fname, sfname, false) == OK) { - curbuf->b_flags |= BF_NOTEDITED; - } - - // ....and a new named one is created - apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, curbuf); - if (curbuf->b_p_bl) { - apply_autocmds(EVENT_BUFADD, NULL, NULL, false, curbuf); - } - if (aborting()) { // autocmds may abort script processing - return FAIL; - } - - // Do filetype detection now if 'filetype' is empty. - if (*curbuf->b_p_ft == NUL) { - if (augroup_exists("filetypedetect")) { - (void)do_doautocmd("filetypedetect BufRead", false, NULL); - } - do_modelines(0); - } - - return OK; -} - -/// Put file name into the specified buffer with quotes -/// -/// Replaces home directory at the start with `~`. -/// -/// @param[out] ret_buf Buffer to save results to. -/// @param[in] buf_len ret_buf length. -/// @param[in] buf buf_T file name is coming from. -/// @param[in] fname File name to write. -static void add_quoted_fname(char *const ret_buf, const size_t buf_len, const buf_T *const buf, - const char *fname) - FUNC_ATTR_NONNULL_ARG(1) -{ - if (fname == NULL) { - fname = "-stdin-"; - } - ret_buf[0] = '"'; - home_replace(buf, fname, ret_buf + 1, buf_len - 4, true); - xstrlcat(ret_buf, "\" ", buf_len); -} - -/// Append message for text mode to IObuff. -/// -/// @param eol_type line ending type -/// -/// @return true if something was appended. -static bool msg_add_fileformat(int eol_type) -{ -#ifndef USE_CRNL - if (eol_type == EOL_DOS) { - STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]")); - return true; - } -#endif - if (eol_type == EOL_MAC) { - STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]")); - return true; - } -#ifdef USE_CRNL - if (eol_type == EOL_UNIX) { - STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]")); - return true; - } -#endif - return false; -} - -/// Append line and character count to IObuff. -void msg_add_lines(int insert_space, long lnum, off_T nchars) -{ - char *p = IObuff + strlen(IObuff); - - if (insert_space) { - *p++ = ' '; - } - if (shortmess(SHM_LINES)) { - vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), "%" PRId64 "L, %" PRId64 "B", - (int64_t)lnum, (int64_t)nchars); - } else { - vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), - NGETTEXT("%" PRId64 " line, ", "%" PRId64 " lines, ", lnum), - (int64_t)lnum); - p += strlen(p); - vim_snprintf(p, (size_t)(IOSIZE - (p - IObuff)), - NGETTEXT("%" PRId64 " byte", "%" PRId64 " bytes", nchars), - (int64_t)nchars); - } -} - -/// Append message for missing line separator to IObuff. -static void msg_add_eol(void) -{ - STRCAT(IObuff, - shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]")); -} - -/// Check modification time of file, before writing to it. -/// The size isn't checked, because using a tool like "gzip" takes care of -/// using the same timestamp but can't set the size. -static int check_mtime(buf_T *buf, FileInfo *file_info) -{ - if (buf->b_mtime_read != 0 - && time_differs(file_info, buf->b_mtime_read, buf->b_mtime_read_ns)) { - msg_scroll = true; // Don't overwrite messages here. - msg_silent = 0; // Must give this prompt. - // Don't use emsg() here, don't want to flush the buffers. - msg_attr(_("WARNING: The file has been changed since reading it!!!"), - HL_ATTR(HLF_E)); - if (ask_yesno(_("Do you really want to write to it"), true) == 'n') { - return FAIL; - } - msg_scroll = false; // Always overwrite the file message now. - } - return OK; -} - -static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST -{ -#if defined(__linux__) || defined(MSWIN) - return file_info->stat.st_mtim.tv_nsec != mtime_ns - // On a FAT filesystem, esp. under Linux, there are only 5 bits to store - // the seconds. Since the roundoff is done when flushing the inode, the - // time may change unexpectedly by one second!!! - || file_info->stat.st_mtim.tv_sec - mtime > 1 - || mtime - file_info->stat.st_mtim.tv_sec > 1; -#else - return file_info->stat.st_mtim.tv_nsec != mtime_ns - || file_info->stat.st_mtim.tv_sec != mtime; -#endif -} - -static int buf_write_convert_with_iconv(struct bw_info *ip, char **bufp, int *lenp) -{ - const char *from; - size_t fromlen; - size_t tolen; - - int len = *lenp; - - // Convert with iconv(). - if (ip->bw_restlen > 0) { - // 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; - char *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, *bufp, (size_t)len); - from = fp; - tolen = ip->bw_conv_buflen - fromlen; - } else { - from = *bufp; - fromlen = (size_t)len; - tolen = ip->bw_conv_buflen; - } - char *to = ip->bw_conv_buf; - - if (ip->bw_first) { - size_t save_len = tolen; - - // 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". - if (to == NULL) { - to = ip->bw_conv_buf; - tolen = save_len; - } - ip->bw_first = false; - } - - // 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) { - ip->bw_conv_error = true; - return FAIL; - } - - // copy remainder to ip->bw_rest[] to be used for the next call. - if (fromlen > 0) { - memmove(ip->bw_rest, (void *)from, fromlen); - } - ip->bw_restlen = (int)fromlen; - - *bufp = ip->bw_conv_buf; - *lenp = (int)(to - ip->bw_conv_buf); - - return OK; -} - -static int buf_write_convert(struct bw_info *ip, char **bufp, int *lenp) -{ - int flags = ip->bw_flags; // extra flags - - if (flags & FIO_UTF8) { - // Convert latin1 in the buffer to UTF-8 in the file. - char *p = ip->bw_conv_buf; // translate to buffer - for (int wlen = 0; wlen < *lenp; wlen++) { - p += utf_char2bytes((uint8_t)(*bufp)[wlen], p); - } - *bufp = ip->bw_conv_buf; - *lenp = (int)(p - ip->bw_conv_buf); - } else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) { - unsigned c; - int n = 0; - // Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or - // Latin1 chars in the file. - // translate in-place (can only get shorter) or to buffer - char *p = flags & FIO_LATIN1 ? *bufp : ip->bw_conv_buf; - for (int wlen = 0; wlen < *lenp; wlen += n) { - if (wlen == 0 && ip->bw_restlen != 0) { - // Use remainder of previous call. Append the start of - // buf[] to get a full sequence. Might still be too - // short! - int l = MIN(*lenp, CONV_RESTLEN - ip->bw_restlen); - memmove(ip->bw_rest + ip->bw_restlen, *bufp, (size_t)l); - n = utf_ptr2len_len((char *)ip->bw_rest, ip->bw_restlen + l); - if (n > ip->bw_restlen + *lenp) { - // 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 + *lenp > CONV_RESTLEN) { - return FAIL; - } - ip->bw_restlen += *lenp; - break; - } - if (n > 1) { - c = (unsigned)utf_ptr2char((char *)ip->bw_rest); - } else { - c = ip->bw_rest[0]; - } - if (n >= ip->bw_restlen) { - n -= ip->bw_restlen; - ip->bw_restlen = 0; - } else { - ip->bw_restlen -= n; - memmove(ip->bw_rest, ip->bw_rest + n, - (size_t)ip->bw_restlen); - n = 0; - } - } else { - n = utf_ptr2len_len(*bufp + wlen, *lenp - wlen); - if (n > *lenp - 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. - if (*lenp - wlen > CONV_RESTLEN) { - return FAIL; - } - ip->bw_restlen = *lenp - wlen; - memmove(ip->bw_rest, *bufp + wlen, - (size_t)ip->bw_restlen); - break; - } - if (n > 1) { - c = (unsigned)utf_ptr2char(*bufp + wlen); - } else { - c = (uint8_t)(*bufp)[wlen]; - } - } - - if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) { - ip->bw_conv_error = true; - ip->bw_conv_error_lnum = ip->bw_start_lnum; - } - if (c == NL) { - ip->bw_start_lnum++; - } - } - if (flags & FIO_LATIN1) { - *lenp = (int)(p - *bufp); - } else { - *bufp = ip->bw_conv_buf; - *lenp = (int)(p - ip->bw_conv_buf); - } - } - - if (ip->bw_iconv_fd != (iconv_t)-1) { - if (buf_write_convert_with_iconv(ip, bufp, lenp) == FAIL) { - return FAIL; - } - } - - return OK; -} - -/// Call write() to write a number of bytes to the file. -/// Handles 'encoding' conversion. -/// -/// @return FAIL for failure, OK otherwise. -static int buf_write_bytes(struct bw_info *ip) -{ - char *buf = ip->bw_buf; // data to write - int len = ip->bw_len; // length of data - int flags = ip->bw_flags; // extra flags - - // Skip conversion when writing the BOM. - if (!(flags & FIO_NOCONVERT)) { - if (buf_write_convert(ip, &buf, &len) == FAIL) { - return FAIL; - } - } - - if (ip->bw_fd < 0) { - // Only checking conversion, which is OK if we get here. - return OK; - } - int wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len); - return (wlen < len) ? FAIL : OK; -} - -/// Convert a Unicode character to bytes. -/// -/// @param c character to convert -/// @param[in,out] pp pointer to store the result at -/// @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 **pp, int flags) - FUNC_ATTR_NONNULL_ALL -{ - uint8_t *p = (uint8_t *)(*pp); - bool error = false; - - if (flags & FIO_UCS4) { - if (flags & FIO_ENDIAN_L) { - *p++ = (uint8_t)c; - *p++ = (uint8_t)(c >> 8); - *p++ = (uint8_t)(c >> 16); - *p++ = (uint8_t)(c >> 24); - } else { - *p++ = (uint8_t)(c >> 24); - *p++ = (uint8_t)(c >> 16); - *p++ = (uint8_t)(c >> 8); - *p++ = (uint8_t)c; - } - } 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 - c -= 0x10000; - if (c >= 0x100000) { - error = true; - } - int cc = (int)(((c >> 10) & 0x3ff) + 0xd800); - if (flags & FIO_ENDIAN_L) { - *p++ = (uint8_t)cc; - *p++ = (uint8_t)(cc >> 8); - } else { - *p++ = (uint8_t)(cc >> 8); - *p++ = (uint8_t)cc; - } - c = (c & 0x3ff) + 0xdc00; - } else { - error = true; - } - } - if (flags & FIO_ENDIAN_L) { - *p++ = (uint8_t)c; - *p++ = (uint8_t)(c >> 8); - } else { - *p++ = (uint8_t)(c >> 8); - *p++ = (uint8_t)c; - } - } else { // Latin1 - if (c >= 0x100) { - error = true; - *p++ = 0xBF; - } else { - *p++ = (uint8_t)c; - } - } - - *pp = (char *)p; - return error; -} - -/// Return true if file encoding "fenc" requires conversion from or to -/// 'encoding'. -/// -/// @param fenc file encoding to check -/// -/// @return true if conversion is required -static bool need_conversion(const char *fenc) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - int same_encoding; - int fenc_flags; - - 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. - int 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) { - // Specified file encoding matches UTF-8. - return false; - } - - // Encodings differ. However, conversion is not needed when 'enc' is any - // Unicode encoding and the file is UTF-8. - return !(fenc_flags == FIO_UTF8); -} - -/// Return the FIO_ flags needed for the internal conversion if 'name' was -/// unicode or latin1, otherwise 0. If "name" is an empty string, -/// use 'encoding'. -/// -/// @param name string to check for encoding -static int get_fio_flags(const char *name) -{ - if (*name == NUL) { - name = p_enc; - } - int prop = enc_canon_props(name); - if (prop & ENC_UNICODE) { - if (prop & ENC_2BYTE) { - if (prop & ENC_ENDIAN_L) { - return FIO_UCS2 | FIO_ENDIAN_L; - } - return FIO_UCS2; - } - if (prop & ENC_4BYTE) { - if (prop & ENC_ENDIAN_L) { - return FIO_UCS4 | FIO_ENDIAN_L; - } - return FIO_UCS4; - } - if (prop & ENC_2WORD) { - if (prop & ENC_ENDIAN_L) { - return FIO_UTF16 | FIO_ENDIAN_L; - } - return FIO_UTF16; - } - return FIO_UTF8; - } - if (prop & ENC_LATIN1) { - return FIO_LATIN1; - } - // must be ENC_DBCS, requires iconv() - return 0; -} - -/// Check for a Unicode BOM (Byte Order Mark) at the start of p[size]. -/// "size" must be at least 2. -/// -/// @return the name of the encoding and set "*lenp" to the length or, -/// NULL when no BOM found. -static char *check_for_bom(const char *p_in, int size, int *lenp, int flags) +/// Check for a Unicode BOM (Byte Order Mark) at the start of p[size]. +/// "size" must be at least 2. +/// +/// @return the name of the encoding and set "*lenp" to the length or, +/// NULL when no BOM found. +static char *check_for_bom(const char *p_in, int size, int *lenp, int flags) { const uint8_t *p = (const uint8_t *)p_in; char *name = NULL; @@ -4166,30 +2306,6 @@ static char *check_for_bom(const char *p_in, int size, int *lenp, int flags) 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 *buf_in, char *name) -{ - uint8_t *buf = (uint8_t *)buf_in; - int flags = get_fio_flags(name); - - // Can't put a BOM in a non-Unicode file. - if (flags == FIO_LATIN1 || flags == 0) { - return 0; - } - - if (flags == FIO_UTF8) { // UTF-8 - buf[0] = 0xef; - buf[1] = 0xbb; - buf[2] = 0xbf; - return 3; - } - char *p = (char *)buf; - (void)ucs2bytes(0xfeff, &p, flags); - return (int)((uint8_t *)p - buf); -} - /// Shorten filename of a buffer. /// /// @param force when true: Use full path from now on for files currently being @@ -4600,7 +2716,7 @@ int vim_rename(const char *from, const char *to) // Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim // is `preserve_exit()`ing. - char *buffer = try_malloc(BUFSIZE); + char *buffer = try_malloc(WRITEBUFSIZE); if (buffer == NULL) { close(fd_out); close(fd_in); @@ -4609,7 +2725,7 @@ int vim_rename(const char *from, const char *to) } int n; - while ((n = (int)read_eintr(fd_in, buffer, BUFSIZE)) > 0) { + while ((n = (int)read_eintr(fd_in, buffer, WRITEBUFSIZE)) > 0) { if (write_eintr(fd_out, buffer, (size_t)n) != n) { errmsg = _("E208: Error writing to \"%s\""); break; -- cgit From ea52961c54797fc27e305eb4bb11a5d2c4cdda58 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 19 Apr 2023 22:49:14 +0800 Subject: refactor: fix PVS warnings (#23200) --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 52fafa6a21..bb17382f98 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3484,7 +3484,7 @@ char *vim_gettempdir(void) static int notfound = 0; bool exists = false; if (vim_tempdir == NULL || !(exists = os_isdir(vim_tempdir))) { - if (vim_tempdir != NULL && !exists) { + if (vim_tempdir != NULL) { notfound++; if (notfound == 1) { ELOG("tempdir disappeared (antivirus or broken cleanup job?): %s", vim_tempdir); -- cgit From 3b0df1780e2c8526bda5dead18ee7cc45925caba Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 26 Apr 2023 23:23:44 +0200 Subject: refactor: uncrustify Notable changes: replace all infinite loops to `while(true)` and remove `int` from `unsigned int`. --- src/nvim/fileio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index bb17382f98..d659987686 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -943,7 +943,7 @@ retry: } else { int ni; long tlen = 0; - for (;;) { + while (true) { p = (uint8_t *)ml_get(read_buf_lnum) + read_buf_col; int n = (int)strlen((char *)p); if ((int)tlen + n + 1 > size) { @@ -1141,7 +1141,7 @@ retry: } if (fio_flags != 0) { - unsigned int u8c; + unsigned u8c; char *dest; char *tail = NULL; @@ -3360,7 +3360,7 @@ int readdir_core(garray_T *gap, const char *path, void *context, CheckItem check return FAIL; } - for (;;) { + while (true) { const char *p = os_scandir_next(&dir); if (p == NULL) { break; @@ -3820,8 +3820,8 @@ long read_eintr(int fd, void *buf, size_t bufsize) { long ret; - for (;;) { - ret = read(fd, buf, (unsigned int)bufsize); + while (true) { + ret = read(fd, buf, (unsigned)bufsize); if (ret >= 0 || errno != EINTR) { break; } @@ -3838,7 +3838,7 @@ long write_eintr(int fd, void *buf, size_t bufsize) // Repeat the write() so long it didn't fail, other than being interrupted // by a signal. while (ret < (long)bufsize) { - long wlen = write(fd, (char *)buf + ret, (unsigned int)(bufsize - (size_t)ret)); + long wlen = write(fd, (char *)buf + ret, (unsigned)(bufsize - (size_t)ret)); if (wlen < 0) { if (errno != EINTR) { break; -- cgit From d36dd2bae8e899b40cc21603e600a5046213bc36 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Tue, 16 May 2023 05:33:03 +0200 Subject: refactor: use xstrl{cpy,cat} on IObuff (#23648) Replace usage of STR{CPY,CAT} with xstrl{cpy,cat} when using on IObuff Co-authored-by: ii14 --- src/nvim/fileio.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index d659987686..57aa063504 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1693,22 +1693,22 @@ failed: #ifdef UNIX if (S_ISFIFO(perm)) { // fifo - STRCAT(IObuff, _("[fifo]")); + xstrlcat(IObuff, _("[fifo]"), IOSIZE); c = true; } if (S_ISSOCK(perm)) { // or socket - STRCAT(IObuff, _("[socket]")); + xstrlcat(IObuff, _("[socket]"), IOSIZE); c = true; } # ifdef OPEN_CHR_FILES if (S_ISCHR(perm)) { // or character special - STRCAT(IObuff, _("[character special]")); + xstrlcat(IObuff, _("[character special]"), IOSIZE); c = true; } # endif #endif if (curbuf->b_p_ro) { - STRCAT(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")); + xstrlcat(IObuff, shortmess(SHM_RO) ? _("[RO]") : _("[readonly]"), IOSIZE); c = true; } if (read_no_eol_lnum) { @@ -1716,18 +1716,18 @@ failed: c = true; } if (ff_error == EOL_DOS) { - STRCAT(IObuff, _("[CR missing]")); + xstrlcat(IObuff, _("[CR missing]"), IOSIZE); c = true; } if (split) { - STRCAT(IObuff, _("[long lines split]")); + xstrlcat(IObuff, _("[long lines split]"), IOSIZE); c = true; } if (notconverted) { - STRCAT(IObuff, _("[NOT converted]")); + xstrlcat(IObuff, _("[NOT converted]"), IOSIZE); c = true; } else if (converted) { - STRCAT(IObuff, _("[converted]")); + xstrlcat(IObuff, _("[converted]"), IOSIZE); c = true; } if (conv_error != 0) { @@ -1739,7 +1739,7 @@ failed: _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte); c = true; } else if (error) { - STRCAT(IObuff, _("[READ ERRORS]")); + xstrlcat(IObuff, _("[READ ERRORS]"), IOSIZE); c = true; } if (msg_add_fileformat(fileformat)) { @@ -2128,17 +2128,17 @@ bool msg_add_fileformat(int eol_type) { #ifndef USE_CRNL if (eol_type == EOL_DOS) { - STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]")); + xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"), IOSIZE); return true; } #endif if (eol_type == EOL_MAC) { - STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]")); + xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"), IOSIZE); return true; } #ifdef USE_CRNL if (eol_type == EOL_UNIX) { - STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]")); + xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"), IOSIZE); return true; } #endif @@ -2170,8 +2170,7 @@ void msg_add_lines(int insert_space, long lnum, off_T nchars) /// Append message for missing line separator to IObuff. void msg_add_eol(void) { - STRCAT(IObuff, - shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]")); + xstrlcat(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"), IOSIZE); } bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST -- cgit From 677e02be4e1255435a39d25a4b12ecbed4fff37b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 23 May 2023 18:11:03 +0800 Subject: refactor: fix clang/PVS warnings (#23731) --- src/nvim/fileio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 57aa063504..e60007bf88 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3481,8 +3481,7 @@ void vim_deltempdir(void) char *vim_gettempdir(void) { static int notfound = 0; - bool exists = false; - if (vim_tempdir == NULL || !(exists = os_isdir(vim_tempdir))) { + if (vim_tempdir == NULL || !os_isdir(vim_tempdir)) { if (vim_tempdir != NULL) { notfound++; if (notfound == 1) { -- cgit From 7a8402ac31aa2e155baafbc925c48527511c1e92 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 28 May 2023 08:06:30 +0800 Subject: vim-patch:9.0.1583: get E304 when using 'cryptmethod' "xchacha20v2" (#23790) Problem: Get E304 when using 'cryptmethod' "xchacha20v2". (Steve Mynott) Solution: Add 4th crypt method to block zero ID check. Avoid syncing a swap file before reading the file. (closes vim/vim#12433) https://github.com/vim/vim/commit/3a2a60ce4a8e73594bca16814672fcc243d093ac Co-authored-by: Bram Moolenaar --- src/nvim/fileio.c | 63 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index e60007bf88..d24ac1c233 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -153,6 +153,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap, int flags, bool silent) { + int retval = FAIL; // jump to "theend" instead of returning int fd = stdin_fd >= 0 ? stdin_fd : 0; int newfile = (flags & READ_NEW); int check_readonly; @@ -240,7 +241,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, && vim_strchr(p_cpo, CPO_FNAMER) != NULL && !(flags & READ_DUMMY)) { if (set_rw_fname(fname, sfname) == FAIL) { - return FAIL; + goto theend; } } @@ -284,10 +285,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (newfile) { if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname, false, curbuf, eap)) { - int status = OK; - + retval = OK; if (aborting()) { - status = FAIL; + retval = FAIL; } // The BufReadCmd code usually uses ":read" to get the text and @@ -295,14 +295,15 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // consider this to work like ":edit", thus reset the // BF_NOTEDITED flag. Then ":write" will work to overwrite the // same file. - if (status == OK) { + if (retval == OK) { curbuf->b_flags &= ~BF_NOTEDITED; } - return status; + goto theend; } } else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname, false, NULL, eap)) { - return aborting() ? FAIL : OK; + retval = aborting() ? FAIL : OK; + goto theend; } curbuf->b_op_start = orig_start; @@ -310,7 +311,8 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (flags & READ_NOFILE) { // Return NOTDONE instead of FAIL so that BufEnter can be triggered // and other operations don't fail. - return NOTDONE; + retval = NOTDONE; + goto theend; } } @@ -328,7 +330,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, filemess(curbuf, fname, _("Illegal file name"), 0); msg_end(); msg_scroll = msg_save; - return FAIL; + goto theend; } // If the name ends in a path separator, we can't open it. Check here, @@ -340,7 +342,8 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } msg_end(); msg_scroll = msg_save; - return NOTDONE; + retval = NOTDONE; + goto theend; } } @@ -365,12 +368,13 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!silent) { filemess(curbuf, fname, _(msg_is_a_directory), 0); } + retval = NOTDONE; } else { filemess(curbuf, fname, _("is not a file"), 0); } msg_end(); msg_scroll = msg_save; - return S_ISDIR(perm) ? NOTDONE : FAIL; + goto theend; } } @@ -431,7 +435,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (fd < 0) { // cannot open at all msg_scroll = msg_save; if (!newfile) { - return FAIL; + goto theend; } if (perm == UV_ENOENT) { // check if the file exists // Set the 'new-file' flag, so that when the file has @@ -450,7 +454,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, || (using_b_fname && (old_b_fname != curbuf->b_fname))) { emsg(_(e_auchangedbuf)); - return FAIL; + goto theend; } } if (!silent) { @@ -472,10 +476,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, // remember the current fileformat save_file_ff(curbuf); - if (aborting()) { // autocmds may abort script processing - return FAIL; + if (!aborting()) { // autocmds may abort script processing + retval = OK; // a new file is not an error } - return OK; // a new file is not an error + goto theend; } #if defined(UNIX) && defined(EOVERFLOW) filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : @@ -491,7 +495,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, #endif curbuf->b_p_ro = true; // must use "w!" now - return FAIL; + goto theend; } // Only set the 'ro' flag for readonly files the first time they are @@ -526,7 +530,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!read_buffer) { close(fd); } - return FAIL; + goto theend; } #ifdef UNIX // Set swap file protection bits after creating it. @@ -561,7 +565,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, if (!read_buffer && !read_stdin) { close(fd); } - return FAIL; + goto theend; } no_wait_return++; // don't wait for return yet @@ -617,7 +621,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, no_wait_return--; msg_scroll = msg_save; curbuf->b_p_ro = true; // must use "w!" now - return FAIL; + goto theend; } // Don't allow the autocommands to change the current buffer. // Try to re-open the file. @@ -636,7 +640,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, emsg(_("E201: *ReadPre autocommands must not change current buffer")); } curbuf->b_p_ro = true; // must use "w!" now - return FAIL; + goto theend; } } @@ -1684,7 +1688,8 @@ failed: } msg_scroll = msg_save; check_marks_read(); - return OK; // an interrupt isn't really an error + retval = OK; // an interrupt isn't really an error + goto theend; } if (!filtering && !(flags & READ_DUMMY) && !silent) { @@ -1860,10 +1865,18 @@ failed: } } - if (recoverymode && error) { - return FAIL; + if (!(recoverymode && error)) { + retval = OK; } - return OK; + +theend: + if (curbuf->b_ml.ml_mfp != NULL + && curbuf->b_ml.ml_mfp->mf_dirty == MF_DIRTY_YES_NOSYNC) { + // OK to sync the swap file now + curbuf->b_ml.ml_mfp->mf_dirty = MF_DIRTY_YES; + } + + return retval; } #ifdef OPEN_CHR_FILES -- cgit From 4e63104c47132adee7d1dc678d69d80e867371bf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 17 Jun 2023 06:23:07 +0800 Subject: vim-patch:9.0.1637: compiler warning for uninitialized variable (#24042) Problem: Compiler warning for uninitialized variable. Solution: Move the variable to an inner block and initialize it. (Christian Brabandt, closes vim/vim#12549) https://github.com/vim/vim/commit/54f50cbf6a470316a262e4389d62424e6f06b81c The "eof" variable is not present in Nvim because it is only used by FEAT_CRYPT. Co-authored-by: Christian Brabandt --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index d24ac1c233..475415272a 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3618,7 +3618,7 @@ bool match_file_list(char *list, char *sfname, char *ffname) // try all patterns in 'wildignore' char *p = list; while (*p) { - char buf[100]; + char buf[MAXPATHL]; copy_option_part(&p, buf, ARRAY_SIZE(buf), ","); char allow_dirs; char *regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false); -- cgit From 7e301ed5b9f72a98086c7004d090ad9aef137485 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 18 Jun 2023 07:08:31 +0800 Subject: vim-patch:9.0.1638: crypt tests hang and cause memory errors (#24053) Problem: crypt tests hang and cause memory errors Solution: Move variable to start of function. https://github.com/vim/vim/commit/438d0c5e58aa475179ade9a1b99013733c5b8f06 N/A patches for version.c: vim-patch:9.0.1639: build failure without the crypt feature Problem: Build failure without the crypt feature. Solution: Adjust #ifdefs https://github.com/vim/vim/commit/bc385a150f9d812bb3e54ff0d5db75d3c6c3bb43 vim-patch:9.0.1640: compiler warning for unused variables without crypt feature Problem: Compiler warning for unused variables without the crypt feature. Solution: Adjust #ifdefs https://github.com/vim/vim/commit/7f29122c8ce2ca224d21abbaeb35e38bc354d95d Co-authored-by: Bram Moolenaar --- src/nvim/fileio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 475415272a..e22bb609b6 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -990,7 +990,8 @@ retry: } } else { // Read bytes from the file. - size = read_eintr(fd, ptr, (size_t)size); + size_t read_size = (size_t)size; + size = read_eintr(fd, ptr, read_size); } if (size <= 0) { -- cgit From cefd774fac76b91f5368833555818c80c992c3b1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 24 Aug 2023 15:14:23 +0200 Subject: refactor(memline): distinguish mutating uses of ml_get_buf() ml_get_buf() takes a third parameters to indicate whether the caller wants to mutate the memline data in place. However the vast majority of the call sites is using this function just to specify a buffer but without any mutation. This makes it harder to grep for the places which actually perform mutation. Solution: Remove the bool param from ml_get_buf(). it now works like ml_get() except for a non-current buffer. Add a new ml_get_buf_mut() function for the mutating use-case, which can be grepped along with the other ml_replace() etc functions which can modify the memline. --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index e22bb609b6..1cbfcff9f4 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2842,7 +2842,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) // Copy the lines in "frombuf" to "tobuf". curbuf = tobuf; for (linenr_T lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) { - char *p = xstrdup(ml_get_buf(frombuf, lnum, false)); + char *p = xstrdup(ml_get_buf(frombuf, lnum)); if (ml_append(lnum - 1, p, 0, false) == FAIL) { xfree(p); retval = FAIL; -- cgit From 008154954791001efcc46c28146e21403f3a698b Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 21 Aug 2023 14:52:17 +0200 Subject: refactor(change): do API changes to buffer without curbuf switch Most of the messy things when changing a non-current buffer is not about the buffer, it is about windows. In particular, it is about `curwin`. When editing a non-current buffer which is displayed in some other window in the current tabpage, one such window will be "borrowed" as the curwin. But this means if two or more non-current windows displayed the buffers, one of them will be treated differenty. this is not desirable. In particular, with nvim_buf_set_text, cursor _column_ position was only corrected for one single window. Two new tests are added: the test with just one non-current window passes, but the one with two didn't. Two corresponding such tests were also added for nvim_buf_set_lines. This already worked correctly on master, but make sure this is well-tested for future refactors. Also, nvim_create_buf no longer invokes autocmds just because you happened to use `scratch=true`. No option value was changed, therefore OptionSet must not be fired. --- src/nvim/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 1cbfcff9f4..5d7ddb657a 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1784,7 +1784,7 @@ failed: curbuf->b_p_ro = true; } - u_clearline(); // cannot use "U" command after adding lines + u_clearline(curbuf); // cannot use "U" command after adding lines // In Ex mode: cursor at last new line. // Otherwise: cursor at first new line. @@ -1793,7 +1793,7 @@ failed: } else { curwin->w_cursor.lnum = from + 1; } - check_cursor_lnum(); + check_cursor_lnum(curwin); beginline(BL_WHITE | BL_FIX); // on first non-blank if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { -- cgit From 68d425ac92599089047d98f1c533981ea917fed1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 25 Sep 2023 12:26:01 +0200 Subject: refactor: remove 'shortmess' save/restore panic for ex commands This was only used to avoid the effect of SHM_OVERALL. This can easily be handled in isolation, instead of clearing out all of 'shortmess' which has unwanted side effects and mystifies what really is going on. --- src/nvim/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 5d7ddb657a..011c5439ea 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -105,7 +105,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) // For further ones overwrite the previous one, reset msg_scroll before // calling filemess(). msg_scroll_save = msg_scroll; - if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) { + if (shortmess(SHM_OVERALL) && !msg_listdo_overwrite && !exiting && p_verbose == 0) { msg_scroll = false; } if (!msg_scroll) { // wait a bit when overwriting an error msg @@ -316,7 +316,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } } - if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0) { + if (((shortmess(SHM_OVER) && !msg_listdo_overwrite) || curbuf->b_help) && p_verbose == 0) { msg_scroll = false; // overwrite previous file message } else { msg_scroll = true; // don't overwrite previous file message -- cgit From c3d1d9445c70846d43d1f091ee0762e16513e225 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 25 Sep 2023 12:21:35 +0200 Subject: refactor(options)!: graduate some more shortmess flags A lot of updated places in the docs were already incorrect since long since they did not reflect the default behaviour. "[dos format]" could've been argued being better for discoverability but that ship has already sailed as it is no longer displayed by default. --- src/nvim/fileio.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 011c5439ea..7ff3e0ec6e 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -459,7 +459,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, } if (!silent) { if (dir_of_file_exists(fname)) { - filemess(curbuf, sfname, new_file_message(), 0); + filemess(curbuf, sfname, _("[New]"), 0); } else { filemess(curbuf, sfname, _("[New DIRECTORY]"), 0); } @@ -1718,7 +1718,7 @@ failed: c = true; } if (read_no_eol_lnum) { - msg_add_eol(); + xstrlcat(IObuff, _("[noeol]"), IOSIZE); c = true; } if (ff_error == EOL_DOS) { @@ -2064,11 +2064,6 @@ static void check_marks_read(void) curbuf->b_marks_read = true; } -char *new_file_message(void) -{ - return shortmess(SHM_NEW) ? _("[New]") : _("[New File]"); -} - /// 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. int set_rw_fname(char *fname, char *sfname) @@ -2142,17 +2137,17 @@ bool msg_add_fileformat(int eol_type) { #ifndef USE_CRNL if (eol_type == EOL_DOS) { - xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"), IOSIZE); + xstrlcat(IObuff, _("[dos]"), IOSIZE); return true; } #endif if (eol_type == EOL_MAC) { - xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"), IOSIZE); + xstrlcat(IObuff, _("[mac]"), IOSIZE); return true; } #ifdef USE_CRNL if (eol_type == EOL_UNIX) { - xstrlcat(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"), IOSIZE); + xstrlcat(IObuff, _("[unix]"), IOSIZE); return true; } #endif @@ -2181,12 +2176,6 @@ void msg_add_lines(int insert_space, long lnum, off_T nchars) } } -/// Append message for missing line separator to IObuff. -void msg_add_eol(void) -{ - xstrlcat(IObuff, shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"), IOSIZE); -} - bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST { #if defined(__linux__) || defined(MSWIN) -- cgit From a66b0fdfaa35715c832b98b8941cc5673505e0c2 Mon Sep 17 00:00:00 2001 From: Rory Nesbitt Date: Wed, 27 Sep 2023 18:09:55 +0100 Subject: feat: NVIM_APPNAME supports relative paths #25233 Problem: NVIM_APPNAME does not allow path separators in the name, so relative paths can't be used: NVIM_APPNAME="neovim-configs/first-config" nvim NVIM_APPNAME="neovim-configs/second-config" nvim Solution: Let NVIM_APPNAME be a relative path. Absolute paths are not supported. fix #23056 fix #24966 --- src/nvim/fileio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 7ff3e0ec6e..7609eb12b4 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3279,12 +3279,18 @@ static void vim_mktempdir(void) char tmp[TEMP_FILE_PATH_MAXLEN]; char path[TEMP_FILE_PATH_MAXLEN]; char user[40] = { 0 }; + char appname[40] = { 0 }; (void)os_get_username(user, sizeof(user)); // Usernames may contain slashes! #19240 memchrsub(user, '/', '_', sizeof(user)); memchrsub(user, '\\', '_', sizeof(user)); + // Appname may be a relative path, replace slashes to make it name-like. + xstrlcpy(appname, get_appname(), sizeof(appname)); + memchrsub(appname, '/', '%', sizeof(appname)); + memchrsub(appname, '\\', '%', sizeof(appname)); + // Make sure the umask doesn't remove the executable bit. // "repl" has been reported to use "0177". mode_t umask_save = umask(0077); @@ -3298,7 +3304,6 @@ static void vim_mktempdir(void) // "/tmp/" exists, now try to create "/tmp/nvim./". add_pathsep(tmp); - const char *appname = get_appname(); xstrlcat(tmp, appname, sizeof(tmp)); xstrlcat(tmp, ".", sizeof(tmp)); xstrlcat(tmp, user, sizeof(tmp)); -- cgit From f91cd31d7d9d70006e0000592637d5d997eab52c Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 27 Sep 2023 21:46:39 +0200 Subject: refactor(messages): fold msg_outtrans_attr into msg_outtrans problem: there are too many different functions in message.c solution: fold some of the functions into themselves --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 7ff3e0ec6e..8a5473acdb 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -118,7 +118,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, IObuff), attr); + msg_outtrans(msg_may_trunc(false, IObuff), attr); msg_clr_eos(); ui_flush(); msg_scrolled_ign = false; -- cgit From b85f1dafc7c0a19704135617454f1c66f41202c1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 27 Sep 2023 22:21:17 +0200 Subject: refactor(messages): fold msg_attr into msg problem: there are too many different functions in message.c solution: fold some of the functions into themselves --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 8a5473acdb..dfa61e7cf7 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2035,7 +2035,7 @@ static char *readfile_charconvert(char *fname, char *fenc, int *fdp) if (errmsg != NULL) { // Don't use emsg(), it breaks mappings, the retry with // another type of conversion might still work. - msg(errmsg); + msg(errmsg, 0); if (tmpname != NULL) { os_remove(tmpname); // delete converted file XFREE_CLEAR(tmpname); -- cgit From 448d4837be7f7bd60ac0b5a3100c0217ac48a495 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 27 Sep 2023 22:24:50 +0200 Subject: refactor(messages): rename msg_trunc_attr and msg_multiline_attr without attr --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index dfa61e7cf7..7c1d495505 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1762,7 +1762,7 @@ failed: if (msg_col > 0) { msg_putchar('\r'); // overwrite previous message } - p = (uint8_t *)msg_trunc_attr(IObuff, false, 0); + p = (uint8_t *)msg_trunc(IObuff, false, 0); } if (read_stdin || read_buffer || restart_edit != 0 -- cgit From bc13bc154aa574e0bb58a50f2e0ca4570efa57c3 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 29 Sep 2023 16:10:54 +0200 Subject: refactor(message): smsg_attr -> smsg --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index cd88cf53ce..5cda5e48ec 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3363,7 +3363,7 @@ int readdir_core(garray_T *gap, const char *path, void *context, CheckItem check Directory dir; if (!os_scandir(&dir, path)) { - smsg(_(e_notopen), path); + smsg(0, _(e_notopen), path); return FAIL; } -- cgit From dc6d0d2daf69e2fdadda81feb97906dbc962a239 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 14:41:34 +0800 Subject: refactor: reorganize option header files (#25437) - Move vimoption_T to option.h - option_defs.h is for option-related types - option_vars.h corresponds to Vim's option.h - option_defs.h and option_vars.h don't include each other --- src/nvim/fileio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 5cda5e48ec..4e8b7be4aa 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -47,6 +47,7 @@ #include "nvim/message.h" #include "nvim/move.h" #include "nvim/option.h" +#include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/fs_defs.h" #include "nvim/os/input.h" -- cgit From 09a17f91d0d362c6e58bfdbe3ccdeacffb0b44b9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 2 Oct 2023 10:45:33 +0800 Subject: refactor: move cmdline completion types to cmdexpand_defs.h (#25465) --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 4e8b7be4aa..e94dfceaad 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -28,7 +28,7 @@ #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" -#include "nvim/ex_cmds.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_eval.h" #include "nvim/fileio.h" #include "nvim/fold.h" -- cgit From e72b546354cd90bf0cd8ee6dd045538d713009ad Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/fileio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index e94dfceaad..05b48966ff 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1753,7 +1753,7 @@ failed: c = true; } - msg_add_lines(c, (long)linecnt, filesize); + msg_add_lines(c, linecnt, filesize); XFREE_CLEAR(keep_msg); p = NULL; @@ -2156,7 +2156,7 @@ 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) +void msg_add_lines(int insert_space, linenr_T lnum, off_T nchars) { char *p = IObuff + strlen(IObuff); @@ -2700,7 +2700,7 @@ int vim_rename(const char *from, const char *to) } // Rename() failed, try copying the file. - long perm = os_getperm(from); + int perm = os_getperm(from); // For systems that support ACL: get the ACL from the original file. vim_acl_T acl = os_get_acl(from); int fd_in = os_open(from, O_RDONLY, 0); @@ -2710,7 +2710,7 @@ int vim_rename(const char *from, const char *to) } // Create the new file with same permissions as the original. - int fd_out = os_open(to, O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm); + int fd_out = os_open(to, O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, perm); if (fd_out < 0) { close(fd_in); os_free_acl(acl); @@ -2905,7 +2905,7 @@ int buf_check_timestamp(buf_T *buf) && (!(file_info_ok = os_fileinfo(buf->b_ffname, &file_info)) || time_differs(&file_info, buf->b_mtime, buf->b_mtime_ns) || (int)file_info.stat.st_mode != buf->b_orig_mode)) { - const long prev_b_mtime = buf->b_mtime; + const int prev_b_mtime = (int)buf->b_mtime; retval = 1; -- cgit From 8e932480f61d6101bf8bea1abc07ed93826221fd Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/fileio.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 05b48966ff..9e60f30cb5 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -212,7 +212,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, bool fenc_alloced; // fenc_next is in allocated memory char *fenc_next = NULL; // next item in 'fencs' or NULL bool advance_fenc = false; - long real_size = 0; + int real_size = 0; iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1 bool did_iconv = false; // true when iconv() failed and trying // 'charconvert' next @@ -947,11 +947,11 @@ retry: size = 0; } else { int ni; - long tlen = 0; + int tlen = 0; while (true) { p = (uint8_t *)ml_get(read_buf_lnum) + read_buf_col; int n = (int)strlen((char *)p); - if ((int)tlen + n + 1 > size) { + if (tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done // below. @@ -2177,7 +2177,8 @@ void msg_add_lines(int insert_space, linenr_T lnum, off_T nchars) } } -bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST +bool time_differs(const FileInfo *file_info, int64_t mtime, int64_t mtime_ns) + FUNC_ATTR_CONST { #if defined(__linux__) || defined(MSWIN) return file_info->stat.st_mtim.tv_nsec != mtime_ns @@ -2728,7 +2729,7 @@ int vim_rename(const char *from, const char *to) } int n; - while ((n = (int)read_eintr(fd_in, buffer, WRITEBUFSIZE)) > 0) { + while ((n = read_eintr(fd_in, buffer, WRITEBUFSIZE)) > 0) { if (write_eintr(fd_out, buffer, (size_t)n) != n) { errmsg = _("E208: Error writing to \"%s\""); break; @@ -2905,7 +2906,7 @@ int buf_check_timestamp(buf_T *buf) && (!(file_info_ok = os_fileinfo(buf->b_ffname, &file_info)) || time_differs(&file_info, buf->b_mtime, buf->b_mtime_ns) || (int)file_info.stat.st_mode != buf->b_orig_mode)) { - const int prev_b_mtime = (int)buf->b_mtime; + const int64_t prev_b_mtime = buf->b_mtime; retval = 1; @@ -3823,9 +3824,9 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs /// Version of read() that retries when interrupted by EINTR (possibly /// by a SIGWINCH). -long read_eintr(int fd, void *buf, size_t bufsize) +int read_eintr(int fd, void *buf, size_t bufsize) { - long ret; + ssize_t ret; while (true) { ret = read(fd, buf, (unsigned)bufsize); @@ -3833,25 +3834,25 @@ long read_eintr(int fd, void *buf, size_t bufsize) break; } } - return ret; + return (int)ret; } /// Version of write() that retries when interrupted by EINTR (possibly /// by a SIGWINCH). -long write_eintr(int fd, void *buf, size_t bufsize) +int write_eintr(int fd, void *buf, size_t bufsize) { - long ret = 0; + int ret = 0; // Repeat the write() so long it didn't fail, other than being interrupted // by a signal. - while (ret < (long)bufsize) { - long wlen = write(fd, (char *)buf + ret, (unsigned)(bufsize - (size_t)ret)); + while (ret < (int)bufsize) { + ssize_t wlen = write(fd, (char *)buf + ret, (unsigned)(bufsize - (size_t)ret)); if (wlen < 0) { if (errno != EINTR) { break; } } else { - ret += wlen; + ret += (int)wlen; } } return ret; -- cgit From acc646ad8fc3ef11fcc63b69f3d8484e4a91accd Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 29 Sep 2023 14:58:48 +0200 Subject: refactor: the long goodbye long is 32 bits on windows, while it is 64 bits on other architectures. This makes the type suboptimal for a codebase meant to be cross-platform. Replace it with more appropriate integer types. --- src/nvim/fileio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 9e60f30cb5..804c9cec11 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -718,7 +718,7 @@ retry: if (read_buffer) { read_buf_lnum = 1; read_buf_col = 0; - } else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0) { + } else if (read_stdin || vim_lseek(fd, 0, SEEK_SET) != 0) { // Can't rewind the file, give up. error = true; goto failed; @@ -880,9 +880,9 @@ retry: // Use buffer >= 64K. Add linerest to double the size if the // line gets very long, to avoid a lot of copying. But don't // read more than 1 Mbyte at a time, so we can be interrupted. - size = 0x10000L + linerest; - if (size > 0x100000L) { - size = 0x100000L; + size = 0x10000 + linerest; + if (size > 0x100000) { + size = 0x100000; } } @@ -1531,7 +1531,7 @@ rewind_retry: if (try_unix && !read_stdin && (read_buffer - || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) { + || vim_lseek(fd, 0, SEEK_SET) == 0)) { fileformat = EOL_UNIX; if (set_options) { set_fileformat(EOL_UNIX, OPT_LOCAL); @@ -3054,7 +3054,7 @@ int buf_check_timestamp(buf_T *buf) if (emsg_silent == 0 && !in_assert_fails) { ui_flush(); // give the user some time to think about it - os_delay(1004L, true); + os_delay(1004, true); // don't redraw and erase the message redraw_cmdline = false; -- cgit From cd63a9addd6e1114c3524fa041ece560550cfe7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 10 Nov 2023 08:39:21 +0800 Subject: refactor: change some xstrndup() and xstrnsave() to xmemdupz() (#25959) When the given length is exactly the number of bytes to copy, xmemdupz() makes the intention clearer. --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 804c9cec11..424bd33b6c 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1993,7 +1993,7 @@ static char *next_fenc(char **pp, bool *alloced) r = enc_canonize(*pp); *pp += strlen(*pp); } else { - r = xstrnsave(*pp, (size_t)(p - *pp)); + r = xmemdupz(*pp, (size_t)(p - *pp)); *pp = p + 1; p = enc_canonize(r); xfree(r); -- cgit From 8e58d37f2e15ac8540377148e55ed08a039aadb6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 11 Nov 2023 11:20:08 +0100 Subject: refactor: remove redundant casts --- src/nvim/fileio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 424bd33b6c..e57fb9664b 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3132,7 +3132,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) savebuf = NULL; } else { // Allocate a buffer without putting it in the buffer list. - savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); + savebuf = buflist_new(NULL, NULL, 1, BLN_DUMMY); set_bufref(&bufref, savebuf); if (savebuf != NULL && buf == curbuf) { // Open the memline. @@ -3153,7 +3153,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) if (saved == OK) { curbuf->b_flags |= BF_CHECK_RO; // check for RO again keep_filetype = true; // don't detect 'filetype' - if (readfile(buf->b_ffname, buf->b_fname, (linenr_T)0, (linenr_T)0, + if (readfile(buf->b_ffname, buf->b_fname, 0, 0, (linenr_T)MAXLNUM, &ea, flags, false) != OK) { if (!aborting()) { semsg(_("E321: Could not reload \"%s\""), buf->b_fname); @@ -3583,10 +3583,10 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname, // 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) + && (vim_regexec(®match, fname, 0) || (sfname != NULL - && vim_regexec(®match, sfname, (colnr_T)0)))) - || (!allow_dirs && vim_regexec(®match, tail, (colnr_T)0)))) { + && vim_regexec(®match, sfname, 0)))) + || (!allow_dirs && vim_regexec(®match, tail, 0)))) { result = true; } -- cgit From 353a4be7e84fdc101318215bdcc8a7e780d737fe Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 12 Nov 2023 13:13:58 +0100 Subject: build: remove PVS We already have an extensive suite of static analysis tools we use, which causes a fair bit of redundancy as we get duplicate warnings. PVS is also prone to give false warnings which creates a lot of work to identify and disable. --- src/nvim/fileio.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index e57fb9664b..3010ded1d0 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // fileio.c: read from and write to a file #include @@ -935,7 +932,7 @@ retry: if (conv_restlen > 0) { // Insert unconverted bytes from previous line. - memmove(ptr, conv_rest, (size_t)conv_restlen); // -V614 + memmove(ptr, conv_rest, (size_t)conv_restlen); ptr += conv_restlen; size -= conv_restlen; } -- cgit From 28f4f3c48498086307ed825d1761edb5789ca0e8 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 12 Nov 2023 15:54:54 +0100 Subject: refactor: follow style guide - reduce variable scope - prefer initialization over declaration and assignment - use bool to represent boolean values --- src/nvim/fileio.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 3010ded1d0..e89bb41745 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -87,7 +87,6 @@ static const char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buf void filemess(buf_T *buf, char *name, char *s, int attr) { - int msg_scroll_save; int prev_msg_col = msg_col; if (msg_silent != 0) { @@ -102,7 +101,7 @@ void filemess(buf_T *buf, char *name, char *s, int attr) // For the first message may have to start a new line. // For further ones overwrite the previous one, reset msg_scroll before // calling filemess(). - msg_scroll_save = msg_scroll; + int msg_scroll_save = msg_scroll; if (shortmess(SHM_OVERALL) && !msg_listdo_overwrite && !exiting && p_verbose == 0) { msg_scroll = false; } @@ -1323,7 +1322,6 @@ retry: // Reading UTF-8: Check if the bytes are valid UTF-8. for (p = (uint8_t *)ptr;; p++) { int todo = (int)(((uint8_t *)ptr + size) - p); - int l; if (todo <= 0) { break; @@ -1333,7 +1331,7 @@ retry: // an incomplete character at the end though, the next // read() will get the next bytes, we'll check it // then. - l = utf_ptr2len_len((char *)p, todo); + int l = utf_ptr2len_len((char *)p, todo); if (l > todo && !incomplete_tail) { // Avoid retrying with a different encoding when // a truncated file is more likely, or attempting @@ -1905,11 +1903,8 @@ bool is_dev_fd_file(char *fname) /// @param endp end of more bytes read static linenr_T readfile_linenr(linenr_T linecnt, char *p, const char *endp) { - char *s; - linenr_T lnum; - - lnum = curbuf->b_ml.ml_line_count - linecnt + 1; - for (s = p; s < endp; s++) { + linenr_T lnum = curbuf->b_ml.ml_line_count - linecnt + 1; + for (char *s = p; s < endp; s++) { if (*s == '\n') { lnum++; } @@ -1977,7 +1972,6 @@ void set_forced_fenc(exarg_T *eap) static char *next_fenc(char **pp, bool *alloced) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - char *p; char *r; *alloced = false; @@ -1985,7 +1979,7 @@ static char *next_fenc(char **pp, bool *alloced) *pp = NULL; return ""; } - p = vim_strchr(*pp, ','); + char *p = vim_strchr(*pp, ','); if (p == NULL) { r = enc_canonize(*pp); *pp += strlen(*pp); @@ -2012,10 +2006,9 @@ static char *next_fenc(char **pp, bool *alloced) /// Returns NULL if the conversion failed ("*fdp" is not set) . static char *readfile_charconvert(char *fname, char *fenc, int *fdp) { - char *tmpname; char *errmsg = NULL; - tmpname = vim_tempname(); + char *tmpname = vim_tempname(); if (tmpname == NULL) { errmsg = _("Can't find temp file for conversion"); } else { @@ -3246,12 +3239,10 @@ void write_lnum_adjust(linenr_T offset) /// unless when it looks like a URL. void forward_slash(char *fname) { - char *p; - if (path_with_url(fname)) { return; } - for (p = fname; *p != NUL; p++) { + for (char *p = fname; *p != NUL; p++) { if (*p == '\\') { *p = '/'; } -- cgit From 1798a4b5e9f0ae56cd800095f79423fea5cae8ca Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: build: bump uncrustify version Biggest change is that uncrustify is silent during linting. --- src/nvim/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index e89bb41745..b68399e428 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -2973,8 +2973,8 @@ int buf_check_timestamp(buf_T *buf) // checked out of CVS). Always warn when the buffer was // changed. if (reason[2] == 'n') { - mesg = _( - "W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well"); + mesg = + _("W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well"); mesg2 = _("See \":help W12\" for more info."); } else if (reason[1] == 'h') { mesg = _("W11: Warning: File \"%s\" has changed since editing started"); -- cgit From a6e3d93421ba13c407a96fac9cc01fa41ec7ad98 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: refactor: enable formatting for ternaries This requires removing the "Inner expression should be aligned" rule from clint as it prevents essentially any formatting regarding ternary operators. --- src/nvim/fileio.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index b68399e428..5bf3410614 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -479,16 +479,17 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, goto theend; } #if defined(UNIX) && defined(EOVERFLOW) - filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") + : // libuv only returns -errno // in Unix and in Windows // open() does not set // EOVERFLOW - (fd == -EOVERFLOW) ? _("[File too big]") : - _("[Permission Denied]")), 0); + (fd == -EOVERFLOW) ? _("[File too big]") + : _("[Permission Denied]")), 0); #else - filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : - _("[Permission Denied]")), 0); + filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") + : _("[Permission Denied]")), 0); #endif curbuf->b_p_ro = true; // must use "w!" now -- cgit From a827003e3052c6d9ee7bdb71518182e9bd76317d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 Nov 2023 11:32:32 +0100 Subject: build: rework IWYU mapping files Create mapping to most of the C spec and some POSIX specific functions. This is more robust than relying files shipped with IWYU. --- src/nvim/fileio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 5bf3410614..fce2ddc211 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "auto/config.h" -- cgit From 6361806aa28edca55ad3316a58bc3e936df9c0eb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Nov 2023 22:58:52 +0800 Subject: refactor: move garray_T to garray_defs.h (#26227) --- src/nvim/fileio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fce2ddc211..0efd826f1d 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -31,6 +31,7 @@ #include "nvim/fileio.h" #include "nvim/fold.h" #include "nvim/garray.h" +#include "nvim/garray_defs.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -- cgit From 38a20dd89f91c45ec8589bf1c50d50732882d38a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 20:58:37 +0800 Subject: build(IWYU): replace most private mappings with pragmas (#26247) --- src/nvim/fileio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 0efd826f1d..6de6f01a52 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -48,6 +48,7 @@ #include "nvim/option.h" #include "nvim/option_vars.h" #include "nvim/optionstr.h" +#include "nvim/os/fs.h" #include "nvim/os/fs_defs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -- cgit From 40139738eb479d0913ec6ce751ca5adfa50ad8c3 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 26 Nov 2023 21:36:02 +0100 Subject: build: enable IWYU on mac --- src/nvim/fileio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 6de6f01a52..dcc1b8eea5 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include -- cgit From 8b428ca8b79ebb7b36c3e403ff3bcb6924a635a6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 16:00:21 +0100 Subject: build(IWYU): fix includes for func_attr.h --- src/nvim/fileio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index dcc1b8eea5..fa9e8d74ff 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -31,6 +31,7 @@ #include "nvim/ex_eval.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" #include "nvim/getchar.h" -- cgit From f4aedbae4cb1f206f5b7c6142697b71dd473059b Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 18:39:38 +0100 Subject: build(IWYU): fix includes for undo_defs.h --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index fa9e8d74ff..3d251e1f0a 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -56,7 +56,7 @@ #include "nvim/os/os.h" #include "nvim/os/time.h" #include "nvim/path.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/regexp.h" #include "nvim/sha256.h" #include "nvim/shada.h" -- cgit From 6c14ae6bfaf51415b555e9a6b85d1d280976358d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 20:27:32 +0100 Subject: refactor: rename types.h to types_defs.h --- src/nvim/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 3d251e1f0a..edebe779d9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -61,7 +61,7 @@ #include "nvim/sha256.h" #include "nvim/shada.h" #include "nvim/strings.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" -- cgit From 79b6ff28ad1204fbb4199b9092f5c578d88cb28e Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 28 Nov 2023 20:31:00 +0100 Subject: refactor: fix headers with IWYU --- src/nvim/fileio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index edebe779d9..303776b2eb 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -16,7 +16,7 @@ #include #include "auto/config.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" @@ -38,9 +38,9 @@ #include "nvim/gettext.h" #include "nvim/globals.h" #include "nvim/highlight_defs.h" -#include "nvim/iconv.h" +#include "nvim/iconv_defs.h" #include "nvim/log.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memfile.h" #include "nvim/memline.h" @@ -64,7 +64,7 @@ #include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/undo.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #ifdef BACKSLASH_IN_FILENAME # include "nvim/charset.h" -- cgit From a6cba103cebce535279db197f9efeb34e9d1171f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 29 Nov 2023 20:32:40 +0800 Subject: refactor: move some constants out of vim_defs.h (#26298) --- src/nvim/fileio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/fileio.c') diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 303776b2eb..0bb664bcf5 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -37,7 +37,7 @@ #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/highlight_defs.h" +#include "nvim/highlight.h" #include "nvim/iconv_defs.h" #include "nvim/log.h" #include "nvim/macros_defs.h" @@ -60,6 +60,7 @@ #include "nvim/regexp.h" #include "nvim/sha256.h" #include "nvim/shada.h" +#include "nvim/state_defs.h" #include "nvim/strings.h" #include "nvim/types_defs.h" #include "nvim/ui.h" -- cgit