dump.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Support code for the hexdump and od applets,
  4. * based on code from util-linux v 2.11l
  5. *
  6. * Copyright (c) 1989
  7. * The Regents of the University of California. All rights reserved.
  8. *
  9. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10. *
  11. * Original copyright notice is retained at the end of this file.
  12. */
  13. #include "libbb.h"
  14. #include "dump.h"
  15. #define F_IGNORE 0x01 /* %_A */
  16. #define F_SETREP 0x02 /* rep count set, not default */
  17. #define F_ADDRESS 0x001 /* print offset */
  18. #define F_BPAD 0x002 /* blank pad */
  19. #define F_C 0x004 /* %_c */
  20. #define F_CHAR 0x008 /* %c */
  21. #define F_DBL 0x010 /* %[EefGf] */
  22. #define F_INT 0x020 /* %[di] */
  23. #define F_P 0x040 /* %_p */
  24. #define F_STR 0x080 /* %s */
  25. #define F_U 0x100 /* %_u */
  26. #define F_UINT 0x200 /* %[ouXx] */
  27. #define F_TEXT 0x400 /* no conversions */
  28. typedef struct priv_dumper_t {
  29. dumper_t pub;
  30. char **argv;
  31. FU *endfu;
  32. off_t savaddress; /* saved address/offset in stream */
  33. off_t eaddress; /* end address */
  34. off_t address; /* address/offset in stream */
  35. int blocksize;
  36. smallint exitval; /* final exit value */
  37. /* former statics */
  38. smallint next__done;
  39. smallint get__ateof; // = 1;
  40. unsigned char *get__curp;
  41. unsigned char *get__savp;
  42. } priv_dumper_t;
  43. static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
  44. static const char size_conv_str[] ALIGN1 =
  45. "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
  46. static const char int_convs[] ALIGN1 = "diouxX";
  47. dumper_t* FAST_FUNC alloc_dumper(void)
  48. {
  49. priv_dumper_t *dumper = xzalloc(sizeof(*dumper));
  50. dumper->pub.dump_length = -1;
  51. dumper->pub.dump_vflag = FIRST;
  52. dumper->get__ateof = 1;
  53. return &dumper->pub;
  54. }
  55. static NOINLINE int bb_dump_size(FS *fs)
  56. {
  57. FU *fu;
  58. int bcnt, cur_size;
  59. char *fmt;
  60. const char *p;
  61. int prec;
  62. /* figure out the data block size needed for each format unit */
  63. for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
  64. if (fu->bcnt) {
  65. cur_size += fu->bcnt * fu->reps;
  66. continue;
  67. }
  68. for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
  69. if (*fmt != '%')
  70. continue;
  71. /*
  72. * skip any special chars -- save precision in
  73. * case it's a %s format.
  74. */
  75. while (strchr(dot_flags_width_chars + 1, *++fmt))
  76. continue;
  77. if (*fmt == '.' && isdigit(*++fmt)) {
  78. prec = atoi(fmt);
  79. while (isdigit(*++fmt))
  80. continue;
  81. }
  82. p = strchr(size_conv_str + 12, *fmt);
  83. if (!p) {
  84. if (*fmt == 's') {
  85. bcnt += prec;
  86. }
  87. if (*fmt == '_') {
  88. ++fmt;
  89. if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
  90. bcnt += 1;
  91. }
  92. }
  93. } else {
  94. bcnt += p[-12];
  95. }
  96. }
  97. cur_size += bcnt * fu->reps;
  98. }
  99. return cur_size;
  100. }
  101. static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
  102. {
  103. FU *fu;
  104. for (fu = fs->nextfu; fu; fu = fu->nextfu) {
  105. PR *pr;
  106. char *p1, *p2, *p3;
  107. char *fmtp;
  108. int nconv = 0;
  109. /*
  110. * break each format unit into print units; each
  111. * conversion character gets its own.
  112. */
  113. for (fmtp = fu->fmt; *fmtp; ) {
  114. unsigned len;
  115. const char *prec;
  116. const char *byte_count_str;
  117. /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL */
  118. pr = xzalloc(sizeof(*pr));
  119. if (!fu->nextpr)
  120. fu->nextpr = pr;
  121. /* skip preceding text and up to the next % sign */
  122. p1 = strchr(fmtp, '%');
  123. if (!p1) { /* only text in the string */
  124. pr->fmt = fmtp;
  125. pr->flags = F_TEXT;
  126. break;
  127. }
  128. /*
  129. * get precision for %s -- if have a byte count, don't
  130. * need it.
  131. */
  132. prec = NULL;
  133. if (fu->bcnt) {
  134. /* skip to conversion character */
  135. while (strchr(dot_flags_width_chars, *++p1))
  136. continue;
  137. } else {
  138. /* skip any special chars, field width */
  139. while (strchr(dot_flags_width_chars + 1, *++p1))
  140. continue;
  141. if (*p1 == '.' && isdigit(*++p1)) {
  142. prec = p1;
  143. while (isdigit(*++p1))
  144. continue;
  145. }
  146. }
  147. p2 = p1 + 1; /* set end pointer */
  148. /*
  149. * figure out the byte count for each conversion;
  150. * rewrite the format as necessary, set up blank-
  151. * padding for end of data.
  152. */
  153. if (*p1 == 'c') {
  154. pr->flags = F_CHAR;
  155. DO_BYTE_COUNT_1:
  156. byte_count_str = "\001";
  157. DO_BYTE_COUNT:
  158. if (fu->bcnt) {
  159. for (;;) {
  160. if (fu->bcnt == *byte_count_str)
  161. break;
  162. if (*++byte_count_str == 0)
  163. bb_error_msg_and_die("bad byte count for conversion character %s", p1);
  164. }
  165. }
  166. /* Unlike the original, output the remainder of the format string. */
  167. pr->bcnt = *byte_count_str;
  168. } else
  169. if (*p1 == 'l') { /* %ld etc */
  170. const char *e;
  171. ++p2;
  172. ++p1;
  173. DO_INT_CONV:
  174. e = strchr(int_convs, *p1); /* "diouxX"? */
  175. if (!e)
  176. goto DO_BAD_CONV_CHAR;
  177. pr->flags = F_INT;
  178. if (e > int_convs + 1) /* not d or i? */
  179. pr->flags = F_UINT;
  180. byte_count_str = "\004\002\001";
  181. goto DO_BYTE_COUNT;
  182. } else
  183. if (strchr(int_convs, *p1)) { /* %d etc */
  184. goto DO_INT_CONV;
  185. } else
  186. if (strchr("eEfgG", *p1)) { /* floating point */
  187. pr->flags = F_DBL;
  188. byte_count_str = "\010\004";
  189. goto DO_BYTE_COUNT;
  190. } else
  191. if (*p1 == 's') {
  192. pr->flags = F_STR;
  193. pr->bcnt = fu->bcnt;
  194. if (fu->bcnt == 0) {
  195. if (!prec)
  196. bb_simple_error_msg_and_die("%%s needs precision or byte count");
  197. pr->bcnt = atoi(prec);
  198. }
  199. } else
  200. if (*p1 == '_') {
  201. p2++; /* move past a in "%_a" */
  202. switch (p1[1]) {
  203. case 'A': /* %_A[dox]: print address and the end */
  204. dumper->endfu = fu;
  205. fu->flags |= F_IGNORE;
  206. /* FALLTHROUGH */
  207. case 'a': /* %_a[dox]: current address */
  208. pr->flags = F_ADDRESS;
  209. p2++; /* move past x in "%_ax" */
  210. if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
  211. goto DO_BAD_CONV_CHAR;
  212. }
  213. *p1 = p1[2];
  214. break;
  215. case 'c': /* %_c: chars, \ooo, \n \r \t etc */
  216. pr->flags = F_C;
  217. /* *p1 = 'c'; set in conv_c */
  218. goto DO_BYTE_COUNT_1;
  219. case 'p': /* %_p: chars, dots for nonprintable */
  220. pr->flags = F_P;
  221. *p1 = 'c';
  222. goto DO_BYTE_COUNT_1;
  223. case 'u': /* %_p: chars, 'nul', 'esc' etc for nonprintable */
  224. pr->flags = F_U;
  225. /* *p1 = 'c'; set in conv_u */
  226. goto DO_BYTE_COUNT_1;
  227. default:
  228. goto DO_BAD_CONV_CHAR;
  229. }
  230. } else {
  231. DO_BAD_CONV_CHAR:
  232. bb_error_msg_and_die("bad conversion character %%%s", p1);
  233. }
  234. /*
  235. * copy to PR format string, set conversion character
  236. * pointer, update original.
  237. */
  238. len = (p1 - fmtp) + 1;
  239. pr->fmt = xstrndup(fmtp, len);
  240. /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
  241. * Skip subsequent text and up to the next % sign and tack the
  242. * additional text onto fmt: eg. if fmt is "%x is a HEX number",
  243. * we lose the " is a HEX number" part of fmt.
  244. */
  245. for (p3 = p2; *p3 && *p3 != '%'; p3++)
  246. continue;
  247. if ((p3 - p2) != 0) {
  248. char *d;
  249. pr->fmt = d = xrealloc(pr->fmt, len + (p3 - p2) + 1);
  250. d += len;
  251. do {
  252. *d++ = *p2++;
  253. } while (p2 != p3);
  254. *d = '\0';
  255. /* now p2 = p3 */
  256. }
  257. pr->cchar = pr->fmt + len - 1; /* must be after realloc! */
  258. fmtp = p2;
  259. /* only one conversion character if byte count */
  260. if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
  261. bb_simple_error_msg_and_die("byte count with multiple conversion characters");
  262. }
  263. }
  264. /*
  265. * if format unit byte count not specified, figure it out
  266. * so can adjust rep count later.
  267. */
  268. if (fu->bcnt == 0)
  269. for (pr = fu->nextpr; pr; pr = pr->nextpr)
  270. fu->bcnt += pr->bcnt;
  271. }
  272. /*
  273. * if the format string interprets any data at all, and it's
  274. * not the same as the blocksize, and its last format unit
  275. * interprets any data at all, and has no iteration count,
  276. * repeat it as necessary.
  277. *
  278. * if rep count is greater than 1, no trailing whitespace
  279. * gets output from the last iteration of the format unit:
  280. * 2/1 "%02x " prints "XX XX", not "XX XX "
  281. * 2/1 "%02x\n" prints "XX\nXX", not "XX\nXX\n"
  282. */
  283. for (fu = fs->nextfu; fu; fu = fu->nextfu) {
  284. if (!fu->nextfu
  285. && fs->bcnt < dumper->blocksize
  286. && !(fu->flags & F_SETREP)
  287. && fu->bcnt
  288. ) {
  289. fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
  290. }
  291. if (fu->reps > 1 && fu->nextpr) {
  292. PR *pr;
  293. char *p1, *p2;
  294. for (pr = fu->nextpr;; pr = pr->nextpr)
  295. if (!pr->nextpr)
  296. break;
  297. p2 = NULL;
  298. for (p1 = pr->fmt; *p1; ++p1)
  299. p2 = isspace(*p1) ? p1 : NULL;
  300. if (p2)
  301. pr->nospace = p2;
  302. }
  303. }
  304. }
  305. static void do_skip(priv_dumper_t *dumper, const char *fname)
  306. {
  307. struct stat sbuf;
  308. xfstat(STDIN_FILENO, &sbuf, fname);
  309. if (S_ISREG(sbuf.st_mode)
  310. && dumper->pub.dump_skip >= sbuf.st_size
  311. ) {
  312. /* If st_size is valid and pub.dump_skip >= st_size */
  313. dumper->pub.dump_skip -= sbuf.st_size;
  314. dumper->address += sbuf.st_size;
  315. return;
  316. }
  317. if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) {
  318. bb_simple_perror_msg_and_die(fname);
  319. }
  320. dumper->address += dumper->pub.dump_skip;
  321. dumper->savaddress = dumper->address;
  322. dumper->pub.dump_skip = 0;
  323. }
  324. static NOINLINE int next(priv_dumper_t *dumper)
  325. {
  326. for (;;) {
  327. const char *fname = *dumper->argv;
  328. if (fname) {
  329. dumper->argv++;
  330. if (NOT_LONE_DASH(fname)) {
  331. if (!freopen(fname, "r", stdin)) {
  332. bb_simple_perror_msg(fname);
  333. dumper->exitval = 1;
  334. continue;
  335. }
  336. }
  337. } else {
  338. if (dumper->next__done)
  339. return 0; /* no next file */
  340. }
  341. dumper->next__done = 1;
  342. if (dumper->pub.dump_skip)
  343. do_skip(dumper, fname ? fname : "stdin");
  344. if (dumper->pub.dump_skip == 0)
  345. return 1;
  346. }
  347. /* NOTREACHED */
  348. }
  349. static unsigned char *get(priv_dumper_t *dumper)
  350. {
  351. int n;
  352. int need, nread;
  353. int blocksize = dumper->blocksize;
  354. if (!dumper->get__curp) {
  355. dumper->address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
  356. dumper->get__curp = xmalloc(blocksize);
  357. dumper->get__savp = xzalloc(blocksize); /* need to be initialized */
  358. } else {
  359. unsigned char *tmp = dumper->get__curp;
  360. dumper->get__curp = dumper->get__savp;
  361. dumper->get__savp = tmp;
  362. dumper->savaddress += blocksize;
  363. dumper->address = dumper->savaddress;
  364. }
  365. need = blocksize;
  366. nread = 0;
  367. while (1) {
  368. /*
  369. * if read the right number of bytes, or at EOF for one file,
  370. * and no other files are available, zero-pad the rest of the
  371. * block and set the end flag.
  372. */
  373. if (!dumper->pub.dump_length || (dumper->get__ateof && !next(dumper))) {
  374. if (need == blocksize) {
  375. return NULL;
  376. }
  377. if (dumper->pub.dump_vflag != ALL /* not "show all"? */
  378. && dumper->pub.dump_vflag != FIRST /* not first line? */
  379. && memcmp(dumper->get__curp, dumper->get__savp, nread) == 0 /* same data? */
  380. ) {
  381. if (dumper->pub.dump_vflag != DUP) {
  382. puts("*");
  383. }
  384. }
  385. memset(dumper->get__curp + nread, 0, need);
  386. dumper->eaddress = dumper->address + nread;
  387. return dumper->get__curp;
  388. }
  389. n = fread(dumper->get__curp + nread, sizeof(unsigned char),
  390. dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin);
  391. if (n == 0) {
  392. if (ferror(stdin)) {
  393. bb_simple_perror_msg(dumper->argv[-1]);
  394. }
  395. dumper->get__ateof = 1;
  396. continue;
  397. }
  398. dumper->get__ateof = 0;
  399. if (dumper->pub.dump_length != -1) {
  400. dumper->pub.dump_length -= n;
  401. }
  402. need -= n;
  403. if (need == 0) {
  404. if (dumper->pub.dump_vflag == ALL /* "show all"? */
  405. || dumper->pub.dump_vflag == FIRST /* first line? */
  406. || memcmp(dumper->get__curp, dumper->get__savp, blocksize) != 0 /* not same data? */
  407. ) {
  408. if (dumper->pub.dump_vflag == DUP || dumper->pub.dump_vflag == FIRST) {
  409. dumper->pub.dump_vflag = WAIT;
  410. }
  411. return dumper->get__curp;
  412. }
  413. if (dumper->pub.dump_vflag == WAIT) {
  414. puts("*");
  415. }
  416. dumper->pub.dump_vflag = DUP;
  417. dumper->savaddress += blocksize;
  418. dumper->address = dumper->savaddress;
  419. need = blocksize;
  420. nread = 0;
  421. } else {
  422. nread += n;
  423. }
  424. }
  425. }
  426. static void bpad(PR *pr)
  427. {
  428. char *p1, *p2;
  429. /*
  430. * remove all conversion flags; '-' is the only one valid
  431. * with %s, and it's not useful here.
  432. */
  433. pr->flags = F_BPAD;
  434. *pr->cchar = 's';
  435. for (p1 = pr->fmt; *p1 != '%'; ++p1)
  436. continue;
  437. for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
  438. if (pr->nospace)
  439. pr->nospace--;
  440. while ((*p2++ = *p1++) != '\0')
  441. continue;
  442. }
  443. static const char conv_str[] ALIGN1 =
  444. "\0" "\\""0""\0"
  445. "\007""\\""a""\0" /* \a */
  446. "\b" "\\""b""\0"
  447. "\f" "\\""f""\0"
  448. "\n" "\\""n""\0"
  449. "\r" "\\""r""\0"
  450. "\t" "\\""t""\0"
  451. "\v" "\\""v""\0"
  452. ;
  453. static void conv_c(PR *pr, unsigned char *p)
  454. {
  455. const char *str = conv_str;
  456. do {
  457. if (*p == *str) {
  458. ++str;
  459. goto strpr; /* map e.g. '\n' to "\\n" */
  460. }
  461. str += 4;
  462. } while (*str);
  463. if (isprint_asciionly(*p)) {
  464. *pr->cchar = 'c';
  465. printf(pr->fmt, *p);
  466. } else {
  467. char buf[4];
  468. /* gcc-8.0.1 needs lots of casts to shut up */
  469. sprintf(buf, "%03o", (unsigned)(uint8_t)*p);
  470. str = buf;
  471. strpr:
  472. *pr->cchar = 's';
  473. printf(pr->fmt, str);
  474. }
  475. }
  476. static void conv_u(PR *pr, unsigned char *p)
  477. {
  478. static const char list[] ALIGN1 =
  479. "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
  480. "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
  481. "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
  482. "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
  483. /* od used nl, not lf */
  484. if (*p <= 0x1f) {
  485. *pr->cchar = 's';
  486. printf(pr->fmt, list + (4 * (int)*p));
  487. } else if (*p == 0x7f) {
  488. *pr->cchar = 's';
  489. printf(pr->fmt, "del");
  490. } else if (*p < 0x7f) { /* isprint() */
  491. *pr->cchar = 'c';
  492. printf(pr->fmt, *p);
  493. } else {
  494. *pr->cchar = 'x';
  495. printf(pr->fmt, (int) *p);
  496. }
  497. }
  498. static void display(priv_dumper_t* dumper)
  499. {
  500. unsigned char *bp;
  501. unsigned char savech = '\0';
  502. while ((bp = get(dumper)) != NULL) {
  503. FS *fs;
  504. unsigned char *savebp;
  505. off_t saveaddress;
  506. fs = dumper->pub.fshead;
  507. savebp = bp;
  508. saveaddress = dumper->address;
  509. for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) {
  510. FU *fu;
  511. for (fu = fs->nextfu; fu; fu = fu->nextfu) {
  512. int cnt;
  513. if (fu->flags & F_IGNORE) {
  514. break;
  515. }
  516. for (cnt = fu->reps; cnt; --cnt) {
  517. PR *pr;
  518. for (pr = fu->nextpr; pr; dumper->address += pr->bcnt,
  519. bp += pr->bcnt, pr = pr->nextpr) {
  520. if (dumper->eaddress
  521. && dumper->address >= dumper->eaddress
  522. ) {
  523. if (dumper->pub.eofstring) {
  524. /* xxd support: requested to not pad incomplete blocks */
  525. fputs(dumper->pub.eofstring, stdout);
  526. return;
  527. }
  528. if (!(pr->flags & (F_TEXT | F_BPAD)))
  529. bpad(pr);
  530. }
  531. if (cnt == 1 && pr->nospace) {
  532. savech = *pr->nospace;
  533. *pr->nospace = '\0';
  534. }
  535. switch (pr->flags) {
  536. case F_ADDRESS:
  537. printf(pr->fmt, (unsigned) dumper->address);
  538. break;
  539. case F_BPAD:
  540. printf(pr->fmt, "");
  541. break;
  542. case F_C:
  543. conv_c(pr, bp);
  544. break;
  545. case F_CHAR:
  546. printf(pr->fmt, *bp);
  547. break;
  548. case F_DBL: {
  549. double dval;
  550. float fval;
  551. switch (pr->bcnt) {
  552. case 4:
  553. memcpy(&fval, bp, sizeof(fval));
  554. printf(pr->fmt, fval);
  555. break;
  556. case 8:
  557. memcpy(&dval, bp, sizeof(dval));
  558. printf(pr->fmt, dval);
  559. break;
  560. }
  561. break;
  562. }
  563. case F_INT: {
  564. int ival;
  565. short sval;
  566. switch (pr->bcnt) {
  567. case 1:
  568. printf(pr->fmt, (int) *bp);
  569. break;
  570. case 2:
  571. memcpy(&sval, bp, sizeof(sval));
  572. printf(pr->fmt, (int) sval);
  573. break;
  574. case 4:
  575. memcpy(&ival, bp, sizeof(ival));
  576. printf(pr->fmt, ival);
  577. break;
  578. }
  579. break;
  580. }
  581. case F_P:
  582. printf(pr->fmt, isprint_asciionly(*bp) ? *bp : '.');
  583. break;
  584. case F_STR:
  585. printf(pr->fmt, (char *) bp);
  586. break;
  587. case F_TEXT:
  588. printf(pr->fmt);
  589. break;
  590. case F_U:
  591. conv_u(pr, bp);
  592. break;
  593. case F_UINT: {
  594. unsigned ival;
  595. unsigned short sval;
  596. switch (pr->bcnt) {
  597. case 1:
  598. printf(pr->fmt, (unsigned) *bp);
  599. break;
  600. case 2:
  601. memcpy(&sval, bp, sizeof(sval));
  602. printf(pr->fmt, (unsigned) sval);
  603. break;
  604. case 4:
  605. memcpy(&ival, bp, sizeof(ival));
  606. printf(pr->fmt, ival);
  607. break;
  608. }
  609. break;
  610. }
  611. }
  612. if (cnt == 1 && pr->nospace) {
  613. *pr->nospace = savech;
  614. }
  615. }
  616. }
  617. }
  618. }
  619. }
  620. if (dumper->endfu) {
  621. PR *pr;
  622. /*
  623. * if eaddress not set, error or file size was multiple
  624. * of blocksize, and no partial block ever found.
  625. */
  626. if (!dumper->eaddress) {
  627. if (!dumper->address) {
  628. return;
  629. }
  630. dumper->eaddress = dumper->address;
  631. }
  632. for (pr = dumper->endfu->nextpr; pr; pr = pr->nextpr) {
  633. switch (pr->flags) {
  634. case F_ADDRESS:
  635. printf(pr->fmt, (unsigned) dumper->eaddress);
  636. break;
  637. case F_TEXT:
  638. printf(pr->fmt);
  639. break;
  640. }
  641. }
  642. }
  643. }
  644. #define dumper ((priv_dumper_t*)pub_dumper)
  645. int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv)
  646. {
  647. FS *tfs;
  648. int blocksize;
  649. /* figure out the data block size */
  650. blocksize = 0;
  651. tfs = dumper->pub.fshead;
  652. while (tfs) {
  653. tfs->bcnt = bb_dump_size(tfs);
  654. if (blocksize < tfs->bcnt) {
  655. blocksize = tfs->bcnt;
  656. }
  657. tfs = tfs->nextfs;
  658. }
  659. dumper->blocksize = blocksize;
  660. /* rewrite the rules, do syntax checking */
  661. for (tfs = dumper->pub.fshead; tfs; tfs = tfs->nextfs) {
  662. rewrite(dumper, tfs);
  663. }
  664. dumper->argv = argv;
  665. display(dumper);
  666. return dumper->exitval;
  667. }
  668. void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
  669. {
  670. const char *p;
  671. FS *tfs;
  672. FU **nextfupp;
  673. /* start new linked list of format units */
  674. tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
  675. if (!dumper->pub.fshead) {
  676. dumper->pub.fshead = tfs;
  677. } else {
  678. FS *fslast = dumper->pub.fshead;
  679. while (fslast->nextfs)
  680. fslast = fslast->nextfs;
  681. fslast->nextfs = tfs;
  682. }
  683. nextfupp = &tfs->nextfu;
  684. /* take the format string and break it up into format units */
  685. p = fmt;
  686. for (;;) {
  687. FU *tfu;
  688. const char *savep;
  689. p = skip_whitespace(p);
  690. if (*p == '\0') {
  691. break;
  692. }
  693. /* allocate a new format unit and link it in */
  694. /* NOSTRICT */
  695. /* DBU:[dave@cray.com] zalloc so that forward pointers start out NULL */
  696. tfu = xzalloc(sizeof(FU));
  697. *nextfupp = tfu;
  698. nextfupp = &tfu->nextfu;
  699. tfu->reps = 1;
  700. /* if leading digit, repetition count */
  701. if (isdigit(*p)) {
  702. for (savep = p; isdigit(*p); ++p)
  703. continue;
  704. if (!isspace(*p) && *p != '/') {
  705. bb_error_msg_and_die("bad format {%s}", fmt);
  706. }
  707. /* may overwrite either white space or slash */
  708. tfu->reps = atoi(savep);
  709. tfu->flags = F_SETREP;
  710. /* skip trailing white space */
  711. p = skip_whitespace(++p);
  712. }
  713. /* skip slash and trailing white space */
  714. if (*p == '/') {
  715. p = skip_whitespace(p + 1);
  716. }
  717. /* byte count */
  718. if (isdigit(*p)) {
  719. // TODO: use bb_strtou
  720. savep = p;
  721. while (isdigit(*++p))
  722. continue;
  723. if (!isspace(*p)) {
  724. bb_error_msg_and_die("bad format {%s}", fmt);
  725. }
  726. // Above check prohibits formats such as '/1"%02x"' - it requires space after 1.
  727. // Other than this, formats can be pretty much jammed together:
  728. // "%07_ax:"8/2 "%04x|""\n"
  729. // but this space is required. The check *can* be removed, but
  730. // keeping it to stay compat with util-linux hexdump.
  731. tfu->bcnt = atoi(savep);
  732. /* skip trailing white space */
  733. p = skip_whitespace(p + 1);
  734. }
  735. /* format */
  736. if (*p != '"') {
  737. bb_error_msg_and_die("bad format {%s}", fmt);
  738. }
  739. for (savep = ++p; *p != '"';) {
  740. if (*p++ == '\0') {
  741. bb_error_msg_and_die("bad format {%s}", fmt);
  742. }
  743. }
  744. tfu->fmt = xstrndup(savep, p - savep);
  745. /* alphabetic escape sequences have to be done in place */
  746. strcpy_and_process_escape_sequences(tfu->fmt, tfu->fmt);
  747. /* unknown mappings are not changed: "\z" -> '\\' 'z' */
  748. /* trailing backslash, if any, is preserved */
  749. #if 0
  750. char *p1;
  751. char *p2;
  752. p1 = tfu->fmt;
  753. for (p2 = p1;; ++p1, ++p2) {
  754. *p2 = *p1;
  755. if (*p1 == '\0')
  756. break;
  757. if (*p1 == '\\') {
  758. const char *cs;
  759. p1++;
  760. *p2 = *p1;
  761. if (*p1 == '\0') {
  762. /* "...\" trailing backslash. Eaten. */
  763. break;
  764. }
  765. cs = conv_str + 4; /* skip NUL element */
  766. do {
  767. /* map e.g. "\n" -> '\n' */
  768. if (*p1 == cs[2]) {
  769. *p2 = cs[0];
  770. break;
  771. }
  772. cs += 4;
  773. } while (*cs);
  774. /* unknown mappings remove bkslash: "\z" -> 'z' */
  775. }
  776. }
  777. #endif
  778. p++;
  779. }
  780. }
  781. /*
  782. * Copyright (c) 1989 The Regents of the University of California.
  783. * All rights reserved.
  784. *
  785. * Redistribution and use in source and binary forms, with or without
  786. * modification, are permitted provided that the following conditions
  787. * are met:
  788. * 1. Redistributions of source code must retain the above copyright
  789. * notice, this list of conditions and the following disclaimer.
  790. * 2. Redistributions in binary form must reproduce the above copyright
  791. * notice, this list of conditions and the following disclaimer in the
  792. * documentation and/or other materials provided with the distribution.
  793. * 3. Neither the name of the University nor the names of its contributors
  794. * may be used to endorse or promote products derived from this software
  795. * without specific prior written permission.
  796. *
  797. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND
  798. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  799. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  800. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  801. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  802. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  803. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  804. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  805. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  806. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  807. * SUCH DAMAGE.
  808. */