od.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /* od.c - Provide octal/hex dumps of data
  2. *
  3. * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
  4. * Copyright 2012 Rob Landley <rob@landley.net>
  5. *
  6. * See http://opengroup.org/onlinepubs/9699919799/utilities/od.html
  7. USE_OD(NEWTOY(od, "j#vw#<1=16N#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
  8. config OD
  9. bool "od"
  10. default y
  11. help
  12. usage: od [-bcdosxv] [-j #] [-N #] [-w #] [-A doxn] [-t acdfoux[#]]
  13. Dump data in octal/hex.
  14. -A Address base (decimal, octal, hexadecimal, none)
  15. -j Skip this many bytes of input
  16. -N Stop dumping after this many bytes
  17. -t Output type a(scii) c(har) d(ecimal) f(loat) o(ctal) u(nsigned) (he)x
  18. plus optional size in bytes
  19. aliases: -b=-t o1, -c=-t c, -d=-t u2, -o=-t o2, -s=-t d2, -x=-t x2
  20. -v Don't collapse repeated lines together
  21. -w Total line width in bytes (default 16)
  22. */
  23. #define FOR_od
  24. #include "toys.h"
  25. GLOBALS(
  26. struct arg_list *t;
  27. char *A;
  28. long N, w, j;
  29. int address_idx;
  30. unsigned types, leftover, star;
  31. char *buf; // Points to buffers[0] or buffers[1].
  32. char *bufs[2]; // Used to detect duplicate lines.
  33. off_t pos;
  34. )
  35. static char *ascii = "nulsohstxetxeotenqackbel bs ht nl vt ff cr so si"
  36. "dledc1dc2dc3dc4naksynetbcan emsubesc fs gs rs us sp";
  37. struct odtype {
  38. int type;
  39. int size;
  40. };
  41. static int od_out_t(struct odtype *t, char *buf, int *offset)
  42. {
  43. unsigned k;
  44. int throw = 0, pad = 0;
  45. // Handle ascii
  46. if (t->type < 2) {
  47. char c = TT.buf[(*offset)++];
  48. pad += 4;
  49. if (!t->type) {
  50. c &= 127;
  51. if (c<=32) sprintf(buf, "%.3s", ascii+(3*c));
  52. else if (c==127) strcpy(buf, "del");
  53. else sprintf(buf, "%c", c);
  54. } else {
  55. char *bfnrtav = "\b\f\n\r\t\a\v", *s = strchr(bfnrtav, c);
  56. if (s) sprintf(buf, "\\%c", "bfnrtav0"[s-bfnrtav]);
  57. else if (c < 32 || c >= 127) sprintf(buf, "%03o", c);
  58. else {
  59. // TODO: this should be UTF8 aware.
  60. sprintf(buf, "%c", c);
  61. }
  62. }
  63. } else if (CFG_TOYBOX_FLOAT && t->type == 6) {
  64. long double ld;
  65. union {float f; double d; long double ld;} fdl;
  66. memcpy(&fdl, TT.buf+*offset, t->size);
  67. *offset += t->size;
  68. if (sizeof(float) == t->size) {
  69. ld = fdl.f;
  70. pad += (throw = 8)+7;
  71. } else if (sizeof(double) == t->size) {
  72. ld = fdl.d;
  73. pad += (throw = 17)+8;
  74. } else if (sizeof(long double) == t->size) {
  75. ld = fdl.ld;
  76. pad += (throw = 21)+9;
  77. } else error_exit("bad -tf '%d'", t->size);
  78. sprintf(buf, "%.*Le", throw, ld);
  79. // Integer types
  80. } else {
  81. unsigned long long ll = 0, or;
  82. char *c[] = {"%*lld", "%*llu", "%0*llo", "%0*llx"},
  83. *class = c[t->type-2];
  84. // Work out width of field
  85. if (t->size == 8) {
  86. or = -1LL;
  87. if (t->type == 2) or >>= 1;
  88. } else or = (1LL<<(8*t->size))-1;
  89. throw = sprintf(buf, class, 0, or);
  90. // Accumulate integer based on size argument
  91. for (k=0; k < t->size; k++) {
  92. or = TT.buf[(*offset)++];
  93. ll |= or << (8*(IS_BIG_ENDIAN ? t->size-k-1 : k));
  94. }
  95. // Handle negative values
  96. if (t->type == 2) {
  97. or = sizeof(or) - t->size;
  98. throw++;
  99. if (or && (ll & (1l<<((8*t->size)-1))))
  100. ll |= ((or<<(8*or))-1) << (8*t->size);
  101. }
  102. sprintf(buf, class, throw, ll);
  103. pad += throw+1;
  104. }
  105. return pad;
  106. }
  107. static void od_outline(void)
  108. {
  109. unsigned flags = toys.optflags;
  110. char buf[128], *abases[] = {"", "%07lld", "%07llo", "%06llx"};
  111. struct odtype *types = (struct odtype *)toybuf;
  112. int i, j, len, pad;
  113. if (TT.leftover<TT.w) memset(TT.buf+TT.leftover, 0, TT.w-TT.leftover);
  114. // Handle duplciate lines as *
  115. if (!(flags&FLAG_v) && TT.j != TT.pos && TT.leftover
  116. && !memcmp(TT.bufs[0], TT.bufs[1], TT.w))
  117. {
  118. if (!TT.star) {
  119. xputs("*");
  120. TT.star++;
  121. }
  122. // Print line position
  123. } else {
  124. TT.star = 0;
  125. // off_t varies so expand it to largest possible size
  126. xprintf(abases[TT.address_idx], (long long)TT.pos);
  127. if (!TT.leftover) {
  128. if (TT.address_idx) xputc('\n');
  129. return;
  130. }
  131. }
  132. TT.pos += len = TT.leftover;
  133. TT.leftover = 0;
  134. if (TT.star) return;
  135. // Find largest "pad" of the output types.
  136. for (i = pad = 0; i<TT.types; i++) {
  137. int bytes = 0;
  138. // If more than one byte of input consumed, average rounding up.
  139. j = od_out_t(types+i, buf, &bytes);
  140. j = (j+bytes-1)/bytes;
  141. if (j > pad) pad = j;
  142. }
  143. // For each output type, print one line
  144. for (i=0; i<TT.types; i++) {
  145. for (j = 0; j<len;) {
  146. int bytes = j;
  147. // pad for as many bytes as were consumed, and indent non-numbered lines
  148. od_out_t(types+i, buf, &bytes);
  149. xprintf("%*s", pad*(bytes-j) + 7*(!!i)*!j, buf);
  150. j = bytes;
  151. }
  152. xputc('\n');
  153. }
  154. // Toggle buffer for "same as last time" check.
  155. TT.buf = (TT.buf == TT.bufs[0]) ? TT.bufs[1] : TT.bufs[0];
  156. }
  157. // Loop through input files
  158. static void do_od(int fd, char *name)
  159. {
  160. // Skip input, possibly more than one entire file.
  161. if (TT.j > TT.pos) {
  162. off_t pos = TT.j-TT.pos, off = lskip(fd, pos);
  163. if (off >= 0) TT.pos += pos-off;
  164. if (TT.j > TT.pos) return;
  165. }
  166. for(;;) {
  167. char *buf = TT.buf + TT.leftover;
  168. int len = TT.w - TT.leftover;
  169. if (toys.optflags & FLAG_N) {
  170. if (!TT.N) break;
  171. if (TT.N < len) len = TT.N;
  172. }
  173. len = readall(fd, buf, len);
  174. if (len < 0) {
  175. perror_msg_raw(name);
  176. break;
  177. }
  178. if (TT.N) TT.N -= len;
  179. TT.leftover += len;
  180. if (TT.leftover < TT.w) break;
  181. od_outline();
  182. }
  183. }
  184. // Handle one -t argument (including implicit ones)
  185. static void append_base(char *base)
  186. {
  187. char *s = base;
  188. struct odtype *types = (struct odtype *)toybuf;
  189. int type;
  190. for (;;) {
  191. int size = 1;
  192. if (!*s) return;
  193. if (TT.types >= sizeof(toybuf)/sizeof(struct odtype)) break;
  194. if (-1 == (type = stridx("acduox"USE_TOYBOX_FLOAT("f"), *(s++)))) break;
  195. if (isdigit(*s)) {
  196. size = strtol(s, &s, 10);
  197. if (type < 2 && size != 1) break;
  198. if (CFG_TOYBOX_FLOAT && type == 6 && size == sizeof(long double));
  199. else if (size < 1 || size > 8) break;
  200. } else if (CFG_TOYBOX_FLOAT && type == 6) {
  201. int sizes[] = {sizeof(float), sizeof(double), sizeof(long double)};
  202. if (-1 == (size = stridx("FDL", *s))) size = sizeof(double);
  203. else {
  204. s++;
  205. size = sizes[size];
  206. }
  207. } else if (type > 1) {
  208. if (-1 == (size = stridx("CSIL", *s))) size = 4;
  209. else {
  210. s++;
  211. size = 1 << size;
  212. }
  213. }
  214. types[TT.types].type = type;
  215. types[TT.types].size = size;
  216. TT.types++;
  217. }
  218. error_exit("bad -t %s", base);
  219. }
  220. void od_main(void)
  221. {
  222. struct arg_list *arg;
  223. TT.bufs[0] = xzalloc(TT.w);
  224. TT.bufs[1] = xzalloc(TT.w);
  225. TT.buf = TT.bufs[0];
  226. if (!TT.A) TT.address_idx = 2;
  227. else if (0>(TT.address_idx = stridx("ndox", *TT.A)))
  228. error_exit("bad -A '%c'", *TT.A);
  229. // Collect -t entries
  230. for (arg = TT.t; arg; arg = arg->next) append_base(arg->arg);
  231. if (toys.optflags & FLAG_b) append_base("o1");
  232. if (toys.optflags & FLAG_c) append_base("c");
  233. if (toys.optflags & FLAG_d) append_base("u2");
  234. if (toys.optflags & FLAG_o) append_base("o2");
  235. if (toys.optflags & FLAG_s) append_base("d2");
  236. if (toys.optflags & FLAG_x) append_base("x2");
  237. if (!TT.types) append_base("o2");
  238. loopfiles(toys.optargs, do_od);
  239. if (TT.leftover) od_outline();
  240. od_outline();
  241. if (CFG_TOYBOX_FREE) {
  242. free(TT.bufs[0]);
  243. free(TT.bufs[1]);
  244. }
  245. }