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