blob: 5a43b7c7052b44bb529242aea49dcf0df7931b51 [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() */
Glenn L McGrath60281112001-11-02 11:39:46 +000028#include "libbb.h"
Manuel Novoa III cad53642003-03-19 09:13:01 +000029#include "dump.h"
Glenn L McGrath60281112001-11-02 11:39:46 +000030
Manuel Novoa III cad53642003-03-19 09:13:01 +000031enum _vflag bb_dump_vflag = FIRST;
32FS *bb_dump_fshead; /* head of format strings */
Glenn L McGrath60281112001-11-02 11:39:46 +000033static FU *endfu;
34static char **_argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000035static off_t savaddress; /* saved address/offset in stream */
36static off_t eaddress; /* end address */
37static off_t address; /* address/offset in stream */
Manuel Novoa III cad53642003-03-19 09:13:01 +000038off_t bb_dump_skip; /* bytes to skip */
39static int exitval; /* final exit value */
40int bb_dump_blocksize; /* data block size */
41int bb_dump_length = -1; /* max bytes to read */
Glenn L McGrath60281112001-11-02 11:39:46 +000042
Manuel Novoa III cad53642003-03-19 09:13:01 +000043static const char index_str[] = ".#-+ 0123456789";
Glenn L McGrath60281112001-11-02 11:39:46 +000044
Manuel Novoa III cad53642003-03-19 09:13:01 +000045static const char size_conv_str[] =
46"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
47
48static const char lcc[] = "diouxX";
49
50int bb_dump_size(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000051{
52 register FU *fu;
Manuel Novoa III cad53642003-03-19 09:13:01 +000053 register int bcnt, cur_size;
Glenn L McGrath60281112001-11-02 11:39:46 +000054 register char *fmt;
Manuel Novoa III cad53642003-03-19 09:13:01 +000055 const char *p;
Glenn L McGrath60281112001-11-02 11:39:46 +000056 int prec;
57
Manuel Novoa III cad53642003-03-19 09:13:01 +000058 /* figure out the data block bb_dump_size needed for each format unit */
59 for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +000060 if (fu->bcnt) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000061 cur_size += fu->bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000062 continue;
63 }
64 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
65 if (*fmt != '%')
66 continue;
67 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +000068 * bb_dump_skip any special chars -- save precision in
Glenn L McGrath60281112001-11-02 11:39:46 +000069 * case it's a %s format.
70 */
Manuel Novoa III cad53642003-03-19 09:13:01 +000071 while (strchr(index_str + 1, *++fmt));
Glenn L McGrath60281112001-11-02 11:39:46 +000072 if (*fmt == '.' && isdigit(*++fmt)) {
73 prec = atoi(fmt);
74 while (isdigit(*++fmt));
75 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000076 if (!(p = strchr(size_conv_str + 12, *fmt))) {
77 if (*fmt == 's') {
78 bcnt += prec;
79 } else if (*fmt == '_') {
80 ++fmt;
81 if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
82 bcnt += 1;
83 }
Glenn L McGrath60281112001-11-02 11:39:46 +000084 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000085 } else {
86 bcnt += size_conv_str[p - (size_conv_str + 12)];
Glenn L McGrath60281112001-11-02 11:39:46 +000087 }
88 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000089 cur_size += bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000090 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000091 return (cur_size);
Glenn L McGrath60281112001-11-02 11:39:46 +000092}
93
Manuel Novoa III cad53642003-03-19 09:13:01 +000094static void rewrite(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000095{
96 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
97 register PR *pr, **nextpr = NULL;
98 register FU *fu;
Eric Andersen4a11e0f2003-04-19 23:18:35 +000099 register char *p1, *p2, *p3;
Glenn L McGrath60281112001-11-02 11:39:46 +0000100 char savech, *fmtp;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000101 const char *byte_count_str;
Glenn L McGrath60281112001-11-02 11:39:46 +0000102 int nconv, prec = 0;
103
104 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
105 /*
106 * break each format unit into print units; each
107 * conversion character gets its own.
108 */
109 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
110 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000111 /* DBU:[dvae@cray.com] calloc so that forward ptrs start out NULL*/
112 pr = (PR *) xcalloc(1,sizeof(PR));
Glenn L McGrath60281112001-11-02 11:39:46 +0000113 if (!fu->nextpr)
114 fu->nextpr = pr;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000115 /* ignore nextpr -- its unused inside the loop and is
116 * uninitialized 1st time thru.
117 */
Glenn L McGrath60281112001-11-02 11:39:46 +0000118
Manuel Novoa III cad53642003-03-19 09:13:01 +0000119 /* bb_dump_skip preceding text and up to the next % sign */
Glenn L McGrath60281112001-11-02 11:39:46 +0000120 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
121
122 /* only text in the string */
123 if (!*p1) {
124 pr->fmt = fmtp;
125 pr->flags = F_TEXT;
126 break;
127 }
128
129 /*
130 * get precision for %s -- if have a byte count, don't
131 * need it.
132 */
133 if (fu->bcnt) {
134 sokay = USEBCNT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000135 /* bb_dump_skip to conversion character */
136 for (++p1; strchr(index_str, *p1); ++p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000137 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000138 /* bb_dump_skip any special chars, field width */
139 while (strchr(index_str + 1, *++p1));
Glenn L McGrath60281112001-11-02 11:39:46 +0000140 if (*p1 == '.' && isdigit(*++p1)) {
141 sokay = USEPREC;
142 prec = atoi(p1);
143 while (isdigit(*++p1));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000144 } else
Glenn L McGrath60281112001-11-02 11:39:46 +0000145 sokay = NOTOKAY;
146 }
147
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000148 p2 = p1 + 1; /* set end pointer */
Glenn L McGrath60281112001-11-02 11:39:46 +0000149
150 /*
151 * figure out the byte count for each conversion;
152 * rewrite the format as necessary, set up blank-
Manuel Novoa III cad53642003-03-19 09:13:01 +0000153 * pbb_dump_adding for end of data.
Glenn L McGrath60281112001-11-02 11:39:46 +0000154 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000155
156 if (*p1 == 'c') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000157 pr->flags = F_CHAR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000158 DO_BYTE_COUNT_1:
159 byte_count_str = "\001";
160 DO_BYTE_COUNT:
161 if (fu->bcnt) {
162 do {
163 if (fu->bcnt == *byte_count_str) {
164 break;
165 }
166 } while (*++byte_count_str);
Glenn L McGrath60281112001-11-02 11:39:46 +0000167 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000168 /* Unlike the original, output the remainder of the format string. */
169 if (!*byte_count_str) {
170 bb_error_msg_and_die("bad byte count for conversion character %s.", p1);
171 }
172 pr->bcnt = *byte_count_str;
173 } else if (*p1 == 'l') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000174 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000175 ++p1;
176 DO_INT_CONV:
177 {
178 const char *e;
179 if (!(e = strchr(lcc, *p1))) {
180 goto DO_BAD_CONV_CHAR;
181 }
Glenn L McGrath60281112001-11-02 11:39:46 +0000182 pr->flags = F_INT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000183 if (e > lcc + 1) {
184 pr->flags = F_UINT;
185 }
186 byte_count_str = "\004\002\001";
187 goto DO_BYTE_COUNT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000188 }
189 /* NOTREACHED */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000190 } else if (strchr(lcc, *p1)) {
191 goto DO_INT_CONV;
192 } else if (strchr("eEfgG", *p1)) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000193 pr->flags = F_DBL;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000194 byte_count_str = "\010\004";
195 goto DO_BYTE_COUNT;
196 } else if (*p1 == 's') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000197 pr->flags = F_STR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000198 if (sokay == USEBCNT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000199 pr->bcnt = fu->bcnt;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000200 } else if (sokay == USEPREC) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000201 pr->bcnt = prec;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000202 } else { /* NOTOKAY */
203 bb_error_msg_and_die("%%s requires a precision or a byte count.");
Glenn L McGrath60281112001-11-02 11:39:46 +0000204 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000205 } else if (*p1 == '_') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000206 ++p2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000207 switch (p1[1]) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000208 case 'A':
209 endfu = fu;
210 fu->flags |= F_IGNORE;
211 /* FALLTHROUGH */
212 case 'a':
213 pr->flags = F_ADDRESS;
214 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000215 if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
216 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000217 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000218 *p1 = p1[2];
Glenn L McGrath60281112001-11-02 11:39:46 +0000219 break;
220 case 'c':
221 pr->flags = F_C;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000222 /* *p1 = 'c'; set in conv_c */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000223 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000224 case 'p':
225 pr->flags = F_P;
226 *p1 = 'c';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000227 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000228 case 'u':
229 pr->flags = F_U;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000230 /* *p1 = 'c'; set in conv_u */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000231 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000232 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000233 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000234 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000235 } else {
236 DO_BAD_CONV_CHAR:
237 bb_error_msg_and_die("bad conversion character %%%s.\n", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000238 }
239
240 /*
241 * copy to PR format string, set conversion character
242 * pointer, update original.
243 */
244 savech = *p2;
245 p1[1] = '\0';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000246 pr->fmt = bb_xstrdup(fmtp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000247 *p2 = savech;
248 pr->cchar = pr->fmt + (p1 - fmtp);
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000249
250 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
251 * Skip subsequent text and up to the next % sign and tack the
252 * additional text onto fmt: eg. if fmt is "%x is a HEX number",
253 * we lose the " is a HEX number" part of fmt.
254 */
255 for (p3 = p2; *p3 && *p3 != '%'; p3++);
256 if (p3 > p2)
257 {
258 savech = *p3;
259 *p3 = '\0';
260 if (!(pr->fmt = realloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1)))
Glenn L McGrath923dd792003-04-21 10:26:39 +0000261 bb_perror_msg_and_die("hexdump");
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000262 strcat(pr->fmt, p2);
263 *p3 = savech;
264 p2 = p3;
265 }
266
Glenn L McGrath60281112001-11-02 11:39:46 +0000267 fmtp = p2;
268
269 /* only one conversion character if byte count */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000270 if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000271 bb_error_msg_and_die("byte count with multiple conversion characters.\n");
Glenn L McGrath60281112001-11-02 11:39:46 +0000272 }
273 }
274 /*
275 * if format unit byte count not specified, figure it out
276 * so can adjust rep count later.
277 */
278 if (!fu->bcnt)
279 for (pr = fu->nextpr; pr; pr = pr->nextpr)
280 fu->bcnt += pr->bcnt;
281 }
282 /*
283 * if the format string interprets any data at all, and it's
Manuel Novoa III cad53642003-03-19 09:13:01 +0000284 * not the same as the bb_dump_blocksize, and its last format unit
Glenn L McGrath60281112001-11-02 11:39:46 +0000285 * interprets any data at all, and has no iteration count,
286 * repeat it as necessary.
287 *
288 * if, rep count is greater than 1, no trailing whitespace
289 * gets output from the last iteration of the format unit.
290 */
291 for (fu = fs->nextfu;; fu = fu->nextfu) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000292 if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000293 !(fu->flags & F_SETREP) && fu->bcnt)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000294 fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000295 if (fu->reps > 1) {
296 for (pr = fu->nextpr;; pr = pr->nextpr)
297 if (!pr->nextpr)
298 break;
299 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
300 p2 = isspace(*p1) ? p1 : NULL;
301 if (p2)
302 pr->nospace = p2;
303 }
304 if (!fu->nextfu)
305 break;
306 }
307}
308
Manuel Novoa III cad53642003-03-19 09:13:01 +0000309static void do_skip(char *fname, int statok)
Glenn L McGrath60281112001-11-02 11:39:46 +0000310{
311 struct stat sbuf;
312
313 if (statok) {
314 if (fstat(fileno(stdin), &sbuf)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000315 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000316 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000317 if ((!(S_ISCHR(sbuf.st_mode) ||
318 S_ISBLK(sbuf.st_mode) ||
Manuel Novoa III cad53642003-03-19 09:13:01 +0000319 S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
320 /* If bb_dump_size valid and bb_dump_skip >= size */
321 bb_dump_skip -= sbuf.st_size;
Glenn L McGrath60281112001-11-02 11:39:46 +0000322 address += sbuf.st_size;
323 return;
324 }
325 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000326 if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
327 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000328 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000329 savaddress = address += bb_dump_skip;
330 bb_dump_skip = 0;
Glenn L McGrath60281112001-11-02 11:39:46 +0000331}
332
Manuel Novoa III cad53642003-03-19 09:13:01 +0000333static int next(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000334{
335 static int done;
336 int statok;
337
338 if (argv) {
339 _argv = argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000340 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000341 }
342 for (;;) {
343 if (*_argv) {
344 if (!(freopen(*_argv, "r", stdin))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000345 bb_perror_msg("%s", *_argv);
Glenn L McGrath60281112001-11-02 11:39:46 +0000346 exitval = 1;
347 ++_argv;
348 continue;
349 }
350 statok = done = 1;
351 } else {
352 if (done++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000353 return (0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000354 statok = 0;
355 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000356 if (bb_dump_skip)
357 do_skip(statok ? *_argv : "stdin", statok);
Glenn L McGrath60281112001-11-02 11:39:46 +0000358 if (*_argv)
359 ++_argv;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000360 if (!bb_dump_skip)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000361 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000362 }
363 /* NOTREACHED */
364}
365
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000366static u_char *get(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000367{
368 static int ateof = 1;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000369 static u_char *curp=NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
Glenn L McGrath60281112001-11-02 11:39:46 +0000370 register int n;
371 int need, nread;
372 u_char *tmpp;
373
374 if (!curp) {
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000375 address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
Manuel Novoa III cad53642003-03-19 09:13:01 +0000376 curp = (u_char *) xmalloc(bb_dump_blocksize);
377 savp = (u_char *) xmalloc(bb_dump_blocksize);
Glenn L McGrath60281112001-11-02 11:39:46 +0000378 } else {
379 tmpp = curp;
380 curp = savp;
381 savp = tmpp;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000382 address = savaddress += bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000383 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000384 for (need = bb_dump_blocksize, nread = 0;;) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000385 /*
386 * if read the right number of bytes, or at EOF for one file,
387 * and no other files are available, zero-pad the rest of the
388 * block and set the end flag.
389 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000390 if (!bb_dump_length || (ateof && !next((char **) NULL))) {
391 if (need == bb_dump_blocksize) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000392 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000393 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000394 if (bb_dump_vflag != ALL && !bcmp(curp, savp, nread)) {
395 if (bb_dump_vflag != DUP) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000396 printf("*\n");
397 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000398 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000399 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000400 bzero((char *) curp + nread, need);
Glenn L McGrath60281112001-11-02 11:39:46 +0000401 eaddress = address + nread;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000402 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000403 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000404 n = fread((char *) curp + nread, sizeof(u_char),
Manuel Novoa III cad53642003-03-19 09:13:01 +0000405 bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
Glenn L McGrath60281112001-11-02 11:39:46 +0000406 if (!n) {
407 if (ferror(stdin)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000408 bb_perror_msg("%s", _argv[-1]);
Glenn L McGrath60281112001-11-02 11:39:46 +0000409 }
410 ateof = 1;
411 continue;
412 }
413 ateof = 0;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000414 if (bb_dump_length != -1) {
415 bb_dump_length -= n;
Glenn L McGrath60281112001-11-02 11:39:46 +0000416 }
417 if (!(need -= n)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000418 if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
419 || bcmp(curp, savp, bb_dump_blocksize)) {
420 if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
421 bb_dump_vflag = WAIT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000422 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000423 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000424 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000425 if (bb_dump_vflag == WAIT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000426 printf("*\n");
427 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000428 bb_dump_vflag = DUP;
429 address = savaddress += bb_dump_blocksize;
430 need = bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000431 nread = 0;
432 } else {
433 nread += n;
434 }
435 }
436}
437
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000438static void bpad(PR * pr)
Glenn L McGrath60281112001-11-02 11:39:46 +0000439{
440 register char *p1, *p2;
441
442 /*
443 * remove all conversion flags; '-' is the only one valid
444 * with %s, and it's not useful here.
445 */
446 pr->flags = F_BPAD;
447 *pr->cchar = 's';
448 for (p1 = pr->fmt; *p1 != '%'; ++p1);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000449 for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000450 while ((*p2++ = *p1++) != 0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000451}
452
Manuel Novoa III cad53642003-03-19 09:13:01 +0000453static const char conv_str[] =
454 "\0\\0\0"
455 "\007\\a\0" /* \a */
456 "\b\\b\0"
457 "\f\\b\0"
458 "\n\\n\0"
459 "\r\\r\0"
460 "\t\\t\0"
461 "\v\\v\0"
462 "\0";
Glenn L McGrath60281112001-11-02 11:39:46 +0000463
Manuel Novoa III cad53642003-03-19 09:13:01 +0000464
465static void conv_c(PR * pr, u_char * p)
466{
467 const char *str = conv_str;
468 char buf[10];
469
470 do {
471 if (*p == *str) {
472 ++str;
473 goto strpr;
474 }
475 str += 4;
476 } while (*str);
477
Glenn L McGrath60281112001-11-02 11:39:46 +0000478 if (isprint(*p)) {
479 *pr->cchar = 'c';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000480 (void) printf(pr->fmt, *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000481 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000482 sprintf(buf, "%03o", (int) *p);
483 str = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000484 strpr:
Glenn L McGrath60281112001-11-02 11:39:46 +0000485 *pr->cchar = 's';
486 printf(pr->fmt, str);
487 }
488}
489
Manuel Novoa III cad53642003-03-19 09:13:01 +0000490static void conv_u(PR * pr, u_char * p)
Glenn L McGrath60281112001-11-02 11:39:46 +0000491{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000492 static const char list[] =
493 "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
494 "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
495 "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
496 "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
Glenn L McGrath60281112001-11-02 11:39:46 +0000497
498 /* od used nl, not lf */
499 if (*p <= 0x1f) {
500 *pr->cchar = 's';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000501 printf(pr->fmt, list[4 * (int)(*p)]);
Glenn L McGrath60281112001-11-02 11:39:46 +0000502 } else if (*p == 0x7f) {
503 *pr->cchar = 's';
504 printf(pr->fmt, "del");
505 } else if (isprint(*p)) {
506 *pr->cchar = 'c';
507 printf(pr->fmt, *p);
508 } else {
509 *pr->cchar = 'x';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000510 printf(pr->fmt, (int) *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000511 }
512}
513
Manuel Novoa III cad53642003-03-19 09:13:01 +0000514static void display(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000515{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000516/* extern FU *endfu; */
Glenn L McGrath60281112001-11-02 11:39:46 +0000517 register FS *fs;
518 register FU *fu;
519 register PR *pr;
520 register int cnt;
521 register u_char *bp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000522
Manuel Novoa III cad53642003-03-19 09:13:01 +0000523 off_t saveaddress;
Glenn L McGrath60281112001-11-02 11:39:46 +0000524 u_char savech = 0, *savebp;
525
526 while ((bp = get()) != NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000527 for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000528 fs = fs->nextfs, bp = savebp, address = saveaddress) {
529 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000530 if (fu->flags & F_IGNORE) {
531 break;
532 }
533 for (cnt = fu->reps; cnt; --cnt) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000534 for (pr = fu->nextpr; pr; address += pr->bcnt,
535 bp += pr->bcnt, pr = pr->nextpr) {
536 if (eaddress && address >= eaddress &&
537 !(pr->flags & (F_TEXT | F_BPAD))) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000538 bpad(pr);
539 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000540 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000541 savech = *pr->nospace;
542 *pr->nospace = '\0';
Glenn L McGrath60281112001-11-02 11:39:46 +0000543 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000544/* PRINT; */
545 switch (pr->flags) {
546 case F_ADDRESS:
547 printf(pr->fmt, address);
548 break;
549 case F_BPAD:
550 printf(pr->fmt, "");
551 break;
552 case F_C:
553 conv_c(pr, bp);
554 break;
555 case F_CHAR:
556 printf(pr->fmt, *bp);
557 break;
558 case F_DBL:{
559 double dval;
560 float fval;
561
562 switch (pr->bcnt) {
563 case 4:
564 bcopy((char *) bp, (char *) &fval,
565 sizeof(fval));
566 printf(pr->fmt, fval);
567 break;
568 case 8:
569 bcopy((char *) bp, (char *) &dval,
570 sizeof(dval));
571 printf(pr->fmt, dval);
572 break;
573 }
574 break;
575 }
576 case F_INT:{
577 int ival;
578 short sval;
579
580 switch (pr->bcnt) {
581 case 1:
582 printf(pr->fmt, (int) *bp);
583 break;
584 case 2:
585 bcopy((char *) bp, (char *) &sval,
586 sizeof(sval));
587 printf(pr->fmt, (int) sval);
588 break;
589 case 4:
590 bcopy((char *) bp, (char *) &ival,
591 sizeof(ival));
592 printf(pr->fmt, ival);
593 break;
594 }
595 break;
596 }
597 case F_P:
598 printf(pr->fmt, isprint(*bp) ? *bp : '.');
599 break;
600 case F_STR:
601 printf(pr->fmt, (char *) bp);
602 break;
603 case F_TEXT:
604 printf(pr->fmt);
605 break;
606 case F_U:
607 conv_u(pr, bp);
608 break;
609 case F_UINT:{
610 u_int ival;
611 u_short sval;
612
613 switch (pr->bcnt) {
614 case 1:
615 printf(pr->fmt, (u_int) * bp);
616 break;
617 case 2:
618 bcopy((char *) bp, (char *) &sval,
619 sizeof(sval));
620 printf(pr->fmt, (u_int) sval);
621 break;
622 case 4:
623 bcopy((char *) bp, (char *) &ival,
624 sizeof(ival));
625 printf(pr->fmt, ival);
626 break;
627 }
628 break;
629 }
630 }
631 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000632 *pr->nospace = savech;
633 }
634 }
635 }
636 }
637 }
638 }
639 if (endfu) {
640 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +0000641 * if eaddress not set, error or file bb_dump_size was multiple of
642 * bb_dump_blocksize, and no partial block ever found.
Glenn L McGrath60281112001-11-02 11:39:46 +0000643 */
644 if (!eaddress) {
645 if (!address) {
646 return;
647 }
648 eaddress = address;
649 }
650 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000651 switch (pr->flags) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000652 case F_ADDRESS:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000653 (void) printf(pr->fmt, eaddress);
Glenn L McGrath60281112001-11-02 11:39:46 +0000654 break;
655 case F_TEXT:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000656 (void) printf(pr->fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000657 break;
658 }
659 }
660 }
661}
662
Manuel Novoa III cad53642003-03-19 09:13:01 +0000663int bb_dump_dump(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000664{
665 register FS *tfs;
666
Manuel Novoa III cad53642003-03-19 09:13:01 +0000667 /* figure out the data block bb_dump_size */
668 for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
669 tfs->bcnt = bb_dump_size(tfs);
670 if (bb_dump_blocksize < tfs->bcnt) {
671 bb_dump_blocksize = tfs->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000672 }
673 }
674 /* rewrite the rules, do syntax checking */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000675 for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000676 rewrite(tfs);
677 }
678
679 next(argv);
680 display();
681
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000682 return (exitval);
Glenn L McGrath60281112001-11-02 11:39:46 +0000683}
684
Manuel Novoa III cad53642003-03-19 09:13:01 +0000685void bb_dump_add(const char *fmt)
Glenn L McGrath60281112001-11-02 11:39:46 +0000686{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000687 register const char *p;
Glenn L McGrath60281112001-11-02 11:39:46 +0000688 register char *p1;
689 register char *p2;
690 static FS **nextfs;
691 FS *tfs;
692 FU *tfu, **nextfu;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000693 const char *savep;
Glenn L McGrath60281112001-11-02 11:39:46 +0000694
695 /* start new linked list of format units */
696 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000697 tfs = (FS *) xcalloc(1,sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000698 if (!bb_dump_fshead) {
699 bb_dump_fshead = tfs;
Glenn L McGrath60281112001-11-02 11:39:46 +0000700 } else {
701 *nextfs = tfs;
702 }
703 nextfs = &tfs->nextfs;
704 nextfu = &tfs->nextfu;
705
706 /* take the format string and break it up into format units */
707 for (p = fmt;;) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000708 /* bb_dump_skip leading white space */
709 p = bb_skip_whitespace(p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000710 if (!*p) {
711 break;
712 }
713
714 /* allocate a new format unit and link it in */
715 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000716 /* DBU:[dave@cray.com] calloc so that forward pointers start out NULL */
717 tfu = (FU *) xcalloc(1,sizeof(FU));
Glenn L McGrath60281112001-11-02 11:39:46 +0000718 *nextfu = tfu;
719 nextfu = &tfu->nextfu;
720 tfu->reps = 1;
721
722 /* if leading digit, repetition count */
723 if (isdigit(*p)) {
724 for (savep = p; isdigit(*p); ++p);
725 if (!isspace(*p) && *p != '/') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000726 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000727 }
728 /* may overwrite either white space or slash */
729 tfu->reps = atoi(savep);
730 tfu->flags = F_SETREP;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000731 /* bb_dump_skip trailing white space */
732 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000733 }
734
Manuel Novoa III cad53642003-03-19 09:13:01 +0000735 /* bb_dump_skip slash and trailing white space */
Glenn L McGrath60281112001-11-02 11:39:46 +0000736 if (*p == '/') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000737 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000738 }
739
740 /* byte count */
741 if (isdigit(*p)) {
742 for (savep = p; isdigit(*p); ++p);
743 if (!isspace(*p)) {
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 tfu->bcnt = atoi(savep);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000747 /* bb_dump_skip trailing white space */
748 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000749 }
750
751 /* format */
752 if (*p != '"') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000753 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000754 }
755 for (savep = ++p; *p != '"';) {
756 if (*p++ == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000757 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000758 }
759 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000760 tfu->fmt = xmalloc(p - savep + 1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000761 strncpy(tfu->fmt, savep, p - savep);
762 tfu->fmt[p - savep] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000763/* escape(tfu->fmt); */
Glenn L McGrath60281112001-11-02 11:39:46 +0000764
765 p1 = tfu->fmt;
766
767 /* alphabetic escape sequences have to be done in place */
768 for (p2 = p1;; ++p1, ++p2) {
769 if (!*p1) {
770 *p2 = *p1;
771 break;
772 }
773 if (*p1 == '\\') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000774 const char *cs = conv_str + 4;
775 ++p1;
776 *p2 = *p1;
777 do {
778 if (*p1 == cs[2]) {
779 *p2 = cs[0];
780 break;
781 }
782 cs += 4;
783 } while (*cs);
Glenn L McGrath60281112001-11-02 11:39:46 +0000784 }
785 }
786
787 p++;
788 }
789}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000790
Glenn L McGrath60281112001-11-02 11:39:46 +0000791/*
792 * Copyright (c) 1989 The Regents of the University of California.
793 * All rights reserved.
794 *
795 * Redistribution and use in source and binary forms, with or without
796 * modification, are permitted provided that the following conditions
797 * are met:
798 * 1. Redistributions of source code must retain the above copyright
799 * notice, this list of conditions and the following disclaimer.
800 * 2. Redistributions in binary form must reproduce the above copyright
801 * notice, this list of conditions and the following disclaimer in the
802 * documentation and/or other materials provided with the distribution.
Aaron Lehmann69d41782002-06-23 22:25:24 +0000803 * 3. Neither the name of the University nor the names of its contributors
Glenn L McGrath60281112001-11-02 11:39:46 +0000804 * may be used to endorse or promote products derived from this software
805 * without specific prior written permission.
806 *
807 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
808 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
809 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
810 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
811 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
812 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
813 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
814 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
815 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
816 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
817 * SUCH DAMAGE.
818 */