Removed check() and replaced with err()/errx()

This commit is contained in:
Bruce Hill 2021-01-26 17:54:23 -08:00
parent d9cca805a0
commit de0fec8fcb
7 changed files with 80 additions and 51 deletions

82
bp.c
View File

@ -4,6 +4,7 @@
// See `man ./bp.1` for more details
//
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
@ -96,12 +97,14 @@ __attribute__((nonnull))
static char *getflag(const char *flag, char *argv[], int *i)
{
size_t n = strlen(flag);
check(argv[*i], "Attempt to get flag from NULL argument");
if (!argv[*i])
errx(EXIT_FAILURE, "Attempt to get flag from NULL argument");
if (strncmp(argv[*i], flag, n) == 0) {
if (argv[*i][n] == '=') {
return &argv[*i][n+1];
} else if (argv[*i][n] == '\0') {
check(argv[*i+1], "Expected argument after '%s'\n\n%s", flag, usage);
if (!argv[*i+1])
errx(EXIT_FAILURE, "Expected argument after '%s'\n\n%s", flag, usage);
++(*i);
return argv[*i];
}
@ -116,7 +119,8 @@ static char *getflag(const char *flag, char *argv[], int *i)
__attribute__((nonnull))
static int boolflag(const char *flag, char *argv[], int *i)
{
check(argv[*i], "Attempt to get flag from NULL argument");
if (!argv[*i])
errx(EXIT_FAILURE, "Attempt to get flag from NULL argument");
if (streq(argv[*i], flag)) return 1;
if (flag[0] == '-' && flag[1] != '-' && flag[2] == '\0' && argv[*i][0] == '-' && argv[*i][1] != '-') {
char *p = strchr(argv[*i], flag[1]);
@ -287,10 +291,11 @@ static int inplace_modify_file(def_t *defs, file_t *f, pat_t *pattern)
exit(EXIT_FAILURE);
// Lazy-open file for writing upon first match:
if (inplace_file == NULL) {
check(snprintf(tmp_filename, PATH_MAX, "%s.tmp.XXXXXX", f->filename) <= (int)PATH_MAX,
"Failed to build temporary file template");
if (snprintf(tmp_filename, PATH_MAX, "%s.tmp.XXXXXX", f->filename) > (int)PATH_MAX)
errx(EXIT_FAILURE, "Failed to build temporary file template");
int out_fd = mkstemp(tmp_filename);
check(out_fd >= 0, "Failed to create temporary inplace file");
if (out_fd < 0)
err(EXIT_FAILURE, "Failed to create temporary inplace file");
in_use_tempfile = tmp_filename;
inplace_file = fdopen(out_fd, "w");
if (confirm == CONFIRM_ASK && f->filename)
@ -309,8 +314,8 @@ static int inplace_modify_file(def_t *defs, file_t *f, pat_t *pattern)
// TODO: if I want to implement backup files then add a line like this:
// if (backup) rename(f->filename, f->filename + ".bak");
check(rename(tmp_filename, f->filename) == 0,
"Failed to write file replacement for %s", f->filename);
if (rename(tmp_filename, f->filename) != 0)
err(EXIT_FAILURE, "Failed to write file replacement for %s", f->filename);
in_use_tempfile = NULL;
}
@ -386,7 +391,8 @@ static int process_file(def_t *defs, const char *filename, pat_t *pattern)
}
#ifdef DEBUG_HEAP
check(recycle_all_matches() == 0, "Memory leak: there should no longer be any matches in use at this point.");
if (recycle_all_matches() != 0)
errx("Memory leak: there should no longer be any matches in use at this point.");
#endif
destroy_file(&f);
(void)fflush(stdout);
@ -402,11 +408,11 @@ static int process_dir(def_t *defs, const char *dirname, pat_t *pattern)
int matches = 0;
glob_t globbuf;
char globpath[PATH_MAX+1] = {'\0'};
check(snprintf(globpath, PATH_MAX, "%s/*", dirname) <= (int)PATH_MAX,
"Filename is too long: %s/*", dirname);
if (snprintf(globpath, PATH_MAX, "%s/*", dirname) > (int)PATH_MAX)
errx(EXIT_FAILURE, "Filename is too long: %s/*", dirname);
int status = glob(globpath, 0, NULL, &globbuf);
check(status != GLOB_ABORTED && status != GLOB_NOSPACE,
"Failed to get directory contents: %s", dirname);
if (status == GLOB_ABORTED || status == GLOB_NOSPACE)
err(EXIT_FAILURE, "Failed to get directory contents: %s", dirname);
if (status != GLOB_NOMATCH) {
struct stat statbuf;
for (size_t i = 0; i < globbuf.gl_pathc; i++) {
@ -465,12 +471,14 @@ int main(int argc, char *argv[])
} else if (BOOLFLAG("-l") || BOOLFLAG("--list-files")) {
mode = MODE_LISTFILES;
} else if (FLAG("-r") || FLAG("--replace")) {
check(pattern, "No pattern has been defined for replacement to operate on");
if (!pattern)
errx(EXIT_FAILURE, "No pattern has been defined for replacement to operate on");
// TODO: spoof file as sprintf("pattern => '%s'", flag)
// except that would require handling edge cases like quotation marks etc.
file_t *replace_file = spoof_file(&loaded_files, "<replace argument>", flag);
pattern = bp_replacement(replace_file, pattern, replace_file->contents);
check(pattern, "Replacement failed to compile: %s", flag);
if (!pattern)
errx(EXIT_FAILURE, "Replacement failed to compile: %s", flag);
} else if (FLAG("-g") || FLAG("--grammar")) {
file_t *f = NULL;
if (strlen(flag) > 3 && strncmp(&flag[strlen(flag)-3], ".bp", 3) == 0)
@ -479,7 +487,8 @@ int main(int argc, char *argv[])
f = load_filef(&loaded_files, "%s/.config/"BP_NAME"/%s.bp", getenv("HOME"), flag);
if (f == NULL)
f = load_filef(&loaded_files, "/etc/xdg/"BP_NAME"/%s.bp", flag);
check(f != NULL, "Couldn't find grammar: %s", flag);
if (f == NULL)
errx(EXIT_FAILURE, "Couldn't find grammar: %s", flag);
defs = load_grammar(defs, f); // Keep in memory for debug output
} else if (FLAG("-p") || FLAG("--pattern")) {
file_t *arg_file = spoof_file(&loaded_files, "<pattern argument>", flag);
@ -524,7 +533,8 @@ int main(int argc, char *argv[])
if (pattern != NULL) break;
file_t *arg_file = spoof_file(&loaded_files, "<pattern argument>", argv[argi]);
pat_t *p = bp_stringpattern(arg_file, arg_file->contents);
check(p, "Pattern failed to compile: %s", argv[argi]);
if (!p)
errx(EXIT_FAILURE, "Pattern failed to compile: %s", argv[argi]);
pattern = chain_together(arg_file, pattern, p);
} else {
printf("Unrecognized flag: %s\n\n%s\n", argv[argi], usage);
@ -545,10 +555,12 @@ 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(sigaction(signals[i], &sa, NULL) == 0, "Failed to set signal handler");
if (sigaction(signals[i], &sa, NULL) != 0)
err(EXIT_FAILURE, "Failed to set signal handler");
// Handle exit() calls gracefully:
check(atexit(&cleanup) == 0, "Failed to set cleanup handler at exit");
if (atexit(&cleanup) != 0)
err(EXIT_FAILURE, "Failed to set cleanup handler at exit");
// User input/output is handled through /dev/tty so that normal unix pipes
// can work properly while simultaneously asking for user input.
@ -562,7 +574,8 @@ int main(int argc, char *argv[])
(void)fflush(tty_out);
char *patstr = NULL;
size_t len = 0;
check(getline(&patstr, &len, tty_in) > 0, "No pattern provided");
if (getline(&patstr, &len, tty_in) <= 0)
err(EXIT_FAILURE, "No pattern provided");
file_t *arg_file = spoof_file(&loaded_files, "<pattern argument>", patstr);
for (const char *str = arg_file->contents; str < arg_file->end; ) {
def_t *d = bp_definition(defs, arg_file, str);
@ -583,7 +596,8 @@ int main(int argc, char *argv[])
free(patstr);
}
check(pattern != NULL, "No pattern was given");
if (pattern == NULL)
errx(EXIT_FAILURE, "No pattern was given");
// To ensure recursion (and left recursion in particular) works properly,
// we need to define a rule called "pattern" with the value of whatever
@ -596,24 +610,29 @@ int main(int argc, char *argv[])
if (mode == MODE_JSON) printf("[");
if (git_mode) { // Get the list of files from `git --ls-files ...`
int fds[2];
check(pipe(fds) == 0, "Failed to create pipe");
if (pipe(fds) != 0)
err(EXIT_FAILURE, "Failed to create pipe");
pid_t child = fork();
check(child != -1, "Failed to fork");
if (child == -1)
err(EXIT_FAILURE, "Failed to fork");
if (child == 0) {
char **git_args = memcheck(calloc((size_t)(2+(argc-argi)+1), sizeof(char*)));
int g = 0;
git_args[g++] = "git";
git_args[g++] = "ls-files";
while (argi < argc) git_args[g++] = argv[argi++];
check(dup2(fds[STDOUT_FILENO], STDOUT_FILENO) == STDOUT_FILENO,
"Failed to hook up pipe to stdout");
check(close(fds[STDIN_FILENO]) == 0, "Failed to close read end of pipe");
if (dup2(fds[STDOUT_FILENO], STDOUT_FILENO) != STDOUT_FILENO)
err(EXIT_FAILURE, "Failed to hook up pipe to stdout");
if (close(fds[STDIN_FILENO]) != 0)
err(EXIT_FAILURE, "Failed to close read end of pipe");
(void)execvp("git", git_args);
_exit(EXIT_FAILURE);
}
check(close(fds[STDOUT_FILENO]) == 0, "Failed to close write end of pipe");
if (close(fds[STDOUT_FILENO]) != 0)
err(EXIT_FAILURE, "Failed to close write end of pipe");
FILE *fp = fdopen(fds[STDIN_FILENO], "r");
check(fp != NULL, "Could not open file descriptor");
if (fp == NULL)
err(EXIT_FAILURE, "Could not open file descriptor");
char *path = NULL;
size_t size = 0;
ssize_t len = 0;
@ -622,11 +641,12 @@ int main(int argc, char *argv[])
found += process_file(defs, path, pattern);
}
if (path) xfree(&path);
check(fclose(fp) == 0, "Failed to close read end of pipe");
if (fclose(fp) != 0)
err(EXIT_FAILURE, "Failed to close read end of pipe");
int status;
while (waitpid(child, &status, 0) != child) continue;
check((WIFEXITED(status) == 1) && (WEXITSTATUS(status) == 0),
"`git --ls-files` failed. Do you have git installed?");
if (!((WIFEXITED(status) == 1) && (WEXITSTATUS(status) == 0)))
errx(EXIT_FAILURE, "`git --ls-files` failed. Do you have git installed?");
} else if (argi < argc) {
// Files pass in as command line args:
struct stat statbuf;

View File

@ -2,6 +2,7 @@
// definitions.c - Code for defining named pattern rules
//
#include <err.h>
#include <stdlib.h>
#include <string.h>
@ -39,7 +40,8 @@ def_t *load_grammar(def_t *defs, file_t *f)
exit(EXIT_FAILURE);
}
size_t namelen = (size_t)(src - name);
check(matchchar(&src, ':'), "Expected ':' in definition");
if (!matchchar(&src, ':'))
errx(EXIT_FAILURE, "Expected ':' in definition");
pat_t *pat = bp_pattern(f, src);
if (pat == NULL) break;
defs = with_def(defs, namelen, name, pat);

14
files.c
View File

@ -3,6 +3,7 @@
//
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
@ -51,8 +52,8 @@ file_t *load_filef(file_t **files, const char *fmt, ...)
char filename[PATH_MAX+1] = {'\0'};
va_list args;
va_start(args, fmt);
check(vsnprintf(filename, PATH_MAX, fmt, args) <= (int)PATH_MAX,
"File name is too large");
if (vsnprintf(filename, PATH_MAX, fmt, args) > (int)PATH_MAX)
errx(EXIT_FAILURE, "File name is too large");
va_end(args);
return load_file(files, filename);
}
@ -93,7 +94,10 @@ file_t *load_file(file_t **files, const char *filename)
}
finished_loading:
if (fd != STDIN_FILENO) check(close(fd) == 0, "Failed to close file");
if (fd != STDIN_FILENO) {
if (close(fd) != 0)
err(EXIT_FAILURE, "Failed to close file");
}
f->end = &f->contents[length];
populate_lines(f);
if (files != NULL) {
@ -137,8 +141,8 @@ void destroy_file(file_t **f)
if ((*f)->contents) {
if ((*f)->mmapped) {
check(munmap((*f)->contents, (size_t)((*f)->end - (*f)->contents)) == 0,
"Failure to un-memory-map some memory");
if (munmap((*f)->contents, (size_t)((*f)->end - (*f)->contents)) != 0)
err(EXIT_FAILURE, "Failure to un-memory-map some memory");
(*f)->contents = NULL;
} else {
xfree(&((*f)->contents));

10
match.c
View File

@ -3,6 +3,7 @@
//
#include <ctype.h>
#include <err.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -313,7 +314,8 @@ static match_t *match(def_t *defs, file_t *f, const char *str, pat_t *pat, bool
}
case BP_AFTER: {
ssize_t backtrack = pat->args.pat->len;
check(backtrack != -1, "'<' is only allowed for fixed-length operations");
if (backtrack == -1)
errx(EXIT_FAILURE, "'<' is only allowed for fixed-length operations");
if (str - backtrack < f->contents) return NULL;
match_t *before = match(defs, f, str - backtrack, pat->args.pat, ignorecase);
if (before == NULL) return NULL;
@ -426,7 +428,8 @@ static match_t *match(def_t *defs, file_t *f, const char *str, pat_t *pat, bool
}
case BP_REF: {
def_t *def = lookup(defs, pat->args.name.len, pat->args.name.name);
check(def != NULL, "Unknown identifier: '%.*s'", (int)pat->args.name.len, pat->args.name.name);
if (def == NULL)
errx(EXIT_FAILURE, "Unknown identifier: '%.*s'", (int)pat->args.name.len, pat->args.name.name);
pat_t *ref = def->pat;
pat_t rec_op = {
@ -474,7 +477,8 @@ static match_t *match(def_t *defs, file_t *f, const char *str, pat_t *pat, bool
--m->refcount;
}
check(m, "Match should be non-null at this point");
if (!m)
errx(EXIT_FAILURE, "Match should be non-null at this point");
// This match wrapper mainly exists for record-keeping purposes and
// does not affect correctness. It also helps with visualization of
// match results.

View File

@ -3,6 +3,7 @@
//
#include <ctype.h>
#include <err.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@ -180,7 +181,8 @@ static pat_t *bp_simplepattern(file_t *f, const char *str)
pat_t *pat = _bp_simplepattern(f, str);
if (pat == NULL) return pat;
check(pat->end != NULL, "pat->end is uninitialized!");
if (pat->end == NULL)
errx(EXIT_FAILURE, "pat->end is uninitialized!");
// Expand postfix operators (if any)
str = after_spaces(pat->end);
@ -503,7 +505,8 @@ pat_t *bp_stringpattern(file_t *f, const char *str)
// etc.) or \\, then check for an interpolated value:
if (e != str[1] || e == '\\' || e == 'N') {
interp = bp_simplepattern(f, str);
check(interp, "Failed to match pattern %.*s", 2, str);
if (!interp)
errx(EXIT_FAILURE, "Failed to match pattern %.*s", 2, str);
break;
} else {
interp = bp_simplepattern(f, str + 1);

13
utils.c
View File

@ -3,6 +3,7 @@
//
#include <ctype.h>
#include <err.h>
#include <stdlib.h>
#include <unistd.h>
@ -123,10 +124,8 @@ char unescapechar(const char *escaped, const char **end)
//
void *memcheck(void *p)
{
if (p == NULL) {
fprintf(stderr, "memory allocation failure\n");
exit(EXIT_FAILURE);
}
if (p == NULL)
err(EXIT_FAILURE, "memory allocation failure");
return p;
}
@ -147,10 +146,8 @@ int memicmp(const void *v1, const void *v2, size_t n)
//
void xfree(void *p)
{
if (*(void**)p == NULL) {
fprintf(stderr, "Attempt to free(NULL)\n");
exit(EXIT_FAILURE);
}
if (*(void**)p == NULL)
errx(EXIT_FAILURE, "attempt to free(NULL)");
free(*(void**)p);
p = NULL;
}

View File

@ -13,7 +13,6 @@
#include "match.h"
#define streq(a, b) (strcmp(a, b) == 0)
#define check(cond, ...) do { if (!(cond)) { (void)fprintf(stderr, __VA_ARGS__); (void)fwrite("\n", 1, 1, stderr); exit(EXIT_FAILURE); } } while(false)
#define new(t) memcheck(calloc(1, sizeof(t)))
#define xcalloc(a,b) memcheck(calloc(a,b))
#define xrealloc(a,b) memcheck(realloc(a,b))