1 // Copyright © Tavian Barnes <tavianator@tavianator.com>
2 // SPDX-License-Identifier: 0BSD
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);
21 va_start(args, format);
22 vfprintf(stderr, format, args);
25 fprintf(stderr, "\n");
30 void bfs_perror(const struct bfs_ctx *ctx, const char *str) {
31 bfs_error(ctx, "%s: %m.\n", str);
34 void bfs_error(const struct bfs_ctx *ctx, const char *format, ...) {
36 va_start(args, format);
37 bfs_verror(ctx, format, args);
41 bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...) {
43 va_start(args, format);
44 bool ret = bfs_vwarning(ctx, format, args);
49 bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...) {
51 va_start(args, format);
52 bool ret = bfs_vdebug(ctx, flag, format, args);
57 void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args) {
60 bfs_error_prefix(ctx);
63 cvfprintf(ctx->cerr, format, args);
66 bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args) {
69 if (bfs_warning_prefix(ctx)) {
71 cvfprintf(ctx->cerr, format, args);
78 bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args) {
81 if (bfs_debug_prefix(ctx, flag)) {
83 cvfprintf(ctx->cerr, format, args);
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]);
95 void bfs_error_prefix(const struct bfs_ctx *ctx) {
96 cfprintf(ctx->cerr, "${bld}%s:${rs} ${err}error:${rs} ", bfs_cmd(ctx));
99 bool bfs_warning_prefix(const struct bfs_ctx *ctx) {
101 cfprintf(ctx->cerr, "${bld}%s:${rs} ${wrn}warning:${rs} ", bfs_cmd(ctx));
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));
117 /** Recursive part of highlight_expr(). */
118 static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool args[]) {
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);
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);
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) {
150 return highlight_expr_recursive(ctx, expr, args);
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) {
156 bfs_warning_prefix(ctx);
158 bfs_error_prefix(ctx);
161 dchar **argv = ZALLOC_ARRAY(dchar *, ctx->argc);
166 for (size_t i = 0; i < ctx->argc; ++i) {
167 if (dstrescat(&argv[i], ctx->argv[i], WESC_SHELL | WESC_TTY) != 0) {
173 for (size_t i = 0; i < ctx->argc; ++i) {
175 cfprintf(ctx->cerr, " ");
180 cfprintf(ctx->cerr, "${bld}%s${rs}", argv[i]);
182 cfprintf(ctx->cerr, "%s", argv[i]);
186 cfprintf(ctx->cerr, "\n");
189 bfs_warning_prefix(ctx);
191 bfs_error_prefix(ctx);
194 for (size_t i = 0; i < max_argc; ++i) {
196 if (args[i - 1] && args[i]) {
197 cfprintf(ctx->cerr, "~");
199 cfprintf(ctx->cerr, " ");
203 if (args[i] && (i == 0 || !args[i - 1])) {
205 cfprintf(ctx->cerr, "${wrn}");
207 cfprintf(ctx->cerr, "${err}");
211 size_t len = xstrwidth(argv[i]);
212 for (size_t j = 0; j < len; ++j) {
214 cfprintf(ctx->cerr, "~");
216 cfprintf(ctx->cerr, " ");
220 if (args[i] && (i + 1 >= max_argc || !args[i + 1])) {
221 cfprintf(ctx->cerr, "${rs}");
225 cfprintf(ctx->cerr, "\n");
228 for (size_t i = 0; i < ctx->argc; ++i) {
234 void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]) {
235 bfs_argv_diag(ctx, args, false);
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);
245 bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]) {
250 bfs_argv_diag(ctx, args, true);
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);