summaryrefslogtreecommitdiff
path: root/util/sbase/od.c
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2025-10-04 09:14:33 +0100
committerLeah Rowe <leah@libreboot.org>2025-10-04 09:20:12 +0100
commite9a910b33c7837b4b868e3abda18eb4810df7f02 (patch)
tree749e1830cb0607952df1a1afc0ae09ec1db54140 /util/sbase/od.c
parent2cfaba181b3c68761871fa47b32725c934423c14 (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/od.c')
-rw-r--r--util/sbase/od.c332
1 files changed, 332 insertions, 0 deletions
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 <ctype.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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, "<stdin>", 1) < 0)
+ ret = 1;
+ } else {
+ for (; *argv; argc--, argv++) {
+ if (!strcmp(*argv, "-")) {
+ *argv = "<stdin>";
+ 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, "<stdout>") | fshut(stderr, "<stderr>");
+
+ return ret;
+}