/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "hexdump.h" static void doskip(const char *, int); static u_char *get(void); #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif enum _vflag vflag = FIRST; static off_t address; /* address/offset in stream */ static off_t eaddress; /* end address */ static inline void print(PR *pr, u_char *bp) { switch(pr->flags) { case F_ADDRESS: (void)printf(pr->fmt, (quad_t)address); break; case F_BPAD: (void)printf(pr->fmt, ""); break; case F_C: conv_c(pr, bp); break; case F_CHAR: (void)printf(pr->fmt, *bp); break; case F_DBL: { double dval; float fval; switch(pr->bcnt) { case 4: memmove(&fval, bp, sizeof(fval)); (void)printf(pr->fmt, fval); break; case 8: memmove(&dval, bp, sizeof(dval)); (void)printf(pr->fmt, dval); break; } break; } case F_INT: { short sval; /* int16_t */ int ival; /* int32_t */ long long Lval; /* int64_t, quad_t */ switch(pr->bcnt) { case 1: (void)printf(pr->fmt, (quad_t)*bp); break; case 2: memmove(&sval, bp, sizeof(sval)); (void)printf(pr->fmt, (quad_t)sval); break; case 4: memmove(&ival, bp, sizeof(ival)); (void)printf(pr->fmt, (quad_t)ival); break; case 8: memmove(&Lval, bp, sizeof(Lval)); (void)printf(pr->fmt, (quad_t)Lval); break; } break; } case F_P: (void)printf(pr->fmt, isprint(*bp) ? *bp : '.'); break; case F_STR: (void)printf(pr->fmt, (char *)bp); break; case F_TEXT: (void)printf("%s", pr->fmt); break; case F_U: conv_u(pr, bp); break; case F_UINT: { unsigned short sval; /* u_int16_t */ unsigned int ival; /* u_int32_t */ unsigned long long Lval;/* u_int64_t, u_quad_t */ switch(pr->bcnt) { case 1: (void)printf(pr->fmt, (u_quad_t)*bp); break; case 2: memmove(&sval, bp, sizeof(sval)); (void)printf(pr->fmt, (u_quad_t)sval); break; case 4: memmove(&ival, bp, sizeof(ival)); (void)printf(pr->fmt, (u_quad_t)ival); break; case 8: memmove(&Lval, bp, sizeof(Lval)); (void)printf(pr->fmt, (u_quad_t)Lval); break; } break; } } } static void bpad(PR *pr) { static const char *spec = " -0+#"; char *p1, *p2; /* * remove all conversion flags; '-' is the only one valid * with %s, and it's not useful here. */ pr->flags = F_BPAD; pr->cchar[0] = 's'; pr->cchar[1] = 0; for (p1 = pr->fmt; *p1 != '%'; ++p1); for (p2 = ++p1; *p1 && strchr(spec, *p1); ++p1); while ((*p2++ = *p1++) != 0) ; } void display(void) { register FS *fs; register FU *fu; register PR *pr; register int cnt; register u_char *bp; off_t saveaddress; u_char savech = 0, *savebp; while ((bp = get()) != NULL) for (fs = fshead, savebp = bp, saveaddress = address; fs; fs = fs->nextfs, bp = savebp, address = saveaddress) for (fu = fs->nextfu; fu; fu = fu->nextfu) { if (fu->flags&F_IGNORE) break; for (cnt = fu->reps; cnt; --cnt) for (pr = fu->nextpr; pr; address += pr->bcnt, bp += pr->bcnt, pr = pr->nextpr) { if (eaddress && address >= eaddress && !(pr->flags&(F_TEXT|F_BPAD))) bpad(pr); if (cnt == 1 && pr->nospace) { savech = *pr->nospace; *pr->nospace = '\0'; } print(pr, bp); if (cnt == 1 && pr->nospace) *pr->nospace = savech; } } if (endfu) { /* * if eaddress not set, error or file size was multiple of * blocksize, and no partial block ever found. */ if (!eaddress) { if (!address) return; eaddress = address; } for (pr = endfu->nextpr; pr; pr = pr->nextpr) switch(pr->flags) { case F_ADDRESS: (void)printf(pr->fmt, (quad_t)eaddress); break; case F_TEXT: (void)printf("%s", pr->fmt); break; } } } static char **_argv; static u_char * get(void) { static int ateof = 1; static u_char *curp, *savp; int n; int need, nread; u_char *tmpp; if (!curp) { curp = emalloc(blocksize); savp = emalloc(blocksize); } else { tmpp = curp; curp = savp; savp = tmpp; address += blocksize; } for (need = blocksize, nread = 0;;) { /* * if read the right number of bytes, or at EOF for one file, * and no other files are available, zero-pad the rest of the * block and set the end flag. */ if (!length || (ateof && !next(NULL))) { if (need == blocksize) return(NULL); if (!need && vflag != ALL && !memcmp(curp, savp, nread)) { if (vflag != DUP) (void)printf("*\n"); return(NULL); } if (need > 0) memset((char *)curp + nread, 0, need); eaddress = address + nread; return(curp); } n = fread((char *)curp + nread, sizeof(u_char), length == -1 ? need : MIN(length, need), stdin); if (!n) { if (ferror(stdin)) (void)fprintf(stderr, "hexdump: %s: %s\n", _argv[-1], strerror(errno)); ateof = 1; continue; } ateof = 0; if (length != -1) length -= n; if (!(need -= n)) { if (vflag == ALL || vflag == FIRST || memcmp(curp, savp, blocksize)) { if (vflag == DUP || vflag == FIRST) vflag = WAIT; return(curp); } if (vflag == WAIT) (void)printf("*\n"); vflag = DUP; address += blocksize; need = blocksize; nread = 0; } else nread += n; } } int next(char **argv) { static int done; int statok; if (argv) { _argv = argv; return(1); } for (;;) { if (*_argv) { if (!(freopen(*_argv, "r", stdin))) { (void)fprintf(stderr, "hexdump: %s: %s\n", *_argv, strerror(errno)); exitval = 1; ++_argv; continue; } statok = done = 1; } else { if (done++) return(0); statok = 0; } if (skip) doskip(statok ? *_argv : "stdin", statok); if (*_argv) ++_argv; if (!skip) return(1); } /* NOTREACHED */ } static void doskip(const char *fname, int statok) { struct stat sbuf; if (statok) { if (fstat(fileno(stdin), &sbuf)) { (void)fprintf(stderr, "hexdump: %s: %s.\n", fname, strerror(errno)); exit(1); } if (S_ISREG(sbuf.st_mode) && skip > sbuf.st_size) { /* If size valid and skip >= size */ skip -= sbuf.st_size; address += sbuf.st_size; return; } } /* sbuf may be undefined here - do not test it */ if (fseek(stdin, skip, SEEK_SET)) { (void)fprintf(stderr, "hexdump: %s: %s.\n", fname, strerror(errno)); exit(1); } address += skip; skip = 0; } void * emalloc(int sz) { void *p; if (!(p = malloc((u_int)sz))) nomem(); memset(p, 0, sz); return(p); } void nomem() { (void)fprintf(stderr, "hexdump: %s.\n", strerror(errno)); exit(1); }