blob: 98f004ff6acce0643d560c70031ee31bd1d374dd [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>
Eric Andersen8ee2b272004-03-27 11:26:32 +000027#include <unistd.h>
Glenn L McGrath60281112001-11-02 11:39:46 +000028#include <ctype.h> /* for isdigit() */
Glenn L McGrath60281112001-11-02 11:39:46 +000029#include "libbb.h"
Manuel Novoa III cad53642003-03-19 09:13:01 +000030#include "dump.h"
Glenn L McGrath60281112001-11-02 11:39:46 +000031
Manuel Novoa III cad53642003-03-19 09:13:01 +000032enum _vflag bb_dump_vflag = FIRST;
33FS *bb_dump_fshead; /* head of format strings */
Glenn L McGrath60281112001-11-02 11:39:46 +000034static FU *endfu;
35static char **_argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000036static off_t savaddress; /* saved address/offset in stream */
37static off_t eaddress; /* end address */
38static off_t address; /* address/offset in stream */
Manuel Novoa III cad53642003-03-19 09:13:01 +000039off_t bb_dump_skip; /* bytes to skip */
40static int exitval; /* final exit value */
41int bb_dump_blocksize; /* data block size */
42int bb_dump_length = -1; /* max bytes to read */
Glenn L McGrath60281112001-11-02 11:39:46 +000043
Manuel Novoa III cad53642003-03-19 09:13:01 +000044static const char index_str[] = ".#-+ 0123456789";
Glenn L McGrath60281112001-11-02 11:39:46 +000045
Manuel Novoa III cad53642003-03-19 09:13:01 +000046static const char size_conv_str[] =
47"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
48
49static const char lcc[] = "diouxX";
50
51int bb_dump_size(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000052{
53 register FU *fu;
Manuel Novoa III cad53642003-03-19 09:13:01 +000054 register int bcnt, cur_size;
Glenn L McGrath60281112001-11-02 11:39:46 +000055 register char *fmt;
Manuel Novoa III cad53642003-03-19 09:13:01 +000056 const char *p;
Glenn L McGrath60281112001-11-02 11:39:46 +000057 int prec;
58
Manuel Novoa III cad53642003-03-19 09:13:01 +000059 /* figure out the data block bb_dump_size needed for each format unit */
60 for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +000061 if (fu->bcnt) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000062 cur_size += fu->bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000063 continue;
64 }
65 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
66 if (*fmt != '%')
67 continue;
68 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +000069 * bb_dump_skip any special chars -- save precision in
Glenn L McGrath60281112001-11-02 11:39:46 +000070 * case it's a %s format.
71 */
Manuel Novoa III cad53642003-03-19 09:13:01 +000072 while (strchr(index_str + 1, *++fmt));
Glenn L McGrath60281112001-11-02 11:39:46 +000073 if (*fmt == '.' && isdigit(*++fmt)) {
74 prec = atoi(fmt);
75 while (isdigit(*++fmt));
76 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000077 if (!(p = strchr(size_conv_str + 12, *fmt))) {
78 if (*fmt == 's') {
79 bcnt += prec;
80 } else if (*fmt == '_') {
81 ++fmt;
82 if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
83 bcnt += 1;
84 }
Glenn L McGrath60281112001-11-02 11:39:46 +000085 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000086 } else {
87 bcnt += size_conv_str[p - (size_conv_str + 12)];
Glenn L McGrath60281112001-11-02 11:39:46 +000088 }
89 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000090 cur_size += bcnt * fu->reps;
Glenn L McGrath60281112001-11-02 11:39:46 +000091 }
Manuel Novoa III cad53642003-03-19 09:13:01 +000092 return (cur_size);
Glenn L McGrath60281112001-11-02 11:39:46 +000093}
94
Manuel Novoa III cad53642003-03-19 09:13:01 +000095static void rewrite(FS * fs)
Glenn L McGrath60281112001-11-02 11:39:46 +000096{
97 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
98 register PR *pr, **nextpr = NULL;
99 register FU *fu;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000100 register char *p1, *p2, *p3;
Glenn L McGrath60281112001-11-02 11:39:46 +0000101 char savech, *fmtp;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000102 const char *byte_count_str;
Glenn L McGrath60281112001-11-02 11:39:46 +0000103 int nconv, prec = 0;
104
105 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
106 /*
107 * break each format unit into print units; each
108 * conversion character gets its own.
109 */
110 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
111 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000112 /* DBU:[dvae@cray.com] calloc so that forward ptrs start out NULL*/
113 pr = (PR *) xcalloc(1,sizeof(PR));
Glenn L McGrath60281112001-11-02 11:39:46 +0000114 if (!fu->nextpr)
115 fu->nextpr = pr;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000116 /* ignore nextpr -- its unused inside the loop and is
117 * uninitialized 1st time thru.
118 */
Glenn L McGrath60281112001-11-02 11:39:46 +0000119
Manuel Novoa III cad53642003-03-19 09:13:01 +0000120 /* bb_dump_skip preceding text and up to the next % sign */
Glenn L McGrath60281112001-11-02 11:39:46 +0000121 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
122
123 /* only text in the string */
124 if (!*p1) {
125 pr->fmt = fmtp;
126 pr->flags = F_TEXT;
127 break;
128 }
129
130 /*
131 * get precision for %s -- if have a byte count, don't
132 * need it.
133 */
134 if (fu->bcnt) {
135 sokay = USEBCNT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000136 /* bb_dump_skip to conversion character */
137 for (++p1; strchr(index_str, *p1); ++p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000138 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000139 /* bb_dump_skip any special chars, field width */
140 while (strchr(index_str + 1, *++p1));
Glenn L McGrath60281112001-11-02 11:39:46 +0000141 if (*p1 == '.' && isdigit(*++p1)) {
142 sokay = USEPREC;
143 prec = atoi(p1);
144 while (isdigit(*++p1));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000145 } else
Glenn L McGrath60281112001-11-02 11:39:46 +0000146 sokay = NOTOKAY;
147 }
148
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000149 p2 = p1 + 1; /* set end pointer */
Glenn L McGrath60281112001-11-02 11:39:46 +0000150
151 /*
152 * figure out the byte count for each conversion;
153 * rewrite the format as necessary, set up blank-
Manuel Novoa III cad53642003-03-19 09:13:01 +0000154 * pbb_dump_adding for end of data.
Glenn L McGrath60281112001-11-02 11:39:46 +0000155 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000156
157 if (*p1 == 'c') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000158 pr->flags = F_CHAR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000159 DO_BYTE_COUNT_1:
160 byte_count_str = "\001";
161 DO_BYTE_COUNT:
162 if (fu->bcnt) {
163 do {
164 if (fu->bcnt == *byte_count_str) {
165 break;
166 }
167 } while (*++byte_count_str);
Glenn L McGrath60281112001-11-02 11:39:46 +0000168 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000169 /* Unlike the original, output the remainder of the format string. */
170 if (!*byte_count_str) {
171 bb_error_msg_and_die("bad byte count for conversion character %s.", p1);
172 }
173 pr->bcnt = *byte_count_str;
174 } else if (*p1 == 'l') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000175 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000176 ++p1;
177 DO_INT_CONV:
178 {
179 const char *e;
180 if (!(e = strchr(lcc, *p1))) {
181 goto DO_BAD_CONV_CHAR;
182 }
Glenn L McGrath60281112001-11-02 11:39:46 +0000183 pr->flags = F_INT;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000184 if (e > lcc + 1) {
185 pr->flags = F_UINT;
186 }
187 byte_count_str = "\004\002\001";
188 goto DO_BYTE_COUNT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000189 }
190 /* NOTREACHED */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000191 } else if (strchr(lcc, *p1)) {
192 goto DO_INT_CONV;
193 } else if (strchr("eEfgG", *p1)) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000194 pr->flags = F_DBL;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000195 byte_count_str = "\010\004";
196 goto DO_BYTE_COUNT;
197 } else if (*p1 == 's') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000198 pr->flags = F_STR;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000199 if (sokay == USEBCNT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000200 pr->bcnt = fu->bcnt;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000201 } else if (sokay == USEPREC) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000202 pr->bcnt = prec;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000203 } else { /* NOTOKAY */
204 bb_error_msg_and_die("%%s requires a precision or a byte count.");
Glenn L McGrath60281112001-11-02 11:39:46 +0000205 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000206 } else if (*p1 == '_') {
Glenn L McGrath60281112001-11-02 11:39:46 +0000207 ++p2;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000208 switch (p1[1]) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000209 case 'A':
210 endfu = fu;
211 fu->flags |= F_IGNORE;
212 /* FALLTHROUGH */
213 case 'a':
214 pr->flags = F_ADDRESS;
215 ++p2;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000216 if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
217 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000218 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000219 *p1 = p1[2];
Glenn L McGrath60281112001-11-02 11:39:46 +0000220 break;
221 case 'c':
222 pr->flags = F_C;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000223 /* *p1 = 'c'; set in conv_c */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000224 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000225 case 'p':
226 pr->flags = F_P;
227 *p1 = 'c';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000228 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000229 case 'u':
230 pr->flags = F_U;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000231 /* *p1 = 'c'; set in conv_u */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000232 goto DO_BYTE_COUNT_1;
Glenn L McGrath60281112001-11-02 11:39:46 +0000233 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000234 goto DO_BAD_CONV_CHAR;
Glenn L McGrath60281112001-11-02 11:39:46 +0000235 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000236 } else {
237 DO_BAD_CONV_CHAR:
238 bb_error_msg_and_die("bad conversion character %%%s.\n", p1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000239 }
240
241 /*
242 * copy to PR format string, set conversion character
243 * pointer, update original.
244 */
245 savech = *p2;
246 p1[1] = '\0';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000247 pr->fmt = bb_xstrdup(fmtp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000248 *p2 = savech;
249 pr->cchar = pr->fmt + (p1 - fmtp);
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000250
251 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000252 * Skip subsequent text and up to the next % sign and tack the
253 * additional text onto fmt: eg. if fmt is "%x is a HEX number",
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000254 * we lose the " is a HEX number" part of fmt.
255 */
256 for (p3 = p2; *p3 && *p3 != '%'; p3++);
257 if (p3 > p2)
258 {
259 savech = *p3;
260 *p3 = '\0';
261 if (!(pr->fmt = realloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1)))
Glenn L McGrath923dd792003-04-21 10:26:39 +0000262 bb_perror_msg_and_die("hexdump");
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000263 strcat(pr->fmt, p2);
264 *p3 = savech;
265 p2 = p3;
266 }
267
Glenn L McGrath60281112001-11-02 11:39:46 +0000268 fmtp = p2;
269
270 /* only one conversion character if byte count */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000271 if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000272 bb_error_msg_and_die("byte count with multiple conversion characters.\n");
Glenn L McGrath60281112001-11-02 11:39:46 +0000273 }
274 }
275 /*
276 * if format unit byte count not specified, figure it out
277 * so can adjust rep count later.
278 */
279 if (!fu->bcnt)
280 for (pr = fu->nextpr; pr; pr = pr->nextpr)
281 fu->bcnt += pr->bcnt;
282 }
283 /*
284 * if the format string interprets any data at all, and it's
Manuel Novoa III cad53642003-03-19 09:13:01 +0000285 * not the same as the bb_dump_blocksize, and its last format unit
Glenn L McGrath60281112001-11-02 11:39:46 +0000286 * interprets any data at all, and has no iteration count,
287 * repeat it as necessary.
288 *
289 * if, rep count is greater than 1, no trailing whitespace
290 * gets output from the last iteration of the format unit.
291 */
292 for (fu = fs->nextfu;; fu = fu->nextfu) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000293 if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000294 !(fu->flags & F_SETREP) && fu->bcnt)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000295 fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000296 if (fu->reps > 1) {
297 for (pr = fu->nextpr;; pr = pr->nextpr)
298 if (!pr->nextpr)
299 break;
300 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
301 p2 = isspace(*p1) ? p1 : NULL;
302 if (p2)
303 pr->nospace = p2;
304 }
305 if (!fu->nextfu)
306 break;
307 }
308}
309
Manuel Novoa III cad53642003-03-19 09:13:01 +0000310static void do_skip(char *fname, int statok)
Glenn L McGrath60281112001-11-02 11:39:46 +0000311{
312 struct stat sbuf;
313
314 if (statok) {
Eric Andersen70060d22004-03-27 10:02:48 +0000315 if (fstat(STDIN_FILENO, &sbuf)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000316 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000317 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000318 if ((!(S_ISCHR(sbuf.st_mode) ||
319 S_ISBLK(sbuf.st_mode) ||
Manuel Novoa III cad53642003-03-19 09:13:01 +0000320 S_ISFIFO(sbuf.st_mode))) && bb_dump_skip >= sbuf.st_size) {
321 /* If bb_dump_size valid and bb_dump_skip >= size */
322 bb_dump_skip -= sbuf.st_size;
Glenn L McGrath60281112001-11-02 11:39:46 +0000323 address += sbuf.st_size;
324 return;
325 }
326 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000327 if (fseek(stdin, bb_dump_skip, SEEK_SET)) {
328 bb_perror_msg_and_die("%s", fname);
Glenn L McGrath60281112001-11-02 11:39:46 +0000329 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000330 savaddress = address += bb_dump_skip;
331 bb_dump_skip = 0;
Glenn L McGrath60281112001-11-02 11:39:46 +0000332}
333
Manuel Novoa III cad53642003-03-19 09:13:01 +0000334static int next(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000335{
336 static int done;
337 int statok;
338
339 if (argv) {
340 _argv = argv;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000341 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000342 }
343 for (;;) {
344 if (*_argv) {
345 if (!(freopen(*_argv, "r", stdin))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000346 bb_perror_msg("%s", *_argv);
Glenn L McGrath60281112001-11-02 11:39:46 +0000347 exitval = 1;
348 ++_argv;
349 continue;
350 }
351 statok = done = 1;
352 } else {
353 if (done++)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000354 return (0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000355 statok = 0;
356 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000357 if (bb_dump_skip)
358 do_skip(statok ? *_argv : "stdin", statok);
Glenn L McGrath60281112001-11-02 11:39:46 +0000359 if (*_argv)
360 ++_argv;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000361 if (!bb_dump_skip)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000362 return (1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000363 }
364 /* NOTREACHED */
365}
366
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000367static u_char *get(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000368{
369 static int ateof = 1;
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000370 static u_char *curp=NULL, *savp; /*DBU:[dave@cray.com]initialize curp */
Glenn L McGrath60281112001-11-02 11:39:46 +0000371 register int n;
372 int need, nread;
373 u_char *tmpp;
374
375 if (!curp) {
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000376 address = (off_t)0; /*DBU:[dave@cray.com] initialize,initialize..*/
Manuel Novoa III cad53642003-03-19 09:13:01 +0000377 curp = (u_char *) xmalloc(bb_dump_blocksize);
378 savp = (u_char *) xmalloc(bb_dump_blocksize);
Glenn L McGrath60281112001-11-02 11:39:46 +0000379 } else {
380 tmpp = curp;
381 curp = savp;
382 savp = tmpp;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000383 address = savaddress += bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000384 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000385 for (need = bb_dump_blocksize, nread = 0;;) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000386 /*
387 * if read the right number of bytes, or at EOF for one file,
388 * and no other files are available, zero-pad the rest of the
389 * block and set the end flag.
390 */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000391 if (!bb_dump_length || (ateof && !next((char **) NULL))) {
392 if (need == bb_dump_blocksize) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000393 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000394 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000395 if (bb_dump_vflag != ALL && !bcmp(curp, savp, nread)) {
396 if (bb_dump_vflag != DUP) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000397 printf("*\n");
398 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000399 return ((u_char *) NULL);
Glenn L McGrath60281112001-11-02 11:39:46 +0000400 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000401 bzero((char *) curp + nread, need);
Glenn L McGrath60281112001-11-02 11:39:46 +0000402 eaddress = address + nread;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000403 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000404 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000405 n = fread((char *) curp + nread, sizeof(u_char),
Manuel Novoa III cad53642003-03-19 09:13:01 +0000406 bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
Glenn L McGrath60281112001-11-02 11:39:46 +0000407 if (!n) {
408 if (ferror(stdin)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000409 bb_perror_msg("%s", _argv[-1]);
Glenn L McGrath60281112001-11-02 11:39:46 +0000410 }
411 ateof = 1;
412 continue;
413 }
414 ateof = 0;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000415 if (bb_dump_length != -1) {
416 bb_dump_length -= n;
Glenn L McGrath60281112001-11-02 11:39:46 +0000417 }
418 if (!(need -= n)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000419 if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
420 || bcmp(curp, savp, bb_dump_blocksize)) {
421 if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
422 bb_dump_vflag = WAIT;
Glenn L McGrath60281112001-11-02 11:39:46 +0000423 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000424 return (curp);
Glenn L McGrath60281112001-11-02 11:39:46 +0000425 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000426 if (bb_dump_vflag == WAIT) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000427 printf("*\n");
428 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000429 bb_dump_vflag = DUP;
430 address = savaddress += bb_dump_blocksize;
431 need = bb_dump_blocksize;
Glenn L McGrath60281112001-11-02 11:39:46 +0000432 nread = 0;
433 } else {
434 nread += n;
435 }
436 }
437}
438
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000439static void bpad(PR * pr)
Glenn L McGrath60281112001-11-02 11:39:46 +0000440{
441 register char *p1, *p2;
442
443 /*
444 * remove all conversion flags; '-' is the only one valid
445 * with %s, and it's not useful here.
446 */
447 pr->flags = F_BPAD;
448 *pr->cchar = 's';
449 for (p1 = pr->fmt; *p1 != '%'; ++p1);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000450 for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000451 while ((*p2++ = *p1++) != 0);
Glenn L McGrath60281112001-11-02 11:39:46 +0000452}
453
Manuel Novoa III cad53642003-03-19 09:13:01 +0000454static const char conv_str[] =
455 "\0\\0\0"
456 "\007\\a\0" /* \a */
457 "\b\\b\0"
458 "\f\\b\0"
459 "\n\\n\0"
460 "\r\\r\0"
461 "\t\\t\0"
462 "\v\\v\0"
463 "\0";
Glenn L McGrath60281112001-11-02 11:39:46 +0000464
Manuel Novoa III cad53642003-03-19 09:13:01 +0000465
466static void conv_c(PR * pr, u_char * p)
467{
468 const char *str = conv_str;
469 char buf[10];
470
471 do {
472 if (*p == *str) {
473 ++str;
474 goto strpr;
475 }
476 str += 4;
477 } while (*str);
478
Glenn L McGrath60281112001-11-02 11:39:46 +0000479 if (isprint(*p)) {
480 *pr->cchar = 'c';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000481 (void) printf(pr->fmt, *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000482 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000483 sprintf(buf, "%03o", (int) *p);
484 str = buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000485 strpr:
Glenn L McGrath60281112001-11-02 11:39:46 +0000486 *pr->cchar = 's';
487 printf(pr->fmt, str);
488 }
489}
490
Manuel Novoa III cad53642003-03-19 09:13:01 +0000491static void conv_u(PR * pr, u_char * p)
Glenn L McGrath60281112001-11-02 11:39:46 +0000492{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000493 static const char list[] =
494 "nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
495 "bs\0_ht\0_lf\0_vt\0_ff\0_cr\0_so\0_si\0_"
496 "dle\0dcl\0dc2\0dc3\0dc4\0nak\0syn\0etb\0"
497 "can\0em\0_sub\0esc\0fs\0_gs\0_rs\0_us";
Glenn L McGrath60281112001-11-02 11:39:46 +0000498
499 /* od used nl, not lf */
500 if (*p <= 0x1f) {
501 *pr->cchar = 's';
Glenn L McGratheeb06bf2004-07-23 01:35:41 +0000502 printf(pr->fmt, list + (4 * (int)*p));
Glenn L McGrath60281112001-11-02 11:39:46 +0000503 } else if (*p == 0x7f) {
504 *pr->cchar = 's';
505 printf(pr->fmt, "del");
506 } else if (isprint(*p)) {
507 *pr->cchar = 'c';
508 printf(pr->fmt, *p);
509 } else {
510 *pr->cchar = 'x';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000511 printf(pr->fmt, (int) *p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000512 }
513}
514
Manuel Novoa III cad53642003-03-19 09:13:01 +0000515static void display(void)
Glenn L McGrath60281112001-11-02 11:39:46 +0000516{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000517/* extern FU *endfu; */
Glenn L McGrath60281112001-11-02 11:39:46 +0000518 register FS *fs;
519 register FU *fu;
520 register PR *pr;
521 register int cnt;
522 register u_char *bp;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000523
Manuel Novoa III cad53642003-03-19 09:13:01 +0000524 off_t saveaddress;
Glenn L McGrath60281112001-11-02 11:39:46 +0000525 u_char savech = 0, *savebp;
526
527 while ((bp = get()) != NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000528 for (fs = bb_dump_fshead, savebp = bp, saveaddress = address; fs;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000529 fs = fs->nextfs, bp = savebp, address = saveaddress) {
530 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000531 if (fu->flags & F_IGNORE) {
532 break;
533 }
534 for (cnt = fu->reps; cnt; --cnt) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000535 for (pr = fu->nextpr; pr; address += pr->bcnt,
536 bp += pr->bcnt, pr = pr->nextpr) {
537 if (eaddress && address >= eaddress &&
538 !(pr->flags & (F_TEXT | F_BPAD))) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000539 bpad(pr);
540 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000541 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000542 savech = *pr->nospace;
543 *pr->nospace = '\0';
Glenn L McGrath60281112001-11-02 11:39:46 +0000544 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000545/* PRINT; */
546 switch (pr->flags) {
547 case F_ADDRESS:
Glenn L McGrathff5309a2004-05-02 08:38:53 +0000548 printf(pr->fmt, (unsigned int) address);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000549 break;
550 case F_BPAD:
551 printf(pr->fmt, "");
552 break;
553 case F_C:
554 conv_c(pr, bp);
555 break;
556 case F_CHAR:
557 printf(pr->fmt, *bp);
558 break;
559 case F_DBL:{
560 double dval;
561 float fval;
562
563 switch (pr->bcnt) {
564 case 4:
565 bcopy((char *) bp, (char *) &fval,
566 sizeof(fval));
567 printf(pr->fmt, fval);
568 break;
569 case 8:
570 bcopy((char *) bp, (char *) &dval,
571 sizeof(dval));
572 printf(pr->fmt, dval);
573 break;
574 }
575 break;
576 }
577 case F_INT:{
578 int ival;
579 short sval;
580
581 switch (pr->bcnt) {
582 case 1:
583 printf(pr->fmt, (int) *bp);
584 break;
585 case 2:
586 bcopy((char *) bp, (char *) &sval,
587 sizeof(sval));
588 printf(pr->fmt, (int) sval);
589 break;
590 case 4:
591 bcopy((char *) bp, (char *) &ival,
592 sizeof(ival));
593 printf(pr->fmt, ival);
594 break;
595 }
596 break;
597 }
598 case F_P:
599 printf(pr->fmt, isprint(*bp) ? *bp : '.');
600 break;
601 case F_STR:
602 printf(pr->fmt, (char *) bp);
603 break;
604 case F_TEXT:
605 printf(pr->fmt);
606 break;
607 case F_U:
608 conv_u(pr, bp);
609 break;
610 case F_UINT:{
Eric Andersen0f56de62004-01-30 22:52:27 +0000611 unsigned int ival;
612 unsigned short sval;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000613
614 switch (pr->bcnt) {
615 case 1:
Eric Andersen0f56de62004-01-30 22:52:27 +0000616 printf(pr->fmt, (unsigned int) * bp);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000617 break;
618 case 2:
619 bcopy((char *) bp, (char *) &sval,
620 sizeof(sval));
Eric Andersen0f56de62004-01-30 22:52:27 +0000621 printf(pr->fmt, (unsigned int) sval);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000622 break;
623 case 4:
624 bcopy((char *) bp, (char *) &ival,
625 sizeof(ival));
626 printf(pr->fmt, ival);
627 break;
628 }
629 break;
630 }
631 }
632 if (cnt == 1 && pr->nospace) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000633 *pr->nospace = savech;
634 }
635 }
636 }
637 }
638 }
639 }
640 if (endfu) {
641 /*
Manuel Novoa III cad53642003-03-19 09:13:01 +0000642 * if eaddress not set, error or file bb_dump_size was multiple of
643 * bb_dump_blocksize, and no partial block ever found.
Glenn L McGrath60281112001-11-02 11:39:46 +0000644 */
645 if (!eaddress) {
646 if (!address) {
647 return;
648 }
649 eaddress = address;
650 }
651 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000652 switch (pr->flags) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000653 case F_ADDRESS:
Glenn L McGrathd2b860f2004-03-05 05:47:19 +0000654 (void) printf(pr->fmt, (unsigned int) eaddress);
Glenn L McGrath60281112001-11-02 11:39:46 +0000655 break;
656 case F_TEXT:
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000657 (void) printf(pr->fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000658 break;
659 }
660 }
661 }
662}
663
Manuel Novoa III cad53642003-03-19 09:13:01 +0000664int bb_dump_dump(char **argv)
Glenn L McGrath60281112001-11-02 11:39:46 +0000665{
666 register FS *tfs;
667
Manuel Novoa III cad53642003-03-19 09:13:01 +0000668 /* figure out the data block bb_dump_size */
669 for (bb_dump_blocksize = 0, tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
670 tfs->bcnt = bb_dump_size(tfs);
671 if (bb_dump_blocksize < tfs->bcnt) {
672 bb_dump_blocksize = tfs->bcnt;
Glenn L McGrath60281112001-11-02 11:39:46 +0000673 }
674 }
675 /* rewrite the rules, do syntax checking */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000676 for (tfs = bb_dump_fshead; tfs; tfs = tfs->nextfs) {
Glenn L McGrath60281112001-11-02 11:39:46 +0000677 rewrite(tfs);
678 }
679
680 next(argv);
681 display();
682
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000683 return (exitval);
Glenn L McGrath60281112001-11-02 11:39:46 +0000684}
685
Manuel Novoa III cad53642003-03-19 09:13:01 +0000686void bb_dump_add(const char *fmt)
Glenn L McGrath60281112001-11-02 11:39:46 +0000687{
Manuel Novoa III cad53642003-03-19 09:13:01 +0000688 register const char *p;
Glenn L McGrath60281112001-11-02 11:39:46 +0000689 register char *p1;
690 register char *p2;
691 static FS **nextfs;
692 FS *tfs;
693 FU *tfu, **nextfu;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000694 const char *savep;
Glenn L McGrath60281112001-11-02 11:39:46 +0000695
696 /* start new linked list of format units */
697 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000698 tfs = (FS *) xcalloc(1,sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000699 if (!bb_dump_fshead) {
700 bb_dump_fshead = tfs;
Glenn L McGrath60281112001-11-02 11:39:46 +0000701 } else {
702 *nextfs = tfs;
703 }
704 nextfs = &tfs->nextfs;
705 nextfu = &tfs->nextfu;
706
707 /* take the format string and break it up into format units */
708 for (p = fmt;;) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000709 /* bb_dump_skip leading white space */
710 p = bb_skip_whitespace(p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000711 if (!*p) {
712 break;
713 }
714
715 /* allocate a new format unit and link it in */
716 /* NOSTRICT */
Eric Andersen4a11e0f2003-04-19 23:18:35 +0000717 /* DBU:[dave@cray.com] calloc so that forward pointers start out NULL */
718 tfu = (FU *) xcalloc(1,sizeof(FU));
Glenn L McGrath60281112001-11-02 11:39:46 +0000719 *nextfu = tfu;
720 nextfu = &tfu->nextfu;
721 tfu->reps = 1;
722
723 /* if leading digit, repetition count */
724 if (isdigit(*p)) {
725 for (savep = p; isdigit(*p); ++p);
726 if (!isspace(*p) && *p != '/') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000727 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000728 }
729 /* may overwrite either white space or slash */
730 tfu->reps = atoi(savep);
731 tfu->flags = F_SETREP;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000732 /* bb_dump_skip trailing white space */
733 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000734 }
735
Manuel Novoa III cad53642003-03-19 09:13:01 +0000736 /* bb_dump_skip slash and trailing white space */
Glenn L McGrath60281112001-11-02 11:39:46 +0000737 if (*p == '/') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000738 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000739 }
740
741 /* byte count */
742 if (isdigit(*p)) {
743 for (savep = p; isdigit(*p); ++p);
744 if (!isspace(*p)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000745 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000746 }
747 tfu->bcnt = atoi(savep);
Manuel Novoa III cad53642003-03-19 09:13:01 +0000748 /* bb_dump_skip trailing white space */
749 p = bb_skip_whitespace(++p);
Glenn L McGrath60281112001-11-02 11:39:46 +0000750 }
751
752 /* format */
753 if (*p != '"') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000754 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000755 }
756 for (savep = ++p; *p != '"';) {
757 if (*p++ == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000758 bb_error_msg_and_die("bad format {%s}", fmt);
Glenn L McGrath60281112001-11-02 11:39:46 +0000759 }
760 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000761 tfu->fmt = xmalloc(p - savep + 1);
Glenn L McGrath60281112001-11-02 11:39:46 +0000762 strncpy(tfu->fmt, savep, p - savep);
763 tfu->fmt[p - savep] = '\0';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000764/* escape(tfu->fmt); */
Glenn L McGrath60281112001-11-02 11:39:46 +0000765
766 p1 = tfu->fmt;
767
768 /* alphabetic escape sequences have to be done in place */
769 for (p2 = p1;; ++p1, ++p2) {
770 if (!*p1) {
771 *p2 = *p1;
772 break;
773 }
774 if (*p1 == '\\') {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000775 const char *cs = conv_str + 4;
776 ++p1;
777 *p2 = *p1;
778 do {
779 if (*p1 == cs[2]) {
780 *p2 = cs[0];
781 break;
782 }
783 cs += 4;
784 } while (*cs);
Glenn L McGrath60281112001-11-02 11:39:46 +0000785 }
786 }
787
788 p++;
789 }
790}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000791
Glenn L McGrath60281112001-11-02 11:39:46 +0000792/*
793 * Copyright (c) 1989 The Regents of the University of California.
794 * All rights reserved.
795 *
796 * Redistribution and use in source and binary forms, with or without
797 * modification, are permitted provided that the following conditions
798 * are met:
799 * 1. Redistributions of source code must retain the above copyright
800 * notice, this list of conditions and the following disclaimer.
801 * 2. Redistributions in binary form must reproduce the above copyright
802 * notice, this list of conditions and the following disclaimer in the
803 * documentation and/or other materials provided with the distribution.
Aaron Lehmann69d41782002-06-23 22:25:24 +0000804 * 3. Neither the name of the University nor the names of its contributors
Glenn L McGrath60281112001-11-02 11:39:46 +0000805 * may be used to endorse or promote products derived from this software
806 * without specific prior written permission.
807 *
808 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
809 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
810 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
811 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
812 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
813 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
814 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
815 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
816 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
817 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
818 * SUCH DAMAGE.
819 */