Hi, I've started to do an implementation of 'od' - it is most of the way there, but I'm not particularly happy with the method I've used for determining which 'printf' format string and which data alignment to use. At the moment I'm essentially reparsing the -t XX parameters each time you want to print a new character, which has pretty hideous performance (and currently doesn't support the -to2o4 syntax). I'm debating about pre-parsing these, and then a list of function pointers. This would also require me to have ~20 tiny stub functions, which basically just do a printf with a different format string & data type, and return the length of data that they've consumed (or possibly iterate over an entire line, I haven't decided).
Does anyone have any comments about an alternative method to do this? Thanks, Andre -- Bluewater Systems - An Aiotec Company Andre Renaud [email protected] 5 Amuri Park, 404 Barbadoes St www.bluewatersys.com PO Box 13 889, Christchurch 8013 www.aiotec.co.nz New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
/* vi: set sw=4 ts=4: * * od.c - Provide octal/hex dumps of data * * Copyright 2012 Andre Renaud <[email protected]> * * 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); }
_______________________________________________ Toybox mailing list [email protected] http://lists.landley.net/listinfo.cgi/toybox-landley.net
