From e9a910b33c7837b4b868e3abda18eb4810df7f02 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sat, 4 Oct 2025 09:14:33 +0100 Subject: 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 --- util/sbase/od.c | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 util/sbase/od.c (limited to 'util/sbase/od.c') diff --git a/util/sbase/od.c b/util/sbase/od.c new file mode 100644 index 00000000..0b1c5c60 --- /dev/null +++ b/util/sbase/od.c @@ -0,0 +1,332 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include + +#include "queue.h" +#include "util.h" + +struct type { + unsigned char format; + unsigned int len; + TAILQ_ENTRY(type) entry; +}; + +static TAILQ_HEAD(head, type) head = TAILQ_HEAD_INITIALIZER(head); +static unsigned char addr_format = 'o'; +static off_t skip = 0; +static off_t max = -1; +static size_t linelen = 1; +static int big_endian; + +static void +printaddress(off_t addr) +{ + char fmt[] = "%07j#"; + + if (addr_format == 'n') { + fputc(' ', stdout); + } else { + fmt[4] = addr_format; + printf(fmt, (intmax_t)addr); + } +} + +static void +printchunk(const unsigned char *s, unsigned char format, size_t len) +{ + long long res, basefac; + size_t i; + char fmt[] = " %#*ll#"; + unsigned char c; + + const char *namedict[] = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", + "bel", "bs", "ht", "nl", "vt", "ff", "cr", + "so", "si", "dle", "dc1", "dc2", "dc3", "dc4", + "nak", "syn", "etb", "can", "em", "sub", "esc", + "fs", "gs", "rs", "us", "sp", + }; + const char *escdict[] = { + ['\0'] = "\\0", ['\a'] = "\\a", + ['\b'] = "\\b", ['\t'] = "\\t", + ['\n'] = "\\n", ['\v'] = "\\v", + ['\f'] = "\\f", ['\r'] = "\\r", + }; + + switch (format) { + case 'a': + c = *s & ~128; /* clear high bit as required by standard */ + if (c < LEN(namedict) || c == 127) { + printf(" %3s", (c == 127) ? "del" : namedict[c]); + } else { + printf(" %3c", c); + } + break; + case 'c': + if (strchr("\a\b\t\n\v\f\r\0", *s)) { + printf(" %3s", escdict[*s]); + } else if (!isprint(*s)) { + printf(" %3o", *s); + } else { + printf(" %3c", *s); + } + break; + default: + if (big_endian) { + for (res = 0, basefac = 1, i = len; i; i--) { + res += s[i - 1] * basefac; + basefac <<= 8; + } + } else { + for (res = 0, basefac = 1, i = 0; i < len; i++) { + res += s[i] * basefac; + basefac <<= 8; + } + } + fmt[2] = big_endian ? '-' : ' '; + fmt[6] = format; + printf(fmt, (int)(3 * len + len - 1), res); + } +} + +static void +printline(const unsigned char *line, size_t len, off_t addr) +{ + struct type *t = NULL; + size_t i; + int first = 1; + unsigned char *tmp; + + if (TAILQ_EMPTY(&head)) + goto once; + TAILQ_FOREACH(t, &head, entry) { +once: + if (first) { + printaddress(addr); + first = 0; + } else { + printf("%*c", (addr_format == 'n') ? 1 : 7, ' '); + } + for (i = 0; i < len; i += MIN(len - i, t ? t->len : 4)) { + if (len - i < (t ? t->len : 4)) { + tmp = ecalloc(t ? t->len : 4, 1); + memcpy(tmp, line + i, len - i); + printchunk(tmp, t ? t->format : 'o', + t ? t->len : 4); + free(tmp); + } else { + printchunk(line + i, t ? t->format : 'o', + t ? t->len : 4); + } + } + fputc('\n', stdout); + if (TAILQ_EMPTY(&head) || (!len && !first)) + break; + } +} + +static int +od(int fd, char *fname, int last) +{ + static unsigned char *line; + static size_t lineoff; + static off_t addr; + unsigned char buf[BUFSIZ]; + size_t i, size = sizeof(buf); + ssize_t n; + + while (skip - addr > 0) { + n = read(fd, buf, MIN(skip - addr, sizeof(buf))); + if (n < 0) + weprintf("read %s:", fname); + if (n <= 0) + return n; + addr += n; + } + if (!line) + line = emalloc(linelen); + + for (;;) { + if (max >= 0) + size = MIN(max - (addr - skip), size); + if ((n = read(fd, buf, size)) <= 0) + break; + for (i = 0; i < n; i++, addr++) { + line[lineoff++] = buf[i]; + if (lineoff == linelen) { + printline(line, lineoff, addr - lineoff + 1); + lineoff = 0; + } + } + } + if (n < 0) { + weprintf("read %s:", fname); + return n; + } + if (lineoff && last) + printline(line, lineoff, addr - lineoff); + if (last) + printline((unsigned char *)"", 0, addr); + return 0; +} + +static int +lcm(unsigned int a, unsigned int b) +{ + unsigned int c, d, e; + + for (c = a, d = b; c ;) { + e = c; + c = d % c; + d = e; + } + + return a / d * b; +} + +static void +addtype(char format, int len) +{ + struct type *t; + + t = emalloc(sizeof(*t)); + t->format = format; + t->len = len; + TAILQ_INSERT_TAIL(&head, t, entry); +} + +static void +usage(void) +{ + eprintf("usage: %s [-bdosvx] [-A addressformat] [-E | -e] [-j skip] " + "[-t outputformat] [file ...]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int fd; + struct type *t; + int ret = 0, len; + char *s; + + big_endian = (*(uint16_t *)"\0\xff" == 0xff); + + ARGBEGIN { + case 'A': + s = EARGF(usage()); + if (strlen(s) != 1 || !strchr("doxn", s[0])) + usage(); + addr_format = s[0]; + break; + case 'b': + addtype('o', 1); + break; + case 'd': + addtype('u', 2); + break; + case 'E': + case 'e': + big_endian = (ARGC() == 'E'); + break; + case 'j': + if ((skip = parseoffset(EARGF(usage()))) < 0) + usage(); + break; + case 'N': + if ((max = parseoffset(EARGF(usage()))) < 0) + usage(); + break; + case 'o': + addtype('o', 2); + break; + case 's': + addtype('d', 2); + break; + case 't': + s = EARGF(usage()); + for (; *s; s++) { + switch (*s) { + case 'a': + case 'c': + addtype(*s, 1); + break; + case 'd': + case 'o': + case 'u': + case 'x': + /* todo: allow multiple digits */ + if (*(s+1) > '0' && *(s+1) <= '9') { + len = *(s+1) - '0'; + } else { + switch (*(s+1)) { + case 'C': + len = sizeof(char); + break; + case 'S': + len = sizeof(short); + break; + case 'I': + len = sizeof(int); + break; + case 'L': + len = sizeof(long); + break; + default: + len = sizeof(int); + } + } + addtype(*s++, len); + break; + default: + usage(); + } + } + break; + case 'v': + /* always set - use uniq(1) to handle duplicate lines */ + break; + case 'x': + addtype('x', 2); + break; + default: + usage(); + } ARGEND + + /* line length is lcm of type lengths and >= 16 by doubling */ + TAILQ_FOREACH(t, &head, entry) + linelen = lcm(linelen, t->len); + if (TAILQ_EMPTY(&head)) + linelen = 16; + while (linelen < 16) + linelen *= 2; + + if (!argc) { + if (od(0, "", 1) < 0) + ret = 1; + } else { + for (; *argv; argc--, argv++) { + if (!strcmp(*argv, "-")) { + *argv = ""; + fd = 0; + } else if ((fd = open(*argv, O_RDONLY)) < 0) { + weprintf("open %s:", *argv); + ret = 1; + continue; + } + if (od(fd, *argv, (!*(argv + 1))) < 0) + ret = 1; + if (fd != 0) + close(fd); + } + } + + ret |= fshut(stdout, "") | fshut(stderr, ""); + + return ret; +} -- cgit v1.2.1