blob: 1afad83fdce00eb15e2a6235a63fca98caeb5c43 [file] [log] [blame]
Glenn L McGrath60281112001-11-02 11:39:46 +00001/*
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 <ctype.h> /* for isdigit() */
28#include "dump.h"
29#include "libbb.h"
30
31enum _vflag vflag = FIRST;
32FS *fshead; /* head of format strings */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000033extern FS *fshead; /* head of format strings */
Glenn L McGrath60281112001-11-02 11:39:46 +000034extern int blocksize;
35static FU *endfu;
36static char **_argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000037static off_t savaddress; /* saved address/offset in stream */
38static off_t eaddress; /* end address */
39static off_t address; /* address/offset in stream */
40off_t skip; /* bytes to skip */
Glenn L McGrath60281112001-11-02 11:39:46 +000041off_t saveaddress;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000042int exitval; /* final exit value */
43int blocksize; /* data block size */
44int length = -1; /* max bytes to read */
Glenn L McGrath60281112001-11-02 11:39:46 +000045
46
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000047int size(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000048{
49 register FU *fu;
50 register int bcnt, cursize;
51 register char *fmt;
52 int prec;
53
54 /* figure out the data block size needed for each format unit */
55 for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
56 if (fu->bcnt) {
57 cursize += fu->bcnt * fu->reps;
58 continue;
59 }
60 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
61 if (*fmt != '%')
62 continue;
63 /*
64 * skip any special chars -- save precision in
65 * case it's a %s format.
66 */
67 while (index(".#-+ 0123456789" + 1, *++fmt));
68 if (*fmt == '.' && isdigit(*++fmt)) {
69 prec = atoi(fmt);
70 while (isdigit(*++fmt));
71 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000072 switch (*fmt) {
Glenn L McGrath60281112001-11-02 11:39:46 +000073 case 'c':
74 bcnt += 1;
75 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000076 case 'd':
77 case 'i':
78 case 'o':
79 case 'u':
80 case 'x':
81 case 'X':
Glenn L McGrath60281112001-11-02 11:39:46 +000082 bcnt += 4;
83 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000084 case 'e':
85 case 'E':
86 case 'f':
87 case 'g':
88 case 'G':
Glenn L McGrath60281112001-11-02 11:39:46 +000089 bcnt += 8;
90 break;
91 case 's':
92 bcnt += prec;
93 break;
94 case '_':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000095 switch (*++fmt) {
96 case 'c':
97 case 'p':
98 case 'u':
Glenn L McGrath60281112001-11-02 11:39:46 +000099 bcnt += 1;
100 break;
101 }
102 }
103 }
104 cursize += bcnt * fu->reps;
105 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000106 return (cursize);
Glenn L McGrath60281112001-11-02 11:39:46 +0000107}
108
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000109void rewrite(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +0000110{
111 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
112 register PR *pr, **nextpr = NULL;
113 register FU *fu;
114 register char *p1, *p2;
115 char savech, *fmtp;
116 int nconv, prec = 0;
117
118 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
119 /*
120 * break each format unit into print units; each
121 * conversion character gets its own.
122 */
123 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
124 /* NOSTRICT */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000125 pr = (PR *) xmalloc(sizeof(PR));
Glenn L McGrath60281112001-11-02 11:39:46 +0000126 if (!fu->nextpr)
127 fu->nextpr = pr;
128 else
129 *nextpr = pr;
130
131 /* skip preceding text and up to the next % sign */
132 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
133
134 /* only text in the string */
135 if (!*p1) {
136 pr->fmt = fmtp;
137 pr->flags = F_TEXT;
138 break;
139 }
140
141 /*
142 * get precision for %s -- if have a byte count, don't
143 * need it.
144 */
145 if (fu->bcnt) {
146 sokay = USEBCNT;
147 /* skip to conversion character */
148 for (++p1; index(".#-+ 0123456789", *p1); ++p1);
149 } else {
150 /* skip any special chars, field width */
151 while (index(".#-+ 0123456789" + 1, *++p1));
152 if (*p1 == '.' && isdigit(*++p1)) {
153 sokay = USEPREC;
154 prec = atoi(p1);
155 while (isdigit(*++p1));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000156 } else
Glenn L McGrath60281112001-11-02 11:39:46 +0000157 sokay = NOTOKAY;
158 }
159
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000160 p2 = p1 + 1; /* set end pointer */
Glenn L McGrath60281112001-11-02 11:39:46 +0000161
162 /*
163 * figure out the byte count for each conversion;
164 * rewrite the format as necessary, set up blank-
165 * padding for end of data.
166 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000167 switch (*p1) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000168 case 'c':
169 pr->flags = F_CHAR;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000170 switch (fu->bcnt) {
171 case 0:
172 case 1:
Glenn L McGrath60281112001-11-02 11:39:46 +0000173 pr->bcnt = 1;
174 break;
175 default:
176 p1[1] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000177 error_msg_and_die
178 ("bad byte count for conversion character %s.", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000179 }
180 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000181 case 'd':
182 case 'i':
Glenn L McGrath60281112001-11-02 11:39:46 +0000183 pr->flags = F_INT;
184 goto sw1;
185 case 'l':
186 ++p2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000187 switch (p1[1]) {
188 case 'd':
189 case 'i':
Glenn L McGrath60281112001-11-02 11:39:46 +0000190 ++p1;
191 pr->flags = F_INT;
192 goto sw1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000193 case 'o':
194 case 'u':
195 case 'x':
196 case 'X':
Glenn L McGrath60281112001-11-02 11:39:46 +0000197 ++p1;
198 pr->flags = F_UINT;
199 goto sw1;
200 default:
201 p1[2] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000202 error_msg_and_die
203 ("hexdump: bad conversion character %%%s.\n", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000204 }
205 /* NOTREACHED */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000206 case 'o':
207 case 'u':
208 case 'x':
209 case 'X':
Glenn L McGrath60281112001-11-02 11:39:46 +0000210 pr->flags = F_UINT;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000211 sw1:switch (fu->bcnt) {
212 case 0:
213 case 4:
Glenn L McGrath60281112001-11-02 11:39:46 +0000214 pr->bcnt = 4;
215 break;
216 case 1:
217 pr->bcnt = 1;
218 break;
219 case 2:
220 pr->bcnt = 2;
221 break;
222 default:
223 p1[1] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000224 error_msg_and_die
225 ("bad byte count for conversion character %s.", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000226 }
227 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000228 case 'e':
229 case 'E':
230 case 'f':
231 case 'g':
232 case 'G':
Glenn L McGrath60281112001-11-02 11:39:46 +0000233 pr->flags = F_DBL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000234 switch (fu->bcnt) {
235 case 0:
236 case 8:
Glenn L McGrath60281112001-11-02 11:39:46 +0000237 pr->bcnt = 8;
238 break;
239 case 4:
240 pr->bcnt = 4;
241 break;
242 default:
243 p1[1] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000244 error_msg_and_die
245 ("bad byte count for conversion character %s.", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000246 }
247 break;
248 case 's':
249 pr->flags = F_STR;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000250 switch (sokay) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000251 case NOTOKAY:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000252 error_msg_and_die
253 ("%%s requires a precision or a byte count.");
Glenn L McGrath60281112001-11-02 11:39:46 +0000254 case USEBCNT:
255 pr->bcnt = fu->bcnt;
256 break;
257 case USEPREC:
258 pr->bcnt = prec;
259 break;
260 }
261 break;
262 case '_':
263 ++p2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000264 switch (p1[1]) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000265 case 'A':
266 endfu = fu;
267 fu->flags |= F_IGNORE;
268 /* FALLTHROUGH */
269 case 'a':
270 pr->flags = F_ADDRESS;
271 ++p2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000272 switch (p1[2]) {
273 case 'd':
274 case 'o':
275 case 'x':
Glenn L McGrath60281112001-11-02 11:39:46 +0000276 *p1 = p1[2];
277 break;
278 default:
279 p1[3] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000280 error_msg_and_die
281 ("hexdump: bad conversion character %%%s.\n", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000282 }
283 break;
284 case 'c':
285 pr->flags = F_C;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000286 /* *p1 = 'c'; set in conv_c */
Glenn L McGrath60281112001-11-02 11:39:46 +0000287 goto sw2;
288 case 'p':
289 pr->flags = F_P;
290 *p1 = 'c';
291 goto sw2;
292 case 'u':
293 pr->flags = F_U;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000294 /* *p1 = 'c'; set in conv_u */
295 sw2:switch (fu->bcnt) {
296 case 0:
297 case 1:
Glenn L McGrath60281112001-11-02 11:39:46 +0000298 pr->bcnt = 1;
299 break;
300 default:
301 p1[2] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000302 error_msg_and_die
303 ("bad byte count for conversion character %s.",
304 p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000305 }
306 break;
307 default:
308 p1[2] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000309 error_msg_and_die
310 ("hexdump: bad conversion character %%%s.\n", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000311 }
312 break;
313 default:
314 p1[1] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000315 error_msg_and_die("hexdump: bad conversion character %%%s.\n",
316 p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000317 }
318
319 /*
320 * copy to PR format string, set conversion character
321 * pointer, update original.
322 */
323 savech = *p2;
324 p1[1] = '\0';
325 if (!(pr->fmt = strdup(fmtp)))
326 perror_msg_and_die("hexdump");
327 *p2 = savech;
328 pr->cchar = pr->fmt + (p1 - fmtp);
329 fmtp = p2;
330
331 /* only one conversion character if byte count */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000332 if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
333 error_msg_and_die
334 ("hexdump: byte count with multiple conversion characters.\n");
Glenn L McGrath60281112001-11-02 11:39:46 +0000335 }
336 }
337 /*
338 * if format unit byte count not specified, figure it out
339 * so can adjust rep count later.
340 */
341 if (!fu->bcnt)
342 for (pr = fu->nextpr; pr; pr = pr->nextpr)
343 fu->bcnt += pr->bcnt;
344 }
345 /*
346 * if the format string interprets any data at all, and it's
347 * not the same as the blocksize, and its last format unit
348 * interprets any data at all, and has no iteration count,
349 * repeat it as necessary.
350 *
351 * if, rep count is greater than 1, no trailing whitespace
352 * gets output from the last iteration of the format unit.
353 */
354 for (fu = fs->nextfu;; fu = fu->nextfu) {
355 if (!fu->nextfu && fs->bcnt < blocksize &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000356 !(fu->flags & F_SETREP) && fu->bcnt)
Glenn L McGrath60281112001-11-02 11:39:46 +0000357 fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
358 if (fu->reps > 1) {
359 for (pr = fu->nextpr;; pr = pr->nextpr)
360 if (!pr->nextpr)
361 break;
362 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
363 p2 = isspace(*p1) ? p1 : NULL;
364 if (p2)
365 pr->nospace = p2;
366 }
367 if (!fu->nextfu)
368 break;
369 }
370}
371
372static void doskip(char *fname, int statok)
373{
374 struct stat sbuf;
375
376 if (statok) {
377 if (fstat(fileno(stdin), &sbuf)) {
378 perror_msg_and_die("hexdump: %s", fname);
379 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000380 if ((!(S_ISCHR(sbuf.st_mode) ||
381 S_ISBLK(sbuf.st_mode) ||
382 S_ISFIFO(sbuf.st_mode))) && skip >= sbuf.st_size) {
383 /* If size valid and skip >= size */
Glenn L McGrath60281112001-11-02 11:39:46 +0000384 skip -= sbuf.st_size;
385 address += sbuf.st_size;
386 return;
387 }
388 }
389 if (fseek(stdin, skip, SEEK_SET)) {
390 perror_msg_and_die("hexdump: %s", fname);
391 }
392 savaddress = address += skip;
393 skip = 0;
394}
395
396int next(char **argv)
397{
398 static int done;
399 int statok;
400
401 if (argv) {
402 _argv = argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000403 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000404 }
405 for (;;) {
406 if (*_argv) {
407 if (!(freopen(*_argv, "r", stdin))) {
408 perror_msg("%s", *_argv);
409 exitval = 1;
410 ++_argv;
411 continue;
412 }
413 statok = done = 1;
414 } else {
415 if (done++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000416 return (0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000417 statok = 0;
418 }
419 if (skip)
420 doskip(statok ? *_argv : "stdin", statok);
421 if (*_argv)
422 ++_argv;
423 if (!skip)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000424 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000425 }
426 /* NOTREACHED */
427}
428
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000429static u_char *get(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000430{
431 static int ateof = 1;
432 static u_char *curp, *savp;
433 register int n;
434 int need, nread;
435 u_char *tmpp;
436
437 if (!curp) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000438 curp = (u_char *) xmalloc(blocksize);
439 savp = (u_char *) xmalloc(blocksize);
Glenn L McGrath60281112001-11-02 11:39:46 +0000440 } else {
441 tmpp = curp;
442 curp = savp;
443 savp = tmpp;
444 address = savaddress += blocksize;
445 }
446 for (need = blocksize, nread = 0;;) {
447 /*
448 * if read the right number of bytes, or at EOF for one file,
449 * and no other files are available, zero-pad the rest of the
450 * block and set the end flag.
451 */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000452 if (!length || (ateof && !next((char **) NULL))) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000453 if (need == blocksize) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000454 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000455 }
456 if (vflag != ALL && !bcmp(curp, savp, nread)) {
457 if (vflag != DUP) {
458 printf("*\n");
459 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000460 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000461 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000462 bzero((char *) curp + nread, need);
Glenn L McGrath60281112001-11-02 11:39:46 +0000463 eaddress = address + nread;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000464 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000465 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000466 n = fread((char *) curp + nread, sizeof(u_char),
467 length == -1 ? need : MIN(length, need), stdin);
Glenn L McGrath60281112001-11-02 11:39:46 +0000468 if (!n) {
469 if (ferror(stdin)) {
470 perror_msg("%s", _argv[-1]);
471 }
472 ateof = 1;
473 continue;
474 }
475 ateof = 0;
476 if (length != -1) {
477 length -= n;
478 }
479 if (!(need -= n)) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000480 if (vflag == ALL || vflag == FIRST || bcmp(curp, savp, blocksize)) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000481 if (vflag == DUP || vflag == FIRST) {
482 vflag = WAIT;
483 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000484 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000485 }
486 if (vflag == WAIT) {
487 printf("*\n");
488 }
489 vflag = DUP;
490 address = savaddress += blocksize;
491 need = blocksize;
492 nread = 0;
493 } else {
494 nread += n;
495 }
496 }
497}
498
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000499static void bpad(PR * pr)
Glenn L McGrath60281112001-11-02 11:39:46 +0000500{
501 register char *p1, *p2;
502
503 /*
504 * remove all conversion flags; '-' is the only one valid
505 * with %s, and it's not useful here.
506 */
507 pr->flags = F_BPAD;
508 *pr->cchar = 's';
509 for (p1 = pr->fmt; *p1 != '%'; ++p1);
510 for (p2 = ++p1; *p1 && index(" -0+#", *p1); ++p1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000511 while ((*p2++ = *p1++) != 0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000512}
513
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000514void conv_c(PR * pr, u_char * p)
Glenn L McGrath60281112001-11-02 11:39:46 +0000515{
516 char buf[10], *str;
517
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000518 switch (*p) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000519 case '\0':
520 str = "\\0";
521 goto strpr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000522 /* case '\a': */
Glenn L McGrath60281112001-11-02 11:39:46 +0000523 case '\007':
524 str = "\\a";
525 goto strpr;
526 case '\b':
527 str = "\\b";
528 goto strpr;
529 case '\f':
530 str = "\\f";
531 goto strpr;
532 case '\n':
533 str = "\\n";
534 goto strpr;
535 case '\r':
536 str = "\\r";
537 goto strpr;
538 case '\t':
539 str = "\\t";
540 goto strpr;
541 case '\v':
542 str = "\\v";
543 goto strpr;
544 default:
545 break;
546 }
547 if (isprint(*p)) {
548 *pr->cchar = 'c';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000549 (void) printf(pr->fmt, *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000550 } else {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000551 sprintf(str = buf, "%03o", (int) *p);
552 strpr:
Glenn L McGrath60281112001-11-02 11:39:46 +0000553 *pr->cchar = 's';
554 printf(pr->fmt, str);
555 }
556}
557
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000558void conv_u(PR * pr, u_char * p)
Glenn L McGrath60281112001-11-02 11:39:46 +0000559{
560 static char *list[] = {
561 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000562 "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
Glenn L McGrath60281112001-11-02 11:39:46 +0000563 "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb",
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000564 "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
Glenn L McGrath60281112001-11-02 11:39:46 +0000565 };
566
567 /* od used nl, not lf */
568 if (*p <= 0x1f) {
569 *pr->cchar = 's';
570 printf(pr->fmt, list[*p]);
571 } else if (*p == 0x7f) {
572 *pr->cchar = 's';
573 printf(pr->fmt, "del");
574 } else if (isprint(*p)) {
575 *pr->cchar = 'c';
576 printf(pr->fmt, *p);
577 } else {
578 *pr->cchar = 'x';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000579 printf(pr->fmt, (int) *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000580 }
581}
582
583void display(void)
584{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000585/* extern FU *endfu; */
Glenn L McGrath60281112001-11-02 11:39:46 +0000586 register FS *fs;
587 register FU *fu;
588 register PR *pr;
589 register int cnt;
590 register u_char *bp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000591
592/* off_t saveaddress; */
Glenn L McGrath60281112001-11-02 11:39:46 +0000593 u_char savech = 0, *savebp;
594
595 while ((bp = get()) != NULL) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000596 for (fs = fshead, savebp = bp, saveaddress = address; fs;
597 fs = fs->nextfs, bp = savebp, address = saveaddress) {
598 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000599 if (fu->flags & F_IGNORE) {
600 break;
601 }
602 for (cnt = fu->reps; cnt; --cnt) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000603 for (pr = fu->nextpr; pr; address += pr->bcnt,
604 bp += pr->bcnt, pr = pr->nextpr) {
605 if (eaddress && address >= eaddress &&
606 !(pr->flags & (F_TEXT | F_BPAD))) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000607 bpad(pr);
608 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000609 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000610 savech = *pr->nospace;
611 *pr->nospace = '\0';
Glenn L McGrath60281112001-11-02 11:39:46 +0000612 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000613/* PRINT; */
614 switch (pr->flags) {
615 case F_ADDRESS:
616 printf(pr->fmt, address);
617 break;
618 case F_BPAD:
619 printf(pr->fmt, "");
620 break;
621 case F_C:
622 conv_c(pr, bp);
623 break;
624 case F_CHAR:
625 printf(pr->fmt, *bp);
626 break;
627 case F_DBL:{
628 double dval;
629 float fval;
630
631 switch (pr->bcnt) {
632 case 4:
633 bcopy((char *) bp, (char *) &fval,
634 sizeof(fval));
635 printf(pr->fmt, fval);
636 break;
637 case 8:
638 bcopy((char *) bp, (char *) &dval,
639 sizeof(dval));
640 printf(pr->fmt, dval);
641 break;
642 }
643 break;
644 }
645 case F_INT:{
646 int ival;
647 short sval;
648
649 switch (pr->bcnt) {
650 case 1:
651 printf(pr->fmt, (int) *bp);
652 break;
653 case 2:
654 bcopy((char *) bp, (char *) &sval,
655 sizeof(sval));
656 printf(pr->fmt, (int) sval);
657 break;
658 case 4:
659 bcopy((char *) bp, (char *) &ival,
660 sizeof(ival));
661 printf(pr->fmt, ival);
662 break;
663 }
664 break;
665 }
666 case F_P:
667 printf(pr->fmt, isprint(*bp) ? *bp : '.');
668 break;
669 case F_STR:
670 printf(pr->fmt, (char *) bp);
671 break;
672 case F_TEXT:
673 printf(pr->fmt);
674 break;
675 case F_U:
676 conv_u(pr, bp);
677 break;
678 case F_UINT:{
679 u_int ival;
680 u_short sval;
681
682 switch (pr->bcnt) {
683 case 1:
684 printf(pr->fmt, (u_int) * bp);
685 break;
686 case 2:
687 bcopy((char *) bp, (char *) &sval,
688 sizeof(sval));
689 printf(pr->fmt, (u_int) sval);
690 break;
691 case 4:
692 bcopy((char *) bp, (char *) &ival,
693 sizeof(ival));
694 printf(pr->fmt, ival);
695 break;
696 }
697 break;
698 }
699 }
700 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000701 *pr->nospace = savech;
702 }
703 }
704 }
705 }
706 }
707 }
708 if (endfu) {
709 /*
710 * if eaddress not set, error or file size was multiple of
711 * blocksize, and no partial block ever found.
712 */
713 if (!eaddress) {
714 if (!address) {
715 return;
716 }
717 eaddress = address;
718 }
719 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000720 switch (pr->flags) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000721 case F_ADDRESS:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000722 (void) printf(pr->fmt, eaddress);
Glenn L McGrath60281112001-11-02 11:39:46 +0000723 break;
724 case F_TEXT:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000725 (void) printf(pr->fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000726 break;
727 }
728 }
729 }
730}
731
732int dump(char **argv)
733{
734 register FS *tfs;
735
736 /* figure out the data block size */
737 for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) {
738 tfs->bcnt = size(tfs);
739 if (blocksize < tfs->bcnt) {
740 blocksize = tfs->bcnt;
741 }
742 }
743 /* rewrite the rules, do syntax checking */
744 for (tfs = fshead; tfs; tfs = tfs->nextfs) {
745 rewrite(tfs);
746 }
747
748 next(argv);
749 display();
750
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000751 return (exitval);
Glenn L McGrath60281112001-11-02 11:39:46 +0000752}
753
754void add(char *fmt)
755{
756 register char *p;
757 register char *p1;
758 register char *p2;
759 static FS **nextfs;
760 FS *tfs;
761 FU *tfu, **nextfu;
762 char *savep;
763
764 /* start new linked list of format units */
765 /* NOSTRICT */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000766 tfs = (FS *) xmalloc(sizeof(FS));
Glenn L McGrath60281112001-11-02 11:39:46 +0000767 if (!fshead) {
768 fshead = tfs;
769 } else {
770 *nextfs = tfs;
771 }
772 nextfs = &tfs->nextfs;
773 nextfu = &tfs->nextfu;
774
775 /* take the format string and break it up into format units */
776 for (p = fmt;;) {
777 /* skip leading white space */
778 for (; isspace(*p); ++p);
779 if (!*p) {
780 break;
781 }
782
783 /* allocate a new format unit and link it in */
784 /* NOSTRICT */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000785 tfu = (FU *) xmalloc(sizeof(FU));
Glenn L McGrath60281112001-11-02 11:39:46 +0000786 *nextfu = tfu;
787 nextfu = &tfu->nextfu;
788 tfu->reps = 1;
789
790 /* if leading digit, repetition count */
791 if (isdigit(*p)) {
792 for (savep = p; isdigit(*p); ++p);
793 if (!isspace(*p) && *p != '/') {
794 error_msg_and_die("hexdump: bad format {%s}", fmt);
795 }
796 /* may overwrite either white space or slash */
797 tfu->reps = atoi(savep);
798 tfu->flags = F_SETREP;
799 /* skip trailing white space */
800 for (++p; isspace(*p); ++p);
801 }
802
803 /* skip slash and trailing white space */
804 if (*p == '/') {
805 while (isspace(*++p));
806 }
807
808 /* byte count */
809 if (isdigit(*p)) {
810 for (savep = p; isdigit(*p); ++p);
811 if (!isspace(*p)) {
812 error_msg_and_die("hexdump: bad format {%s}", fmt);
813 }
814 tfu->bcnt = atoi(savep);
815 /* skip trailing white space */
816 for (++p; isspace(*p); ++p);
817 }
818
819 /* format */
820 if (*p != '"') {
821 error_msg_and_die("hexdump: bad format {%s}", fmt);
822 }
823 for (savep = ++p; *p != '"';) {
824 if (*p++ == 0) {
825 error_msg_and_die("hexdump: bad format {%s}", fmt);
826 }
827 }
828 if (!(tfu->fmt = malloc(p - savep + 1))) {
829 perror_msg_and_die("hexdump");
830 }
831 strncpy(tfu->fmt, savep, p - savep);
832 tfu->fmt[p - savep] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000833/* escape(tfu->fmt); */
Glenn L McGrath60281112001-11-02 11:39:46 +0000834
835 p1 = tfu->fmt;
836
837 /* alphabetic escape sequences have to be done in place */
838 for (p2 = p1;; ++p1, ++p2) {
839 if (!*p1) {
840 *p2 = *p1;
841 break;
842 }
843 if (*p1 == '\\') {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000844 switch (*++p1) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000845 case 'a':
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000846 /* *p2 = '\a'; */
Glenn L McGrath60281112001-11-02 11:39:46 +0000847 *p2 = '\007';
848 break;
849 case 'b':
850 *p2 = '\b';
851 break;
852 case 'f':
853 *p2 = '\f';
854 break;
855 case 'n':
856 *p2 = '\n';
857 break;
858 case 'r':
859 *p2 = '\r';
860 break;
861 case 't':
862 *p2 = '\t';
863 break;
864 case 'v':
865 *p2 = '\v';
866 break;
867 default:
868 *p2 = *p1;
869 break;
870 }
871 }
872 }
873
874 p++;
875 }
876}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000877
Glenn L McGrath60281112001-11-02 11:39:46 +0000878/*
879 * Copyright (c) 1989 The Regents of the University of California.
880 * All rights reserved.
881 *
882 * Redistribution and use in source and binary forms, with or without
883 * modification, are permitted provided that the following conditions
884 * are met:
885 * 1. Redistributions of source code must retain the above copyright
886 * notice, this list of conditions and the following disclaimer.
887 * 2. Redistributions in binary form must reproduce the above copyright
888 * notice, this list of conditions and the following disclaimer in the
889 * documentation and/or other materials provided with the distribution.
Aaron Lehmann69d41782002-06-23 22:25:24 +0000890 * 3. Neither the name of the University nor the names of its contributors
Glenn L McGrath60281112001-11-02 11:39:46 +0000891 * may be used to endorse or promote products derived from this software
892 * without specific prior written permission.
893 *
894 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
895 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
896 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
897 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
898 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
899 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
900 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
901 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
902 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
903 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
904 * SUCH DAMAGE.
905 */