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