blob: 09db24692d75a90b2735503511e65043ba39343d [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
13#include <stdlib.h>
14#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() */
Glenn L McGrath60281112001-11-02 11:39:46 +000017#include "libbb.h"
Manuel Novoa III cad53642003-03-19 09:13:01 +000018#include "dump.h"
Glenn L McGrath60281112001-11-02 11:39:46 +000019
Manuel Novoa III cad53642003-03-19 09:13:01 +000020enum _vflag bb_dump_vflag = FIRST;
21FS *bb_dump_fshead; /* head of format strings */
Glenn L McGrath60281112001-11-02 11:39:46 +000022static FU *endfu;
23static char **_argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000024static off_t savaddress; /* saved address/offset in stream */
25static off_t eaddress; /* end address */
26static off_t address; /* address/offset in stream */
Manuel Novoa III cad53642003-03-19 09:13:01 +000027off_t bb_dump_skip; /* bytes to skip */
28static int exitval; /* final exit value */
29int bb_dump_blocksize; /* data block size */
30int bb_dump_length = -1; /* max bytes to read */
Glenn L McGrath60281112001-11-02 11:39:46 +000031
Manuel Novoa III cad53642003-03-19 09:13:01 +000032static const char index_str[] = ".#-+ 0123456789";
Glenn L McGrath60281112001-11-02 11:39:46 +000033
Manuel Novoa III cad53642003-03-19 09:13:01 +000034static const char size_conv_str[] =
35"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
36
37static const char lcc[] = "diouxX";
38
39int bb_dump_size(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000040{
41 register FU *fu;
Manuel Novoa III cad53642003-03-19 09:13:01 +000042 register int bcnt, cur_size;
Glenn L McGrath60281112001-11-02 11:39:46 +000043 register char *fmt;
Manuel Novoa III cad53642003-03-19 09:13:01 +000044 const char *p;
Glenn L McGrath60281112001-11-02 11:39:46 +000045 int prec;
46
Manuel Novoa III cad53642003-03-19 09:13:01 +000047 /* figure out the data block bb_dump_size needed for each format unit */
48 for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +000049 if (fu->bcnt) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000050 cur_size += fu->bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000051 continue;
52 }
53 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
54 if (*fmt != '%')
55 continue;
56 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +000057 * bb_dump_skip any special chars -- save precision in
Glenn L McGrath60281112001-11-02 11:39:46 +000058 * case it's a %s format.
59 */
Manuel Novoa III cad53642003-03-19 09:13:01 +000060 while (strchr(index_str + 1, *++fmt));
Glenn L McGrath60281112001-11-02 11:39:46 +000061 if (*fmt == '.' && isdigit(*++fmt)) {
62 prec = atoi(fmt);
63 while (isdigit(*++fmt));
64 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000065 if (!(p = strchr(size_conv_str + 12, *fmt))) {
66 if (*fmt == 's') {
67 bcnt += prec;
68 } else if (*fmt == '_') {
69 ++fmt;
70 if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
71 bcnt += 1;
72 }
Glenn L McGrath60281112001-11-02 11:39:46 +000073 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000074 } else {
75 bcnt += size_conv_str[p - (size_conv_str + 12)];
Glenn L McGrath60281112001-11-02 11:39:46 +000076 }
77 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000078 cur_size += bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000079 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000080 return (cur_size);
Glenn L McGrath60281112001-11-02 11:39:46 +000081}
82
Manuel Novoa III cad53642003-03-19 09:13:01 +000083static void rewrite(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000084{
85 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
86 register PR *pr, **nextpr = NULL;
87 register FU *fu;
Eric Andersen4a11e0f2003-04-19 23:18:35 +000088 register char *p1, *p2, *p3;
Glenn L McGrath60281112001-11-02 11:39:46 +000089 char savech, *fmtp;
Manuel Novoa III cad53642003-03-19 09:13:01 +000090 const char *byte_count_str;
Glenn L McGrath60281112001-11-02 11:39:46 +000091 int nconv, prec = 0;
92
93 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
94 /*
95 * break each format unit into print units; each
96 * conversion character gets its own.
97 */
98 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
99 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000100 /* DBU:[dvae@cray.com] calloc so that forward ptrs start out NULL*/
101 pr = (PR *) xcalloc(1,sizeof(PR));
Glenn L McGrath60281112001-11-02 11:39:46 +0000102 if (!fu->nextpr)
103 fu->nextpr = pr;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000104 /* ignore nextpr -- its unused inside the loop and is
105 * uninitialized 1st time thru.
106 */
Glenn L McGrath60281112001-11-02 11:39:46 +0000107
Manuel Novoa III cad53642003-03-19 09:13:01 +0000108 /* bb_dump_skip preceding text and up to the next % sign */
Glenn L McGrath60281112001-11-02 11:39:46 +0000109 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
110
111 /* only text in the string */
112 if (!*p1) {
113 pr->fmt = fmtp;
114 pr->flags = F_TEXT;
115 break;
116 }
117
118 /*
119 * get precision for %s -- if have a byte count, don't
120 * need it.
121 */
122 if (fu->bcnt) {
123 sokay = USEBCNT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000124 /* bb_dump_skip to conversion character */
125 for (++p1; strchr(index_str, *p1); ++p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000126 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000127 /* bb_dump_skip any special chars, field width */
128 while (strchr(index_str + 1, *++p1));
Glenn L McGrath60281112001-11-02 11:39:46 +0000129 if (*p1 == '.' && isdigit(*++p1)) {
130 sokay = USEPREC;
131 prec = atoi(p1);
132 while (isdigit(*++p1));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000133 } else
Glenn L McGrath60281112001-11-02 11:39:46 +0000134 sokay = NOTOKAY;
135 }
136
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000137 p2 = p1 + 1; /* set end pointer */
Glenn L McGrath60281112001-11-02 11:39:46 +0000138
139 /*
140 * figure out the byte count for each conversion;
141 * rewrite the format as necessary, set up blank-
Manuel Novoa III cad53642003-03-19 09:13:01 +0000142 * pbb_dump_adding for end of data.
Glenn L McGrath60281112001-11-02 11:39:46 +0000143 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000144
145 if (*p1 == 'c') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000146 pr->flags = F_CHAR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000147 DO_BYTE_COUNT_1:
148 byte_count_str = "\001";
149 DO_BYTE_COUNT:
150 if (fu->bcnt) {
151 do {
152 if (fu->bcnt == *byte_count_str) {
153 break;
154 }
155 } while (*++byte_count_str);
Glenn L McGrath60281112001-11-02 11:39:46 +0000156 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000157 /* Unlike the original, output the remainder of the format string. */
158 if (!*byte_count_str) {
159 bb_error_msg_and_die("bad byte count for conversion character %s.", p1);
160 }
161 pr->bcnt = *byte_count_str;
162 } else if (*p1 == 'l') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000163 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000164 ++p1;
165 DO_INT_CONV:
166 {
167 const char *e;
168 if (!(e = strchr(lcc, *p1))) {
169 goto DO_BAD_CONV_CHAR;
170 }
Glenn L McGrath60281112001-11-02 11:39:46 +0000171 pr->flags = F_INT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000172 if (e > lcc + 1) {
173 pr->flags = F_UINT;
174 }
175 byte_count_str = "\004\002\001";
176 goto DO_BYTE_COUNT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000177 }
178 /* NOTREACHED */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000179 } else if (strchr(lcc, *p1)) {
180 goto DO_INT_CONV;
181 } else if (strchr("eEfgG", *p1)) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000182 pr->flags = F_DBL;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000183 byte_count_str = "\010\004";
184 goto DO_BYTE_COUNT;
185 } else if (*p1 == 's') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000186 pr->flags = F_STR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000187 if (sokay == USEBCNT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000188 pr->bcnt = fu->bcnt;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000189 } else if (sokay == USEPREC) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000190 pr->bcnt = prec;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000191 } else { /* NOTOKAY */
192 bb_error_msg_and_die("%%s requires a precision or a byte count.");
Glenn L McGrath60281112001-11-02 11:39:46 +0000193 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000194 } else if (*p1 == '_') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000195 ++p2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000196 switch (p1[1]) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000197 case 'A':
198 endfu = fu;
199 fu->flags |= F_IGNORE;
200 /* FALLTHROUGH */
201 case 'a':
202 pr->flags = F_ADDRESS;
203 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000204 if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
205 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000206 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000207 *p1 = p1[2];
Glenn L McGrath60281112001-11-02 11:39:46 +0000208 break;
209 case 'c':
210 pr->flags = F_C;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000211 /* *p1 = 'c'; set in conv_c */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000212 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000213 case 'p':
214 pr->flags = F_P;
215 *p1 = 'c';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000216 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000217 case 'u':
218 pr->flags = F_U;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000219 /* *p1 = 'c'; set in conv_u */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000220 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000221 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000222 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000223 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000224 } else {
225 DO_BAD_CONV_CHAR:
226 bb_error_msg_and_die("bad conversion character %%%s.\n", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000227 }
228
229 /*
230 * copy to PR format string, set conversion character
231 * pointer, update original.
232 */
233 savech = *p2;
234 p1[1] = '\0';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000235 pr->fmt = bb_xstrdup(fmtp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000236 *p2 = savech;
237 pr->cchar = pr->fmt + (p1 - fmtp);
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000238
239 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000240 * Skip subsequent text and up to the next % sign and tack the
241 * additional text onto fmt: eg. if fmt is "%x is a HEX number",
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000242 * we lose the " is a HEX number" part of fmt.
243 */
244 for (p3 = p2; *p3 && *p3 != '%'; p3++);
245 if (p3 > p2)
246 {
247 savech = *p3;
248 *p3 = '\0';
249 if (!(pr->fmt = realloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1)))
Glenn L McGrath923dd792003-04-21 10:26:39 +0000250 bb_perror_msg_and_die("hexdump");
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000251 strcat(pr->fmt, p2);
252 *p3 = savech;
253 p2 = p3;
254 }
255
Glenn L McGrath60281112001-11-02 11:39:46 +0000256 fmtp = p2;
257
258 /* only one conversion character if byte count */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000259 if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000260 bb_error_msg_and_die("byte count with multiple conversion characters.\n");
Glenn L McGrath60281112001-11-02 11:39:46 +0000261 }
262 }
263 /*
264 * if format unit byte count not specified, figure it out
265 * so can adjust rep count later.
266 */
267 if (!fu->bcnt)
268 for (pr = fu->nextpr; pr; pr = pr->nextpr)
269 fu->bcnt += pr->bcnt;
270 }
271 /*
272 * if the format string interprets any data at all, and it's
Manuel Novoa III cad53642003-03-19 09:13:01 +0000273 * not the same as the bb_dump_blocksize, and its last format unit
Glenn L McGrath60281112001-11-02 11:39:46 +0000274 * interprets any data at all, and has no iteration count,
275 * repeat it as necessary.
276 *
277 * if, rep count is greater than 1, no trailing whitespace
278 * gets output from the last iteration of the format unit.
279 */
280 for (fu = fs->nextfu;; fu = fu->nextfu) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000281 if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000282 !(fu->flags & F_SETREP) && fu->bcnt)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000283 fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000284 if (fu->reps > 1) {
285 for (pr = fu->nextpr;; pr = pr->nextpr)
286 if (!pr->nextpr)
287 break;
288 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
289 p2 = isspace(*p1) ? p1 : NULL;
290 if (p2)
291 pr->nospace = p2;
292 }
293 if (!fu->nextfu)
294 break;
295 }
296}
297
Manuel Novoa III cad53642003-03-19 09:13:01 +0000298static void do_skip(char *fname, int statok)
Glenn L McGrath60281112001-11-02 11:39:46 +0000299{
300 struct stat sbuf;
301
302 if (statok) {
Eric Andersen70060d22004-03-27 10:02:48 +0000303 if (fstat(STDIN_FILENO, &sbuf)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000304 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000305 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000306 if ((!(S_ISCHR(sbuf.st_mode) ||
307 S_ISBLK(sbuf.st_mode) ||
Manuel Novoa III cad53642003-03-19 09:13:01 +0000308 S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
309 /* If bb_dump_size valid and bb_dump_skip >= size */
310 bb_dump_skip -= sbuf.st_size;
Glenn L McGrath60281112001-11-02 11:39:46 +0000311 address += sbuf.st_size;
312 return;
313 }
314 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000315 if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
316 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000317 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000318 savaddress = address += bb_dump_skip;
319 bb_dump_skip = 0;
Glenn L McGrath60281112001-11-02 11:39:46 +0000320}
321
Manuel Novoa III cad53642003-03-19 09:13:01 +0000322static int next(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000323{
324 static int done;
325 int statok;
326
327 if (argv) {
328 _argv = argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000329 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000330 }
331 for (;;) {
332 if (*_argv) {
333 if (!(freopen(*_argv, "r", stdin))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000334 bb_perror_msg("%s", *_argv);
Glenn L McGrath60281112001-11-02 11:39:46 +0000335 exitval = 1;
336 ++_argv;
337 continue;
338 }
339 statok = done = 1;
340 } else {
341 if (done++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000342 return (0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000343 statok = 0;
344 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000345 if (bb_dump_skip)
346 do_skip(statok ? *_argv : "stdin", statok);
Glenn L McGrath60281112001-11-02 11:39:46 +0000347 if (*_argv)
348 ++_argv;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000349 if (!bb_dump_skip)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000350 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000351 }
352 /* NOTREACHED */
353}
354
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000355static u_char *get(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000356{
357 static int ateof = 1;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000358 static u_char *curp=NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
Glenn L McGrath60281112001-11-02 11:39:46 +0000359 register int n;
360 int need, nread;
361 u_char *tmpp;
362
363 if (!curp) {
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000364 address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
Manuel Novoa III cad53642003-03-19 09:13:01 +0000365 curp = (u_char *) xmalloc(bb_dump_blocksize);
366 savp = (u_char *) xmalloc(bb_dump_blocksize);
Glenn L McGrath60281112001-11-02 11:39:46 +0000367 } else {
368 tmpp = curp;
369 curp = savp;
370 savp = tmpp;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000371 address = savaddress += bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000372 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000373 for (need = bb_dump_blocksize, nread = 0;;) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000374 /*
375 * if read the right number of bytes, or at EOF for one file,
376 * and no other files are available, zero-pad the rest of the
377 * block and set the end flag.
378 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000379 if (!bb_dump_length || (ateof && !next((char **) NULL))) {
380 if (need == bb_dump_blocksize) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000381 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000382 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000383 if (bb_dump_vflag != ALL && !bcmp(curp, savp, nread)) {
384 if (bb_dump_vflag != DUP) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000385 printf("*\n");
386 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000387 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000388 }
Bernhard Reutner-Fischer30385572006-01-31 17:57:48 +0000389 memset((char *) curp + nread, 0, need);
Glenn L McGrath60281112001-11-02 11:39:46 +0000390 eaddress = address + nread;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000391 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000392 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000393 n = fread((char *) curp + nread, sizeof(u_char),
Manuel Novoa III cad53642003-03-19 09:13:01 +0000394 bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
Glenn L McGrath60281112001-11-02 11:39:46 +0000395 if (!n) {
396 if (ferror(stdin)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000397 bb_perror_msg("%s", _argv[-1]);
Glenn L McGrath60281112001-11-02 11:39:46 +0000398 }
399 ateof = 1;
400 continue;
401 }
402 ateof = 0;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000403 if (bb_dump_length != -1) {
404 bb_dump_length -= n;
Glenn L McGrath60281112001-11-02 11:39:46 +0000405 }
406 if (!(need -= n)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000407 if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
408 || bcmp(curp, savp, bb_dump_blocksize)) {
409 if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
410 bb_dump_vflag = WAIT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000411 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000412 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000413 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000414 if (bb_dump_vflag == WAIT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000415 printf("*\n");
416 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000417 bb_dump_vflag = DUP;
418 address = savaddress += bb_dump_blocksize;
419 need = bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000420 nread = 0;
421 } else {
422 nread += n;
423 }
424 }
425}
426
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000427static void bpad(PR * pr)
Glenn L McGrath60281112001-11-02 11:39:46 +0000428{
429 register char *p1, *p2;
430
431 /*
432 * remove all conversion flags; '-' is the only one valid
433 * with %s, and it's not useful here.
434 */
435 pr->flags = F_BPAD;
436 *pr->cchar = 's';
437 for (p1 = pr->fmt; *p1 != '%'; ++p1);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000438 for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000439 while ((*p2++ = *p1++) != 0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000440}
441
Manuel Novoa III cad53642003-03-19 09:13:01 +0000442static const char conv_str[] =
443 "\0\\0\0"
444 "\007\\a\0" /* \a */
445 "\b\\b\0"
446 "\f\\b\0"
447 "\n\\n\0"
448 "\r\\r\0"
449 "\t\\t\0"
450 "\v\\v\0"
451 "\0";
Glenn L McGrath60281112001-11-02 11:39:46 +0000452
Manuel Novoa III cad53642003-03-19 09:13:01 +0000453
454static void conv_c(PR * pr, u_char * p)
455{
456 const char *str = conv_str;
457 char buf[10];
458
459 do {
460 if (*p == *str) {
461 ++str;
462 goto strpr;
463 }
464 str += 4;
465 } while (*str);
466
Glenn L McGrath60281112001-11-02 11:39:46 +0000467 if (isprint(*p)) {
468 *pr->cchar = 'c';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000469 (void) printf(pr->fmt, *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000470 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000471 sprintf(buf, "%03o", (int) *p);
472 str = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000473 strpr:
Glenn L McGrath60281112001-11-02 11:39:46 +0000474 *pr->cchar = 's';
475 printf(pr->fmt, str);
476 }
477}
478
Manuel Novoa III cad53642003-03-19 09:13:01 +0000479static void conv_u(PR * pr, u_char * p)
Glenn L McGrath60281112001-11-02 11:39:46 +0000480{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000481 static const char list[] =
482 "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
483 "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
484 "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
485 "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
Glenn L McGrath60281112001-11-02 11:39:46 +0000486
487 /* od used nl, not lf */
488 if (*p <= 0x1f) {
489 *pr->cchar = 's';
Glenn L McGratheeb06bf2004-07-23 01:35:41 +0000490 printf(pr->fmt, list + (4 * (int)*p));
Glenn L McGrath60281112001-11-02 11:39:46 +0000491 } else if (*p == 0x7f) {
492 *pr->cchar = 's';
493 printf(pr->fmt, "del");
494 } else if (isprint(*p)) {
495 *pr->cchar = 'c';
496 printf(pr->fmt, *p);
497 } else {
498 *pr->cchar = 'x';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000499 printf(pr->fmt, (int) *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000500 }
501}
502
Manuel Novoa III cad53642003-03-19 09:13:01 +0000503static void display(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000504{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000505/* extern FU *endfu; */
Glenn L McGrath60281112001-11-02 11:39:46 +0000506 register FS *fs;
507 register FU *fu;
508 register PR *pr;
509 register int cnt;
510 register u_char *bp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000511
Manuel Novoa III cad53642003-03-19 09:13:01 +0000512 off_t saveaddress;
Glenn L McGrath60281112001-11-02 11:39:46 +0000513 u_char savech = 0, *savebp;
514
515 while ((bp = get()) != NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000516 for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000517 fs = fs->nextfs, bp = savebp, address = saveaddress) {
518 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000519 if (fu->flags & F_IGNORE) {
520 break;
521 }
522 for (cnt = fu->reps; cnt; --cnt) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000523 for (pr = fu->nextpr; pr; address += pr->bcnt,
524 bp += pr->bcnt, pr = pr->nextpr) {
525 if (eaddress && address >= eaddress &&
526 !(pr->flags & (F_TEXT | F_BPAD))) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000527 bpad(pr);
528 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000529 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000530 savech = *pr->nospace;
531 *pr->nospace = '\0';
Glenn L McGrath60281112001-11-02 11:39:46 +0000532 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000533/* PRINT; */
534 switch (pr->flags) {
535 case F_ADDRESS:
Glenn L McGrathff5309a2004-05-02 08:38:53 +0000536 printf(pr->fmt, (unsigned int) address);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000537 break;
538 case F_BPAD:
539 printf(pr->fmt, "");
540 break;
541 case F_C:
542 conv_c(pr, bp);
543 break;
544 case F_CHAR:
545 printf(pr->fmt, *bp);
546 break;
547 case F_DBL:{
548 double dval;
549 float fval;
550
551 switch (pr->bcnt) {
552 case 4:
553 bcopy((char *) bp, (char *) &fval,
554 sizeof(fval));
555 printf(pr->fmt, fval);
556 break;
557 case 8:
558 bcopy((char *) bp, (char *) &dval,
559 sizeof(dval));
560 printf(pr->fmt, dval);
561 break;
562 }
563 break;
564 }
565 case F_INT:{
566 int ival;
567 short sval;
568
569 switch (pr->bcnt) {
570 case 1:
571 printf(pr->fmt, (int) *bp);
572 break;
573 case 2:
574 bcopy((char *) bp, (char *) &sval,
575 sizeof(sval));
576 printf(pr->fmt, (int) sval);
577 break;
578 case 4:
579 bcopy((char *) bp, (char *) &ival,
580 sizeof(ival));
581 printf(pr->fmt, ival);
582 break;
583 }
584 break;
585 }
586 case F_P:
587 printf(pr->fmt, isprint(*bp) ? *bp : '.');
588 break;
589 case F_STR:
590 printf(pr->fmt, (char *) bp);
591 break;
592 case F_TEXT:
593 printf(pr->fmt);
594 break;
595 case F_U:
596 conv_u(pr, bp);
597 break;
598 case F_UINT:{
Eric Andersen0f56de62004-01-30 22:52:27 +0000599 unsigned int ival;
600 unsigned short sval;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000601
602 switch (pr->bcnt) {
603 case 1:
Eric Andersen0f56de62004-01-30 22:52:27 +0000604 printf(pr->fmt, (unsigned int) * bp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000605 break;
606 case 2:
607 bcopy((char *) bp, (char *) &sval,
608 sizeof(sval));
Eric Andersen0f56de62004-01-30 22:52:27 +0000609 printf(pr->fmt, (unsigned int) sval);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000610 break;
611 case 4:
612 bcopy((char *) bp, (char *) &ival,
613 sizeof(ival));
614 printf(pr->fmt, ival);
615 break;
616 }
617 break;
618 }
619 }
620 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000621 *pr->nospace = savech;
622 }
623 }
624 }
625 }
626 }
627 }
628 if (endfu) {
629 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +0000630 * if eaddress not set, error or file bb_dump_size was multiple of
631 * bb_dump_blocksize, and no partial block ever found.
Glenn L McGrath60281112001-11-02 11:39:46 +0000632 */
633 if (!eaddress) {
634 if (!address) {
635 return;
636 }
637 eaddress = address;
638 }
639 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000640 switch (pr->flags) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000641 case F_ADDRESS:
Glenn L McGrathd2b860f2004-03-05 05:47:19 +0000642 (void) printf(pr->fmt, (unsigned int) eaddress);
Glenn L McGrath60281112001-11-02 11:39:46 +0000643 break;
644 case F_TEXT:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000645 (void) printf(pr->fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000646 break;
647 }
648 }
649 }
650}
651
Manuel Novoa III cad53642003-03-19 09:13:01 +0000652int bb_dump_dump(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000653{
654 register FS *tfs;
655
Manuel Novoa III cad53642003-03-19 09:13:01 +0000656 /* figure out the data block bb_dump_size */
657 for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
658 tfs->bcnt = bb_dump_size(tfs);
659 if (bb_dump_blocksize < tfs->bcnt) {
660 bb_dump_blocksize = tfs->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000661 }
662 }
663 /* rewrite the rules, do syntax checking */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000664 for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000665 rewrite(tfs);
666 }
667
668 next(argv);
669 display();
670
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000671 return (exitval);
Glenn L McGrath60281112001-11-02 11:39:46 +0000672}
673
Manuel Novoa III cad53642003-03-19 09:13:01 +0000674void bb_dump_add(const char *fmt)
Glenn L McGrath60281112001-11-02 11:39:46 +0000675{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000676 register const char *p;
Glenn L McGrath60281112001-11-02 11:39:46 +0000677 register char *p1;
678 register char *p2;
679 static FS **nextfs;
680 FS *tfs;
681 FU *tfu, **nextfu;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000682 const char *savep;
Glenn L McGrath60281112001-11-02 11:39:46 +0000683
684 /* start new linked list of format units */
685 /* NOSTRICT */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000686 tfs = (FS *) xcalloc(1,sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000687 if (!bb_dump_fshead) {
688 bb_dump_fshead = tfs;
Glenn L McGrath60281112001-11-02 11:39:46 +0000689 } else {
690 *nextfs = tfs;
691 }
692 nextfs = &tfs->nextfs;
693 nextfu = &tfs->nextfu;
694
695 /* take the format string and break it up into format units */
696 for (p = fmt;;) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000697 /* bb_dump_skip leading white space */
698 p = bb_skip_whitespace(p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000699 if (!*p) {
700 break;
701 }
702
703 /* allocate a new format unit and link it in */
704 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000705 /* DBU:[dave@cray.com] calloc so that forward pointers start out NULL */
706 tfu = (FU *) xcalloc(1,sizeof(FU));
Glenn L McGrath60281112001-11-02 11:39:46 +0000707 *nextfu = tfu;
708 nextfu = &tfu->nextfu;
709 tfu->reps = 1;
710
711 /* if leading digit, repetition count */
712 if (isdigit(*p)) {
713 for (savep = p; isdigit(*p); ++p);
714 if (!isspace(*p) && *p != '/') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000715 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000716 }
717 /* may overwrite either white space or slash */
718 tfu->reps = atoi(savep);
719 tfu->flags = F_SETREP;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000720 /* bb_dump_skip trailing white space */
721 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000722 }
723
Manuel Novoa III cad53642003-03-19 09:13:01 +0000724 /* bb_dump_skip slash and trailing white space */
Glenn L McGrath60281112001-11-02 11:39:46 +0000725 if (*p == '/') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000726 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000727 }
728
729 /* byte count */
730 if (isdigit(*p)) {
731 for (savep = p; isdigit(*p); ++p);
732 if (!isspace(*p)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000733 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000734 }
735 tfu->bcnt = atoi(savep);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000736 /* bb_dump_skip trailing white space */
737 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000738 }
739
740 /* format */
741 if (*p != '"') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000742 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000743 }
744 for (savep = ++p; *p != '"';) {
745 if (*p++ == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000746 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000747 }
748 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000749 tfu->fmt = xmalloc(p - savep + 1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000750 strncpy(tfu->fmt, savep, p - savep);
751 tfu->fmt[p - savep] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000752/* escape(tfu->fmt); */
Glenn L McGrath60281112001-11-02 11:39:46 +0000753
754 p1 = tfu->fmt;
755
756 /* alphabetic escape sequences have to be done in place */
757 for (p2 = p1;; ++p1, ++p2) {
758 if (!*p1) {
759 *p2 = *p1;
760 break;
761 }
762 if (*p1 == '\\') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000763 const char *cs = conv_str + 4;
764 ++p1;
765 *p2 = *p1;
766 do {
767 if (*p1 == cs[2]) {
768 *p2 = cs[0];
769 break;
770 }
771 cs += 4;
772 } while (*cs);
Glenn L McGrath60281112001-11-02 11:39:46 +0000773 }
774 }
775
776 p++;
777 }
778}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000779
Glenn L McGrath60281112001-11-02 11:39:46 +0000780/*
781 * Copyright (c) 1989 The Regents of the University of California.
782 * All rights reserved.
783 *
784 * Redistribution and use in source and binary forms, with or without
785 * modification, are permitted provided that the following conditions
786 * are met:
787 * 1. Redistributions of source code must retain the above copyright
788 * notice, this list of conditions and the following disclaimer.
789 * 2. Redistributions in binary form must reproduce the above copyright
790 * notice, this list of conditions and the following disclaimer in the
791 * documentation and/or other materials provided with the distribution.
Aaron Lehmann69d41782002-06-23 22:25:24 +0000792 * 3. Neither the name of the University nor the names of its contributors
Glenn L McGrath60281112001-11-02 11:39:46 +0000793 * may be used to endorse or promote products derived from this software
794 * without specific prior written permission.
795 *
796 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
797 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
798 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
799 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
800 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
801 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
802 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
803 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
804 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
805 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
806 * SUCH DAMAGE.
807 */