refactor(fileio.c): do not use macros for error handling

This commit is contained in:
Lewis Russell 2023-01-30 17:20:25 +00:00
parent 9417a3d98a
commit 842cf780a6

View File

@ -118,6 +118,13 @@ struct bw_info {
iconv_t bw_iconv_fd; // descriptor for iconv() or -1 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 #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "fileio.c.generated.h" # include "fileio.c.generated.h"
#endif #endif
@ -2245,6 +2252,39 @@ static int buf_write_do_autocmds(buf_T *buf, char **fnamep, char **sfnamep, char
return NOTDONE; 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" /// buf_write() - write to file "fname" lines "start" through "end"
/// ///
/// We do our own buffering here because fwrite() is so slow. /// 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 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 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 retval = OK;
int msg_save = msg_scroll; int msg_save = msg_scroll;
int prev_got_int = got_int; 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; bufsize = BUFSIZE;
} }
Error_T err = { 0 };
int newfile = false; // true if file doesn't exist yet int newfile = false; // true if file doesn't exist yet
int device = false; // writing to a device int device = false; // writing to a device
char *backup = NULL; 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; perm = (long)file_info_old.stat.st_mode;
if (!S_ISREG(file_info_old.stat.st_mode)) { // not a file if (!S_ISREG(file_info_old.stat.st_mode)) { // not a file
if (S_ISDIR(file_info_old.stat.st_mode)) { 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; goto fail;
} }
if (os_nodetype(fname) != NODE_WRITABLE) { 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; goto fail;
} }
// It's a device of some kind (or a fifo) which we can write to // 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. // Check for a writable device name.
char nodetype = fname == NULL ? NODE_OTHER : os_nodetype(fname); char nodetype = fname == NULL ? NODE_OTHER : os_nodetype(fname);
if (nodetype == NODE_OTHER) { 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; goto fail;
} }
if (nodetype == NODE_WRITABLE) { 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) { if (perm < 0) {
newfile = true; newfile = true;
} else if (os_isdir(fname)) { } else if (os_isdir(fname)) {
SET_ERRMSG_NUM("E502", _("is a directory")); err = set_err_num("E502", _("is a directory"));
goto fail; goto fail;
} }
if (overwriting) { 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 (!forceit && file_readonly) {
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
SET_ERRMSG_NUM("E504", _(err_readonly)); err = set_err_num("E504", _(err_readonly));
} else { } else {
SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)")); err = set_err_num("E505", _("is read-only (add ! to override)"));
} }
goto fail; 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 // copy the file
if (os_copy(fname, backup, UV_FS_COPYFILE_FICLONE) != 0) { 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); XFREE_CLEAR(backup);
backup = NULL; backup = NULL;
continue; continue;
@ -2730,21 +2761,21 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
#ifdef HAVE_ACL #ifdef HAVE_ACL
os_set_acl(backup, acl); os_set_acl(backup, acl);
#endif #endif
SET_ERRMSG(NULL); err = set_err(NULL);
break; break;
} }
} }
nobackup: nobackup:
if (backup == NULL && errmsg == NULL) { if (backup == NULL && err.msg == NULL) {
SET_ERRMSG(_("E509: Cannot create backup file (add ! to override)")); err = set_err(_("E509: Cannot create backup file (add ! to override)"));
} }
// Ignore errors when forceit is true. // Ignore errors when forceit is true.
if ((some_error || errmsg != NULL) && !forceit) { if ((some_error || err.msg != NULL) && !forceit) {
retval = FAIL; retval = FAIL;
goto fail; goto fail;
} }
SET_ERRMSG(NULL); err = set_err(NULL);
} else { } else {
// Make a backup by renaming the original file. // Make a backup by renaming the original file.
@ -2752,7 +2783,7 @@ nobackup:
// overwrite a read-only file. But rename may be possible // overwrite a read-only file. But rename may be possible
// anyway, thus we need an extra check here. // anyway, thus we need an extra check here.
if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) { 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; goto fail;
} }
@ -2832,7 +2863,7 @@ nobackup:
} }
} }
if (backup == NULL && !forceit) { 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; goto fail;
} }
} }
@ -2877,7 +2908,7 @@ nobackup:
&& !(exiting && backup != NULL)) { && !(exiting && backup != NULL)) {
ml_preserve(buf, false, !!p_fs); ml_preserve(buf, false, !!p_fs);
if (got_int) { if (got_int) {
SET_ERRMSG(_(e_interr)); err = set_err(_(e_interr));
goto restore_backup; goto restore_backup;
} }
} }
@ -2939,7 +2970,7 @@ nobackup:
if (*p_ccv != NUL) { if (*p_ccv != NUL) {
wfname = vim_tempname(); wfname = vim_tempname();
if (wfname == NULL) { // Can't write without a tempfile! 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; goto restore_backup;
} }
} }
@ -2952,7 +2983,7 @@ nobackup:
&& write_info.bw_iconv_fd == (iconv_t)-1 && write_info.bw_iconv_fd == (iconv_t)-1
&& wfname == fname) { && wfname == fname) {
if (!forceit) { 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; goto restore_backup;
} }
notconverted = true; notconverted = true;
@ -3002,7 +3033,7 @@ nobackup:
// A forced write will try to create a new file if the old one // 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 still readonly. This may also happen when the directory
// is read-only. In that case the mch_remove() will fail. // is read-only. In that case the mch_remove() will fail.
if (errmsg == NULL) { if (err.msg == NULL) {
#ifdef UNIX #ifdef UNIX
FileInfo file_info; FileInfo file_info;
@ -3010,10 +3041,10 @@ nobackup:
if ((!newfile && os_fileinfo_hardlinks(&file_info_old) > 1) if ((!newfile && os_fileinfo_hardlinks(&file_info_old) > 1)
|| (os_fileinfo_link(fname, &file_info) || (os_fileinfo_link(fname, &file_info)
&& !os_fileinfo_id_equal(&file_info, &file_info_old))) { && !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 { } else {
#endif #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 if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
&& perm >= 0) { && perm >= 0) {
#ifdef UNIX #ifdef UNIX
@ -3076,7 +3107,7 @@ restore_backup:
} }
write_info.bw_fd = fd; write_info.bw_fd = fd;
} }
SET_ERRMSG(NULL); err = set_err(NULL);
write_info.bw_buf = buffer; write_info.bw_buf = buffer;
nchars = 0; nchars = 0;
@ -3226,7 +3257,7 @@ restore_backup:
if (p_fs && (error = os_fsync(fd)) != 0 && !device if (p_fs && (error = os_fsync(fd)) != 0 && !device
// fsync not supported on this storage. // fsync not supported on this storage.
&& error != UV_ENOTSUP) { && error != UV_ENOTSUP) {
SET_ERRMSG_ARG(e_fsync, error); err = set_err_arg(e_fsync, error);
end = 0; end = 0;
} }
@ -3253,7 +3284,7 @@ restore_backup:
#endif #endif
if ((error = os_close(fd)) != 0) { 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; end = 0;
} }
@ -3289,23 +3320,23 @@ restore_backup:
if (end == 0) { if (end == 0) {
// Error encountered. // Error encountered.
if (errmsg == NULL) { if (err.msg == NULL) {
if (write_info.bw_conv_error) { if (write_info.bw_conv_error) {
if (write_info.bw_conv_error_lnum == 0) { if (write_info.bw_conv_error_lnum == 0) {
SET_ERRMSG(_("E513: write error, conversion failed " err = set_err(_("E513: write error, conversion failed "
"(make 'fenc' empty to override)")); "(make 'fenc' empty to override)"));
} else { } else {
errmsg_allocated = true; err = set_err(xmalloc(300));
SET_ERRMSG(xmalloc(300)); err.alloc = true;
vim_snprintf(errmsg, 300, // NOLINT(runtime/printf) vim_snprintf(err.msg, 300, // NOLINT(runtime/printf)
_("E513: write error, conversion failed in line %" PRIdLINENR _("E513: write error, conversion failed in line %" PRIdLINENR
" (make 'fenc' empty to override)"), " (make 'fenc' empty to override)"),
write_info.bw_conv_error_lnum); write_info.bw_conv_error_lnum);
} }
} else if (got_int) { } else if (got_int) {
SET_ERRMSG(_(e_interr)); err = set_err(_(e_interr));
} else { } 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); os_free_acl(acl);
#endif #endif
if (errmsg != NULL) { if (err.msg != NULL) {
// - 100 to save some space for further error message // - 100 to save some space for further error message
#ifndef UNIX #ifndef UNIX
add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)sfname); add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)sfname);
#else #else
add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)fname); add_quoted_fname(IObuff, IOSIZE - 100, buf, (const char *)fname);
#endif #endif
if (errnum != NULL) { emit_err(&err);
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);
}
retval = FAIL; retval = FAIL;
if (end == 0) { if (end == 0) {
@ -3570,9 +3588,6 @@ nofail:
got_int |= prev_got_int; got_int |= prev_got_int;
return retval; 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 /// Set the name of the current buffer. Use when the buffer doesn't have a