summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--color.c45
-rw-r--r--color.h6
-rw-r--r--diag.c64
-rw-r--r--diag.h53
-rw-r--r--eval.c63
-rw-r--r--exec.c11
-rw-r--r--parse.c137
-rw-r--r--printf.c26
9 files changed, 271 insertions, 136 deletions
diff --git a/Makefile b/Makefile
index ad997b1..c631c35 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,7 @@ ALL_LDLIBS = $(LOCAL_LDLIBS) $(LDLIBS)
all: bfs
-bfs: bftw.o color.o dstring.o eval.o exec.o main.o mtab.o opt.o parse.o printf.o spawn.o stat.o typo.o util.o
+bfs: bftw.o color.o diag.o dstring.o eval.o exec.o main.o mtab.o opt.o parse.o printf.o spawn.o stat.o typo.o util.o
$(CC) $(ALL_LDFLAGS) $^ $(ALL_LDLIBS) -o $@
sanitized: CFLAGS := -g $(WFLAGS) -fsanitize=address -fsanitize=undefined
diff --git a/color.c b/color.c
index 1d0fa30..9a19990 100644
--- a/color.c
+++ b/color.c
@@ -473,58 +473,61 @@ done:
}
int cfprintf(CFILE *cfile, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ int ret = cvfprintf(cfile, format, args);
+ va_end(args);
+ return ret;
+}
+
+int cvfprintf(CFILE *cfile, const char *format, va_list args) {
const struct colors *colors = cfile->colors;
FILE *file = cfile->file;
-
- int ret = -1;
int error = errno;
- va_list args;
- va_start(args, format);
-
for (const char *i = format; *i; ++i) {
const char *percent = strchr(i, '%');
if (!percent) {
if (fputs(i, file) == EOF) {
- goto done;
+ return -1;
}
break;
}
size_t len = percent - i;
if (fwrite(i, 1, len, file) != len) {
- goto done;
+ return -1;
}
i = percent + 1;
switch (*i) {
case '%':
if (fputc('%', file) == EOF) {
- goto done;
+ return -1;
}
break;
case 'c':
if (fputc(va_arg(args, int), file) == EOF) {
- goto done;
+ return -1;
}
break;
case 'd':
if (fprintf(file, "%d", va_arg(args, int)) < 0) {
- goto done;
+ return -1;
}
break;
case 'g':
if (fprintf(file, "%g", va_arg(args, double)) < 0) {
- goto done;
+ return -1;
}
break;
case 's':
if (fputs(va_arg(args, const char *), file) == EOF) {
- goto done;
+ return -1;
}
break;
@@ -534,25 +537,25 @@ int cfprintf(CFILE *cfile, const char *format, ...) {
goto invalid;
}
if (fprintf(file, "%zu", va_arg(args, size_t)) < 0) {
- goto done;
+ return -1;
}
break;
case 'm':
if (fputs(strerror(error), file) == EOF) {
- goto done;
+ return -1;
}
break;
case 'P':
if (print_path(cfile, va_arg(args, const struct BFTW *)) != 0) {
- goto done;
+ return -1;
}
break;
case 'L':
if (print_link(cfile, va_arg(args, const struct BFTW *)) != 0) {
- goto done;
+ return -1;
}
break;
@@ -578,7 +581,7 @@ int cfprintf(CFILE *cfile, const char *format, ...) {
}
if (*esc) {
if (print_esc(*esc, file) != 0) {
- goto done;
+ return -1;
}
}
@@ -590,13 +593,9 @@ int cfprintf(CFILE *cfile, const char *format, ...) {
invalid:
assert(false);
errno = EINVAL;
- goto done;
+ return -1;
}
}
- ret = 0;
-
-done:
- va_end(args);
- return ret;
+ return 0;
}
diff --git a/color.h b/color.h
index 419180c..a68378e 100644
--- a/color.h
+++ b/color.h
@@ -18,6 +18,7 @@
#define BFS_COLOR_H
#include "bftw.h"
+#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
@@ -108,4 +109,9 @@ int cfclose(CFILE *cfile);
*/
int cfprintf(CFILE *cfile, const char *format, ...);
+/**
+ * cfprintf() variant that takes a va_list.
+ */
+int cvfprintf(CFILE *cfile, const char *format, va_list args);
+
#endif // BFS_COLOR_H
diff --git a/diag.c b/diag.c
new file mode 100644
index 0000000..d45e38b
--- /dev/null
+++ b/diag.c
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * bfs *
+ * Copyright (C) 2019 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#include "diag.h"
+#include "cmdline.h"
+#include "color.h"
+#include "util.h"
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+void bfs_error(const struct cmdline *cmdline, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ bfs_verror(cmdline, format, args);
+ va_end(args);
+}
+
+void bfs_warning(const struct cmdline *cmdline, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ bfs_vwarning(cmdline, format, args);
+ va_end(args);
+}
+
+void bfs_verror(const struct cmdline *cmdline, const char *format, va_list args) {
+ int error = errno;
+
+ bfs_error_prefix(cmdline);
+
+ errno = error;
+ cvfprintf(cmdline->cerr, format, args);
+}
+
+void bfs_vwarning(const struct cmdline *cmdline, const char *format, va_list args) {
+ int error = errno;
+
+ bfs_warning_prefix(cmdline);
+
+ errno = error;
+ cvfprintf(cmdline->cerr, format, args);
+}
+
+void bfs_error_prefix(const struct cmdline *cmdline) {
+ cfprintf(cmdline->cerr, "%{bld}%s:%{rs} %{er}error:%{rs} ", xbasename(cmdline->argv[0]));
+}
+
+void bfs_warning_prefix(const struct cmdline *cmdline) {
+ cfprintf(cmdline->cerr, "%{bld}%s:%{rs} %{wr}warning:%{rs} ", xbasename(cmdline->argv[0]));
+}
diff --git a/diag.h b/diag.h
new file mode 100644
index 0000000..24ee92a
--- /dev/null
+++ b/diag.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+ * bfs *
+ * Copyright (C) 2019 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifndef BFS_DIAG_H
+#define BFS_DIAG_H
+
+#include "cmdline.h"
+#include <stdarg.h>
+
+/**
+ * Shorthand for printing error messages.
+ */
+void bfs_error(const struct cmdline *cmdline, const char *format, ...);
+
+/**
+ * Shorthand for printing warning messages.
+ */
+void bfs_warning(const struct cmdline *cmdline, const char *format, ...);
+
+/**
+ * bfs_error() variant that takes a va_list.
+ */
+void bfs_verror(const struct cmdline *cmdline, const char *format, va_list args);
+
+/**
+ * bfs_warning() variant that takes a va_list.
+ */
+void bfs_vwarning(const struct cmdline *cmdline, const char *format, va_list args);
+
+/**
+ * Print the error message prefix.
+ */
+void bfs_error_prefix(const struct cmdline *cmdline);
+
+/**
+ * Print the warning message prefix.
+ */
+void bfs_warning_prefix(const struct cmdline *cmdline);
+
+#endif // BFS_DIAG_H
diff --git a/eval.c b/eval.c
index fa2be65..f7632d8 100644
--- a/eval.c
+++ b/eval.c
@@ -18,6 +18,7 @@
#include "bftw.h"
#include "cmdline.h"
#include "color.h"
+#include "diag.h"
#include "dstring.h"
#include "exec.h"
#include "mtab.h"
@@ -31,6 +32,7 @@
#include <fnmatch.h>
#include <grp.h>
#include <pwd.h>
+#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -58,6 +60,22 @@ struct eval_state {
};
/**
+ * Print an error message.
+ */
+static void eval_error(const struct eval_state *state, const char *format, ...) {
+ int error = errno;
+ const struct cmdline *cmdline = state->cmdline;
+
+ bfs_error(cmdline, "%P: ", state->ftwbuf);
+
+ va_list args;
+ va_start(args, format);
+ errno = error;
+ cvfprintf(cmdline->cerr, format, args);
+ va_end(args);
+}
+
+/**
* Check if an error should be ignored.
*/
static bool eval_should_ignore(const struct eval_state *state, int error) {
@@ -69,9 +87,9 @@ static bool eval_should_ignore(const struct eval_state *state, int error) {
/**
* Report an error that occurs during evaluation.
*/
-static void eval_error(struct eval_state *state) {
+static void eval_report_error(struct eval_state *state) {
if (!eval_should_ignore(state, errno)) {
- cfprintf(state->cmdline->cerr, "%{er}error: '%s': %m%{rs}\n", state->ftwbuf->path);
+ eval_error(state, "%m.\n");
*state->ret = EXIT_FAILURE;
}
}
@@ -128,7 +146,7 @@ static const struct bfs_stat *eval_stat(struct eval_state *state) {
if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, ftwbuf->at_flags, BFS_STAT_BROKEN_OK, &state->statbuf) == 0) {
ftwbuf->statbuf = &state->statbuf;
} else {
- eval_error(state);
+ eval_report_error(state);
}
}
return ftwbuf->statbuf;
@@ -216,8 +234,7 @@ bool eval_capable(const struct expr *expr, struct eval_state *state) {
static const struct timespec *eval_stat_time(const struct bfs_stat *statbuf, enum bfs_stat_field field, const struct eval_state *state) {
const struct timespec *ret = bfs_stat_time(statbuf, field);
if (!ret) {
- cfprintf(state->cmdline->cerr, "%{er}error: '%s': Couldn't get file %s time: %m%{rs}\n",
- state->ftwbuf->path, bfs_stat_field_name(field));
+ eval_error(state, "Couldn't get file %s: %m.\n", bfs_stat_field_name(field));
*state->ret = EXIT_FAILURE;
}
return ret;
@@ -360,13 +377,13 @@ bool eval_delete(const struct expr *expr, struct eval_state *state) {
flag |= AT_REMOVEDIR;
}
} else {
- eval_error(state);
+ eval_report_error(state);
return false;
}
}
if (unlinkat(ftwbuf->at_fd, ftwbuf->at_path, flag) != 0) {
- eval_error(state);
+ eval_report_error(state);
return false;
}
@@ -378,7 +395,7 @@ static int eval_exec_finish(const struct expr *expr, const struct cmdline *cmdli
int ret = 0;
if (expr->execbuf && bfs_exec_finish(expr->execbuf) != 0) {
if (errno != 0) {
- cfprintf(cmdline->cerr, "%{er}error: %s %s: %m%{rs}\n", expr->argv[0], expr->argv[1]);
+ bfs_error(cmdline, "%s %s: %m.\n", expr->argv[0], expr->argv[1]);
}
ret = -1;
}
@@ -397,7 +414,7 @@ static int eval_exec_finish(const struct expr *expr, const struct cmdline *cmdli
bool eval_exec(const struct expr *expr, struct eval_state *state) {
bool ret = bfs_exec(expr->execbuf, state->ftwbuf) == 0;
if (errno != 0) {
- cfprintf(state->cmdline->cerr, "%{er}error: %s %s: %m%{rs}\n", expr->argv[0], expr->argv[1]);
+ eval_error(state, "%s %s: %m.\n", expr->argv[0], expr->argv[1]);
*state->ret = EXIT_FAILURE;
}
return ret;
@@ -430,13 +447,13 @@ bool eval_empty(const struct expr *expr, struct eval_state *state) {
if (ftwbuf->typeflag == BFTW_DIR) {
int dfd = openat(ftwbuf->at_fd, ftwbuf->at_path, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
if (dfd < 0) {
- eval_error(state);
+ eval_report_error(state);
goto done;
}
DIR *dir = fdopendir(dfd);
if (!dir) {
- eval_error(state);
+ eval_report_error(state);
close(dfd);
goto done;
}
@@ -446,7 +463,7 @@ bool eval_empty(const struct expr *expr, struct eval_state *state) {
while (true) {
struct dirent *de;
if (xreaddir(dir, &de) != 0) {
- eval_error(state);
+ eval_report_error(state);
goto done_dir;
}
if (!de) {
@@ -548,7 +565,7 @@ bool eval_lname(const struct expr *expr, struct eval_state *state) {
name = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, statbuf->size);
if (!name) {
- eval_error(state);
+ eval_report_error(state);
goto done;
}
@@ -574,7 +591,7 @@ bool eval_name(const struct expr *expr, struct eval_state *state) {
if (slash && slash > name) {
copy = strndup(name, slash - name);
if (!copy) {
- eval_error(state);
+ eval_report_error(state);
return false;
}
name = copy;
@@ -722,7 +739,7 @@ done:
return true;
error:
- eval_error(state);
+ eval_report_error(state);
return true;
}
@@ -736,7 +753,7 @@ bool eval_fprint(const struct expr *expr, struct eval_state *state) {
}
if (cfprintf(cfile, "%P\n", state->ftwbuf) < 0) {
- eval_error(state);
+ eval_report_error(state);
}
return true;
@@ -749,7 +766,7 @@ bool eval_fprint0(const struct expr *expr, struct eval_state *state) {
const char *path = state->ftwbuf->path;
size_t length = strlen(path) + 1;
if (fwrite(path, 1, length, expr->cfile->file) != length) {
- eval_error(state);
+ eval_report_error(state);
}
return true;
}
@@ -765,7 +782,7 @@ bool eval_fprintf(const struct expr *expr, struct eval_state *state) {
}
if (bfs_printf(expr->cfile->file, expr->printf, state->ftwbuf) != 0) {
- eval_error(state);
+ eval_report_error(state);
}
done:
@@ -806,7 +823,7 @@ bool eval_fprintx(const struct expr *expr, struct eval_state *state) {
return true;
error:
- eval_error(state);
+ eval_report_error(state);
return true;
}
@@ -848,7 +865,7 @@ bool eval_regex(const struct expr *expr, struct eval_state *state) {
} else if (err != REG_NOMATCH) {
char *str = xregerror(err, expr->regex);
if (str) {
- cfprintf(state->cmdline->cerr, "%{er}error: '%s': %s%{rs}\n", path, str);
+ eval_error(state, "%s.\n", str);
free(str);
} else {
perror("xregerror()");
@@ -936,7 +953,7 @@ bool eval_xtype(const struct expr *expr, struct eval_state *state) {
// Broken symlink
return eval_type(expr, state);
} else {
- eval_error(state);
+ eval_report_error(state);
return false;
}
}
@@ -1152,7 +1169,7 @@ static enum bftw_action cmdline_callback(struct BFTW *ftwbuf, void *ptr) {
if (ftwbuf->typeflag == BFTW_ERROR) {
if (!eval_should_ignore(&state, ftwbuf->error)) {
args->ret = EXIT_FAILURE;
- cfprintf(cmdline->cerr, "%{er}error: '%s': %s%{rs}\n", ftwbuf->path, strerror(ftwbuf->error));
+ eval_error(&state, "%s.\n", strerror(ftwbuf->error));
}
state.action = BFTW_SKIP_SUBTREE;
goto done;
@@ -1160,7 +1177,7 @@ static enum bftw_action cmdline_callback(struct BFTW *ftwbuf, void *ptr) {
if (cmdline->xargs_safe && strpbrk(ftwbuf->path, " \t\n\'\"\\")) {
args->ret = EXIT_FAILURE;
- cfprintf(cmdline->cerr, "%{er}error: '%s': Path is not safe for xargs.%{rs}\n", ftwbuf->path);
+ eval_error(&state, "Path is not safe for xargs.\n");
state.action = BFTW_SKIP_SUBTREE;
goto done;
}
diff --git a/exec.c b/exec.c
index 35bf061..3a35063 100644
--- a/exec.c
+++ b/exec.c
@@ -18,6 +18,7 @@
#include "bftw.h"
#include "cmdline.h"
#include "color.h"
+#include "diag.h"
#include "dstring.h"
#include "spawn.h"
#include "util.h"
@@ -114,8 +115,6 @@ static size_t bfs_exec_arg_max(const struct bfs_exec *execbuf) {
}
struct bfs_exec *parse_bfs_exec(char **argv, enum bfs_exec_flags flags, const struct cmdline *cmdline) {
- CFILE *cerr = cmdline->cerr;
-
struct bfs_exec *execbuf = malloc(sizeof(*execbuf));
if (!execbuf) {
perror("malloc()");
@@ -142,9 +141,9 @@ struct bfs_exec *parse_bfs_exec(char **argv, enum bfs_exec_flags flags, const st
const char *arg = argv[i];
if (!arg) {
if (execbuf->flags & BFS_EXEC_CONFIRM) {
- cfprintf(cerr, "%{er}error: %s: Expected '... ;'.%{rs}\n", argv[0]);
+ bfs_error(cmdline, "%s: Expected '... ;'.\n", argv[0]);
} else {
- cfprintf(cerr, "%{er}error: %s: Expected '... ;' or '... {} +'.%{rs}\n", argv[0]);
+ bfs_error(cmdline, "%s: Expected '... ;' or '... {} +'.\n", argv[0]);
}
goto fail;
} else if (strcmp(arg, ";") == 0) {
@@ -161,7 +160,7 @@ struct bfs_exec *parse_bfs_exec(char **argv, enum bfs_exec_flags flags, const st
execbuf->tmpl_argc = i - 1;
if (execbuf->tmpl_argc == 0) {
- cfprintf(cerr, "%{er}error: %s: Missing command.%{rs}\n", argv[0]);
+ bfs_error(cmdline, "%s: Missing command.\n", argv[0]);
goto fail;
}
@@ -176,7 +175,7 @@ struct bfs_exec *parse_bfs_exec(char **argv, enum bfs_exec_flags flags, const st
for (i = 0; i < execbuf->tmpl_argc - 1; ++i) {
char *arg = execbuf->tmpl_argv[i];
if (strstr(arg, "{}")) {
- cfprintf(cerr, "%{er}error: %s ... +: Only one '{}' is supported.%{rs}\n", argv[0]);
+ bfs_error(cmdline, "%s ... +: Only one '{}' is supported.\n", argv[0]);
goto fail;
}
execbuf->argv[i] = arg;
diff --git a/parse.c b/parse.c
index bb71c76..e678840 100644
--- a/parse.c
+++ b/parse.c
@@ -16,6 +16,7 @@
#include "bfs.h"
#include "cmdline.h"
+#include "diag.h"
#include "dstring.h"
#include "eval.h"
#include "exec.h"
@@ -265,7 +266,7 @@ int free_cmdline(struct cmdline *cmdline) {
if (cfclose(ofile->cfile) != 0) {
if (cerr) {
- cfprintf(cerr, "%{er}error: '%s': %m%{rs}\n", ofile->path);
+ bfs_error(cmdline, "'%s': %m.\n", ofile->path);
}
ret = -1;
}
@@ -276,7 +277,7 @@ int free_cmdline(struct cmdline *cmdline) {
if (cout && fflush(cout->file) != 0) {
if (cerr) {
- cfprintf(cerr, "%{er}error: standard output: %m%{rs}\n");
+ bfs_error(cmdline, "standard output: %m.\n");
}
ret = -1;
}
@@ -370,6 +371,26 @@ enum token_type {
};
/**
+ * Print an error message during parsing.
+ */
+static void parse_error(const struct parser_state *state, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ bfs_verror(state->cmdline, format, args);
+ va_end(args);
+}
+
+/**
+ * Print a warning message during parsing.
+ */
+static void parse_warning(const struct parser_state *state, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ bfs_vwarning(state->cmdline, format, args);
+ va_end(args);
+}
+
+/**
* Fill in a "-print"-type expression.
*/
static void init_print_expr(struct parser_state *state, struct expr *expr) {
@@ -388,13 +409,13 @@ static int expr_open(struct parser_state *state, struct expr *expr, const char *
CFILE *cfile = cfopen(path, state->use_color ? cmdline->colors : NULL);
if (!cfile) {
- cfprintf(cmdline->cerr, "%{er}error: '%s': %m%{rs}\n", path);
+ parse_error(state, "'%s': %m.\n", path);
goto out;
}
struct bfs_stat sb;
if (bfs_fstat(fileno(cfile->file), &sb) != 0) {
- cfprintf(cmdline->cerr, "%{er}error: '%s': %m%{rs}\n", path);
+ parse_error(state, "'%s': %m.\n", path);
goto out_close;
}
@@ -442,7 +463,7 @@ static int stat_arg(const struct parser_state *state, struct expr *expr, struct
int ret = bfs_stat(AT_FDCWD, expr->sdata, at_flags, BFS_STAT_BROKEN_OK, sb);
if (ret != 0) {
- cfprintf(cmdline->cerr, "%{er}error: '%s': %m%{rs}\n", expr->sdata);
+ parse_error(state, "'%s': %m.\n", expr->sdata);
}
return ret;
}
@@ -601,7 +622,7 @@ static const char *parse_int(const struct parser_state *state, const char *str,
bad:
if (!(flags & IF_QUIET)) {
- cfprintf(state->cmdline->cerr, "%{er}error: '%s' is not a valid integer.%{rs}\n", str);
+ parse_error(state, "'%s' is not a valid integer.\n", str);
}
return NULL;
}
@@ -666,10 +687,10 @@ static struct expr *parse_option(struct parser_state *state, size_t argc) {
const char *arg = *parser_advance(state, T_OPTION, argc);
if (state->warn && state->non_option_seen) {
- cfprintf(state->cmdline->cerr,
- "%{wr}warning: The '%s' option applies to the entire command line. For clarity, place\n"
- "it before any non-option arguments.%{rs}\n\n",
- arg);
+ parse_warning(state,
+ "The '%s' option applies to the entire command line. For clarity, place\n"
+ "it before any non-option arguments.\n\n",
+ arg);
}
@@ -712,7 +733,7 @@ static struct expr *parse_unary_positional_option(struct parser_state *state, co
const char *arg = state->argv[0];
*value = state->argv[1];
if (!*value) {
- cfprintf(state->cmdline->cerr, "%{er}error: %s needs a value.%{rs}\n", arg);
+ parse_error(state, "%s needs a value.\n", arg);
return NULL;
}
@@ -745,7 +766,7 @@ static struct expr *parse_unary_test(struct parser_state *state, eval_fn *eval)
const char *arg = state->argv[0];
const char *value = state->argv[1];
if (!value) {
- cfprintf(state->cmdline->cerr, "%{er}error: %s needs a value.%{rs}\n", arg);
+ parse_error(state, "%s needs a value.\n", arg);
return NULL;
}
@@ -782,7 +803,7 @@ static struct expr *parse_unary_action(struct parser_state *state, eval_fn *eval
const char *arg = state->argv[0];
const char *value = state->argv[1];
if (!value) {
- cfprintf(state->cmdline->cerr, "%{er}error: %s needs a value.%{rs}\n", arg);
+ parse_error(state, "%s needs a value.\n", arg);
return NULL;
}
@@ -836,7 +857,7 @@ static struct expr *parse_debug(struct parser_state *state, int arg1, int arg2)
const char *arg = state->argv[0];
const char *flag = state->argv[1];
if (!flag) {
- cfprintf(cmdline->cerr, "%{er}error: %s needs a flag.%{rs}\n\n", arg);
+ parse_error(state, " %s needs a flag.\n\n", arg);
debug_help(cmdline->cerr);
return NULL;
}
@@ -862,7 +883,7 @@ static struct expr *parse_debug(struct parser_state *state, int arg1, int arg2)
} else if (strcmp(flag, "all") == 0) {
cmdline->debug |= DEBUG_ALL;
} else {
- cfprintf(cmdline->cerr, "%{wr}warning: Unrecognized debug flag '%s'.%{rs}\n\n", flag);
+ parse_warning(state, "Unrecognized debug flag '%s'.\n\n", flag);
debug_help(cmdline->cerr);
cfprintf(cmdline->cerr, "\n");
}
@@ -883,7 +904,7 @@ static struct expr *parse_optlevel(struct parser_state *state, int arg1, int arg
}
if (state->warn && *optlevel > 4) {
- cfprintf(state->cmdline->cerr, "%{wr}warning: %s is the same as -O4.%{rs}\n\n", state->argv[0]);
+ parse_warning(state, "%s is the same as -O4.\n\n", state->argv[0]);
}
return parse_nullary_flag(state);
@@ -935,7 +956,7 @@ static struct expr *parse_acl(struct parser_state *state, int flag, int arg2) {
}
return expr;
#else
- cfprintf(state->cmdline->cerr, "%{er}error: %s is missing platform support.%{rs}\n", state->argv[0]);
+ parse_error(state, "%s is missing platform support.\n", state->argv[0]);
return NULL;
#endif
}
@@ -993,7 +1014,7 @@ static struct expr *parse_capable(struct parser_state *state, int flag, int arg2
}
return expr;
#else
- cfprintf(state->cmdline->cerr, "%{er}error: %s is missing platform support.%{rs}\n", state->argv[0]);
+ parse_error(state, "%s is missing platform support.\n", state->argv[0]);
return NULL;
#endif
}
@@ -1091,7 +1112,7 @@ static struct expr *parse_depth_limit(struct parser_state *state, int is_min, in
const char *arg = state->argv[0];
const char *value = state->argv[1];
if (!value) {
- cfprintf(cmdline->cerr, "%{er}error: %s needs a value.%{rs}\n", arg);
+ parse_error(state, "%s needs a value.\n", arg);
return NULL;
}
@@ -1190,7 +1211,7 @@ static struct expr *parse_f(struct parser_state *state, int arg1, int arg2) {
const char *path = state->argv[0];
if (!path) {
- cfprintf(state->cmdline->cerr, "%{er}error: -f requires a path.%{rs}\n");
+ parse_error(state, "-f requires a path.\n");
return NULL;
}
@@ -1268,13 +1289,13 @@ static struct expr *parse_fprintf(struct parser_state *state, int arg1, int arg2
const char *file = state->argv[1];
if (!file) {
- cfprintf(state->cmdline->cerr, "%{er}error: %s needs a file.%{rs}\n", arg);
+ parse_error(state, "%s needs a file.\n", arg);
return NULL;
}
const char *format = state->argv[2];
if (!format) {
- cfprintf(state->cmdline->cerr, "%{er}error: %s needs a format string.%{rs}\n", arg);
+ parse_error(state, "%s needs a format string.\n", arg);
return NULL;
}
@@ -1311,7 +1332,7 @@ static struct expr *parse_fstype(struct parser_state *state, int arg1, int arg2)
if (!cmdline->mtab) {
cmdline->mtab = parse_bfs_mtab();
if (!cmdline->mtab) {
- cfprintf(cmdline->cerr, "%{er}error: Couldn't parse the mount table: %m%{rs}\n");
+ parse_error(state, "Couldn't parse the mount table: %m.\n");
return NULL;
}
}
@@ -1343,7 +1364,7 @@ static struct expr *parse_group(struct parser_state *state, int arg1, int arg2)
goto fail;
}
} else {
- cfprintf(state->cmdline->cerr, "%{er}error: %s %s: No such group.%{rs}\n", arg, expr->sdata);
+ parse_error(state, "%s %s: No such group.\n", arg, expr->sdata);
goto fail;
}
@@ -1387,7 +1408,7 @@ static struct expr *parse_user(struct parser_state *state, int arg1, int arg2) {
goto fail;
}
} else {
- cfprintf(state->cmdline->cerr, "%{er}error: %s %s: No such user.%{rs}\n", arg, expr->sdata);
+ parse_error(state, "%s %s: No such user.\n", arg, expr->sdata);
goto fail;
}
@@ -1475,7 +1496,7 @@ static struct expr *parse_fnmatch(const struct parser_state *state, struct expr
#ifdef FNM_CASEFOLD
expr->idata = FNM_CASEFOLD;
#else
- cfprintf(state->cmdline->cerr, "%{er}error: %s is missing platform support.%{rs}\n", expr->argv[0]);
+ parse_error(state, "%s is missing platform support.\n", expr->argv[0]);
free_expr(expr);
return NULL;
#endif
@@ -1538,11 +1559,9 @@ static enum bfs_stat_field parse_newerxy_field(char c) {
* Parse -newerXY.
*/
static struct expr *parse_newerxy(struct parser_state *state, int arg1, int arg2) {
- CFILE *cerr = state->cmdline->cerr;
-
const char *arg = state->argv[0];
if (strlen(arg) != 8) {
- cfprintf(cerr, "%{er}error: Expected -newerXY; found %s.%{rs}\n", arg);
+ parse_error(state, "Expected -newerXY; found %s.\n", arg);
return NULL;
}
@@ -1553,17 +1572,17 @@ static struct expr *parse_newerxy(struct parser_state *state, int arg1, int arg2
expr->stat_field = parse_newerxy_field(arg[6]);
if (!expr->stat_field) {
- cfprintf(cerr, "%{er}error: %s: For -newerXY, X should be 'a', 'c', 'm', or 'B'.%{rs}\n", arg);
+ parse_error(state, "%s: For -newerXY, X should be 'a', 'c', 'm', or 'B'.\n", arg);
goto fail;
}
if (arg[7] == 't') {
- cfprintf(cerr, "%{er}error: %s: Explicit reference times ('t') are not supported.%{rs}\n", arg);
+ parse_error(state, "%s: Explicit reference times ('t') are not supported.\n", arg);
goto fail;
} else {
enum bfs_stat_field field = parse_newerxy_field(arg[7]);
if (!field) {
- cfprintf(cerr, "%{er}error: %s: For -newerXY, Y should be 'a', 'c', 'm', 'B', or 't'.%{rs}\n", arg);
+ parse_error(state, "%s: For -newerXY, Y should be 'a', 'c', 'm', 'B', or 't'.\n", arg);
goto fail;
}
@@ -1572,10 +1591,10 @@ static struct expr *parse_newerxy(struct parser_state *state, int arg1, int arg2
goto fail;
}
+
const struct timespec *reftime = bfs_stat_time(&sb, field);
if (!reftime) {
- cfprintf(cerr, "%{er}error: '%s': Couldn't get file %s: %m.%{rs}\n",
- expr->sdata, bfs_stat_field_name(field));
+ parse_error(state, "'%s': Couldn't get file %s.\n", expr->sdata, bfs_stat_field_name(field));
goto fail;
}
@@ -1613,9 +1632,7 @@ static struct expr *parse_nohidden(struct parser_state *state, int arg1, int arg
*/
static struct expr *parse_noleaf(struct parser_state *state, int arg1, int arg2) {
if (state->warn) {
- cfprintf(state->cmdline->cerr,
- "%{wr}warning: bfs does not apply the optimization that %s inhibits.%{rs}\n\n",
- state->argv[0]);
+ parse_warning(state, "bfs does not apply the optimization that %s inhibits.\n\n", state->argv[0]);
}
return parse_nullary_option(state);
@@ -1847,7 +1864,7 @@ done:
return 0;
fail:
- cfprintf(state->cmdline->cerr, "%{er}error: '%s' is an invalid mode.%{rs}\n", mode);
+ parse_error(state, "'%s' is an invalid mode.\n", mode);
return -1;
}
@@ -1991,7 +2008,7 @@ static struct expr *parse_regex(struct parser_state *state, int flags, int arg2)
if (err != 0) {
char *str = xregerror(err, expr->regex);
if (str) {
- cfprintf(state->cmdline->cerr, "%{er}error: %s %s: %s.%{rs}\n", expr->argv[0], expr->argv[1], str);
+ parse_error(state, "%s %s: %s.\n", expr->argv[0], expr->argv[1], str);
free(str);
} else {
perror("xregerror()");
@@ -2044,7 +2061,7 @@ static struct expr *parse_regextype(struct parser_state *state, int arg1, int ar
return expr;
fail_bad_type:
- cfprintf(state->cmdline->cerr, "%{er}error: Unsupported -regextype '%s'.%{rs}\n\n", type);
+ parse_error(state, "Unsupported -regextype '%s'.\n\n", type);
fail_list_types:
fputs("Supported types are:\n\n", file);
fputs(" posix-basic: POSIX basic regular expressions (BRE)\n", file);
@@ -2133,9 +2150,8 @@ static struct expr *parse_size(struct parser_state *state, int arg1, int arg2) {
return expr;
bad_unit:
- cfprintf(state->cmdline->cerr,
- "%{er}error: %s %s: Expected a size unit (one of cwbkMGTP); found %s.%{rs}\n",
- expr->argv[0], expr->argv[1], unit);
+ parse_error(state, "%s %s: Expected a size unit (one of cwbkMGTP); found '%s'.\n",
+ expr->argv[0], expr->argv[1], unit);
fail:
free_expr(expr);
return NULL;
@@ -2205,15 +2221,12 @@ static struct expr *parse_type(struct parser_state *state, int x, int arg2) {
break;
case '\0':
- cfprintf(state->cmdline->cerr,
- "%{er}error: %s %s: Expected a type flag.%{rs}\n",
- expr->argv[0], expr->argv[1]);
+ parse_error(state, "%s %s: Expected a type flag.\n", expr->argv[0], expr->argv[1]);
goto fail;
default:
- cfprintf(state->cmdline->cerr,
- "%{er}error: %s %s: Unknown type flag '%c' (expected one of [bcdpflsD]).%{rs}\n",
- expr->argv[0], expr->argv[1], *c);
+ parse_error(state, "%s %s: Unknown type flag '%c' (expected one of [bcdpflsD]).\n",
+ expr->argv[0], expr->argv[1], *c);
goto fail;
}
@@ -2229,9 +2242,7 @@ static struct expr *parse_type(struct parser_state *state, int x, int arg2) {
++c;
continue;
} else {
- cfprintf(state->cmdline->cerr,
- "%{er}error: %s %s: Types must be comma-separated.%{rs}\n",
- expr->argv[0], expr->argv[1]);
+ parse_error(state, "%s %s: Types must be comma-separated.\n", expr->argv[0], expr->argv[1]);
goto fail;
}
}
@@ -2701,8 +2712,6 @@ static const struct table_entry *table_lookup_fuzzy(const char *arg) {
* | ACTION
*/
static struct expr *parse_literal(struct parser_state *state) {
- struct cmdline *cmdline = state->cmdline;
-
// Paths are already skipped at this point
const char *arg = state->argv[0];
@@ -2721,9 +2730,7 @@ static struct expr *parse_literal(struct parser_state *state) {
match = table_lookup_fuzzy(arg);
- cfprintf(cmdline->cerr,
- "%{er}error: Unknown argument '%s'; did you mean '%s'?%{rs}",
- arg, match->arg);
+ parse_error(state, "Unknown argument '%s'; did you mean '%s'?", arg, match->arg);
if (!state->interactive || !match->parse) {
fprintf(stderr, "\n");
@@ -2745,7 +2752,7 @@ unmatched:
return NULL;
unexpected:
- cfprintf(cmdline->cerr, "%{er}error: Expected a predicate; found '%s'.%{rs}\n", arg);
+ parse_error(state, "Expected a predicate; found '%s'.\n", arg);
return NULL;
}
@@ -2755,15 +2762,13 @@ unexpected:
* | LITERAL
*/
static struct expr *parse_factor(struct parser_state *state) {
- CFILE *cerr = state->cmdline->cerr;
-
if (skip_paths(state) != 0) {
return NULL;
}
const char *arg = state->argv[0];
if (!arg) {
- cfprintf(cerr, "%{er}error: Expression terminated prematurely after '%s'.%{rs}\n", state->last_arg);
+ parse_error(state, "Expression terminated prematurely after '%s'.\n", state->last_arg);
return NULL;
}
@@ -2782,7 +2787,7 @@ static struct expr *parse_factor(struct parser_state *state) {
arg = state->argv[0];
if (!arg || strcmp(arg, ")") != 0) {
- cfprintf(cerr, "%{er}error: Expected a ')' after '%s'.%{rs}\n", state->argv[-1]);
+ parse_error(state, "Expected a ')' after '%s'.\n", state->argv[-1]);
free_expr(expr);
return NULL;
}
@@ -2930,8 +2935,6 @@ static struct expr *parse_whole_expr(struct parser_state *state) {
return NULL;
}
- CFILE *cerr = state->cmdline->cerr;
-
struct expr *expr = &expr_true;
if (state->argv[0]) {
expr = parse_expr(state);
@@ -2941,7 +2944,7 @@ static struct expr *parse_whole_expr(struct parser_state *state) {
}
if (state->argv[0]) {
- cfprintf(cerr, "%{er}error: Unexpected argument '%s'.%{rs}\n", state->argv[0]);
+ parse_error(state, "Unexpected argument '%s'.\n", state->argv[0]);
goto fail;
}
@@ -2959,10 +2962,10 @@ static struct expr *parse_whole_expr(struct parser_state *state) {
}
if (state->warn && state->depth_arg && state->prune_arg) {
- cfprintf(cerr, "%{wr}warning: %s does not work in the presence of %s.%{rs}\n", state->prune_arg, state->depth_arg);
+ parse_warning(state, "%s does not work in the presence of %s.\n", state->prune_arg, state->depth_arg);
if (state->interactive) {
- cfprintf(cerr, "%{wr}Do you want to continue?%{rs} ");
+ fprintf(stderr, "Do you want to continue? ");
if (ynprompt() == 0) {
goto fail;
}
diff --git a/printf.c b/printf.c
index 4fc2dfb..595e9dd 100644
--- a/printf.c
+++ b/printf.c
@@ -17,6 +17,7 @@
#include "printf.h"
#include "cmdline.h"
#include "color.h"
+#include "diag.h"
#include "dstring.h"
#include "expr.h"
#include "mtab.h"
@@ -476,8 +477,6 @@ static int append_literal(struct bfs_printf_directive ***tail, struct bfs_printf
}
struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline) {
- CFILE *cerr = cmdline->cerr;
-
struct bfs_printf *command = malloc(sizeof(*command));
if (!command) {
perror("malloc()");
@@ -532,11 +531,11 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
goto done;
case '\0':
- cfprintf(cerr, "%{er}error: '%s': Incomplete escape sequence '\\'.%{rs}\n", format);
+ bfs_error(cmdline, "'%s': Incomplete escape sequence '\\'.\n", format);
goto error;
default:
- cfprintf(cerr, "%{er}error: '%s': Unrecognized escape sequence '\\%c'.%{rs}\n", format, c);
+ bfs_error(cmdline, "'%s': Unrecognized escape sequence '\\%c'.\n", format, c);
goto error;
}
} else if (c == '%') {
@@ -570,7 +569,7 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
case ' ':
case '-':
if (strchr(directive->str, c)) {
- cfprintf(cerr, "%{er}error: '%s': Duplicate flag '%c'.%{rs}\n", format, c);
+ bfs_error(cmdline, "'%s': Duplicate flag '%c'.\n", format, c);
goto directive_error;
}
if (dstrapp(&directive->str, c) != 0) {
@@ -633,7 +632,7 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
if (!cmdline->mtab) {
cmdline->mtab = parse_bfs_mtab();
if (!cmdline->mtab) {
- cfprintf(cmdline->cerr, "%{er}error: Couldn't parse the mount table: %m%{rs}\n");
+ bfs_error(cmdline, "Couldn't parse the mount table: %m.\n");
goto directive_error;
}
}
@@ -738,32 +737,27 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
command->needs_stat = true;
c = *++i;
if (!c) {
- cfprintf(cerr, "%{er}error: '%s': Incomplete time specifier '%s%c'.%{rs}\n",
- format, directive->str, i[-1]);
+ bfs_error(cmdline, "'%s': Incomplete time specifier '%s%c'.\n", format, directive->str, i[-1]);
goto directive_error;
} else if (strchr("%+@aAbBcCdDeFgGhHIjklmMnprRsStTuUVwWxXyYzZ", c)) {
directive->c = c;
} else {
- cfprintf(cerr, "%{er}error: '%s': Unrecognized time specifier '%%%c%c'.%{rs}\n",
- format, i[-1], c);
+ bfs_error(cmdline, "'%s': Unrecognized time specifier '%%%c%c'.\n", format, i[-1], c);
goto directive_error;
}
break;
case '\0':
- cfprintf(cerr, "%{er}error: '%s': Incomplete format specifier '%s'.%{rs}\n",
- format, directive->str);
+ bfs_error(cmdline, "'%s': Incomplete format specifier '%s'.\n", format, directive->str);
goto directive_error;
default:
- cfprintf(cerr, "%{er}error: '%s': Unrecognized format specifier '%%%c'.%{rs}\n",
- format, c);
+ bfs_error(cmdline, "'%s': Unrecognized format specifier '%%%c'.\n", format, c);
goto directive_error;
}
if (must_be_numeric && strcmp(specifier, "s") == 0) {
- cfprintf(cerr, "%{er}error: '%s': Invalid flags '%s' for string format '%%%c'.%{rs}\n",
- format, directive->str + 1, c);
+ bfs_error(cmdline, "'%s': Invalid flags '%s' for string format '%%%c'.\n", format, directive->str + 1, c);
goto directive_error;
}