2 * Support code for the hexdump and od applets,
3 * based on code from util-linux v 2.11l
6 * The Regents of the University of California. All rights reserved.
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.
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.
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
22 * Original copyright notice is retained at the end of this file.
27 #include <ctype.h> /* for isdigit() */
31 enum _vflag vflag = FIRST;
32 FS *fshead; /* head of format strings */
33 extern FS *fshead; /* head of format strings */
37 static off_t savaddress; /* saved address/offset in stream */
38 static off_t eaddress; /* end address */
39 static off_t address; /* address/offset in stream */
40 off_t skip; /* bytes to skip */
42 int exitval; /* final exit value */
43 int blocksize; /* data block size */
44 int length = -1; /* max bytes to read */
50 register int bcnt, cursize;
54 /* figure out the data block size needed for each format unit */
55 for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
57 cursize += fu->bcnt * fu->reps;
60 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
64 * skip any special chars -- save precision in
65 * case it's a %s format.
67 while (index(".#-+ 0123456789" + 1, *++fmt));
68 if (*fmt == '.' && isdigit(*++fmt)) {
70 while (isdigit(*++fmt));
76 case 'd': case 'i': case 'o': case 'u':
80 case 'e': case 'E': case 'f': case 'g': case 'G':
88 case 'c': case 'p': case 'u':
94 cursize += bcnt * fu->reps;
101 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
102 register PR *pr, **nextpr = NULL;
104 register char *p1, *p2;
108 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
110 * break each format unit into print units; each
111 * conversion character gets its own.
113 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
115 pr = (PR *)xmalloc(sizeof(PR));
121 /* skip preceding text and up to the next % sign */
122 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
124 /* only text in the string */
132 * get precision for %s -- if have a byte count, don't
137 /* skip to conversion character */
138 for (++p1; index(".#-+ 0123456789", *p1); ++p1);
140 /* skip any special chars, field width */
141 while (index(".#-+ 0123456789" + 1, *++p1));
142 if (*p1 == '.' && isdigit(*++p1)) {
145 while (isdigit(*++p1));
151 p2 = p1 + 1; /* set end pointer */
154 * figure out the byte count for each conversion;
155 * rewrite the format as necessary, set up blank-
156 * padding for end of data.
167 error_msg_and_die("bad byte count for conversion character %s.", p1);
180 case 'o': case 'u': case 'x': case 'X':
186 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
189 case 'o': case 'u': case 'x': case 'X':
191 sw1: switch(fu->bcnt) {
203 error_msg_and_die("bad byte count for conversion character %s.", p1);
206 case 'e': case 'E': case 'f': case 'g': case 'G':
217 error_msg_and_die("bad byte count for conversion character %s.", p1);
224 error_msg_and_die("%%s requires a precision or a byte count.");
238 fu->flags |= F_IGNORE;
241 pr->flags = F_ADDRESS;
244 case 'd': case 'o': case'x':
249 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
254 /* *p1 = 'c'; set in conv_c */
262 /* *p1 = 'c'; set in conv_u */
263 sw2: switch(fu->bcnt) {
269 error_msg_and_die("bad byte count for conversion character %s.", p1);
274 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
279 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
283 * copy to PR format string, set conversion character
284 * pointer, update original.
288 if (!(pr->fmt = strdup(fmtp)))
289 perror_msg_and_die("hexdump");
291 pr->cchar = pr->fmt + (p1 - fmtp);
294 /* only one conversion character if byte count */
295 if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) {
296 error_msg_and_die("hexdump: byte count with multiple conversion characters.\n");
300 * if format unit byte count not specified, figure it out
301 * so can adjust rep count later.
304 for (pr = fu->nextpr; pr; pr = pr->nextpr)
305 fu->bcnt += pr->bcnt;
308 * if the format string interprets any data at all, and it's
309 * not the same as the blocksize, and its last format unit
310 * interprets any data at all, and has no iteration count,
311 * repeat it as necessary.
313 * if, rep count is greater than 1, no trailing whitespace
314 * gets output from the last iteration of the format unit.
316 for (fu = fs->nextfu;; fu = fu->nextfu) {
317 if (!fu->nextfu && fs->bcnt < blocksize &&
318 !(fu->flags&F_SETREP) && fu->bcnt)
319 fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
321 for (pr = fu->nextpr;; pr = pr->nextpr)
324 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
325 p2 = isspace(*p1) ? p1 : NULL;
334 static void doskip(char *fname, int statok)
339 if (fstat(fileno(stdin), &sbuf)) {
340 perror_msg_and_die("hexdump: %s", fname);
342 if ( ( ! (S_ISCHR(sbuf.st_mode) ||
343 S_ISBLK(sbuf.st_mode) ||
344 S_ISFIFO(sbuf.st_mode)) ) &&
345 skip >= sbuf.st_size) {
346 /* If size valid and skip >= size */
347 skip -= sbuf.st_size;
348 address += sbuf.st_size;
352 if (fseek(stdin, skip, SEEK_SET)) {
353 perror_msg_and_die("hexdump: %s", fname);
355 savaddress = address += skip;
359 int next(char **argv)
370 if (!(freopen(*_argv, "r", stdin))) {
371 perror_msg("%s", *_argv);
383 doskip(statok ? *_argv : "stdin", statok);
395 static int ateof = 1;
396 static u_char *curp, *savp;
402 curp = (u_char *)xmalloc(blocksize);
403 savp = (u_char *)xmalloc(blocksize);
408 address = savaddress += blocksize;
410 for (need = blocksize, nread = 0;;) {
412 * if read the right number of bytes, or at EOF for one file,
413 * and no other files are available, zero-pad the rest of the
414 * block and set the end flag.
416 if (!length || (ateof && !next((char **)NULL))) {
417 if (need == blocksize) {
418 return((u_char *)NULL);
420 if (vflag != ALL && !bcmp(curp, savp, nread)) {
424 return((u_char *)NULL);
426 bzero((char *)curp + nread, need);
427 eaddress = address + nread;
430 n = fread((char *)curp + nread, sizeof(u_char),
431 length == -1 ? need : MIN(length, need), stdin);
434 perror_msg("%s", _argv[-1]);
444 if (vflag == ALL || vflag == FIRST ||
445 bcmp(curp, savp, blocksize)) {
446 if (vflag == DUP || vflag == FIRST) {
455 address = savaddress += blocksize;
464 static void bpad(PR *pr)
466 register char *p1, *p2;
469 * remove all conversion flags; '-' is the only one valid
470 * with %s, and it's not useful here.
474 for (p1 = pr->fmt; *p1 != '%'; ++p1);
475 for (p2 = ++p1; *p1 && index(" -0+#", *p1); ++p1);
476 while ((*p2++ = *p1++) != 0) ;
479 void conv_c(PR *pr, u_char *p)
514 (void)printf(pr->fmt, *p);
516 sprintf(str = buf, "%03o", (int)*p);
519 printf(pr->fmt, str);
523 void conv_u(PR *pr, u_char *p)
525 static char *list[] = {
526 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
527 "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
528 "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb",
529 "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
532 /* od used nl, not lf */
535 printf(pr->fmt, list[*p]);
536 } else if (*p == 0x7f) {
538 printf(pr->fmt, "del");
539 } else if (isprint(*p)) {
544 printf(pr->fmt, (int)*p);
556 // off_t saveaddress;
557 u_char savech = 0, *savebp;
559 while ((bp = get()) != NULL) {
560 for (fs = fshead, savebp = bp, saveaddress = address; fs;
561 fs = fs->nextfs, bp = savebp, address = saveaddress) {
562 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
563 if (fu->flags & F_IGNORE) {
566 for (cnt = fu->reps; cnt; --cnt) {
567 for (pr = fu->nextpr; pr; address += pr->bcnt,
568 bp += pr->bcnt, pr = pr->nextpr) {
569 if (eaddress && address >= eaddress &&
570 !(pr->flags&(F_TEXT|F_BPAD))) {
573 if (cnt == 1 && pr->nospace) {
574 savech = *pr->nospace;
580 printf(pr->fmt, address);
589 printf(pr->fmt, *bp);
596 bcopy((char *)bp, (char *)&fval, sizeof(fval));
597 printf(pr->fmt, fval);
600 bcopy((char *)bp, (char *)&dval, sizeof(dval));
601 printf(pr->fmt, dval);
611 printf(pr->fmt, (int)*bp);
614 bcopy((char *)bp, (char *)&sval, sizeof(sval));
615 printf(pr->fmt, (int)sval);
618 bcopy((char *)bp, (char *)&ival, sizeof(ival));
619 printf(pr->fmt, ival);
625 printf(pr->fmt, isprint(*bp) ? *bp : '.');
628 printf(pr->fmt, (char *)bp);
641 printf(pr->fmt, (u_int)*bp);
644 bcopy((char *)bp, (char *)&sval, sizeof(sval));
645 printf(pr->fmt, (u_int)sval);
648 bcopy((char *)bp, (char *)&ival, sizeof(ival));
649 printf(pr->fmt, ival);
655 if (cnt == 1 && pr->nospace) {
656 *pr->nospace = savech;
665 * if eaddress not set, error or file size was multiple of
666 * blocksize, and no partial block ever found.
674 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
677 (void)printf(pr->fmt, eaddress);
680 (void)printf(pr->fmt);
687 int dump(char **argv)
691 /* figure out the data block size */
692 for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) {
693 tfs->bcnt = size(tfs);
694 if (blocksize < tfs->bcnt) {
695 blocksize = tfs->bcnt;
698 /* rewrite the rules, do syntax checking */
699 for (tfs = fshead; tfs; tfs = tfs->nextfs) {
719 /* start new linked list of format units */
721 tfs = (FS *)xmalloc(sizeof(FS));
727 nextfs = &tfs->nextfs;
728 nextfu = &tfs->nextfu;
730 /* take the format string and break it up into format units */
732 /* skip leading white space */
733 for (; isspace(*p); ++p);
738 /* allocate a new format unit and link it in */
740 tfu = (FU *)xmalloc(sizeof(FU));
742 nextfu = &tfu->nextfu;
745 /* if leading digit, repetition count */
747 for (savep = p; isdigit(*p); ++p);
748 if (!isspace(*p) && *p != '/') {
749 error_msg_and_die("hexdump: bad format {%s}", fmt);
751 /* may overwrite either white space or slash */
752 tfu->reps = atoi(savep);
753 tfu->flags = F_SETREP;
754 /* skip trailing white space */
755 for (++p; isspace(*p); ++p);
758 /* skip slash and trailing white space */
760 while (isspace(*++p));
765 for (savep = p; isdigit(*p); ++p);
767 error_msg_and_die("hexdump: bad format {%s}", fmt);
769 tfu->bcnt = atoi(savep);
770 /* skip trailing white space */
771 for (++p; isspace(*p); ++p);
776 error_msg_and_die("hexdump: bad format {%s}", fmt);
778 for (savep = ++p; *p != '"';) {
780 error_msg_and_die("hexdump: bad format {%s}", fmt);
783 if (!(tfu->fmt = malloc(p - savep + 1))) {
784 perror_msg_and_die("hexdump");
786 strncpy(tfu->fmt, savep, p - savep);
787 tfu->fmt[p - savep] = '\0';
792 /* alphabetic escape sequences have to be done in place */
793 for (p2 = p1;; ++p1, ++p2) {
833 * Copyright (c) 1989 The Regents of the University of California.
834 * All rights reserved.
836 * Redistribution and use in source and binary forms, with or without
837 * modification, are permitted provided that the following conditions
839 * 1. Redistributions of source code must retain the above copyright
840 * notice, this list of conditions and the following disclaimer.
841 * 2. Redistributions in binary form must reproduce the above copyright
842 * notice, this list of conditions and the following disclaimer in the
843 * documentation and/or other materials provided with the distribution.
844 * 3. Neither the name of the University nor the names of its contributors
845 * may be used to endorse or promote products derived from this software
846 * without specific prior written permission.
848 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
849 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
850 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
851 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
852 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
853 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
854 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
855 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
856 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
857 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF