aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/fileio.c')
-rw-r--r--src/nvim/fileio.c846
1 files changed, 458 insertions, 388 deletions
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 29114201d2..feb16f44d4 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1,3 +1,6 @@
+// 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
*/
@@ -200,18 +203,14 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
{
int msg_scroll_save;
- if (msg_silent != 0)
+ if (msg_silent != 0) {
return;
- msg_add_fname(buf, name); /* put file name in IObuff with quotes */
- /* If it's extremely long, truncate it. */
- if (STRLEN(IObuff) > IOSIZE - 80)
- IObuff[IOSIZE - 80] = NUL;
- STRCAT(IObuff, s);
- /*
- * For the first message may have to start a new line.
- * For further ones overwrite the previous one, reset msg_scroll before
- * calling filemess().
- */
+ }
+ add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name);
+ xstrlcat((char *)IObuff, (const char *)s, IOSIZE);
+ // For the first message may have to start a new line.
+ // For further ones overwrite the previous one, reset msg_scroll before
+ // calling filemess().
msg_scroll_save = msg_scroll;
if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
msg_scroll = FALSE;
@@ -248,8 +247,9 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
* stdin)
* READ_DUMMY read into a dummy buffer (to check if file contents changed)
* READ_KEEP_UNDO don't clear undo info or read it from a file
+ * READ_FIFO read from fifo/socket instead of a file
*
- * return FAIL for failure, OK otherwise
+ * return FAIL for failure, NOTDONE for directory (failure), or OK
*/
int
readfile (
@@ -258,7 +258,7 @@ readfile (
linenr_T from,
linenr_T lines_to_skip,
linenr_T lines_to_read,
- exarg_T *eap, /* can be NULL! */
+ exarg_T *eap, // can be NULL!
int flags
)
{
@@ -268,6 +268,7 @@ readfile (
int filtering = (flags & READ_FILTER);
int read_stdin = (flags & READ_STDIN);
int read_buffer = (flags & READ_BUFFER);
+ int read_fifo = (flags & READ_FIFO);
int set_options = newfile || read_buffer
|| (eap != NULL && eap->read_edit);
linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
@@ -281,9 +282,9 @@ readfile (
int wasempty; /* buffer was empty before reading */
colnr_T len;
long size = 0;
- char_u *p;
- off_t filesize = 0;
- int skip_read = FALSE;
+ char_u *p = NULL;
+ off_T filesize = 0;
+ int skip_read = false;
context_sha256_T sha_ctx;
int read_undo_file = FALSE;
int split = 0; /* number of split lines */
@@ -427,8 +428,8 @@ readfile (
}
}
- if (!read_buffer && !read_stdin) {
- perm = os_getperm(fname);
+ if (!read_buffer && !read_stdin && !read_fifo) {
+ perm = os_getperm((const char *)fname);
#ifdef UNIX
// On Unix it is possible to read a directory, so we have to
// check for it before os_open().
@@ -444,13 +445,14 @@ readfile (
// ... or a character special file named /dev/fd/<n>
# endif
) {
- if (S_ISDIR(perm))
+ if (S_ISDIR(perm)) {
filemess(curbuf, fname, (char_u *)_("is a directory"), 0);
- else
+ } else {
filemess(curbuf, fname, (char_u *)_("is not a file"), 0);
+ }
msg_end();
msg_scroll = msg_save;
- return FAIL;
+ return S_ISDIR(perm) ? NOTDONE : FAIL;
}
#endif
}
@@ -468,8 +470,8 @@ readfile (
if (check_readonly && !readonlymode)
curbuf->b_p_ro = FALSE;
- if (newfile && !read_stdin && !read_buffer) {
- /* Remember time of file. */
+ if (newfile && !read_stdin && !read_buffer && !read_fifo) {
+ // Remember time of file.
FileInfo file_info;
if (os_fileinfo((char *)fname, &file_info)) {
buf_store_file_info(curbuf, &file_info);
@@ -613,10 +615,12 @@ readfile (
return FAIL;
}
#ifdef UNIX
- /* Set swap file protection bits after creating it. */
+ // Set swap file protection bits after creating it.
if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL
- && curbuf->b_ml.ml_mfp->mf_fname != NULL)
- (void)os_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
+ && curbuf->b_ml.ml_mfp->mf_fname != NULL) {
+ (void)os_setperm((const char *)curbuf->b_ml.ml_mfp->mf_fname,
+ (long)swap_mode);
+ }
#endif
}
@@ -699,16 +703,9 @@ readfile (
wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
if (!recoverymode && !filtering && !(flags & READ_DUMMY)) {
- /*
- * Show the user that we are busy reading the input. Sometimes this
- * may take a while. When reading from stdin another program may
- * still be running, don't move the cursor to the last line, unless
- * always using the GUI.
- */
- if (read_stdin) {
- mch_msg(_("Nvim: Reading from stdin...\n"));
- } else if (!read_buffer)
+ if (!read_stdin && !read_buffer) {
filemess(curbuf, sfname, (char_u *)"", 0);
+ }
}
msg_scroll = FALSE; /* overwrite the file message */
@@ -738,43 +735,16 @@ readfile (
fenc = (char_u *)""; /* binary: don't convert */
fenc_alloced = FALSE;
} else if (curbuf->b_help) {
- char_u firstline[80];
- int fc;
-
- /* Help files are either utf-8 or latin1. Try utf-8 first, if this
- * fails it must be latin1.
- * Always do this when 'encoding' is "utf-8". Otherwise only do
- * this when needed to avoid [converted] remarks all the time.
- * It is needed when the first line contains non-ASCII characters.
- * That is only in *.??x files. */
- fenc = (char_u *)"latin1";
- c = enc_utf8;
- if (!c && !read_stdin) {
- fc = fname[STRLEN(fname) - 1];
- if (TOLOWER_ASC(fc) == 'x') {
- /* Read the first line (and a bit more). Immediately rewind to
- * the start of the file. If the read() fails "len" is -1. */
- len = read_eintr(fd, firstline, 80);
- lseek(fd, (off_t)0L, SEEK_SET);
- for (p = firstline; p < firstline + len; ++p)
- if (*p >= 0x80) {
- c = TRUE;
- break;
- }
- }
- }
+ // Help files are either utf-8 or latin1. Try utf-8 first, if this
+ // fails it must be latin1.
+ // It is needed when the first line contains non-ASCII characters.
+ // That is only in *.??x files.
+ fenc_next = (char_u *)"latin1";
+ fenc = (char_u *)"utf-8";
- if (c) {
- fenc_next = fenc;
- fenc = (char_u *)"utf-8";
+ fenc_alloced = false;
- /* When the file is utf-8 but a character doesn't fit in
- * 'encoding' don't retry. In help text editing utf-8 bytes
- * doesn't make sense. */
- if (!enc_utf8)
- keep_dest_enc = TRUE;
- }
- fenc_alloced = FALSE;
+ c = 1;
} else if (*p_fencs == NUL) {
fenc = curbuf->b_p_fenc; /* use format from buffer */
fenc_alloced = FALSE;
@@ -809,9 +779,9 @@ retry:
if (read_buffer) {
read_buf_lnum = 1;
read_buf_col = 0;
- } else if (read_stdin || lseek(fd, (off_t)0L, SEEK_SET) != 0) {
- /* Can't rewind the file, give up. */
- error = TRUE;
+ } else if (read_stdin || vim_lseek(fd, (off_T)0L, SEEK_SET) != 0) {
+ // Can't rewind the file, give up.
+ error = true;
goto failed;
}
/* Delete the previously read lines. */
@@ -927,6 +897,7 @@ retry:
* and we can't do it internally or with iconv().
*/
if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
+ && !read_fifo
# ifdef USE_ICONV
&& iconv_fd == (iconv_t)-1
# endif
@@ -967,7 +938,7 @@ retry:
/* Set "can_retry" when it's possible to rewind the file and try with
* another "fenc" value. It's FALSE when no other "fenc" to try, reading
* stdin or fixed at a specific encoding. */
- can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc);
+ can_retry = (*fenc != NUL && !read_stdin && !keep_dest_enc && !read_fifo);
if (!skip_read) {
linerest = 0;
@@ -979,6 +950,7 @@ retry:
&& curbuf->b_ffname != NULL
&& curbuf->b_p_udf
&& !filtering
+ && !read_fifo
&& !read_stdin
&& !read_buffer);
if (read_undo_file)
@@ -1646,19 +1618,16 @@ rewind_retry:
if (fileformat == EOL_DOS) {
if (ptr[-1] == CAR) { /* remove CR */
ptr[-1] = NUL;
- --len;
- }
- /*
- * Reading in Dos format, but no CR-LF found!
- * When 'fileformats' includes "unix", delete all
- * the lines read so far and start all over again.
- * Otherwise give an error message later.
- */
- else if (ff_error != EOL_DOS) {
- if ( try_unix
- && !read_stdin
- && (read_buffer
- || lseek(fd, (off_t)0L, SEEK_SET) == 0)) {
+ len--;
+ } else if (ff_error != EOL_DOS) {
+ // Reading in Dos format, but no CR-LF found!
+ // When 'fileformats' includes "unix", delete all
+ // the lines read so far and start all over again.
+ // Otherwise give an error message later.
+ if (try_unix
+ && !read_stdin
+ && (read_buffer
+ || vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) {
fileformat = EOL_UNIX;
if (set_options)
set_fileformat(EOL_UNIX, OPT_LOCAL);
@@ -1741,16 +1710,11 @@ failed:
}
# endif
- if (!read_buffer && !read_stdin)
- close(fd); /* errors are ignored */
-#ifdef HAVE_FD_CLOEXEC
- else {
- int fdflags = fcntl(fd, F_GETFD);
- if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
- (void)fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
- }
+ if (!read_buffer && !read_stdin) {
+ close(fd); // errors are ignored
+ } else {
+ (void)os_set_cloexec(fd);
}
-#endif
xfree(buffer);
if (read_stdin) {
@@ -1809,8 +1773,8 @@ failed:
}
if (!filtering && !(flags & READ_DUMMY)) {
- msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
- c = FALSE;
+ add_quoted_fname((char *)IObuff, IOSIZE, curbuf, (const char *)sfname);
+ c = false;
#ifdef UNIX
# ifdef S_ISFIFO
@@ -1881,17 +1845,22 @@ failed:
xfree(keep_msg);
keep_msg = NULL;
+ p = NULL;
msg_scrolled_ign = TRUE;
- p = msg_trunc_attr(IObuff, FALSE, 0);
+
+ if (!read_stdin && !read_buffer) {
+ p = msg_trunc_attr(IObuff, FALSE, 0);
+ }
+
if (read_stdin || read_buffer || restart_edit != 0
- || (msg_scrolled != 0 && !need_wait_return))
- /* Need to repeat the message after redrawing when:
- * - When reading from stdin (the screen will be cleared next).
- * - When restart_edit is set (otherwise there will be a delay
- * before redrawing).
- * - When the screen was scrolled but there is no wait-return
- * prompt. */
+ || (msg_scrolled != 0 && !need_wait_return)) {
+ // Need to repeat the message after redrawing when:
+ // - When reading from stdin (the screen will be cleared next).
+ // - When restart_edit is set (otherwise there will be a delay before
+ // redrawing).
+ // - When the screen was scrolled but there is no wait-return prompt.
set_keep_msg(p, 0);
+ }
msg_scrolled_ign = FALSE;
}
@@ -1954,7 +1923,7 @@ failed:
u_read_undo(NULL, hash, fname);
}
- if (!read_stdin && !read_buffer) {
+ if (!read_stdin && !read_fifo && (!read_buffer || sfname != NULL)) {
int m = msg_scroll;
int n = msg_scrolled;
@@ -1972,7 +1941,7 @@ failed:
if (filtering) {
apply_autocmds_exarg(EVENT_FILTERREADPOST, NULL, sfname,
false, curbuf, eap);
- } else if (newfile) {
+ } else if (newfile || (read_buffer && sfname != NULL)) {
apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname,
false, curbuf, eap);
if (!au_did_filetype && *curbuf->b_p_ft != NUL) {
@@ -2005,7 +1974,7 @@ failed:
/// Do not accept "/dev/fd/[012]", opening these may hang Vim.
///
/// @param fname file name to check
-static bool is_dev_fd_file(char_u *fname)
+bool is_dev_fd_file(char_u *fname)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
return STRNCMP(fname, "/dev/fd/", 8) == 0
@@ -2262,9 +2231,16 @@ buf_write (
int len;
linenr_T lnum;
long nchars;
- char_u *errmsg = NULL;
- int errmsg_allocated = FALSE;
- char_u *errnum = NULL;
+#define SET_ERRMSG_NUM(num, msg) \
+ errnum = num, errmsg = msg, errmsgarg = 0
+#define SET_ERRMSG_ARG(msg, error) \
+ errnum = NULL, errmsg = msg, errmsgarg = error
+#define SET_ERRMSG(msg) \
+ errnum = NULL, errmsg = msg, errmsgarg = 0
+ const char *errnum = NULL;
+ char *errmsg = NULL;
+ int errmsgarg = 0;
+ bool errmsg_allocated = false;
char_u *buffer;
char_u smallbuf[SMBUFSIZE];
char_u *backup_ext;
@@ -2286,7 +2262,6 @@ buf_write (
/* 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 attr;
int fileformat;
int write_bin;
struct bw_info write_info; /* info for buf_write_bytes() */
@@ -2396,6 +2371,7 @@ buf_write (
int did_cmd = FALSE;
int nofile_err = FALSE;
int empty_memline = (buf->b_ml.ml_mfp == NULL);
+ bufref_T bufref;
/*
* Apply PRE autocommands.
@@ -2411,8 +2387,9 @@ buf_write (
if (fname == buf->b_sfname)
buf_fname_s = TRUE;
- /* set curwin/curbuf to buf and save a few things */
+ // 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,
@@ -2460,14 +2437,13 @@ buf_write (
/* 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 (!buf_valid(buf))
+ // 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()
@@ -2580,13 +2556,11 @@ buf_write (
perm = 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)) {
- errnum = (char_u *)"E502: ";
- errmsg = (char_u *)_("is a directory");
+ SET_ERRMSG_NUM("E502", _("is a directory"));
goto fail;
}
if (os_nodetype((char *)fname) != NODE_WRITABLE) {
- errnum = (char_u *)"E503: ";
- errmsg = (char_u *)_("is not a file or writable device");
+ SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
goto fail;
}
/* It's a device of some kind (or a fifo) which we can write to
@@ -2596,14 +2570,11 @@ buf_write (
perm = -1;
}
}
-#else /* win32 */
- /*
- * Check for a writable device name.
- */
- c = os_nodetype((char *)fname);
+#else // win32
+ // Check for a writable device name.
+ c = fname == NULL ? NODE_OTHER : os_nodetype((char *)fname);
if (c == NODE_OTHER) {
- errnum = (char_u *)"E503: ";
- errmsg = (char_u *)_("is not a file or writable device");
+ SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
goto fail;
}
if (c == NODE_WRITABLE) {
@@ -2611,20 +2582,18 @@ buf_write (
newfile = TRUE;
perm = -1;
} else {
- perm = os_getperm(fname);
- if (perm < 0)
- newfile = TRUE;
- else if (os_isdir(fname)) {
- errnum = (char_u *)"E502: ";
- errmsg = (char_u *)_("is a directory");
+ perm = os_getperm((const char *)fname);
+ if (perm < 0) {
+ newfile = true;
+ } else if (os_isdir(fname)) {
+ SET_ERRMSG_NUM("E502", _("is a directory"));
goto fail;
}
if (overwriting) {
os_fileinfo((char *)fname, &file_info_old);
}
-
}
-#endif /* !UNIX */
+#endif // !UNIX
if (!device && !newfile) {
/*
@@ -2635,11 +2604,9 @@ buf_write (
if (!forceit && file_readonly) {
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
- errnum = (char_u *)"E504: ";
- errmsg = (char_u *)_(err_readonly);
+ SET_ERRMSG_NUM("E504", _(err_readonly));
} else {
- errnum = (char_u *)"E505: ";
- errmsg = (char_u *)_("is read-only (add ! to override)");
+ SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)"));
}
goto fail;
}
@@ -2875,9 +2842,9 @@ buf_write (
xfree(backup);
backup = NULL;
} else {
- /* set file protection same as original file, but
- * strip s-bit */
- (void)os_setperm(backup, perm & 0777);
+ // set file protection same as original file, but
+ // strip s-bit.
+ (void)os_setperm((const char *)backup, perm & 0777);
#ifdef UNIX
/*
@@ -2888,7 +2855,8 @@ buf_write (
*/
if (file_info_new.stat.st_gid != file_info_old.stat.st_gid
&& os_fchown(bfd, -1, file_info_old.stat.st_gid) != 0) {
- os_setperm(backup, (perm & 0707) | ((perm & 07) << 3));
+ os_setperm((const char *)backup,
+ (perm & 0707) | ((perm & 07) << 3));
}
# ifdef HAVE_SELINUX
mch_copy_sec(fname, backup);
@@ -2906,23 +2874,27 @@ buf_write (
while ((write_info.bw_len = read_eintr(fd, copybuf,
BUFSIZE)) > 0) {
if (buf_write_bytes(&write_info) == FAIL) {
- errmsg = (char_u *)_(
- "E506: Can't write to backup file (add ! to override)");
+ SET_ERRMSG(_(
+ "E506: Can't write to backup file (add ! to override)"));
break;
}
os_breakcheck();
if (got_int) {
- errmsg = (char_u *)_(e_interr);
+ SET_ERRMSG(_(e_interr));
break;
}
}
- if (close(bfd) < 0 && errmsg == NULL)
- errmsg = (char_u *)_(
- "E507: Close error for backup file (add ! to override)");
- if (write_info.bw_len < 0)
- errmsg = (char_u *)_(
- "E508: Can't read file for backup (add ! to override)");
+ int error;
+ if ((error = os_close(bfd)) != 0 && errmsg == NULL) {
+ SET_ERRMSG_ARG(_("E507: Close error for backup file "
+ "(add ! to override): %s"),
+ error);
+ }
+ if (write_info.bw_len < 0) {
+ SET_ERRMSG(_(
+ "E508: Can't read file for backup (add ! to override)"));
+ }
#ifdef UNIX
set_file_time(backup,
file_info_old.stat.st_atim.tv_sec,
@@ -2939,18 +2911,19 @@ buf_write (
}
}
nobackup:
- close(fd); /* ignore errors for closing read file */
+ os_close(fd); // Ignore errors for closing read file.
xfree(copybuf);
- if (backup == NULL && errmsg == NULL)
- errmsg = (char_u *)_(
- "E509: Cannot create backup file (add ! to override)");
- /* ignore errors when forceit is TRUE */
+ if (backup == NULL && errmsg == NULL) {
+ SET_ERRMSG(_(
+ "E509: Cannot create backup file (add ! to override)"));
+ }
+ // Ignore errors when forceit is TRUE.
if ((some_error || errmsg != NULL) && !forceit) {
retval = FAIL;
goto fail;
}
- errmsg = NULL;
+ SET_ERRMSG(NULL);
} else {
char_u *dirp;
char_u *p;
@@ -2965,8 +2938,7 @@ nobackup:
* anyway, thus we need an extra check here.
*/
if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
- errnum = (char_u *)"E504: ";
- errmsg = (char_u *)_(err_readonly);
+ SET_ERRMSG_NUM("E504", _(err_readonly));
goto fail;
}
@@ -3030,7 +3002,7 @@ nobackup:
}
}
if (backup == NULL && !forceit) {
- errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
+ SET_ERRMSG(_("E510: Can't make backup file (add ! to override)"));
goto fail;
}
}
@@ -3042,8 +3014,8 @@ nobackup:
&& file_info_old.stat.st_uid == getuid()
&& vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
perm |= 0200;
- (void)os_setperm(fname, perm);
- made_writable = TRUE;
+ (void)os_setperm((const char *)fname, perm);
+ made_writable = true;
}
#endif
@@ -3071,7 +3043,7 @@ nobackup:
&& !(exiting && backup != NULL)) {
ml_preserve(buf, FALSE);
if (got_int) {
- errmsg = (char_u *)_(e_interr);
+ SET_ERRMSG(_(e_interr));
goto restore_backup;
}
}
@@ -3142,8 +3114,8 @@ nobackup:
*/
if (*p_ccv != NUL) {
wfname = vim_tempname();
- if (wfname == NULL) { /* Can't write without a tempfile! */
- errmsg = (char_u *)_("E214: Can't find temp file for writing");
+ if (wfname == NULL) { // Can't write without a tempfile!
+ SET_ERRMSG(_("E214: Can't find temp file for writing"));
goto restore_backup;
}
}
@@ -3155,8 +3127,8 @@ nobackup:
&& wfname == fname
) {
if (!forceit) {
- errmsg = (char_u *)_(
- "E213: Cannot convert (add ! to write without conversion)");
+ SET_ERRMSG(_(
+ "E213: Cannot convert (add ! to write without conversion)"));
goto restore_backup;
}
notconverted = TRUE;
@@ -3187,15 +3159,14 @@ nobackup:
#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) > 1)
+ // 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((char *)fname, &file_info)
&& !os_fileinfo_id_equal(&file_info, &file_info_old))) {
- errmsg = (char_u *)_("E166: Can't open linked file for writing");
- } else
+ SET_ERRMSG(_("E166: Can't open linked file for writing"));
+ } else {
#endif
- {
- errmsg = (char_u *)_("E212: Can't open file for writing");
+ SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd);
if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
&& perm >= 0) {
#ifdef UNIX
@@ -3213,7 +3184,9 @@ nobackup:
os_remove((char *)wfname);
continue;
}
+#ifdef UNIX
}
+#endif
}
restore_backup:
@@ -3255,7 +3228,7 @@ restore_backup:
xfree(wfname);
goto fail;
}
- errmsg = NULL;
+ SET_ERRMSG(NULL);
write_info.bw_fd = fd;
@@ -3375,7 +3348,6 @@ restore_backup:
nchars += len;
}
-#if defined(UNIX)
// 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
@@ -3384,11 +3356,11 @@ restore_backup:
// 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.
- if (p_fs && os_fsync(fd) != 0 && !device) {
- errmsg = (char_u *)_("E667: Fsync failed");
+ int error;
+ if (p_fs && (error = os_fsync(fd)) != 0 && !device) {
+ SET_ERRMSG_ARG(_("E667: Fsync failed: %s"), error);
end = 0;
}
-#endif
#ifdef HAVE_SELINUX
/* Probably need to set the security context. */
@@ -3407,8 +3379,9 @@ restore_backup:
|| 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, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
- if (perm >= 0) /* set permission again, may have changed */
- (void)os_setperm(wfname, perm);
+ if (perm >= 0) { // Set permission again, may have changed.
+ (void)os_setperm((const char *)wfname, perm);
+ }
}
buf_set_file_id(buf);
} else if (!buf->file_id_valid) {
@@ -3417,8 +3390,8 @@ restore_backup:
}
#endif
- if (close(fd) != 0) {
- errmsg = (char_u *)_("E512: Close failed");
+ if ((error = os_close(fd)) != 0) {
+ SET_ERRMSG_ARG(_("E512: Close failed: %s"), error);
end = 0;
}
@@ -3426,8 +3399,9 @@ restore_backup:
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, perm);
+ if (perm >= 0) { // Set perm. of new file same as old file.
+ (void)os_setperm((const char *)wfname, 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). */
@@ -3454,21 +3428,24 @@ restore_backup:
if (end == 0) {
if (errmsg == NULL) {
if (write_info.bw_conv_error) {
- if (write_info.bw_conv_error_lnum == 0)
- errmsg = (char_u *)_(
- "E513: write error, conversion failed (make 'fenc' empty to override)");
- else {
- errmsg_allocated = TRUE;
- errmsg = xmalloc(300);
- vim_snprintf((char *)errmsg, 300,
- _("E513: write error, conversion failed in line %" PRId64
+ if (write_info.bw_conv_error_lnum == 0) {
+ SET_ERRMSG(_(
+ "E513: write error, conversion failed "
+ "(make 'fenc' empty to override)"));
+ } else {
+ errmsg_allocated = true;
+ SET_ERRMSG(xmalloc(300));
+ vim_snprintf(
+ errmsg, 300,
+ _("E513: write error, conversion failed in line %" PRIdLINENR
" (make 'fenc' empty to override)"),
- (int64_t)write_info.bw_conv_error_lnum);
+ write_info.bw_conv_error_lnum);
}
- } else if (got_int)
- errmsg = (char_u *)_(e_interr);
- else
- errmsg = (char_u *)_("E514: write error (file system full?)");
+ } else if (got_int) {
+ SET_ERRMSG(_(e_interr));
+ } else {
+ SET_ERRMSG(_("E514: write error (file system full?)"));
+ }
}
/*
@@ -3523,8 +3500,8 @@ restore_backup:
fname = sfname; /* use shortname now, for the messages */
#endif
if (!filtering) {
- msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
- c = FALSE;
+ add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname);
+ c = false;
if (write_info.bw_conv_error) {
STRCAT(IObuff, _(" CONVERSION ERROR"));
c = TRUE;
@@ -3633,7 +3610,7 @@ restore_backup:
close(empty_fd);
}
if (org != NULL) {
- os_setperm((char_u *)org, os_getperm(fname) & 0777);
+ os_setperm(org, os_getperm((const char *)fname) & 0777);
xfree(org);
}
}
@@ -3673,33 +3650,32 @@ nofail:
#endif
if (errmsg != NULL) {
- int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
-
- attr = hl_attr(HLF_E); /* set highlight for error messages */
- msg_add_fname(buf,
+ // - 100 to save some space for further error message
#ifndef UNIX
- sfname
+ add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)sfname);
#else
- fname
+ add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)fname);
#endif
- ); /* put file name in IObuff with quotes */
- if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
- IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
- /* If the error message has the form "is ...", put the error number in
- * front of the file name. */
if (errnum != NULL) {
- STRMOVE(IObuff + numlen, IObuff);
- memmove(IObuff, errnum, (size_t)numlen);
+ if (errmsgarg != 0) {
+ emsgf("%s: %s%s: %s", errnum, IObuff, errmsg, os_strerror(errmsgarg));
+ } else {
+ emsgf("%s: %s%s", errnum, IObuff, errmsg);
+ }
+ } else if (errmsgarg != 0) {
+ emsgf(errmsg, os_strerror(errmsgarg));
+ } else {
+ emsgf(errmsg);
}
- STRCAT(IObuff, errmsg);
- emsg(IObuff);
- if (errmsg_allocated)
+ if (errmsg_allocated) {
xfree(errmsg);
+ }
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);
+ attr | MSG_HIST);
MSG_PUTS_ATTR(_(
"don't quit the editor until the file is successfully written!"),
attr | MSG_HIST);
@@ -3759,6 +3735,9 @@ nofail:
got_int |= prev_got_int;
return retval;
+#undef SET_ERRMSG
+#undef SET_ERRMSG_ARG
+#undef SET_ERRMSG_NUM
}
/*
@@ -3802,16 +3781,25 @@ static int set_rw_fname(char_u *fname, char_u *sfname)
return OK;
}
-/*
- * Put file name into IObuff with quotes.
- */
-void msg_add_fname(buf_T *buf, char_u *fname)
+/// 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 = (char_u *)"-stdin-";
- home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
- IObuff[0] = '"';
- STRCAT(IObuff, "\" ");
+ if (fname == NULL) {
+ fname = "-stdin-";
+ }
+ ret_buf[0] = '"';
+ home_replace(buf, (const char_u *)fname, (char_u *)ret_buf + 1,
+ (int)buf_len - 4, true);
+ xstrlcat(ret_buf, "\" ", buf_len);
}
/// Append message for text mode to IObuff.
@@ -3843,7 +3831,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)
+void msg_add_lines(int insert_space, long lnum, off_T nchars)
{
char_u *p;
@@ -3888,15 +3876,15 @@ static int check_mtime(buf_T *buf, FileInfo *file_info)
if (buf->b_mtime_read != 0
&& time_differs(file_info->stat.st_mtim.tv_sec,
buf->b_mtime_read)) {
- 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((char_u *)_("Do you really want to write to it"),
- TRUE) == 'n')
+ 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 */
+ }
+ msg_scroll = false; // Always overwrite the file message now.
}
return OK;
}
@@ -4553,9 +4541,10 @@ int put_time(FILE *fd, time_t time_)
/// 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
-//
+///
/// @return -1 for failure, 0 for success
-int vim_rename(char_u *from, char_u *to)
+int vim_rename(const char_u *from, const char_u *to)
+ FUNC_ATTR_NONNULL_ALL
{
int fd_in;
int fd_out;
@@ -4574,10 +4563,12 @@ int vim_rename(char_u *from, char_u *to)
* the file name differs we need to go through a temp file.
*/
if (fnamecmp(from, to) == 0) {
- if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0)
+ if (p_fic && (STRCMP(path_tail((char_u *)from), path_tail((char_u *)to))
+ != 0)) {
use_tmp_file = true;
- else
+ } else {
return 0;
+ }
}
// Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
@@ -4643,9 +4634,9 @@ int vim_rename(char_u *from, char_u *to)
/*
* Rename() failed, try copying the file.
*/
- perm = os_getperm(from);
+ perm = os_getperm((const char *)from);
#ifdef HAVE_ACL
- /* For systems that support ACL: get the ACL from the original file. */
+ // For systems that support ACL: get the ACL from the original file.
acl = mch_get_acl(from);
#endif
fd_in = os_open((char *)from, O_RDONLY, 0);
@@ -4667,7 +4658,7 @@ int vim_rename(char_u *from, char_u *to)
return -1;
}
- // Avoid xmalloc() here as vim_rename() is called by buf_write() when neovim
+ // Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim
// is `preserve_exit()`ing.
buffer = try_malloc(BUFSIZE);
if (buffer == NULL) {
@@ -4693,8 +4684,8 @@ int vim_rename(char_u *from, char_u *to)
errmsg = _("E210: Error reading \"%s\"");
to = from;
}
-#ifndef UNIX /* for Unix os_open() already set the permission */
- os_setperm(to, perm);
+#ifndef UNIX // For Unix os_open() already set the permission.
+ os_setperm((const char *)to, perm);
#endif
#ifdef HAVE_ACL
mch_set_acl(to, acl);
@@ -4726,7 +4717,6 @@ check_timestamps (
int focus /* called for GUI focus event */
)
{
- buf_T *buf;
int didit = 0;
int n;
@@ -4745,32 +4735,33 @@ check_timestamps (
if (!stuff_empty() || global_busy || !typebuf_typed()
|| autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0
- )
- need_check_timestamps = TRUE; /* check later */
- else {
- ++no_wait_return;
- did_check_timestamps = TRUE;
- already_warned = FALSE;
- for (buf = firstbuf; buf != NULL; ) {
- /* Only check buffers in a window. */
+ ) {
+ need_check_timestamps = true; // check later
+ } else {
+ no_wait_return++;
+ did_check_timestamps = true;
+ already_warned = false;
+ FOR_ALL_BUFFERS(buf) {
+ // Only check buffers in a window.
if (buf->b_nwindows > 0) {
+ bufref_T bufref;
+ set_bufref(&bufref, buf);
n = buf_check_timestamp(buf, focus);
- if (didit < n)
+ if (didit < n) {
didit = n;
- if (n > 0 && !buf_valid(buf)) {
- /* Autocommands have removed the buffer, start at the
- * first one again. */
+ }
+ if (n > 0 && !bufref_valid(&bufref)) {
+ // Autocommands have removed the buffer, start at the first one again.
buf = firstbuf;
continue;
}
}
- buf = buf->b_next;
}
--no_wait_return;
need_check_timestamps = FALSE;
if (need_wait_return && didit == 2) {
- /* make sure msg isn't overwritten */
- msg_puts((char_u *)"\n");
+ // make sure msg isn't overwritten
+ msg_puts("\n");
ui_flush();
}
}
@@ -4829,6 +4820,7 @@ buf_check_timestamp (
buf_T *buf,
int focus /* called for GUI focus event */
)
+ FUNC_ATTR_NONNULL_ALL
{
int retval = 0;
char_u *path;
@@ -4844,6 +4836,9 @@ buf_check_timestamp (
char_u *s;
char *reason;
+ bufref_T bufref;
+ set_bufref(&bufref, buf);
+
// If its a terminal, there is no file name, the buffer is not loaded,
// 'buftype' is set, we are in the middle of a save or being called
// recursively: ignore this buffer.
@@ -4913,8 +4908,9 @@ buf_check_timestamp (
allbuf_lock--;
busy = false;
if (n) {
- if (!buf_valid(buf))
+ if (!bufref_valid(&bufref)) {
EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
+ }
s = get_vim_var_str(VV_FCS_CHOICE);
if (STRCMP(s, "reload") == 0 && *reason != 'd')
reload = TRUE;
@@ -4976,8 +4972,8 @@ buf_check_timestamp (
set_vim_var_string(VV_WARNINGMSG, tbuf, -1);
if (can_reload) {
if (*mesg2 != NUL) {
- strncat(tbuf, "\n", tbuf_len);
- strncat(tbuf, mesg2, tbuf_len);
+ xstrlcat(tbuf, "\n", tbuf_len - 1);
+ xstrlcat(tbuf, mesg2, tbuf_len - 1);
}
if (do_dialog(VIM_WARNING, (char_u *) _("Warning"), (char_u *) tbuf,
(char_u *) _("&OK\n&Load File"), 1, NULL, true) == 2) {
@@ -4985,18 +4981,17 @@ buf_check_timestamp (
}
} else if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned) {
if (*mesg2 != NUL) {
- strncat(tbuf, "; ", tbuf_len);
- strncat(tbuf, mesg2, tbuf_len);
+ xstrlcat(tbuf, "; ", tbuf_len - 1);
+ xstrlcat(tbuf, mesg2, tbuf_len - 1);
}
EMSG(tbuf);
retval = 2;
} else {
if (!autocmd_busy) {
msg_start();
- msg_puts_attr((char_u *) tbuf, hl_attr(HLF_E) + MSG_HIST);
+ msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
if (*mesg2 != NUL) {
- msg_puts_attr((char_u *)mesg2,
- hl_attr(HLF_W) + MSG_HIST);
+ msg_puts_attr(mesg2, hl_attr(HLF_W) + MSG_HIST);
}
msg_clr_eos();
(void)msg_end();
@@ -5031,11 +5026,11 @@ buf_check_timestamp (
}
}
- /* Trigger FileChangedShell when the file was changed in any way. */
- if (buf_valid(buf) && retval != 0)
- (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST,
- buf->b_fname, buf->b_fname, FALSE, buf);
-
+ // Trigger FileChangedShell when the file was changed in any way.
+ if (bufref_valid(&bufref) && retval != 0) {
+ (void)apply_autocmds(EVENT_FILECHANGEDSHELLPOST, buf->b_fname, buf->b_fname,
+ false, buf);
+ }
return retval;
}
@@ -5052,6 +5047,7 @@ void buf_reload(buf_T *buf, int orig_mode)
linenr_T old_topline;
int old_ro = buf->b_p_ro;
buf_T *savebuf;
+ bufref_T bufref;
int saved = OK;
aco_save_T aco;
int flags = READ_NEW;
@@ -5087,6 +5083,7 @@ void buf_reload(buf_T *buf, int orig_mode)
} else {
// Allocate a buffer without putting it in the buffer list.
savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
+ set_bufref(&bufref, savebuf);
if (savebuf != NULL && buf == curbuf) {
/* Open the memline. */
curbuf = savebuf;
@@ -5104,19 +5101,21 @@ void buf_reload(buf_T *buf, int orig_mode)
}
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,
- (linenr_T)MAXLNUM, &ea, flags) == FAIL) {
- if (!aborting())
+ 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,
+ (linenr_T)MAXLNUM, &ea, flags) != OK) {
+ if (!aborting()) {
EMSG2(_("E321: Could not reload \"%s\""), buf->b_fname);
- if (savebuf != NULL && buf_valid(savebuf) && buf == curbuf) {
- /* Put the text back from the save buffer. First
- * delete any lines that readfile() added. */
- while (!bufempty())
- if (ml_delete(buf->b_ml.ml_line_count, FALSE) == FAIL)
+ }
+ if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf) {
+ // Put the text back from the save buffer. First
+ // delete any lines that readfile() added.
+ while (!bufempty()) {
+ if (ml_delete(buf->b_ml.ml_line_count, false) == FAIL) {
break;
+ }
+ }
(void)move_lines(savebuf, buf);
}
} else if (buf == curbuf) { /* "buf" still valid */
@@ -5133,8 +5132,9 @@ void buf_reload(buf_T *buf, int orig_mode)
}
xfree(ea.cmd);
- if (savebuf != NULL && buf_valid(savebuf))
- wipe_buffer(savebuf, FALSE);
+ if (savebuf != NULL && bufref_valid(&bufref)) {
+ wipe_buffer(savebuf, false);
+ }
/* Invalidate diff info if necessary. */
diff_invalidate(curbuf);
@@ -5197,7 +5197,7 @@ void forward_slash(char_u *fname)
{
char_u *p;
- if (path_with_url(fname)) {
+ if (path_with_url((const char *)fname)) {
return;
}
for (p = fname; *p != NUL; p++) {
@@ -5258,7 +5258,7 @@ static void vim_maketempdir(void)
/// Delete "name" and everything in it, recursively.
/// @param name The path which should be deleted.
/// @return 0 for success, -1 if some file was not deleted.
-int delete_recursive(char_u *name)
+int delete_recursive(const char *name)
{
int result = 0;
@@ -5272,7 +5272,7 @@ int delete_recursive(char_u *name)
EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS
| EW_DODOT | EW_EMPTYOK) == OK) {
for (int i = 0; i < file_count; i++) {
- if (delete_recursive(files[i]) != 0) {
+ if (delete_recursive((const char *)files[i]) != 0) {
result = -1;
}
}
@@ -5282,9 +5282,9 @@ int delete_recursive(char_u *name)
}
xfree(exp);
- os_rmdir((char *)name);
+ os_rmdir(name);
} else {
- result = os_remove((char *)name) == 0 ? 0 : -1;
+ result = os_remove(name) == 0 ? 0 : -1;
}
return result;
@@ -5296,7 +5296,7 @@ void vim_deltempdir(void)
if (vim_tempdir != NULL) {
// remove the trailing path separator
path_tail(vim_tempdir)[-1] = NUL;
- delete_recursive(vim_tempdir);
+ delete_recursive((const char *)vim_tempdir);
xfree(vim_tempdir);
vim_tempdir = NULL;
}
@@ -5367,11 +5367,9 @@ char_u *vim_tempname(void)
static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
-/*
- * augroups stores a list of autocmd group names.
- */
-static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
-#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
+/// List of autocmd group names
+static garray_T augroups = { 0, 0, sizeof(char_u *), 10, NULL };
+#define AUGROUP_NAME(i) (((char **)augroups.ga_data)[i])
/*
* The ID of the current group. Group 0 is the default one.
@@ -5386,6 +5384,18 @@ static event_T last_event;
static int last_group;
static int autocmd_blocked = 0; /* block all autocmds */
+// use get_deleted_augroup() to get this
+static const char *deleted_augroup = NULL;
+
+static inline const char *get_deleted_augroup(void)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ if (deleted_augroup == NULL) {
+ deleted_augroup = _("--Deleted--");
+ }
+ return deleted_augroup;
+}
+
/*
* Show the autocommands for one AutoPat.
*/
@@ -5405,11 +5415,12 @@ static void show_autocmd(AutoPat *ap, event_T event)
return;
if (event != last_event || ap->group != last_group) {
if (ap->group != AUGROUP_DEFAULT) {
- if (AUGROUP_NAME(ap->group) == NULL)
- msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
- else
+ if (AUGROUP_NAME(ap->group) == NULL) {
+ msg_puts_attr(get_deleted_augroup(), hl_attr(HLF_E));
+ } else {
msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
- msg_puts((char_u *)" ");
+ }
+ msg_puts(" ");
}
msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
last_event = event;
@@ -5538,7 +5549,7 @@ void aubuflocal_remove(buf_T *buf)
if (p_verbose >= 6) {
verbose_enter();
smsg(_("auto-removing autocommand: %s <buffer=%d>"),
- event_nr2name(event), buf->b_fnum);
+ event_nr2name(event), buf->b_fnum);
verbose_leave();
}
}
@@ -5561,9 +5572,10 @@ static int au_new_group(char_u *name)
ga_grow(&augroups, 1);
}
- AUGROUP_NAME(i) = vim_strsave(name);
- if (i == augroups.ga_len)
- ++augroups.ga_len;
+ AUGROUP_NAME(i) = xstrdup((char *)name);
+ if (i == augroups.ga_len) {
+ augroups.ga_len++;
+ }
}
return i;
@@ -5574,11 +5586,33 @@ static void au_del_group(char_u *name)
int i;
i = au_find_group(name);
- if (i == AUGROUP_ERROR) /* the group doesn't exist */
+ if (i == AUGROUP_ERROR) { // the group doesn't exist
EMSG2(_("E367: No such group: \"%s\""), name);
- else {
+ } else if (i == current_augroup) {
+ EMSG(_("E936: Cannot delete the current group"));
+ } else {
+ event_T event;
+ AutoPat *ap;
+ int in_use = false;
+
+ for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ event = (event_T)((int)event + 1)) {
+ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
+ if (ap->group == i && ap->pat != NULL) {
+ give_warning((char_u *)
+ _("W19: Deleting augroup that is still in use"), true);
+ in_use = true;
+ event = NUM_EVENTS;
+ break;
+ }
+ }
+ }
xfree(AUGROUP_NAME(i));
- AUGROUP_NAME(i) = NULL;
+ if (in_use) {
+ AUGROUP_NAME(i) = (char *)get_deleted_augroup();
+ } else {
+ AUGROUP_NAME(i) = NULL;
+ }
}
}
@@ -5590,8 +5624,9 @@ static void au_del_group(char_u *name)
static int au_find_group(const char_u *name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- for (int i = 0; i < augroups.ga_len; ++i) {
- if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0) {
+ for (int i = 0; i < augroups.ga_len; i++) {
+ if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
+ && STRCMP(AUGROUP_NAME(i), name) == 0) {
return i;
}
}
@@ -5628,7 +5663,7 @@ void do_augroup(char_u *arg, int del_group)
for (int i = 0; i < augroups.ga_len; ++i) {
if (AUGROUP_NAME(i) != NULL) {
msg_puts(AUGROUP_NAME(i));
- msg_puts((char_u *)" ");
+ msg_puts(" ");
}
}
msg_clr_eos();
@@ -5640,11 +5675,18 @@ void do_augroup(char_u *arg, int del_group)
void free_all_autocmds(void)
{
for (current_augroup = -1; current_augroup < augroups.ga_len;
- ++current_augroup)
- do_autocmd((char_u *)"", TRUE);
- ga_clear_strings(&augroups);
-}
+ current_augroup++) {
+ do_autocmd((char_u *)"", true);
+ }
+ for (int i = 0; i < augroups.ga_len; i++) {
+ char *const s = ((char **)(augroups.ga_data))[i];
+ if ((const char *)s != get_deleted_augroup()) {
+ xfree(s);
+ }
+ }
+ ga_clear(&augroups);
+}
#endif
/*
@@ -5652,13 +5694,13 @@ void free_all_autocmds(void)
* Return NUM_EVENTS if the event name was not found.
* Return a pointer to the next event name in "end".
*/
-static event_T event_name2nr(char_u *start, char_u **end)
+static event_T event_name2nr(const char_u *start, char_u **end)
{
- char_u *p;
+ const char_u *p;
int i;
int len;
- // the event name ends with end of line, '|', a blank or a comma */
+ // the event name ends with end of line, '|', a blank or a comma
for (p = start; *p && !ascii_iswhite(*p) && *p != ',' && *p != '|'; p++) {
}
for (i = 0; event_names[i].name != NULL; i++) {
@@ -5667,25 +5709,32 @@ static event_T event_name2nr(char_u *start, char_u **end)
break;
}
}
- if (*p == ',')
- ++p;
- *end = p;
- if (event_names[i].name == NULL)
+ if (*p == ',') {
+ p++;
+ }
+ *end = (char_u *)p;
+ if (event_names[i].name == NULL) {
return NUM_EVENTS;
+ }
return event_names[i].event;
}
-/*
- * Return the name for event "event".
- */
-static char_u *event_nr2name(event_T event)
+/// Return the name for event
+///
+/// @param[in] event Event to return name for.
+///
+/// @return Event name, static string. Returns "Unknown" for unknown events.
+static const char *event_nr2name(event_T event)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_CONST
{
int i;
- for (i = 0; event_names[i].name != NULL; ++i)
- if (event_names[i].event == event)
- return (char_u *)event_names[i].name;
- return (char_u *)"Unknown";
+ for (i = 0; event_names[i].name != NULL; i++) {
+ if (event_names[i].event == event) {
+ return event_names[i].name;
+ }
+ }
+ return "Unknown";
}
/*
@@ -6237,6 +6286,7 @@ void ex_doautoall(exarg_T *eap)
aco_save_T aco;
char_u *arg = eap->arg;
int call_do_modelines = check_nomodeline(&arg);
+ bufref_T bufref;
/*
* This is a bit tricky: For some commands curwin->w_buffer needs to be
@@ -6249,8 +6299,9 @@ void ex_doautoall(exarg_T *eap)
if (buf->b_ml.ml_mfp == NULL) {
continue;
}
- /* find a window for this buffer and save some values */
+ // Find a window for this buffer and save some values.
aucmd_prepbuf(&aco, buf);
+ set_bufref(&bufref, buf);
bool did_aucmd;
// execute the autocommands for this buffer
@@ -6266,9 +6317,10 @@ void ex_doautoall(exarg_T *eap)
/* restore the current window */
aucmd_restbuf(&aco);
- /* stop if there is some error or buffer was deleted */
- if (retval == FAIL || !buf_valid(buf))
+ // Stop if there is some error or buffer was deleted.
+ if (retval == FAIL || !bufref_valid(&bufref)) {
break;
+ }
}
check_cursor(); /* just in case lines got deleted */
@@ -6375,7 +6427,7 @@ aucmd_prepbuf (
}
curbuf = buf;
aco->new_curwin = curwin;
- aco->new_curbuf = curbuf;
+ set_bufref(&aco->new_curbuf, curbuf);
}
/// Cleanup after executing autocommands for a (hidden) buffer.
@@ -6409,6 +6461,12 @@ win_found:
win_remove(curwin, NULL);
aucmd_win_used = false;
last_status(false); // may need to remove last status line
+
+ if (!valid_tabpage_win(curtab)) {
+ // no valid window in current tabpage
+ close_tabpage(curtab);
+ }
+
restore_snapshot(SNAP_AUCMD_IDX, false);
(void)win_comp_pos(); // recompute window positions
unblock_autocmds();
@@ -6438,14 +6496,14 @@ win_found:
// Restore the buffer which was previously edited by curwin, if it was
// changed, we are still the same window and the buffer is valid.
if (curwin == aco->new_curwin
- && curbuf != aco->new_curbuf
- && buf_valid(aco->new_curbuf)
- && aco->new_curbuf->b_ml.ml_mfp != NULL) {
+ && curbuf != aco->new_curbuf.br_buf
+ && bufref_valid(&aco->new_curbuf)
+ && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL) {
if (curwin->w_s == &curbuf->b_s) {
- curwin->w_s = &aco->new_curbuf->b_s;
+ curwin->w_s = &aco->new_curbuf.br_buf->b_s;
}
curbuf->b_nwindows--;
- curbuf = aco->new_curbuf;
+ curbuf = aco->new_curbuf.br_buf;
curwin->w_buffer = curbuf;
curbuf->b_nwindows++;
}
@@ -6715,8 +6773,9 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
fname = vim_strsave(fname); /* make a copy, so we can change it */
} else {
sfname = vim_strsave(fname);
- // don't try expanding the following events
+ // Don't try expanding the following events.
if (event == EVENT_COLORSCHEME
+ || event == EVENT_DIRCHANGED
|| event == EVENT_FILETYPE
|| event == EVENT_FUNCUNDEFINED
|| event == EVENT_OPTIONSET
@@ -6725,10 +6784,11 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|| event == EVENT_REMOTEREPLY
|| event == EVENT_SPELLFILEMISSING
|| event == EVENT_SYNTAX
- || event == EVENT_TABCLOSED)
+ || event == EVENT_TABCLOSED) {
fname = vim_strsave(fname);
- else
- fname = (char_u *)FullName_save((char *)fname, FALSE);
+ } else {
+ fname = (char_u *)FullName_save((char *)fname, false);
+ }
}
if (fname == NULL) { /* out of memory */
xfree(sfname);
@@ -6810,8 +6870,8 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
patcmd.next = active_apc_list;
active_apc_list = &patcmd;
- /* set v:cmdarg (only when there is a matching pattern) */
- save_cmdbang = get_vim_var_nr(VV_CMDBANG);
+ // set v:cmdarg (only when there is a matching pattern)
+ save_cmdbang = (long)get_vim_var_nr(VV_CMDBANG);
if (eap != NULL) {
save_cmdarg = set_cmdarg(eap, NULL);
set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
@@ -6945,7 +7005,6 @@ auto_next_pat (
{
AutoPat *ap;
AutoCmd *cp;
- char_u *name;
char *s;
xfree(sourcing_name);
@@ -6964,11 +7023,13 @@ auto_next_pat (
? match_file_pat(NULL, &ap->reg_prog, apc->fname, apc->sfname,
apc->tail, ap->allow_dirs)
: ap->buflocal_nr == apc->arg_bufnr) {
- name = event_nr2name(apc->event);
+ const char *const name = event_nr2name(apc->event);
s = _("%s Auto commands for \"%s\"");
- sourcing_name = xmalloc(STRLEN(s) + STRLEN(name) + ap->patlen + 1);
- sprintf((char *)sourcing_name, s,
- (char *)name, (char *)ap->pat);
+ const size_t sourcing_name_len = (STRLEN(s) + strlen(name) + ap->patlen
+ + 1);
+ sourcing_name = xmalloc(sourcing_name_len);
+ snprintf((char *)sourcing_name, sourcing_name_len, s, name,
+ (char *)ap->pat);
if (p_verbose >= 8) {
verbose_enter();
smsg(_("Executing %s"), sourcing_name);
@@ -7034,7 +7095,7 @@ char_u *getnextac(int c, void *cookie, int indent)
if (p_verbose >= 9) {
verbose_enter_scroll();
smsg(_("autocommand %s"), ac->cmd);
- msg_puts((char_u *)"\n"); /* don't overwrite this either */
+ msg_puts("\n"); // don't overwrite this either
verbose_leave_scroll();
}
retval = vim_strsave(ac->cmd);
@@ -7100,13 +7161,17 @@ bool has_autocmd(event_T event, char_u *sfname, buf_T *buf)
*/
char_u *get_augroup_name(expand_T *xp, int idx)
{
- if (idx == augroups.ga_len) /* add "END" add the end */
+ if (idx == augroups.ga_len) { // add "END" add the end
return (char_u *)"END";
- if (idx >= augroups.ga_len) /* end of list */
+ }
+ if (idx >= augroups.ga_len) { // end of list
return NULL;
- if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
+ }
+ if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) {
+ // skip deleted entries
return (char_u *)"";
- return AUGROUP_NAME(idx); /* return a name */
+ }
+ return (char_u *)AUGROUP_NAME(idx);
}
static int include_groups = FALSE;
@@ -7163,21 +7228,27 @@ set_context_in_autocmd (
*/
char_u *get_event_name(expand_T *xp, int idx)
{
- if (idx < augroups.ga_len) { /* First list group names, if wanted */
- if (!include_groups || AUGROUP_NAME(idx) == NULL)
- return (char_u *)""; /* skip deleted entries */
- return AUGROUP_NAME(idx); /* return a name */
+ if (idx < augroups.ga_len) { // First list group names, if wanted
+ if (!include_groups || AUGROUP_NAME(idx) == NULL
+ || AUGROUP_NAME(idx) == get_deleted_augroup()) {
+ return (char_u *)""; // skip deleted entries
+ }
+ return (char_u *)AUGROUP_NAME(idx);
}
return (char_u *)event_names[idx - augroups.ga_len].name;
}
-/// Return true if autocmd "event" is supported.
-bool autocmd_supported(char_u *event)
+/// Check whether given autocommand is supported
+///
+/// @param[in] event Event to check.
+///
+/// @return True if it is, false otherwise.
+bool autocmd_supported(const char *const event)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
char_u *p;
-
- return event_name2nr(event, &p) != NUM_EVENTS;
+ return event_name2nr((const char_u *)event, &p) != NUM_EVENTS;
}
/// Return true if an autocommand is defined for a group, event and
@@ -7192,26 +7263,24 @@ bool autocmd_supported(char_u *event)
/// exists("#Event#pat")
///
/// @param arg autocommand string
-bool au_exists(const char_u *arg) FUNC_ATTR_WARN_UNUSED_RESULT
+bool au_exists(const char *const arg) FUNC_ATTR_WARN_UNUSED_RESULT
{
- char_u *arg_save;
- char_u *pattern = NULL;
- char_u *event_name;
- char_u *p;
event_T event;
AutoPat *ap;
buf_T *buflocal_buf = NULL;
int group;
bool retval = false;
- /* Make a copy so that we can change the '#' chars to a NUL. */
- arg_save = vim_strsave(arg);
- p = vim_strchr(arg_save, '#');
- if (p != NULL)
+ // Make a copy so that we can change the '#' chars to a NUL.
+ char *const arg_save = xstrdup(arg);
+ char *p = strchr(arg_save, '#');
+ if (p != NULL) {
*p++ = NUL;
+ }
- /* First, look for an autocmd group name */
- group = au_find_group(arg_save);
+ // First, look for an autocmd group name.
+ group = au_find_group((char_u *)arg_save);
+ char *event_name;
if (group == AUGROUP_ERROR) {
/* Didn't match a group name, assume the first argument is an event. */
group = AUGROUP_ALL;
@@ -7223,17 +7292,18 @@ bool au_exists(const char_u *arg) FUNC_ATTR_WARN_UNUSED_RESULT
goto theend;
}
- /* Must be "Group#Event" or "Group#Event#pat". */
+ // Must be "Group#Event" or "Group#Event#pat".
event_name = p;
- p = vim_strchr(event_name, '#');
- if (p != NULL)
- *p++ = NUL; /* "Group#Event#pat" */
+ p = strchr(event_name, '#');
+ if (p != NULL) {
+ *p++ = NUL; // "Group#Event#pat"
+ }
}
- pattern = p; /* "pattern" is NULL when there is no pattern */
+ char *pattern = p; // "pattern" is NULL when there is no pattern.
- /* find the index (enum) for the event name */
- event = event_name2nr(event_name, &p);
+ // Find the index (enum) for the event name.
+ event = event_name2nr((char_u *)event_name, (char_u **)&p);
/* return FALSE if the event name is not recognized */
if (event == NUM_EVENTS)
@@ -7259,7 +7329,7 @@ bool au_exists(const char_u *arg) FUNC_ATTR_WARN_UNUSED_RESULT
&& (group == AUGROUP_ALL || ap->group == group)
&& (pattern == NULL
|| (buflocal_buf == NULL
- ? fnamecmp(ap->pat, pattern) == 0
+ ? fnamecmp(ap->pat, (char_u *)pattern) == 0
: ap->buflocal_nr == buflocal_buf->b_fnum))) {
retval = true;
break;