diff --git a/bp.c b/bp.c index 02345f1..3195885 100644 --- a/bp.c +++ b/bp.c @@ -342,8 +342,8 @@ __attribute__((nonnull(2))) static int process_git_files(def_t *defs, pat_t *pattern, int argc, char *argv[]) { int fds[2]; - check_nonnegative(pipe(fds), "Failed to create pipe"); - pid_t child = check_nonnegative(fork(), "Failed to fork"); + require(pipe(fds), "Failed to create pipe"); + pid_t child = require(fork(), "Failed to fork"); if (child == 0) { const char **git_args = new(char*[3+argc+1]); int g = 0; @@ -351,20 +351,20 @@ static int process_git_files(def_t *defs, pat_t *pattern, int argc, char *argv[] git_args[g++] = "ls-files"; git_args[g++] = "-z"; while (*argv) git_args[g++] = *(argv++); - check_nonnegative(dup2(fds[STDOUT_FILENO], STDOUT_FILENO), "Failed to hook up pipe to stdout"); - check_nonnegative(close(fds[STDIN_FILENO]), "Failed to close read end of pipe"); + require(dup2(fds[STDOUT_FILENO], STDOUT_FILENO), "Failed to hook up pipe to stdout"); + require(close(fds[STDIN_FILENO]), "Failed to close read end of pipe"); (void)execvp("git", (char**)git_args); _exit(EXIT_FAILURE); } - check_nonnegative(close(fds[STDOUT_FILENO]), "Failed to close write end of pipe"); - FILE *fp = check_nonnull(fdopen(fds[STDIN_FILENO], "r"), "Could not open pipe file descriptor"); + require(close(fds[STDOUT_FILENO]), "Failed to close write end of pipe"); + FILE *fp = require(fdopen(fds[STDIN_FILENO], "r"), "Could not open pipe file descriptor"); char *path = NULL; size_t path_size = 0; int found = 0; while (getdelim(&path, &path_size, '\0', fp) > 0) found += process_file(defs, path, pattern); if (path) delete(&path); - check_nonnegative(fclose(fp), "Failed to close read end of pipe"); + require(fclose(fp), "Failed to close read end of pipe"); int status; while (waitpid(child, &status, 0) != child) continue; if (!((WIFEXITED(status) == 1) && (WEXITSTATUS(status) == 0))) @@ -450,7 +450,7 @@ int main(int argc, char *argv[]) if (after_spaces(p->end, true) < arg_file->end) file_err(arg_file, p->end, arg_file->end, "Failed to compile this part of the argument"); pattern = chain_together(arg_file, pattern, p); } else if (FLAG("-w") || FLAG("--word")) { - check_nonnegative(asprintf(&flag, "\\|%s\\|", flag), "Could not allocate memory"); + require(asprintf(&flag, "\\|%s\\|", flag), "Could not allocate memory"); file_t *arg_file = spoof_file(&loaded_files, "", flag, -1); delete(&flag); pat_t *p = bp_stringpattern(arg_file, arg_file->start); @@ -505,10 +505,10 @@ int main(int argc, char *argv[]) int signals[] = {SIGTERM, SIGINT, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGSEGV, SIGTSTP}; struct sigaction sa = {.sa_handler = &sig_handler, .sa_flags = (int)(SA_NODEFER | SA_RESETHAND)}; for (size_t i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) - check_nonnegative(sigaction(signals[i], &sa, NULL), "Failed to set signal handler"); + require(sigaction(signals[i], &sa, NULL), "Failed to set signal handler"); // Handle exit() calls gracefully: - check_nonnegative(atexit(&cleanup), "Failed to set cleanup handler at exit"); + require(atexit(&cleanup), "Failed to set cleanup handler at exit"); // No need for these caches anymore: for (file_t *f = loaded_files; f; f = f->next) diff --git a/files.c b/files.c index 969cc2d..79d2a03 100644 --- a/files.c +++ b/files.c @@ -116,7 +116,7 @@ file_t *load_file(file_t **files, const char *filename) finished_loading: if (fd != STDIN_FILENO) - check_nonnegative(close(fd), "Failed to close file"); + require(close(fd), "Failed to close file"); populate_lines(f); if (files != NULL) { @@ -177,7 +177,7 @@ void destroy_file(file_t **at_f) delete(&f->allocated); if (f->mmapped) { - check_nonnegative(munmap(f->mmapped, (size_t)(f->end - f->mmapped)), + require(munmap(f->mmapped, (size_t)(f->end - f->mmapped)), "Failure to un-memory-map some memory"); f->mmapped = NULL; } diff --git a/utils.c b/utils.c index 5ecbcf1..cb0719c 100644 --- a/utils.c +++ b/utils.c @@ -128,36 +128,6 @@ char unescapechar(const char *escaped, const char **end) return (char)ret; } -// -// If the given argument is NULL, print the error message and exit with -// failure. Otherwise return the given argument. -// -void *check_nonnull(void *p, const char *err_msg, ...) -{ - if (p == NULL) { - va_list args; - va_start(args, err_msg); - verr(EXIT_FAILURE, err_msg, args); - va_end(args); - } - return p; -} - -// -// If the given argument is negative, print the error message and exit with -// failure. Otherwise return the given argument. -// -int check_nonnegative(int i, const char *err_msg, ...) -{ - if (i < 0) { - va_list args; - va_start(args, err_msg); - verr(EXIT_FAILURE, err_msg, args); - va_end(args); - } - return i; -} - // // Case-insensitive memory comparison // diff --git a/utils.h b/utils.h index b645817..04df47a 100644 --- a/utils.h +++ b/utils.h @@ -4,6 +4,8 @@ #ifndef UTILS__H #define UTILS__H +#include +#include #include #include #include @@ -16,10 +18,34 @@ #define S2(x) S1(x) #define __LOCATION__ __FILE__ ":" S2(__LINE__) +#define DEFINE_CHECK_TYPE(t, name, var, expr) \ +static inline t _check_##name(t var, const char *fmt, ...) { \ + if (!(expr)) {\ + va_list args;\ + va_start(args, fmt);\ + verrx(1, fmt, args);\ + va_end(args);\ + }\ + return var;\ +} +DEFINE_CHECK_TYPE(void*, ptr, p, p); +DEFINE_CHECK_TYPE(int, int, i, i >= 0); +DEFINE_CHECK_TYPE(ssize_t, ssize_t, i, i >= 0); +DEFINE_CHECK_TYPE(char, char, c, c); +DEFINE_CHECK_TYPE(_Bool, bool, b, b); + +#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,N,...) N +#define PP_NARG(...) PP_ARG_N(__VA_ARGS__,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0) + +#define _require_fmt(e, ...) _Generic((e), _Bool: _check_bool, int: _check_int, ssize_t: _check_ssize_t, char: _check_char, void*: _check_ptr, default: _check_ptr)((e), ""__VA_ARGS__) +#define require(e, ...) (PP_NARG(e,##__VA_ARGS__) > 1 ? _require_fmt((e), __LOCATION__": "__VA_ARGS__) : _require_fmt((e), __LOCATION__": `%s` failed", #e)) +#define require_true(e, ...) (PP_NARG(e,##__VA_ARGS__) > 1 ? _require_fmt((_Bool)(e), __LOCATION__": "__VA_ARGS__) : _require_fmt((_Bool)(e), __LOCATION__": `%s` is not true", #e)) + +#define new(t) _check_ptr(calloc(1, sizeof(t)), "`new(" #t ")` allocation failure") +#define checked_strdup(s) _check_ptr(strdup(s), "`checked_strdup(" #s ")` allocation failure") +#define grow(arr,n) _check_ptr(realloc(arr,sizeof(arr[0])*(n)), "`grow(" #arr ", " #n ")` allocation failure") + #define streq(a, b) (strcmp(a, b) == 0) -#define new(t) check_nonnull(calloc(1, sizeof(t)), __LOCATION__ ": `new(" #t ")` allocation failure") -#define checked_strdup(s) check_nonnull(strdup(s), __LOCATION__ ": `checked_strdup(" #s ")` allocation failure") -#define grow(arr,n) check_nonnull(realloc(arr,sizeof(arr[0])*(n)), __LOCATION__ ": `groaw(" #arr ", " #n ")` allocation failure") __attribute__((nonnull(1))) char unescapechar(const char *escaped, const char **end); @@ -31,9 +57,6 @@ __attribute__((nonnull)) bool matchchar(const char **str, char c, bool skip_nl); __attribute__((nonnull)) bool matchstr(const char **str, const char *target, bool skip_nl); -__attribute__((returns_nonnull)) -void *check_nonnull(void *p, const char *err_msg, ...); -int check_nonnegative(int i, const char *err_msg, ...); __attribute__((nonnull)) int memicmp(const void *s1, const void *s2, size_t n); __attribute__((nonnull))