dump.c 20 KB

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