]> Sergey Matveev's repositories - bfs.git/blob - src/diag.c
Formatting fixes
[bfs.git] / src / diag.c
1 // Copyright © Tavian Barnes <tavianator@tavianator.com>
2 // SPDX-License-Identifier: 0BSD
3
4 #include "diag.h"
5 #include "alloc.h"
6 #include "bfstd.h"
7 #include "color.h"
8 #include "config.h"
9 #include "ctx.h"
10 #include "dstring.h"
11 #include "expr.h"
12 #include <errno.h>
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 noreturn void bfs_abortf(const struct bfs_loc *loc, const char *format, ...) {
18         fprintf(stderr, "%s: %s@%s:%d: ", xgetprogname(), loc->func, loc->file, loc->line);
19
20         va_list args;
21         va_start(args, format);
22         vfprintf(stderr, format, args);
23         va_end(args);
24
25         fprintf(stderr, "\n");
26
27         abort();
28 }
29
30 void bfs_perror(const struct bfs_ctx *ctx, const char *str) {
31         bfs_error(ctx, "%s: %m.\n", str);
32 }
33
34 void bfs_error(const struct bfs_ctx *ctx, const char *format, ...) {
35         va_list args;
36         va_start(args, format);
37         bfs_verror(ctx, format, args);
38         va_end(args);
39 }
40
41 bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...) {
42         va_list args;
43         va_start(args, format);
44         bool ret = bfs_vwarning(ctx, format, args);
45         va_end(args);
46         return ret;
47 }
48
49 bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...) {
50         va_list args;
51         va_start(args, format);
52         bool ret = bfs_vdebug(ctx, flag, format, args);
53         va_end(args);
54         return ret;
55 }
56
57 void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args) {
58         int error = errno;
59
60         bfs_error_prefix(ctx);
61
62         errno = error;
63         cvfprintf(ctx->cerr, format, args);
64 }
65
66 bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args) {
67         int error = errno;
68
69         if (bfs_warning_prefix(ctx)) {
70                 errno = error;
71                 cvfprintf(ctx->cerr, format, args);
72                 return true;
73         } else {
74                 return false;
75         }
76 }
77
78 bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args) {
79         int error = errno;
80
81         if (bfs_debug_prefix(ctx, flag)) {
82                 errno = error;
83                 cvfprintf(ctx->cerr, format, args);
84                 return true;
85         } else {
86                 return false;
87         }
88 }
89
90 /** Get the command name without any leading directories. */
91 static const char *bfs_cmd(const struct bfs_ctx *ctx) {
92         return ctx->argv[0] + xbaseoff(ctx->argv[0]);
93 }
94
95 void bfs_error_prefix(const struct bfs_ctx *ctx) {
96         cfprintf(ctx->cerr, "${bld}%s:${rs} ${err}error:${rs} ", bfs_cmd(ctx));
97 }
98
99 bool bfs_warning_prefix(const struct bfs_ctx *ctx) {
100         if (ctx->warn) {
101                 cfprintf(ctx->cerr, "${bld}%s:${rs} ${wrn}warning:${rs} ", bfs_cmd(ctx));
102                 return true;
103         } else {
104                 return false;
105         }
106 }
107
108 bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag) {
109         if (ctx->debug & flag) {
110                 cfprintf(ctx->cerr, "${bld}%s:${rs} ${cyn}-D %s${rs}: ", bfs_cmd(ctx), debug_flag_name(flag));
111                 return true;
112         } else {
113                 return false;
114         }
115 }
116
117 /** Recursive part of highlight_expr(). */
118 static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool args[]) {
119         if (!expr) {
120                 return false;
121         }
122
123         bool ret = false;
124
125         for (size_t i = 0; i < ctx->argc; ++i) {
126                 if (&ctx->argv[i] == expr->argv) {
127                         for (size_t j = 0; j < expr->argc; ++j) {
128                                 bfs_assert(i + j < ctx->argc);
129                                 args[i + j] = true;
130                                 ret = true;
131                         }
132                         break;
133                 }
134         }
135
136         if (bfs_expr_is_parent(expr)) {
137                 ret |= highlight_expr_recursive(ctx, expr->lhs, args);
138                 ret |= highlight_expr_recursive(ctx, expr->rhs, args);
139         }
140
141         return ret;
142 }
143
144 /** Highlight an expression in the command line. */
145 static bool highlight_expr(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool args[]) {
146         for (size_t i = 0; i < ctx->argc; ++i) {
147                 args[i] = false;
148         }
149
150         return highlight_expr_recursive(ctx, expr, args);
151 }
152
153 /** Print a highlighted portion of the command line. */
154 static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool args[], bool warning) {
155         if (warning) {
156                 bfs_warning_prefix(ctx);
157         } else {
158                 bfs_error_prefix(ctx);
159         }
160
161         dchar **argv = ZALLOC_ARRAY(dchar *, ctx->argc);
162         if (!argv) {
163                 return;
164         }
165
166         for (size_t i = 0; i < ctx->argc; ++i) {
167                 if (dstrescat(&argv[i], ctx->argv[i], WESC_SHELL | WESC_TTY) != 0) {
168                         goto done;
169                 }
170         }
171
172         size_t max_argc = 0;
173         for (size_t i = 0; i < ctx->argc; ++i) {
174                 if (i > 0) {
175                         cfprintf(ctx->cerr, " ");
176                 }
177
178                 if (args[i]) {
179                         max_argc = i + 1;
180                         cfprintf(ctx->cerr, "${bld}%s${rs}", argv[i]);
181                 } else {
182                         cfprintf(ctx->cerr, "%s", argv[i]);
183                 }
184         }
185
186         cfprintf(ctx->cerr, "\n");
187
188         if (warning) {
189                 bfs_warning_prefix(ctx);
190         } else {
191                 bfs_error_prefix(ctx);
192         }
193
194         for (size_t i = 0; i < max_argc; ++i) {
195                 if (i > 0) {
196                         if (args[i - 1] && args[i]) {
197                                 cfprintf(ctx->cerr, "~");
198                         } else {
199                                 cfprintf(ctx->cerr, " ");
200                         }
201                 }
202
203                 if (args[i] && (i == 0 || !args[i - 1])) {
204                         if (warning) {
205                                 cfprintf(ctx->cerr, "${wrn}");
206                         } else {
207                                 cfprintf(ctx->cerr, "${err}");
208                         }
209                 }
210
211                 size_t len = xstrwidth(argv[i]);
212                 for (size_t j = 0; j < len; ++j) {
213                         if (args[i]) {
214                                 cfprintf(ctx->cerr, "~");
215                         } else {
216                                 cfprintf(ctx->cerr, " ");
217                         }
218                 }
219
220                 if (args[i] && (i + 1 >= max_argc || !args[i + 1])) {
221                         cfprintf(ctx->cerr, "${rs}");
222                 }
223         }
224
225         cfprintf(ctx->cerr, "\n");
226
227 done:
228         for (size_t i = 0; i < ctx->argc; ++i) {
229                 dstrfree(argv[i]);
230         }
231         free(argv);
232 }
233
234 void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]) {
235         bfs_argv_diag(ctx, args, false);
236 }
237
238 void bfs_expr_error(const struct bfs_ctx *ctx, const struct bfs_expr *expr) {
239         bool args[ctx->argc];
240         if (highlight_expr(ctx, expr, args)) {
241                 bfs_argv_error(ctx, args);
242         }
243 }
244
245 bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]) {
246         if (!ctx->warn) {
247                 return false;
248         }
249
250         bfs_argv_diag(ctx, args, true);
251         return true;
252 }
253
254 bool bfs_expr_warning(const struct bfs_ctx *ctx, const struct bfs_expr *expr) {
255         bool args[ctx->argc];
256         if (highlight_expr(ctx, expr, args)) {
257                 return bfs_argv_warning(ctx, args);
258         }
259
260         return false;
261 }