summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2019-01-31 23:56:06 -0500
committerTavian Barnes <tavianator@tavianator.com>2019-02-01 12:50:29 -0500
commit6a5c4c1161291a55b35151562a2d86c0a7a06606 (patch)
tree2ed9645893620c27d643443c9da88a6812b61447
parentaa5f0f5745e4e7392c078d1fe28825c941f52f7c (diff)
downloadbfs-6a5c4c1161291a55b35151562a2d86c0a7a06606.tar.xz
eval: Fix wrong colors in error messages
When reporting an error, we should try to stat the file first so the message can have the right colors.
-rw-r--r--eval.c117
1 files changed, 72 insertions, 45 deletions
diff --git a/eval.c b/eval.c
index 84e68c2..de57b9f 100644
--- a/eval.c
+++ b/eval.c
@@ -60,42 +60,6 @@ struct eval_state {
struct bfs_stat xstatbuf;
};
-/**
- * Print an error message.
- */
-BFS_FORMATTER(2, 3)
-static void eval_error(const struct eval_state *state, const char *format, ...) {
- int error = errno;
- const struct cmdline *cmdline = state->cmdline;
-
- bfs_error(cmdline, "%pP: ", 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) {
- return state->cmdline->ignore_races
- && is_nonexistence_error(error)
- && state->ftwbuf->depth > 0;
-}
-
-/**
- * Report an error that occurs during evaluation.
- */
-static void eval_report_error(struct eval_state *state) {
- if (!eval_should_ignore(state, errno)) {
- eval_error(state, "%m.\n");
- *state->ret = EXIT_FAILURE;
- }
-}
-
#define DEBUG_FLAG(flags, flag) \
do { \
if ((flags & flag) || flags == flag) { \
@@ -143,20 +107,83 @@ static void debug_stat(const struct eval_state *state, int at_flags, enum bfs_st
/**
* Perform a bfs_stat() call if necessary.
*/
-static const struct bfs_stat *eval_stat(struct eval_state *state) {
+static const struct bfs_stat *eval_try_stat(struct eval_state *state) {
struct BFTW *ftwbuf = state->ftwbuf;
- if (!ftwbuf->statbuf) {
- debug_stat(state, ftwbuf->at_flags, BFS_STAT_BROKEN_OK);
- 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_report_error(state);
- }
+
+ if (ftwbuf->statbuf) {
+ goto done;
+ }
+
+ if (ftwbuf->error) {
+ errno = ftwbuf->error;
+ goto done;
+ }
+
+ debug_stat(state, ftwbuf->at_flags, BFS_STAT_BROKEN_OK);
+
+ if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, ftwbuf->at_flags, BFS_STAT_BROKEN_OK, &state->statbuf) == 0) {
+ ftwbuf->statbuf = &state->statbuf;
+ } else {
+ ftwbuf->error = errno;
}
+
+done:
return ftwbuf->statbuf;
}
/**
+ * Print an error message.
+ */
+BFS_FORMATTER(2, 3)
+static void eval_error(struct eval_state *state, const char *format, ...) {
+ int error = errno;
+ const struct cmdline *cmdline = state->cmdline;
+ CFILE *cerr = cmdline->cerr;
+
+ if (cerr->colors) {
+ eval_try_stat(state);
+ }
+
+ bfs_error(cmdline, "%pP: ", state->ftwbuf);
+
+ va_list args;
+ va_start(args, format);
+ errno = error;
+ cvfprintf(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) {
+ return state->cmdline->ignore_races
+ && is_nonexistence_error(error)
+ && state->ftwbuf->depth > 0;
+}
+
+/**
+ * Report an error that occurs during evaluation.
+ */
+static void eval_report_error(struct eval_state *state) {
+ if (!eval_should_ignore(state, errno)) {
+ eval_error(state, "%m.\n");
+ *state->ret = EXIT_FAILURE;
+ }
+}
+
+/**
+ * Perform a bfs_stat() call if necessary.
+ */
+static const struct bfs_stat *eval_stat(struct eval_state *state) {
+ const struct bfs_stat *ret = eval_try_stat(state);
+ if (!ret) {
+ eval_report_error(state);
+ }
+ return ret;
+}
+
+/**
* Perform a bfs_stat() call for tests that flip the follow flag, like -xtype.
*/
static const struct bfs_stat *eval_xstat(struct eval_state *state) {
@@ -235,7 +262,7 @@ bool eval_capable(const struct expr *expr, struct eval_state *state) {
/**
* Get the given timespec field out of a stat buffer.
*/
-static const struct timespec *eval_stat_time(const struct bfs_stat *statbuf, enum bfs_stat_field field, const struct eval_state *state) {
+static const struct timespec *eval_stat_time(const struct bfs_stat *statbuf, enum bfs_stat_field field, struct eval_state *state) {
const struct timespec *ret = bfs_stat_time(statbuf, field);
if (!ret) {
eval_error(state, "Couldn't get file %s: %m.\n", bfs_stat_field_name(field));