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));
104 cursize += bcnt * fu->reps;
109 void rewrite(FS * fs)
111 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
112 register PR *pr, **nextpr = NULL;
114 register char *p1, *p2;
118 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
120 * break each format unit into print units; each
121 * conversion character gets its own.
123 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
125 pr = (PR *) xmalloc(sizeof(PR));
131 /* skip preceding text and up to the next % sign */
132 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
134 /* only text in the string */
142 * get precision for %s -- if have a byte count, don't
147 /* skip to conversion character */
148 for (++p1; index(".#-+ 0123456789", *p1); ++p1);
150 /* skip any special chars, field width */
151 while (index(".#-+ 0123456789" + 1, *++p1));
152 if (*p1 == '.' && isdigit(*++p1)) {
155 while (isdigit(*++p1));
160 p2 = p1 + 1; /* set end pointer */
163 * figure out the byte count for each conversion;
164 * rewrite the format as necessary, set up blank-
165 * padding for end of data.
178 ("bad byte count for conversion character %s.", p1);
203 ("hexdump: bad conversion character %%%s.\n", p1);
211 sw1:switch (fu->bcnt) {
225 ("bad byte count for conversion character %s.", p1);
245 ("bad byte count for conversion character %s.", p1);
253 ("%%s requires a precision or a byte count.");
267 fu->flags |= F_IGNORE;
270 pr->flags = F_ADDRESS;
281 ("hexdump: bad conversion character %%%s.\n", p1);
286 /* *p1 = 'c'; set in conv_c */
294 /* *p1 = 'c'; set in conv_u */
295 sw2:switch (fu->bcnt) {
303 ("bad byte count for conversion character %s.",
310 ("hexdump: bad conversion character %%%s.\n", p1);
315 error_msg_and_die("hexdump: bad conversion character %%%s.\n",
320 * copy to PR format string, set conversion character
321 * pointer, update original.
325 if (!(pr->fmt = strdup(fmtp)))
326 perror_msg_and_die("hexdump");
328 pr->cchar = pr->fmt + (p1 - fmtp);
331 /* only one conversion character if byte count */
332 if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) {
334 ("hexdump: byte count with multiple conversion characters.\n");
338 * if format unit byte count not specified, figure it out
339 * so can adjust rep count later.
342 for (pr = fu->nextpr; pr; pr = pr->nextpr)
343 fu->bcnt += pr->bcnt;
346 * if the format string interprets any data at all, and it's
347 * not the same as the blocksize, and its last format unit
348 * interprets any data at all, and has no iteration count,
349 * repeat it as necessary.
351 * if, rep count is greater than 1, no trailing whitespace
352 * gets output from the last iteration of the format unit.
354 for (fu = fs->nextfu;; fu = fu->nextfu) {
355 if (!fu->nextfu && fs->bcnt < blocksize &&
356 !(fu->flags & F_SETREP) && fu->bcnt)
357 fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
359 for (pr = fu->nextpr;; pr = pr->nextpr)
362 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
363 p2 = isspace(*p1) ? p1 : NULL;
372 static void doskip(char *fname, int statok)
377 if (fstat(fileno(stdin), &sbuf)) {
378 perror_msg_and_die("hexdump: %s", fname);
380 if ((!(S_ISCHR(sbuf.st_mode) ||
381 S_ISBLK(sbuf.st_mode) ||
382 S_ISFIFO(sbuf.st_mode))) && skip >= sbuf.st_size) {
383 /* If size valid and skip >= size */
384 skip -= sbuf.st_size;
385 address += sbuf.st_size;
389 if (fseek(stdin, skip, SEEK_SET)) {
390 perror_msg_and_die("hexdump: %s", fname);
392 savaddress = address += skip;
396 int next(char **argv)
407 if (!(freopen(*_argv, "r", stdin))) {
408 perror_msg("%s", *_argv);
420 doskip(statok ? *_argv : "stdin", statok);
429 static u_char *get(void)
431 static int ateof = 1;
432 static u_char *curp, *savp;
438 curp = (u_char *) xmalloc(blocksize);
439 savp = (u_char *) xmalloc(blocksize);
444 address = savaddress += blocksize;
446 for (need = blocksize, nread = 0;;) {
448 * if read the right number of bytes, or at EOF for one file,
449 * and no other files are available, zero-pad the rest of the
450 * block and set the end flag.
452 if (!length || (ateof && !next((char **) NULL))) {
453 if (need == blocksize) {
454 return ((u_char *) NULL);
456 if (vflag != ALL && !bcmp(curp, savp, nread)) {
460 return ((u_char *) NULL);
462 bzero((char *) curp + nread, need);
463 eaddress = address + nread;
466 n = fread((char *) curp + nread, sizeof(u_char),
467 length == -1 ? need : MIN(length, need), stdin);
470 perror_msg("%s", _argv[-1]);
480 if (vflag == ALL || vflag == FIRST || bcmp(curp, savp, blocksize)) {
481 if (vflag == DUP || vflag == FIRST) {
490 address = savaddress += blocksize;
499 static void bpad(PR * pr)
501 register char *p1, *p2;
504 * remove all conversion flags; '-' is the only one valid
505 * with %s, and it's not useful here.
509 for (p1 = pr->fmt; *p1 != '%'; ++p1);
510 for (p2 = ++p1; *p1 && index(" -0+#", *p1); ++p1);
511 while ((*p2++ = *p1++) != 0);
514 void conv_c(PR * pr, u_char * p)
549 (void) printf(pr->fmt, *p);
551 sprintf(str = buf, "%03o", (int) *p);
554 printf(pr->fmt, str);
558 void conv_u(PR * pr, u_char * p)
560 static char *list[] = {
561 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
562 "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
563 "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb",
564 "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
567 /* od used nl, not lf */
570 printf(pr->fmt, list[*p]);
571 } else if (*p == 0x7f) {
573 printf(pr->fmt, "del");
574 } else if (isprint(*p)) {
579 printf(pr->fmt, (int) *p);
585 /* extern FU *endfu; */
592 /* off_t saveaddress; */
593 u_char savech = 0, *savebp;
595 while ((bp = get()) != NULL) {
596 for (fs = fshead, savebp = bp, saveaddress = address; fs;
597 fs = fs->nextfs, bp = savebp, address = saveaddress) {
598 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
599 if (fu->flags & F_IGNORE) {
602 for (cnt = fu->reps; cnt; --cnt) {
603 for (pr = fu->nextpr; pr; address += pr->bcnt,
604 bp += pr->bcnt, pr = pr->nextpr) {
605 if (eaddress && address >= eaddress &&
606 !(pr->flags & (F_TEXT | F_BPAD))) {
609 if (cnt == 1 && pr->nospace) {
610 savech = *pr->nospace;
616 printf(pr->fmt, address);
625 printf(pr->fmt, *bp);
633 bcopy((char *) bp, (char *) &fval,
635 printf(pr->fmt, fval);
638 bcopy((char *) bp, (char *) &dval,
640 printf(pr->fmt, dval);
651 printf(pr->fmt, (int) *bp);
654 bcopy((char *) bp, (char *) &sval,
656 printf(pr->fmt, (int) sval);
659 bcopy((char *) bp, (char *) &ival,
661 printf(pr->fmt, ival);
667 printf(pr->fmt, isprint(*bp) ? *bp : '.');
670 printf(pr->fmt, (char *) bp);
684 printf(pr->fmt, (u_int) * bp);
687 bcopy((char *) bp, (char *) &sval,
689 printf(pr->fmt, (u_int) sval);
692 bcopy((char *) bp, (char *) &ival,
694 printf(pr->fmt, ival);
700 if (cnt == 1 && pr->nospace) {
701 *pr->nospace = savech;
710 * if eaddress not set, error or file size was multiple of
711 * blocksize, and no partial block ever found.
719 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
722 (void) printf(pr->fmt, eaddress);
725 (void) printf(pr->fmt);
732 int dump(char **argv)
736 /* figure out the data block size */
737 for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) {
738 tfs->bcnt = size(tfs);
739 if (blocksize < tfs->bcnt) {
740 blocksize = tfs->bcnt;
743 /* rewrite the rules, do syntax checking */
744 for (tfs = fshead; tfs; tfs = tfs->nextfs) {
764 /* start new linked list of format units */
766 tfs = (FS *) xmalloc(sizeof(FS));
772 nextfs = &tfs->nextfs;
773 nextfu = &tfs->nextfu;
775 /* take the format string and break it up into format units */
777 /* skip leading white space */
778 for (; isspace(*p); ++p);
783 /* allocate a new format unit and link it in */
785 tfu = (FU *) xmalloc(sizeof(FU));
787 nextfu = &tfu->nextfu;
790 /* if leading digit, repetition count */
792 for (savep = p; isdigit(*p); ++p);
793 if (!isspace(*p) && *p != '/') {
794 error_msg_and_die("hexdump: bad format {%s}", fmt);
796 /* may overwrite either white space or slash */
797 tfu->reps = atoi(savep);
798 tfu->flags = F_SETREP;
799 /* skip trailing white space */
800 for (++p; isspace(*p); ++p);
803 /* skip slash and trailing white space */
805 while (isspace(*++p));
810 for (savep = p; isdigit(*p); ++p);
812 error_msg_and_die("hexdump: bad format {%s}", fmt);
814 tfu->bcnt = atoi(savep);
815 /* skip trailing white space */
816 for (++p; isspace(*p); ++p);
821 error_msg_and_die("hexdump: bad format {%s}", fmt);
823 for (savep = ++p; *p != '"';) {
825 error_msg_and_die("hexdump: bad format {%s}", fmt);
828 if (!(tfu->fmt = malloc(p - savep + 1))) {
829 perror_msg_and_die("hexdump");
831 strncpy(tfu->fmt, savep, p - savep);
832 tfu->fmt[p - savep] = '\0';
833 /* escape(tfu->fmt); */
837 /* alphabetic escape sequences have to be done in place */
838 for (p2 = p1;; ++p1, ++p2) {
879 * Copyright (c) 1989 The Regents of the University of California.
880 * All rights reserved.
882 * Redistribution and use in source and binary forms, with or without
883 * modification, are permitted provided that the following conditions
885 * 1. Redistributions of source code must retain the above copyright
886 * notice, this list of conditions and the following disclaimer.
887 * 2. Redistributions in binary form must reproduce the above copyright
888 * notice, this list of conditions and the following disclaimer in the
889 * documentation and/or other materials provided with the distribution.
890 * 3. Neither the name of the University nor the names of its contributors
891 * may be used to endorse or promote products derived from this software
892 * without specific prior written permission.
894 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
895 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
896 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
897 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
898 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
899 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
900 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
901 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
902 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
903 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF