blob: 45ddb403409dbce48f7ac42032da04688633ed32 [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 *
Bernhard Reutner-Fischer30385572006-01-31 17:57:48 +00008 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGrath60281112001-11-02 11:39:46 +00009 *
10 * Original copyright notice is retained at the end of this file.
11 */
12
Rob Landleyea224be2006-06-18 20:20:07 +000013#include "libbb.h"
Glenn L McGrath60281112001-11-02 11:39:46 +000014#include <string.h>
Eric Andersen8ee2b272004-03-27 11:26:32 +000015#include <unistd.h>
Glenn L McGrath60281112001-11-02 11:39:46 +000016#include <ctype.h> /* for isdigit() */
Manuel Novoa III cad53642003-03-19 09:13:01 +000017#include "dump.h"
Glenn L McGrath60281112001-11-02 11:39:46 +000018
Manuel Novoa III cad53642003-03-19 09:13:01 +000019enum _vflag bb_dump_vflag = FIRST;
20FS *bb_dump_fshead; /* head of format strings */
Glenn L McGrath60281112001-11-02 11:39:46 +000021static FU *endfu;
22static char **_argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000023static off_t savaddress; /* saved address/offset in stream */
24static off_t eaddress; /* end address */
25static off_t address; /* address/offset in stream */
Manuel Novoa III cad53642003-03-19 09:13:01 +000026off_t bb_dump_skip; /* bytes to skip */
27static int exitval; /* final exit value */
28int bb_dump_blocksize; /* data block size */
29int bb_dump_length = -1; /* max bytes to read */
Glenn L McGrath60281112001-11-02 11:39:46 +000030
Manuel Novoa III cad53642003-03-19 09:13:01 +000031static const char index_str[] = ".#-+ 0123456789";
Glenn L McGrath60281112001-11-02 11:39:46 +000032
Manuel Novoa III cad53642003-03-19 09:13:01 +000033static const char size_conv_str[] =
34"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
35
36static const char lcc[] = "diouxX";
37
38int bb_dump_size(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000039{
40 register FU *fu;
Manuel Novoa III cad53642003-03-19 09:13:01 +000041 register int bcnt, cur_size;
Glenn L McGrath60281112001-11-02 11:39:46 +000042 register char *fmt;
Manuel Novoa III cad53642003-03-19 09:13:01 +000043 const char *p;
Glenn L McGrath60281112001-11-02 11:39:46 +000044 int prec;
45
Manuel Novoa III cad53642003-03-19 09:13:01 +000046 /* figure out the data block bb_dump_size needed for each format unit */
47 for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +000048 if (fu->bcnt) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000049 cur_size += fu->bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000050 continue;
51 }
52 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
53 if (*fmt != '%')
54 continue;
55 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +000056 * bb_dump_skip any special chars -- save precision in
Glenn L McGrath60281112001-11-02 11:39:46 +000057 * case it's a %s format.
58 */
Manuel Novoa III cad53642003-03-19 09:13:01 +000059 while (strchr(index_str + 1, *++fmt));
Glenn L McGrath60281112001-11-02 11:39:46 +000060 if (*fmt == '.' && isdigit(*++fmt)) {
61 prec = atoi(fmt);
62 while (isdigit(*++fmt));
63 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000064 if (!(p = strchr(size_conv_str + 12, *fmt))) {
65 if (*fmt == 's') {
66 bcnt += prec;
67 } else if (*fmt == '_') {
68 ++fmt;
69 if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
70 bcnt += 1;
71 }
Glenn L McGrath60281112001-11-02 11:39:46 +000072 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000073 } else {
74 bcnt += size_conv_str[p - (size_conv_str + 12)];
Glenn L McGrath60281112001-11-02 11:39:46 +000075 }
76 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000077 cur_size += bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000078 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000079 return (cur_size);
Glenn L McGrath60281112001-11-02 11:39:46 +000080}
81
Manuel Novoa III cad53642003-03-19 09:13:01 +000082static void rewrite(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000083{
84 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
Rob Landleyea224be2006-06-18 20:20:07 +000085 PR *pr, **nextpr = NULL;
86 FU *fu;
87 char *p1, *p2, *p3;
Glenn L McGrath60281112001-11-02 11:39:46 +000088 char savech, *fmtp;
Manuel Novoa III cad53642003-03-19 09:13:01 +000089 const char *byte_count_str;
Glenn L McGrath60281112001-11-02 11:39:46 +000090 int nconv, prec = 0;
91
92 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
93 /*
94 * break each format unit into print units; each
95 * conversion character gets its own.
96 */
97 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
98 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +000099 /* DBU:[dvae@cray.com] calloc so that forward ptrs start out NULL*/
Rob Landleyea224be2006-06-18 20:20:07 +0000100 pr = xzalloc(sizeof(PR));
Glenn L McGrath60281112001-11-02 11:39:46 +0000101 if (!fu->nextpr)
102 fu->nextpr = pr;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000103 /* ignore nextpr -- its unused inside the loop and is
104 * uninitialized 1st time thru.
105 */
Glenn L McGrath60281112001-11-02 11:39:46 +0000106
Manuel Novoa III cad53642003-03-19 09:13:01 +0000107 /* bb_dump_skip preceding text and up to the next % sign */
Glenn L McGrath60281112001-11-02 11:39:46 +0000108 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
109
110 /* only text in the string */
111 if (!*p1) {
112 pr->fmt = fmtp;
113 pr->flags = F_TEXT;
114 break;
115 }
116
117 /*
118 * get precision for %s -- if have a byte count, don't
119 * need it.
120 */
121 if (fu->bcnt) {
122 sokay = USEBCNT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000123 /* bb_dump_skip to conversion character */
124 for (++p1; strchr(index_str, *p1); ++p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000125 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000126 /* bb_dump_skip any special chars, field width */
127 while (strchr(index_str + 1, *++p1));
Glenn L McGrath60281112001-11-02 11:39:46 +0000128 if (*p1 == '.' && isdigit(*++p1)) {
129 sokay = USEPREC;
130 prec = atoi(p1);
131 while (isdigit(*++p1));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000132 } else
Glenn L McGrath60281112001-11-02 11:39:46 +0000133 sokay = NOTOKAY;
134 }
135
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000136 p2 = p1 + 1; /* set end pointer */
Glenn L McGrath60281112001-11-02 11:39:46 +0000137
138 /*
139 * figure out the byte count for each conversion;
140 * rewrite the format as necessary, set up blank-
Manuel Novoa III cad53642003-03-19 09:13:01 +0000141 * pbb_dump_adding for end of data.
Glenn L McGrath60281112001-11-02 11:39:46 +0000142 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000143
144 if (*p1 == 'c') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000145 pr->flags = F_CHAR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000146 DO_BYTE_COUNT_1:
147 byte_count_str = "\001";
148 DO_BYTE_COUNT:
149 if (fu->bcnt) {
150 do {
151 if (fu->bcnt == *byte_count_str) {
152 break;
153 }
154 } while (*++byte_count_str);
Glenn L McGrath60281112001-11-02 11:39:46 +0000155 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000156 /* Unlike the original, output the remainder of the format string. */
157 if (!*byte_count_str) {
158 bb_error_msg_and_die("bad byte count for conversion character %s.", p1);
159 }
160 pr->bcnt = *byte_count_str;
161 } else if (*p1 == 'l') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000162 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000163 ++p1;
164 DO_INT_CONV:
165 {
166 const char *e;
167 if (!(e = strchr(lcc, *p1))) {
168 goto DO_BAD_CONV_CHAR;
169 }
Glenn L McGrath60281112001-11-02 11:39:46 +0000170 pr->flags = F_INT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000171 if (e > lcc + 1) {
172 pr->flags = F_UINT;
173 }
174 byte_count_str = "\004\002\001";
175 goto DO_BYTE_COUNT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000176 }
177 /* NOTREACHED */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000178 } else if (strchr(lcc, *p1)) {
179 goto DO_INT_CONV;
180 } else if (strchr("eEfgG", *p1)) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000181 pr->flags = F_DBL;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000182 byte_count_str = "\010\004";
183 goto DO_BYTE_COUNT;
184 } else if (*p1 == 's') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000185 pr->flags = F_STR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000186 if (sokay == USEBCNT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000187 pr->bcnt = fu->bcnt;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000188 } else if (sokay == USEPREC) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000189 pr->bcnt = prec;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000190 } else { /* NOTOKAY */
191 bb_error_msg_and_die("%%s requires a precision or a byte count.");
Glenn L McGrath60281112001-11-02 11:39:46 +0000192 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000193 } else if (*p1 == '_') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000194 ++p2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000195 switch (p1[1]) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000196 case 'A':
197 endfu = fu;
198 fu->flags |= F_IGNORE;
199 /* FALLTHROUGH */
200 case 'a':
201 pr->flags = F_ADDRESS;
202 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000203 if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
204 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000205 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000206 *p1 = p1[2];
Glenn L McGrath60281112001-11-02 11:39:46 +0000207 break;
208 case 'c':
209 pr->flags = F_C;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000210 /* *p1 = 'c'; set in conv_c */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000211 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000212 case 'p':
213 pr->flags = F_P;
214 *p1 = 'c';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000215 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000216 case 'u':
217 pr->flags = F_U;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000218 /* *p1 = 'c'; set in conv_u */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000219 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000220 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000221 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000222 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000223 } else {
224 DO_BAD_CONV_CHAR:
225 bb_error_msg_and_die("bad conversion character %%%s.\n", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000226 }
227
228 /*
229 * copy to PR format string, set conversion character
230 * pointer, update original.
231 */
232 savech = *p2;
233 p1[1] = '\0';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000234 pr->fmt = bb_xstrdup(fmtp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000235 *p2 = savech;
236 pr->cchar = pr->fmt + (p1 - fmtp);
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000237
238 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000239 * Skip subsequent text and up to the next % sign and tack the
240 * additional text onto fmt: eg. if fmt is "%x is a HEX number",
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000241 * we lose the " is a HEX number" part of fmt.
242 */
243 for (p3 = p2; *p3 && *p3 != '%'; p3++);
244 if (p3 > p2)
245 {
246 savech = *p3;
247 *p3 = '\0';
Rob Landleyea224be2006-06-18 20:20:07 +0000248 pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1);
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000249 strcat(pr->fmt, p2);
250 *p3 = savech;
251 p2 = p3;
252 }
253
Glenn L McGrath60281112001-11-02 11:39:46 +0000254 fmtp = p2;
255
256 /* only one conversion character if byte count */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000257 if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000258 bb_error_msg_and_die("byte count with multiple conversion characters.\n");
Glenn L McGrath60281112001-11-02 11:39:46 +0000259 }
260 }
261 /*
262 * if format unit byte count not specified, figure it out
263 * so can adjust rep count later.
264 */
265 if (!fu->bcnt)
266 for (pr = fu->nextpr; pr; pr = pr->nextpr)
267 fu->bcnt += pr->bcnt;
268 }
269 /*
270 * if the format string interprets any data at all, and it's
Manuel Novoa III cad53642003-03-19 09:13:01 +0000271 * not the same as the bb_dump_blocksize, and its last format unit
Glenn L McGrath60281112001-11-02 11:39:46 +0000272 * interprets any data at all, and has no iteration count,
273 * repeat it as necessary.
274 *
275 * if, rep count is greater than 1, no trailing whitespace
276 * gets output from the last iteration of the format unit.
277 */
278 for (fu = fs->nextfu;; fu = fu->nextfu) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000279 if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000280 !(fu->flags & F_SETREP) && fu->bcnt)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000281 fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000282 if (fu->reps > 1) {
283 for (pr = fu->nextpr;; pr = pr->nextpr)
284 if (!pr->nextpr)
285 break;
286 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
287 p2 = isspace(*p1) ? p1 : NULL;
288 if (p2)
289 pr->nospace = p2;
290 }
291 if (!fu->nextfu)
292 break;
293 }
294}
295
Manuel Novoa III cad53642003-03-19 09:13:01 +0000296static void do_skip(char *fname, int statok)
Glenn L McGrath60281112001-11-02 11:39:46 +0000297{
298 struct stat sbuf;
299
300 if (statok) {
Eric Andersen70060d22004-03-27 10:02:48 +0000301 if (fstat(STDIN_FILENO, &sbuf)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000302 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000303 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000304 if ((!(S_ISCHR(sbuf.st_mode) ||
305 S_ISBLK(sbuf.st_mode) ||
Manuel Novoa III cad53642003-03-19 09:13:01 +0000306 S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
307 /* If bb_dump_size valid and bb_dump_skip >= size */
308 bb_dump_skip -= sbuf.st_size;
Glenn L McGrath60281112001-11-02 11:39:46 +0000309 address += sbuf.st_size;
310 return;
311 }
312 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000313 if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
314 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000315 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000316 savaddress = address += bb_dump_skip;
317 bb_dump_skip = 0;
Glenn L McGrath60281112001-11-02 11:39:46 +0000318}
319
Manuel Novoa III cad53642003-03-19 09:13:01 +0000320static int next(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000321{
322 static int done;
323 int statok;
324
325 if (argv) {
326 _argv = argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000327 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000328 }
329 for (;;) {
330 if (*_argv) {
331 if (!(freopen(*_argv, "r", stdin))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000332 bb_perror_msg("%s", *_argv);
Glenn L McGrath60281112001-11-02 11:39:46 +0000333 exitval = 1;
334 ++_argv;
335 continue;
336 }
337 statok = done = 1;
338 } else {
339 if (done++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000340 return (0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000341 statok = 0;
342 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000343 if (bb_dump_skip)
344 do_skip(statok ? *_argv : "stdin", statok);
Glenn L McGrath60281112001-11-02 11:39:46 +0000345 if (*_argv)
346 ++_argv;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000347 if (!bb_dump_skip)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000348 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000349 }
350 /* NOTREACHED */
351}
352
Mike Frysinger294254c2006-02-19 22:59:12 +0000353static unsigned char *get(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000354{
355 static int ateof = 1;
Mike Frysinger294254c2006-02-19 22:59:12 +0000356 static unsigned char *curp=NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
Glenn L McGrath60281112001-11-02 11:39:46 +0000357 register int n;
358 int need, nread;
Mike Frysinger294254c2006-02-19 22:59:12 +0000359 unsigned char *tmpp;
Glenn L McGrath60281112001-11-02 11:39:46 +0000360
361 if (!curp) {
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000362 address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
Mike Frysinger294254c2006-02-19 22:59:12 +0000363 curp = (unsigned char *) xmalloc(bb_dump_blocksize);
364 savp = (unsigned char *) xmalloc(bb_dump_blocksize);
Glenn L McGrath60281112001-11-02 11:39:46 +0000365 } else {
366 tmpp = curp;
367 curp = savp;
368 savp = tmpp;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000369 address = savaddress += bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000370 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000371 for (need = bb_dump_blocksize, nread = 0;;) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000372 /*
373 * if read the right number of bytes, or at EOF for one file,
374 * and no other files are available, zero-pad the rest of the
375 * block and set the end flag.
376 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000377 if (!bb_dump_length || (ateof && !next((char **) NULL))) {
378 if (need == bb_dump_blocksize) {
Mike Frysinger294254c2006-02-19 22:59:12 +0000379 return ((unsigned char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000380 }
Mike Frysinger78bd5042006-04-16 05:51:47 +0000381 if (bb_dump_vflag != ALL && !memcmp(curp, savp, nread)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000382 if (bb_dump_vflag != DUP) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000383 printf("*\n");
384 }
Mike Frysinger294254c2006-02-19 22:59:12 +0000385 return ((unsigned char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000386 }
Bernhard Reutner-Fischer30385572006-01-31 17:57:48 +0000387 memset((char *) curp + nread, 0, need);
Glenn L McGrath60281112001-11-02 11:39:46 +0000388 eaddress = address + nread;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000389 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000390 }
Mike Frysinger294254c2006-02-19 22:59:12 +0000391 n = fread((char *) curp + nread, sizeof(unsigned char),
Manuel Novoa III cad53642003-03-19 09:13:01 +0000392 bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
Glenn L McGrath60281112001-11-02 11:39:46 +0000393 if (!n) {
394 if (ferror(stdin)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000395 bb_perror_msg("%s", _argv[-1]);
Glenn L McGrath60281112001-11-02 11:39:46 +0000396 }
397 ateof = 1;
398 continue;
399 }
400 ateof = 0;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000401 if (bb_dump_length != -1) {
402 bb_dump_length -= n;
Glenn L McGrath60281112001-11-02 11:39:46 +0000403 }
404 if (!(need -= n)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000405 if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
Mike Frysinger78bd5042006-04-16 05:51:47 +0000406 || memcmp(curp, savp, bb_dump_blocksize)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000407 if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
408 bb_dump_vflag = WAIT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000409 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000410 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000411 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000412 if (bb_dump_vflag == WAIT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000413 printf("*\n");
414 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000415 bb_dump_vflag = DUP;
416 address = savaddress += bb_dump_blocksize;
417 need = bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000418 nread = 0;
419 } else {
420 nread += n;
421 }
422 }
423}
424
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000425static void bpad(PR * pr)
Glenn L McGrath60281112001-11-02 11:39:46 +0000426{
Rob Landleya6e60372006-06-28 14:36:50 +0000427 char *p1, *p2;
Glenn L McGrath60281112001-11-02 11:39:46 +0000428
429 /*
430 * remove all conversion flags; '-' is the only one valid
431 * with %s, and it's not useful here.
432 */
433 pr->flags = F_BPAD;
434 *pr->cchar = 's';
435 for (p1 = pr->fmt; *p1 != '%'; ++p1);
Rob Landleya6e60372006-06-28 14:36:50 +0000436 for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
437 if (pr->nospace) pr->nospace--;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000438 while ((*p2++ = *p1++) != 0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000439}
440
Manuel Novoa III cad53642003-03-19 09:13:01 +0000441static const char conv_str[] =
442 "\0\\0\0"
443 "\007\\a\0" /* \a */
444 "\b\\b\0"
445 "\f\\b\0"
446 "\n\\n\0"
447 "\r\\r\0"
448 "\t\\t\0"
449 "\v\\v\0"
450 "\0";
Glenn L McGrath60281112001-11-02 11:39:46 +0000451
Manuel Novoa III cad53642003-03-19 09:13:01 +0000452
Mike Frysinger294254c2006-02-19 22:59:12 +0000453static void conv_c(PR * pr, unsigned char * p)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000454{
455 const char *str = conv_str;
456 char buf[10];
457
458 do {
459 if (*p == *str) {
460 ++str;
461 goto strpr;
462 }
463 str += 4;
464 } while (*str);
465
Glenn L McGrath60281112001-11-02 11:39:46 +0000466 if (isprint(*p)) {
467 *pr->cchar = 'c';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000468 (void) printf(pr->fmt, *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000469 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000470 sprintf(buf, "%03o", (int) *p);
471 str = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000472 strpr:
Glenn L McGrath60281112001-11-02 11:39:46 +0000473 *pr->cchar = 's';
474 printf(pr->fmt, str);
475 }
476}
477
Mike Frysinger294254c2006-02-19 22:59:12 +0000478static void conv_u(PR * pr, unsigned char * p)
Glenn L McGrath60281112001-11-02 11:39:46 +0000479{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000480 static const char list[] =
481 "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
482 "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
483 "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
484 "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
Glenn L McGrath60281112001-11-02 11:39:46 +0000485
486 /* od used nl, not lf */
487 if (*p <= 0x1f) {
488 *pr->cchar = 's';
Glenn L McGratheeb06bf2004-07-23 01:35:41 +0000489 printf(pr->fmt, list + (4 * (int)*p));
Glenn L McGrath60281112001-11-02 11:39:46 +0000490 } else if (*p == 0x7f) {
491 *pr->cchar = 's';
492 printf(pr->fmt, "del");
493 } else if (isprint(*p)) {
494 *pr->cchar = 'c';
495 printf(pr->fmt, *p);
496 } else {
497 *pr->cchar = 'x';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000498 printf(pr->fmt, (int) *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000499 }
500}
501
Manuel Novoa III cad53642003-03-19 09:13:01 +0000502static void display(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000503{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000504/* extern FU *endfu; */
Glenn L McGrath60281112001-11-02 11:39:46 +0000505 register FS *fs;
506 register FU *fu;
507 register PR *pr;
508 register int cnt;
Mike Frysinger294254c2006-02-19 22:59:12 +0000509 register unsigned char *bp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000510
Manuel Novoa III cad53642003-03-19 09:13:01 +0000511 off_t saveaddress;
Mike Frysinger294254c2006-02-19 22:59:12 +0000512 unsigned char savech = 0, *savebp;
Glenn L McGrath60281112001-11-02 11:39:46 +0000513
514 while ((bp = get()) != NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000515 for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000516 fs = fs->nextfs, bp = savebp, address = saveaddress) {
517 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000518 if (fu->flags & F_IGNORE) {
519 break;
520 }
521 for (cnt = fu->reps; cnt; --cnt) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000522 for (pr = fu->nextpr; pr; address += pr->bcnt,
523 bp += pr->bcnt, pr = pr->nextpr) {
524 if (eaddress && address >= eaddress &&
525 !(pr->flags & (F_TEXT | F_BPAD))) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000526 bpad(pr);
527 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000528 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000529 savech = *pr->nospace;
530 *pr->nospace = '\0';
Glenn L McGrath60281112001-11-02 11:39:46 +0000531 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000532/* PRINT; */
533 switch (pr->flags) {
534 case F_ADDRESS:
Glenn L McGrathff5309a2004-05-02 08:38:53 +0000535 printf(pr->fmt, (unsigned int) address);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000536 break;
537 case F_BPAD:
538 printf(pr->fmt, "");
539 break;
540 case F_C:
541 conv_c(pr, bp);
542 break;
543 case F_CHAR:
544 printf(pr->fmt, *bp);
545 break;
546 case F_DBL:{
547 double dval;
548 float fval;
549
550 switch (pr->bcnt) {
551 case 4:
Mike Frysinger1a540302006-04-16 05:58:21 +0000552 memmove((char *) &fval, (char *) bp,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000553 sizeof(fval));
554 printf(pr->fmt, fval);
555 break;
556 case 8:
Mike Frysinger1a540302006-04-16 05:58:21 +0000557 memmove((char *) &dval, (char *) bp,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000558 sizeof(dval));
559 printf(pr->fmt, dval);
560 break;
561 }
562 break;
563 }
564 case F_INT:{
565 int ival;
566 short sval;
567
568 switch (pr->bcnt) {
569 case 1:
570 printf(pr->fmt, (int) *bp);
571 break;
572 case 2:
Mike Frysinger1a540302006-04-16 05:58:21 +0000573 memmove((char *) &sval, (char *) bp,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000574 sizeof(sval));
575 printf(pr->fmt, (int) sval);
576 break;
577 case 4:
Mike Frysinger1a540302006-04-16 05:58:21 +0000578 memmove((char *) &ival, (char *) bp,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000579 sizeof(ival));
580 printf(pr->fmt, ival);
581 break;
582 }
583 break;
584 }
585 case F_P:
586 printf(pr->fmt, isprint(*bp) ? *bp : '.');
587 break;
588 case F_STR:
589 printf(pr->fmt, (char *) bp);
590 break;
591 case F_TEXT:
592 printf(pr->fmt);
593 break;
594 case F_U:
595 conv_u(pr, bp);
596 break;
597 case F_UINT:{
Eric Andersen0f56de62004-01-30 22:52:27 +0000598 unsigned int ival;
599 unsigned short sval;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000600
601 switch (pr->bcnt) {
602 case 1:
Eric Andersen0f56de62004-01-30 22:52:27 +0000603 printf(pr->fmt, (unsigned int) * bp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000604 break;
605 case 2:
Mike Frysinger1a540302006-04-16 05:58:21 +0000606 memmove((char *) &sval, (char *) bp,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000607 sizeof(sval));
Eric Andersen0f56de62004-01-30 22:52:27 +0000608 printf(pr->fmt, (unsigned int) sval);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000609 break;
610 case 4:
Mike Frysinger1a540302006-04-16 05:58:21 +0000611 memmove((char *) &ival, (char *) bp,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000612 sizeof(ival));
613 printf(pr->fmt, ival);
614 break;
615 }
616 break;
617 }
618 }
619 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000620 *pr->nospace = savech;
621 }
622 }
623 }
624 }
625 }
626 }
627 if (endfu) {
628 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +0000629 * if eaddress not set, error or file bb_dump_size was multiple of
630 * bb_dump_blocksize, and no partial block ever found.
Glenn L McGrath60281112001-11-02 11:39:46 +0000631 */
632 if (!eaddress) {
633 if (!address) {
634 return;
635 }
636 eaddress = address;
637 }
638 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000639 switch (pr->flags) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000640 case F_ADDRESS:
Glenn L McGrathd2b860f2004-03-05 05:47:19 +0000641 (void) printf(pr->fmt, (unsigned int) eaddress);
Glenn L McGrath60281112001-11-02 11:39:46 +0000642 break;
643 case F_TEXT:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000644 (void) printf(pr->fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000645 break;
646 }
647 }
648 }
649}
650
Manuel Novoa III cad53642003-03-19 09:13:01 +0000651int bb_dump_dump(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000652{
653 register FS *tfs;
654
Manuel Novoa III cad53642003-03-19 09:13:01 +0000655 /* figure out the data block bb_dump_size */
656 for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
657 tfs->bcnt = bb_dump_size(tfs);
658 if (bb_dump_blocksize < tfs->bcnt) {
659 bb_dump_blocksize = tfs->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000660 }
661 }
662 /* rewrite the rules, do syntax checking */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000663 for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000664 rewrite(tfs);
665 }
666
667 next(argv);
668 display();
669
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000670 return (exitval);
Glenn L McGrath60281112001-11-02 11:39:46 +0000671}
672
Manuel Novoa III cad53642003-03-19 09:13:01 +0000673void bb_dump_add(const char *fmt)
Glenn L McGrath60281112001-11-02 11:39:46 +0000674{
Rob Landleyea224be2006-06-18 20:20:07 +0000675 const char *p;
676 char *p1;
677 char *p2;
Glenn L McGrath60281112001-11-02 11:39:46 +0000678 static FS **nextfs;
679 FS *tfs;
680 FU *tfu, **nextfu;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000681 const char *savep;
Glenn L McGrath60281112001-11-02 11:39:46 +0000682
683 /* start new linked list of format units */
Rob Landleyea224be2006-06-18 20:20:07 +0000684 tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000685 if (!bb_dump_fshead) {
686 bb_dump_fshead = tfs;
Glenn L McGrath60281112001-11-02 11:39:46 +0000687 } else {
688 *nextfs = tfs;
689 }
690 nextfs = &tfs->nextfs;
691 nextfu = &tfs->nextfu;
692
693 /* take the format string and break it up into format units */
694 for (p = fmt;;) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000695 /* bb_dump_skip leading white space */
Rob Landleyea224be2006-06-18 20:20:07 +0000696 p = skip_whitespace(p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000697 if (!*p) {
698 break;
699 }
700
701 /* allocate a new format unit and link it in */
702 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000703 /* DBU:[dave@cray.com] calloc so that forward pointers start out NULL */
Rob Landleyea224be2006-06-18 20:20:07 +0000704 tfu = xzalloc(sizeof(FU));
Glenn L McGrath60281112001-11-02 11:39:46 +0000705 *nextfu = tfu;
706 nextfu = &tfu->nextfu;
707 tfu->reps = 1;
708
709 /* if leading digit, repetition count */
710 if (isdigit(*p)) {
711 for (savep = p; isdigit(*p); ++p);
712 if (!isspace(*p) && *p != '/') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000713 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000714 }
715 /* may overwrite either white space or slash */
716 tfu->reps = atoi(savep);
717 tfu->flags = F_SETREP;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000718 /* bb_dump_skip trailing white space */
Rob Landleyea224be2006-06-18 20:20:07 +0000719 p = skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000720 }
721
Manuel Novoa III cad53642003-03-19 09:13:01 +0000722 /* bb_dump_skip slash and trailing white space */
Glenn L McGrath60281112001-11-02 11:39:46 +0000723 if (*p == '/') {
Rob Landleyea224be2006-06-18 20:20:07 +0000724 p = skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000725 }
726
727 /* byte count */
728 if (isdigit(*p)) {
729 for (savep = p; isdigit(*p); ++p);
730 if (!isspace(*p)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000731 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000732 }
733 tfu->bcnt = atoi(savep);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000734 /* bb_dump_skip trailing white space */
Rob Landleyea224be2006-06-18 20:20:07 +0000735 p = skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000736 }
737
738 /* format */
739 if (*p != '"') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000740 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000741 }
742 for (savep = ++p; *p != '"';) {
743 if (*p++ == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000744 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000745 }
746 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000747 tfu->fmt = xmalloc(p - savep + 1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000748 strncpy(tfu->fmt, savep, p - savep);
749 tfu->fmt[p - savep] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000750/* escape(tfu->fmt); */
Glenn L McGrath60281112001-11-02 11:39:46 +0000751
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 == '\\') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000761 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);
Glenn L McGrath60281112001-11-02 11:39:46 +0000771 }
772 }
773
774 p++;
775 }
776}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000777
Glenn L McGrath60281112001-11-02 11:39:46 +0000778/*
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.
Aaron Lehmann69d41782002-06-23 22:25:24 +0000790 * 3. Neither the name of the University nor the names of its contributors
Glenn L McGrath60281112001-11-02 11:39:46 +0000791 * 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 */