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