From 7fc7e98df2ea9c34dd1e0cb188554bed933a16df Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 25 Dec 2018 18:00:14 -0500 Subject: diag: Unify diagnostic formatting This adds a bfs: prefix to error/warning messages for consistency with other command line tools, and leaves only the "error:"/"warning:" part colored like GCC. It also uniformly adds full stops after messages. --- Makefile | 2 +- color.c | 45 ++++++++++----------- color.h | 6 +++ diag.c | 64 +++++++++++++++++++++++++++++ diag.h | 53 ++++++++++++++++++++++++ eval.c | 63 ++++++++++++++++++----------- exec.c | 11 +++-- parse.c | 137 ++++++++++++++++++++++++++++++++------------------------------- printf.c | 26 +++++------- 9 files changed, 271 insertions(+), 136 deletions(-) create mode 100644 diag.c create mode 100644 diag.h 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 #include #include @@ -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 * + * * + * 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 +#include +#include +#include + +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 * + * * + * 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 + +/** + * 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 #include #include +#include #include #include #include @@ -57,6 +59,22 @@ struct eval_state { struct bfs_stat xstatbuf; }; +/** + * 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. */ @@ -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; } @@ -369,6 +370,26 @@ enum token_type { T_OPERATOR, }; +/** + * 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. */ @@ -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; } -- cgit v1.2.3