diff options
Diffstat (limited to 'src/diag.h')
-rw-r--r-- | src/diag.h | 135 |
1 files changed, 73 insertions, 62 deletions
@@ -8,82 +8,74 @@ #ifndef BFS_DIAG_H #define BFS_DIAG_H -#include "prelude.h" +#include "bfs.h" #include "bfstd.h" -#include <stdarg.h> -/** - * static_assert() with an optional second argument. - */ -#if __STDC_VERSION__ >= C23 -# define bfs_static_assert static_assert -#else -# define bfs_static_assert(...) bfs_static_assert_(__VA_ARGS__, #__VA_ARGS__, ) -# define bfs_static_assert_(expr, msg, ...) _Static_assert(expr, msg) -#endif +#include <stdarg.h> /** - * A source code location. + * Wrap a diagnostic format string so it looks like + * + * bfs: func@src/file.c:0: Message */ -struct bfs_loc { - const char *file; - int line; - const char *func; -}; - -#define BFS_LOC_INIT { .file = __FILE__, .line = __LINE__, .func = __func__ } +#define BFS_DIAG_FORMAT_(format) \ + ((format) ? "%s: %s@%s:%d: " format "%s" : "") /** - * Get the current source code location. + * Add arguments to match a BFS_DIAG_FORMAT string. */ -#if __STDC_VERSION__ >= C23 -# define bfs_location() (&(static const struct bfs_loc)BFS_LOC_INIT) -#else -# define bfs_location() (&(const struct bfs_loc)BFS_LOC_INIT) -#endif +#define BFS_DIAG_ARGS_(...) \ + xgetprogname(), __func__, __FILE__, __LINE__, __VA_ARGS__ "\n" /** - * Print a low-level diagnostic message to standard error, formatted like - * - * bfs: func@src/file.c:0: Message + * Print a low-level diagnostic message to standard error. */ -attr(printf(2, 3)) -void bfs_diagf(const struct bfs_loc *loc, const char *format, ...); +_printf(1, 2) +void bfs_diagf(const char *format, ...); /** * Unconditional diagnostic message. */ -#define bfs_diag(...) bfs_diagf(bfs_location(), __VA_ARGS__) +#define bfs_diag(...) \ + bfs_diag_(__VA_ARGS__, ) + +#define bfs_diag_(format, ...) \ + bfs_diagf(BFS_DIAG_FORMAT_(format), BFS_DIAG_ARGS_(__VA_ARGS__)) /** * Print a diagnostic message including the last error. */ #define bfs_ediag(...) \ - bfs_ediag_("" __VA_ARGS__, errstr()) + bfs_ediag_(__VA_ARGS__, ) #define bfs_ediag_(format, ...) \ - bfs_diag(sizeof(format) > 1 ? format ": %s" : "%s", __VA_ARGS__) + bfs_diag_(format "%s%s", __VA_ARGS__ (sizeof("" format) > 1 ? ": " : ""), errstr(), ) /** * Print a message to standard error and abort. */ -attr(cold, printf(2, 3)) -noreturn void bfs_abortf(const struct bfs_loc *loc, const char *format, ...); +_cold +_printf(1, 2) +_noreturn +void bfs_abortf(const char *format, ...); /** * Unconditional abort with a message. */ #define bfs_abort(...) \ - bfs_abortf(bfs_location(), __VA_ARGS__) + bfs_abort_(__VA_ARGS__, ) + +#define bfs_abort_(format, ...) \ + bfs_abortf(BFS_DIAG_FORMAT_(format), BFS_DIAG_ARGS_(__VA_ARGS__)) /** * Abort with a message including the last error. */ #define bfs_eabort(...) \ - bfs_eabort_("" __VA_ARGS__, errstr()) + bfs_eabort_(__VA_ARGS__, ) #define bfs_eabort_(format, ...) \ - bfs_abort(sizeof(format) > 1 ? format ": %s" : "%s", __VA_ARGS__) + ((format) ? bfs_abort_(format ": %s", __VA_ARGS__ errstr(), ) : (void)0) /** * Abort in debug builds; no-op in release builds. @@ -97,30 +89,43 @@ noreturn void bfs_abortf(const struct bfs_loc *loc, const char *format, ...); #endif /** + * Get the default assertion message, if no format string was specified. + */ +#define BFS_DIAG_MSG_(format, str) \ + (sizeof(format) > 1 ? "" : str) + +/** * Unconditional assert. */ #define bfs_verify(...) \ - bfs_verify_(#__VA_ARGS__, __VA_ARGS__, "", "") + bfs_verify_(#__VA_ARGS__, __VA_ARGS__, "", ) #define bfs_verify_(str, cond, format, ...) \ - ((cond) ? (void)0 : bfs_abort( \ + ((cond) ? (void)0 : bfs_verify__(format, BFS_DIAG_MSG_(format, str), __VA_ARGS__)) + +#define bfs_verify__(format, ...) \ + bfs_abortf( \ sizeof(format) > 1 \ - ? "%.0s" format "%s%s" \ - : "Assertion failed: `%s`%s", \ - str, __VA_ARGS__)) + ? BFS_DIAG_FORMAT_("%s" format "%s") \ + : BFS_DIAG_FORMAT_("Assertion failed: `%s`"), \ + BFS_DIAG_ARGS_(__VA_ARGS__)) /** * Unconditional assert, including the last error. */ #define bfs_everify(...) \ - bfs_everify_(#__VA_ARGS__, __VA_ARGS__, "", errstr()) + bfs_everify_(#__VA_ARGS__, __VA_ARGS__, "", ) + #define bfs_everify_(str, cond, format, ...) \ - ((cond) ? (void)0 : bfs_abort( \ + ((cond) ? (void)0 : bfs_everify__(format, BFS_DIAG_MSG_(format, str), __VA_ARGS__)) + +#define bfs_everify__(format, ...) \ + bfs_abortf( \ sizeof(format) > 1 \ - ? "%.0s" format "%s: %s" \ - : "Assertion failed: `%s`: %s", \ - str, __VA_ARGS__)) + ? BFS_DIAG_FORMAT_("%s" format "%s: %s") \ + : BFS_DIAG_FORMAT_("Assertion failed: `%s`: %s"), \ + BFS_DIAG_ARGS_(__VA_ARGS__ errstr(), )) /** * Assert in debug builds; no-op in release builds. @@ -166,13 +171,14 @@ const char *debug_flag_name(enum debug_flags flag); /** * Like perror(), but decorated like bfs_error(). */ -attr(cold) +_cold void bfs_perror(const struct bfs_ctx *ctx, const char *str); /** * Shorthand for printing error messages. */ -attr(cold, printf(2, 3)) +_cold +_printf(2, 3) void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -180,7 +186,8 @@ void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a warning was printed. */ -attr(cold, printf(2, 3)) +_cold +_printf(2, 3) bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -188,67 +195,71 @@ bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a debug message was printed. */ -attr(cold, printf(3, 4)) +_cold +_printf(3, 4) bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...); /** * bfs_error() variant that takes a va_list. */ -attr(cold, printf(2, 0)) +_cold +_printf(2, 0) void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_warning() variant that takes a va_list. */ -attr(cold, printf(2, 0)) +_cold +_printf(2, 0) bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_debug() variant that takes a va_list. */ -attr(cold, printf(3, 0)) +_cold +_printf(3, 0) bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args); /** * Print the error message prefix. */ -attr(cold) +_cold void bfs_error_prefix(const struct bfs_ctx *ctx); /** * Print the warning message prefix. */ -attr(cold) +_cold bool bfs_warning_prefix(const struct bfs_ctx *ctx); /** * Print the debug message prefix. */ -attr(cold) +_cold bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag); /** * Highlight parts of the command line in an error message. */ -attr(cold) +_cold void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in an error message. */ -attr(cold) +_cold void bfs_expr_error(const struct bfs_ctx *ctx, const struct bfs_expr *expr); /** * Highlight parts of the command line in a warning message. */ -attr(cold) +_cold bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in a warning message. */ -attr(cold) +_cold bool bfs_expr_warning(const struct bfs_ctx *ctx, const struct bfs_expr *expr); #endif // BFS_DIAG_H |