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/cut.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/cut.c')
-rw-r--r-- | util/sbase/cut.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/util/sbase/cut.c b/util/sbase/cut.c new file mode 100644 index 00000000..a50bdcb5 --- /dev/null +++ b/util/sbase/cut.c @@ -0,0 +1,215 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "text.h" +#include "utf.h" +#include "util.h" + +typedef struct Range { + size_t min, max; + struct Range *next; +} Range; + +static Range *list = NULL; +static char mode = 0; +static char *delim = "\t"; +static size_t delimlen = 1; +static int nflag = 0; +static int sflag = 0; + +static void +insert(Range *r) +{ + Range *l, *p, *t; + + for (p = NULL, l = list; l; p = l, l = l->next) { + if (r->max && r->max + 1 < l->min) { + r->next = l; + break; + } else if (!l->max || r->min < l->max + 2) { + l->min = MIN(r->min, l->min); + for (p = l, t = l->next; t; p = t, t = t->next) + if (r->max && r->max + 1 < t->min) + break; + l->max = (p->max && r->max) ? MAX(p->max, r->max) : 0; + l->next = t; + return; + } + } + if (p) + p->next = r; + else + list = r; +} + +static void +parselist(char *str) +{ + char *s; + size_t n = 1; + Range *r; + + if (!*str) + eprintf("empty list\n"); + for (s = str; *s; s++) { + if (*s == ' ') + *s = ','; + if (*s == ',') + n++; + } + r = ereallocarray(NULL, n, sizeof(*r)); + for (s = str; n; n--, s++) { + r->min = (*s == '-') ? 1 : strtoul(s, &s, 10); + r->max = (*s == '-') ? strtoul(s + 1, &s, 10) : r->min; + r->next = NULL; + if (!r->min || (r->max && r->max < r->min) || (*s && *s != ',')) + eprintf("bad list value\n"); + insert(r++); + } +} + +static size_t +seek(struct line *s, size_t pos, size_t *prev, size_t count) +{ + size_t n = pos - *prev, i, j; + + if (mode == 'b') { + if (n >= s->len) + return s->len; + if (nflag) + while (n && !UTF8_POINT(s->data[n])) + n--; + *prev += n; + return n; + } else if (mode == 'c') { + for (n++, i = 0; i < s->len; i++) + if (UTF8_POINT(s->data[i]) && !--n) + break; + } else { + for (i = (count < delimlen + 1) ? 0 : delimlen; n && i < s->len; ) { + if ((s->len - i) >= delimlen && + !memcmp(s->data + i, delim, delimlen)) { + if (!--n && count) + break; + i += delimlen; + continue; + } + for (j = 1; j + i <= s->len && !fullrune(s->data + i, j); j++); + i += j; + } + } + *prev = pos; + + return i; +} + +static void +cut(FILE *fp, const char *fname) +{ + Range *r; + struct line s; + static struct line line; + static size_t size; + size_t i, n, p; + ssize_t len; + + while ((len = getline(&line.data, &size, fp)) > 0) { + line.len = len; + if (line.data[line.len - 1] == '\n') + line.data[--line.len] = '\0'; + if (mode == 'f' && !memmem(line.data, line.len, delim, delimlen)) { + if (!sflag) { + fwrite(line.data, 1, line.len, stdout); + fputc('\n', stdout); + } + continue; + } + for (i = 0, p = 1, s = line, r = list; r; r = r->next) { + n = seek(&s, r->min, &p, i); + s.data += n; + s.len -= n; + i += (mode == 'f') ? delimlen : 1; + if (!s.len) + break; + if (!r->max) { + fwrite(s.data, 1, s.len, stdout); + break; + } + n = seek(&s, r->max + 1, &p, i); + i += (mode == 'f') ? delimlen : 1; + if (fwrite(s.data, 1, n, stdout) != n) + eprintf("fwrite <stdout>:"); + s.data += n; + s.len -= n; + } + putchar('\n'); + } + if (ferror(fp)) + eprintf("getline %s:", fname); +} + +static void +usage(void) +{ + eprintf("usage: %s -b list [-n] [file ...]\n" + " %s -c list [file ...]\n" + " %s -f list [-d delim] [-s] [file ...]\n", + argv0, argv0, argv0); +} + +int +main(int argc, char *argv[]) +{ + FILE *fp; + int ret = 0; + + ARGBEGIN { + case 'b': + case 'c': + case 'f': + mode = ARGC(); + parselist(EARGF(usage())); + break; + case 'd': + delim = EARGF(usage()); + if (!*delim) + eprintf("empty delimiter\n"); + delimlen = unescape(delim); + break; + case 'n': + nflag = 1; + break; + case 's': + sflag = 1; + break; + default: + usage(); + } ARGEND + + if (!mode) + usage(); + + if (!argc) + cut(stdin, "<stdin>"); + else { + for (; *argv; argc--, argv++) { + if (!strcmp(*argv, "-")) { + *argv = "<stdin>"; + fp = stdin; + } else if (!(fp = fopen(*argv, "r"))) { + weprintf("fopen %s:", *argv); + ret = 1; + continue; + } + cut(fp, *argv); + if (fp != stdin && fshut(fp, *argv)) + ret = 1; + } + } + + ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); + + return ret; +} |