aboutsummaryrefslogtreecommitdiff
path: root/toys/od.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/od.c')
-rw-r--r--toys/od.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/toys/od.c b/toys/od.c
new file mode 100644
index 00000000..4e9d1002
--- /dev/null
+++ b/toys/od.c
@@ -0,0 +1,250 @@
+/* vi: set sw=4 ts=4:
+ *
+ * od.c - Provide octal/hex dumps of data
+ *
+ * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html
+
+USE_OD(NEWTOY(od, "j#vN#xsodbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
+
+config OD
+ bool "od"
+ default y
+ help
+ usage: od
+*/
+
+#include "toys.h"
+
+#define OD_BLOCK_SIZE 16
+
+#define FLAG_t (1 << 0)
+#define FLAG_A (1 << 1)
+#define FLAG_b (1 << 2)
+#define FLAG_d (1 << 3)
+#define FLAG_o (1 << 4)
+#define FLAG_s (1 << 5)
+#define FLAG_x (1 << 6)
+#define FLAG_N (1 << 7)
+#define FLAG_v (1 << 8)
+
+
+DEFINE_GLOBALS(
+ struct arg_list *output_base;
+ char *address_base;
+ long max_count;
+ long jump_bytes;
+)
+
+#define TT this.od
+
+static const char *ascii[] = {
+ "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"};
+
+static void display_line_1(char base, off_t offset, uint8_t *line, int len)
+{
+ while (len--) {
+ switch (base) {
+ case 'a': {
+ int ch = *line & 0x7f;
+ if (ch < sizeof(ascii)/sizeof(ascii[0]))
+ printf(" %3s", ascii[ch]);
+ else if (ch == 127)
+ printf(" del");
+ else
+ printf(" %c", ch);
+ break;
+ }
+ case 'o': printf(" %3.3o", *line); break;
+ case 'x': printf(" %2.2x", *line); break;
+ case 'd': printf(" %4d", *(int8_t *)line); break;
+ case 'u': printf(" %3u", *line); break;
+ }
+ line++;
+ }
+}
+
+static void display_line_2(char base, off_t offset, uint16_t *line, int len)
+{
+ while (len--) {
+ switch (base) {
+ case 'o': printf(" %6.6o", *line); break;
+ case 'x': printf(" %4.4x", *line); break;
+ case 'd': printf(" %6d", *(int16_t*)line); break;
+ case 'u': printf(" %5u", *line); break;
+ }
+ line++;
+ }
+}
+
+static void display_line_4(char base, off_t offset, uint32_t *line, int len)
+{
+ while (len--) {
+ switch (base) {
+ case 'o': printf(" %11.11o", *line); break;
+ case 'x': printf(" %8.8x", *line); break;
+ case 'd': printf(" %11d", *(int32_t *)line); break;
+ case 'u': printf(" %10u", *line); break;
+ case 'f': printf(" %15g", *(float *)line); break;
+ }
+ line++;
+ }
+}
+
+static void display_line_8(char base, off_t offset, uint64_t *line, int len)
+{
+ while (len--) {
+ switch (base) {
+ //case 'o': printf(" %22.22o", *line); break;
+ case 'x': printf(" %16.16" PRIx64, *line); break;
+ case 'd': printf(" %21" PRId64, *(int64_t *)line); break;
+ case 'u': printf(" %20" PRIu64, *line); break;
+ case 'f': printf(" %23g", *(double *)line);
+ }
+ line++;
+ }
+}
+
+static void display_line(off_t offset, uint8_t *line, int len)
+{
+ struct arg_list *output = TT.output_base;
+ switch (*TT.address_base) {
+ case 'o': printf("%8.8zo", offset); break;
+ case 'd': printf("%7.7zd", offset); break;
+ case 'x': printf("%6.6zx", offset); break;
+ case 'n':
+ default:
+ break;
+ }
+ while (output) {
+ char base = *output->arg;
+ int width = atoi(&output->arg[1]);
+
+ switch (width) {
+ case 1: display_line_1(base, offset, line, len); break;
+ case 2: display_line_2(base, offset, (uint16_t *)line,
+ (len + 1) / 2); break;
+ case 4: display_line_4(base, offset, (uint32_t *)line,
+ (len + 3) / 4); break;
+ case 8: display_line_8(base, offset, (uint64_t *)line,
+ (len + 7) / 8); break;
+ }
+ output = output->next;
+ }
+
+ printf("\n");
+}
+
+static void do_od(int fd, char *name)
+{
+ uint8_t *block[2];
+ int index = 0;
+ off_t offset = 0;
+ int last_match = 0;
+
+ block[0] = (uint8_t *)toybuf;
+ block[1] = (uint8_t *)&toybuf[OD_BLOCK_SIZE];
+
+ if (TT.jump_bytes) {
+ xlseek(fd, TT.jump_bytes, SEEK_SET);
+ offset = TT.jump_bytes;
+ }
+
+ do {
+ int len;
+ int max_len = OD_BLOCK_SIZE;
+ if ((toys.optflags & FLAG_N) &&
+ offset + OD_BLOCK_SIZE > TT.max_count)
+ max_len = TT.max_count - offset;
+ len = xread(fd, block[index], max_len);
+ if (!len)
+ break;
+
+ memset(&block[index][len], 0, OD_BLOCK_SIZE - len);
+
+ if (!(toys.optflags & FLAG_v) &&
+ offset > 0 &&
+ memcmp(block[0], block[1], OD_BLOCK_SIZE) == 0) {
+ if (!last_match)
+ puts("*");
+ last_match = 1;
+ } else {
+ display_line(offset, block[index], len);
+ last_match = 0;
+ }
+ offset += len;
+ index = !index;
+
+ if (len != OD_BLOCK_SIZE)
+ break;
+ } while (1);
+
+ if (!(toys.optflags & FLAG_N) && offset != TT.max_count)
+ display_line(offset, NULL, 0);
+}
+
+static void append_base(char *base)
+{
+ struct arg_list *arg, *prev;
+ arg = xmalloc(sizeof(struct arg_list));
+ prev = TT.output_base;
+ TT.output_base = arg;
+ arg->arg = base;
+ arg->next = prev;
+}
+
+static void valid_bases(void)
+{
+ struct arg_list *arg = TT.output_base;
+ while (arg) {
+ char base = arg->arg[0];
+ int width = 1;
+ if (arg->arg[1])
+ width = atoi(&arg->arg[1]);
+ switch (base) {
+ case 'a':
+ if (width != 1)
+ error_exit("invalid width for ascii base");
+ break;
+ case 'd': case 'x': case 'o': case'u':
+ if (width != 1 && width != 2 &&
+ width != 4 && width != 8)
+ error_exit("this system doesn't provide a %d-byte type",
+ width);
+ break;
+ case 'f':
+ if (width != 4 && width != 8)
+ error_exit("this system doesn't provide a %d-byte floating point type",
+ width);
+ break;
+ default:
+ error_exit("invalid base '%c'", base);
+ }
+
+ arg = arg->next;
+ };
+}
+
+void od_main(void)
+{
+ if (!TT.address_base)
+ TT.address_base = "o";
+ if (toys.optflags & FLAG_b)
+ append_base("o1");
+ if (toys.optflags & FLAG_d)
+ append_base("u2");
+ if (toys.optflags & FLAG_o)
+ append_base("o2");
+ if (toys.optflags & FLAG_s)
+ append_base("d2");
+ if (toys.optflags & FLAG_x)
+ append_base("x2");
+ if (!TT.output_base)
+ append_base("o2");
+ valid_bases();
+ loopfiles(toys.optargs, do_od);
+}