diff options
author | Leah Rowe <leah@libreboot.org> | 2025-10-04 09:14:33 +0100 |
---|---|---|
committer | Leah Rowe <leah@libreboot.org> | 2025-10-04 09:20:12 +0100 |
commit | e9a910b33c7837b4b868e3abda18eb4810df7f02 (patch) | |
tree | 749e1830cb0607952df1a1afc0ae09ec1db54140 /util/sbase/grep.c | |
parent | 2cfaba181b3c68761871fa47b32725c934423c14 (diff) |
config/git: import suckless sbase
i currently use the output of sha512sum in several
places of xbmk, which is a bit unreliable in case
output changes.
other cases where i use util outputs in variables
are probably reliable, because i'm using mostly
posix utilities in those.
to mitigate this, i now import suckless sbase, which
has a reasonable sha512sum implementation.
*every* binary it builds is being placed in build.list,
because i'll probably start using more of them.
for example, i may start modifying the "date"
implementation, adding the GNU-specific options that
i need as mentioned on init.sh
i'm importing it in util/ because the sha512sum
util is needed for verifying project sources, so
if sbase itself is a "project source", that means
we can into a chicken and egg bootstrapping problem.
this is sbase at revision:
055cc1ae1b3a13c3d8f25af0a4a3316590efcd48
Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util/sbase/grep.c')
-rw-r--r-- | util/sbase/grep.c | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/util/sbase/grep.c b/util/sbase/grep.c new file mode 100644 index 00000000..1c978070 --- /dev/null +++ b/util/sbase/grep.c @@ -0,0 +1,290 @@ +/* See LICENSE file for copyright and license details. */ +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include "queue.h" +#include "util.h" + +enum { Match = 0, NoMatch = 1, Error = 2 }; + +static void addpattern(const char *, size_t); +static void addpatternfile(FILE *); +static int grep(FILE *, const char *); + +static int Eflag; +static int Fflag; +static int Hflag; +static int eflag; +static int fflag; +static int hflag; +static int iflag; +static int sflag; +static int vflag; +static int wflag; +static int xflag; +static int many; +static int mode; + +struct pattern { + char *pattern; + regex_t preg; + SLIST_ENTRY(pattern) entry; +}; + +static SLIST_HEAD(phead, pattern) phead; + +static void +addpattern(const char *pattern, size_t patlen) +{ + struct pattern *pnode; + char *tmp; + int bol, eol; + size_t len; + + if (!patlen) + return; + + /* a null BRE/ERE matches every line */ + if (!Fflag) + if (pattern[0] == '\0') + pattern = "^"; + + if (!Fflag && xflag) { + tmp = enmalloc(Error, patlen + 3); + snprintf(tmp, patlen + 3, "%s%s%s", + pattern[0] == '^' ? "" : "^", + pattern, + pattern[patlen - 1] == '$' ? "" : "$"); + } else if (!Fflag && wflag) { + len = patlen + 5 + (Eflag ? 2 : 4); + tmp = enmalloc(Error, len); + + bol = eol = 0; + if (pattern[0] == '^') + bol = 1; + if (pattern[patlen - 1] == '$') + eol = 1; + + snprintf(tmp, len, "%s\\<%s%.*s%s\\>%s", + bol ? "^" : "", + Eflag ? "(" : "\\(", + (int)patlen - bol - eol, pattern + bol, + Eflag ? ")" : "\\)", + eol ? "$" : ""); + } else { + tmp = enstrdup(Error, pattern); + } + + pnode = enmalloc(Error, sizeof(*pnode)); + pnode->pattern = tmp; + SLIST_INSERT_HEAD(&phead, pnode, entry); +} + +static void +addpatternfile(FILE *fp) +{ + static char *buf = NULL; + static size_t size = 0; + ssize_t len = 0; + + while ((len = getline(&buf, &size, fp)) > 0) { + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + addpattern(buf, (size_t)len); + } + if (ferror(fp)) + enprintf(Error, "read error:"); +} + +static int +grep(FILE *fp, const char *str) +{ + static char *buf = NULL; + static size_t size = 0; + ssize_t len = 0; + long c = 0, n; + struct pattern *pnode; + int match, result = NoMatch; + + for (n = 1; (len = getline(&buf, &size, fp)) > 0; n++) { + /* Remove the trailing newline if one is present. */ + if (len && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + match = 0; + SLIST_FOREACH(pnode, &phead, entry) { + if (Fflag) { + if (xflag) { + if (!(iflag ? strcasecmp : strcmp)(buf, pnode->pattern)) { + match = 1; + break; + } + } else { + if ((iflag ? strcasestr : strstr)(buf, pnode->pattern)) { + match = 1; + break; + } + } + } else { + if (regexec(&pnode->preg, buf, 0, NULL, 0) == 0) { + match = 1; + break; + } + } + } + if (match != vflag) { + result = Match; + switch (mode) { + case 'c': + c++; + break; + case 'l': + puts(str); + goto end; + case 'q': + exit(Match); + default: + if (!hflag && (many || Hflag)) + printf("%s:", str); + if (mode == 'n') + printf("%ld:", n); + puts(buf); + break; + } + } + } + if (mode == 'c') + printf("%ld\n", c); +end: + if (ferror(fp)) { + weprintf("%s: read error:", str); + result = Error; + } + return result; +} + +static void +usage(void) +{ + enprintf(Error, "usage: %s [-EFHchilnqsvwx] [-e pattern] [-f file] " + "[pattern] [file ...]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + struct pattern *pnode; + int m, flags = REG_NOSUB, match = NoMatch; + FILE *fp; + char *arg; + + SLIST_INIT(&phead); + + ARGBEGIN { + case 'E': + Eflag = 1; + Fflag = 0; + flags |= REG_EXTENDED; + break; + case 'F': + Fflag = 1; + Eflag = 0; + flags &= ~REG_EXTENDED; + break; + case 'H': + Hflag = 1; + hflag = 0; + break; + case 'e': + arg = EARGF(usage()); + if (!(fp = fmemopen(arg, strlen(arg) + 1, "r"))) + eprintf("fmemopen:"); + addpatternfile(fp); + efshut(fp, arg); + eflag = 1; + break; + case 'f': + arg = EARGF(usage()); + fp = fopen(arg, "r"); + if (!fp) + enprintf(Error, "fopen %s:", arg); + addpatternfile(fp); + efshut(fp, arg); + fflag = 1; + break; + case 'h': + hflag = 1; + Hflag = 0; + break; + case 'c': + case 'l': + case 'n': + case 'q': + mode = ARGC(); + break; + case 'i': + flags |= REG_ICASE; + iflag = 1; + break; + case 's': + sflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'w': + wflag = 1; + break; + case 'x': + xflag = 1; + break; + default: + usage(); + } ARGEND + + if (argc == 0 && !eflag && !fflag) + usage(); /* no pattern */ + + /* just add literal pattern to list */ + if (!eflag && !fflag) { + if (!(fp = fmemopen(argv[0], strlen(argv[0]) + 1, "r"))) + eprintf("fmemopen:"); + addpatternfile(fp); + efshut(fp, argv[0]); + argc--; + argv++; + } + + if (!Fflag) + /* Compile regex for all search patterns */ + SLIST_FOREACH(pnode, &phead, entry) + enregcomp(Error, &pnode->preg, pnode->pattern, flags); + many = (argc > 1); + if (argc == 0) { + match = grep(stdin, "<stdin>"); + } else { + for (; *argv; argc--, argv++) { + if (!strcmp(*argv, "-")) { + *argv = "<stdin>"; + fp = stdin; + } else if (!(fp = fopen(*argv, "r"))) { + if (!sflag) + weprintf("fopen %s:", *argv); + match = Error; + continue; + } + m = grep(fp, *argv); + if (m == Error || (match != Error && m == Match)) + match = m; + if (fp != stdin && fshut(fp, *argv)) + match = Error; + } + } + + if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>")) + match = Error; + + return match; +} |