diff options
Diffstat (limited to 'text-utils/hexdump-display.c')
-rw-r--r-- | text-utils/hexdump-display.c | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/text-utils/hexdump-display.c b/text-utils/hexdump-display.c new file mode 100644 index 0000000..bc92bd0 --- /dev/null +++ b/text-utils/hexdump-display.c @@ -0,0 +1,456 @@ +/* + * 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 <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hexdump.h" +#include "xalloc.h" +#include "c.h" +#include "nls.h" +#include "colors.h" + +static void doskip(const char *, int, struct hexdump *); +static u_char *get(struct hexdump *); + +enum _vflag vflag = FIRST; + +static off_t address; /* address/offset in stream */ +static off_t eaddress; /* end address */ + +static const char *color_cond(struct hexdump_pr *pr, unsigned char *bp, int bcnt) +{ + register struct list_head *p; + register struct hexdump_clr *clr; + off_t offt; + int match; + + list_for_each(p, pr->colorlist) { + clr = list_entry(p, struct hexdump_clr, colorlist); + offt = clr->offt; + match = 0; + + /* no offset or offset outside this print unit */ + if (offt < 0) + offt = address; + if (offt < address || offt + clr->range > address + bcnt) + continue; + + /* match a string */ + if (clr->str) { + if (pr->flags == F_ADDRESS) { + /* TODO */ + } + else if (!strncmp(clr->str, (char *)bp + offt + - address, clr->range)) + match = 1; + /* match a value */ + } else if (clr->val != -1) { + int val = 0; + /* addresses are not part of the input, so we can't + * compare with the contents of bp */ + if (pr->flags == F_ADDRESS) { + if (clr->val == address) + match = 1; + } else { + memcpy(&val, bp + offt - address, clr->range); + if (val == clr->val) + match = 1; + } + /* no conditions, only a color was specified */ + } else + return clr->fmt; + + /* return the format string or check for another */ + if (match ^ clr->invert) + return clr->fmt; + } + + /* no match */ + return NULL; +} + +static inline void +print(struct hexdump_pr *pr, unsigned char *bp) { + + const char *color = NULL; + + if (pr->colorlist && (color = color_cond(pr, bp, pr->bcnt))) + color_enable(color); + + switch(pr->flags) { + case F_ADDRESS: + printf(pr->fmt, address); + break; + case F_BPAD: + printf(pr->fmt, ""); + break; + case F_C: + conv_c(pr, bp); + break; + case F_CHAR: + printf(pr->fmt, *bp); + break; + case F_DBL: + { + double dval; + float fval; + switch(pr->bcnt) { + case 4: + memmove(&fval, bp, sizeof(fval)); + printf(pr->fmt, fval); + break; + case 8: + memmove(&dval, bp, sizeof(dval)); + printf(pr->fmt, dval); + break; + } + break; + } + case F_INT: + { + char cval; /* int8_t */ + short sval; /* int16_t */ + int ival; /* int32_t */ + long long Lval; /* int64_t, int64_t */ + + switch(pr->bcnt) { + case 1: + memmove(&cval, bp, sizeof(cval)); + printf(pr->fmt, (unsigned long long) cval); + break; + case 2: + memmove(&sval, bp, sizeof(sval)); + printf(pr->fmt, (unsigned long long) sval); + break; + case 4: + memmove(&ival, bp, sizeof(ival)); + printf(pr->fmt, (unsigned long long) ival); + break; + case 8: + memmove(&Lval, bp, sizeof(Lval)); + printf(pr->fmt, Lval); + break; + } + break; + } + case F_P: + printf(pr->fmt, isprint(*bp) ? *bp : '.'); + break; + case F_STR: + printf(pr->fmt, (char *)bp); + break; + case F_TEXT: + 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_int64_t */ + + switch(pr->bcnt) { + case 1: + printf(pr->fmt, (unsigned long long) *bp); + break; + case 2: + memmove(&sval, bp, sizeof(sval)); + printf(pr->fmt, (unsigned long long) sval); + break; + case 4: + memmove(&ival, bp, sizeof(ival)); + printf(pr->fmt, (unsigned long long) ival); + break; + case 8: + memmove(&Lval, bp, sizeof(Lval)); + printf(pr->fmt, Lval); + break; + } + break; + } + } + if (color) /* did we colorize something? */ + color_disable(); +} + +static void bpad(struct hexdump_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; + + p1 = pr->fmt; + while (*p1 != '%') + ++p1; + + p2 = ++p1; + while (*p1 && strchr(spec, *p1)) + ++p1; + + while ((*p2++ = *p1++)) + ; +} + +void display(struct hexdump *hex) +{ + register struct list_head *fs; + register struct hexdump_fs *fss; + register struct hexdump_fu *fu; + register struct hexdump_pr *pr; + register int cnt; + register unsigned char *bp; + off_t saveaddress; + unsigned char savech = 0, *savebp; + struct list_head *p, *q, *r; + + while ((bp = get(hex)) != NULL) { + fs = &hex->fshead; savebp = bp; saveaddress = address; + + list_for_each(p, fs) { + fss = list_entry(p, struct hexdump_fs, fslist); + + list_for_each(q, &fss->fulist) { + fu = list_entry(q, struct hexdump_fu, fulist); + + if (fu->flags&F_IGNORE) + break; + + cnt = fu->reps; + + while (cnt) { + list_for_each(r, &fu->prlist) { + pr = list_entry(r, struct hexdump_pr, prlist); + + 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); + *pr->nospace = savech; + } else + print(pr, bp); + + address += pr->bcnt; + bp += pr->bcnt; + } + --cnt; + } + } + bp = savebp; + address = saveaddress; + } + } + 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; + } + list_for_each (p, &endfu->prlist) { + const char *color = NULL; + + pr = list_entry(p, struct hexdump_pr, prlist); + if (colors_wanted() && pr->colorlist + && (color = color_cond(pr, bp, pr->bcnt))) { + color_enable(color); + } + + switch(pr->flags) { + case F_ADDRESS: + printf(pr->fmt, eaddress); + break; + case F_TEXT: + printf("%s", pr->fmt); + break; + } + if (color) /* did we highlight something? */ + color_disable(); + } + } +} + +static char **_argv; + +static u_char * +get(struct hexdump *hex) +{ + static int ateof = 1; + static u_char *curp, *savp; + ssize_t n, need, nread; + u_char *tmpp; + + if (!curp) { + curp = xcalloc(1, hex->blocksize); + savp = xcalloc(1, hex->blocksize); + } else { + tmpp = curp; + curp = savp; + savp = tmpp; + address += hex->blocksize; + } + need = hex->blocksize, nread = 0; + while (TRUE) { + /* + * 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 (!hex->length || (ateof && !next(NULL, hex))) { + if (need == hex->blocksize) + goto retnul; + if (!need && vflag != ALL && + !memcmp(curp, savp, nread)) { + if (vflag != DUP) + printf("*\n"); + goto retnul; + } + if (need > 0) + memset((char *)curp + nread, 0, need); + eaddress = address + nread; + return(curp); + } + if (fileno(stdin) == -1) { + warnx(_("all input file arguments failed")); + goto retnul; + } + n = fread((char *)curp + nread, sizeof(unsigned char), + hex->length == -1 ? need : min(hex->length, need), stdin); + if (!n) { + if (ferror(stdin)) + warn("%s", _argv[-1]); + ateof = 1; + continue; + } + ateof = 0; + if (hex->length != -1) + hex->length -= n; + if (!(need -= n)) { + if (vflag == ALL || vflag == FIRST || + memcmp(curp, savp, hex->blocksize) != 0) { + if (vflag == DUP || vflag == FIRST) + vflag = WAIT; + return(curp); + } + if (vflag == WAIT) + printf("*\n"); + vflag = DUP; + address += hex->blocksize; + need = hex->blocksize; + nread = 0; + } + else + nread += n; + } +retnul: + free (curp); + free (savp); + return NULL; +} + +int next(char **argv, struct hexdump *hex) +{ + static int done; + int statok; + + if (argv) { + _argv = argv; + return(1); + } + while (TRUE) { + if (*_argv) { + if (!(freopen(*_argv, "r", stdin))) { + warn("%s", *_argv); + hex->exitval = EXIT_FAILURE; + ++_argv; + continue; + } + statok = done = 1; + } else { + if (done++) + return(0); + statok = 0; + } + if (hex->skip) + doskip(statok ? *_argv : "stdin", statok, hex); + if (*_argv) + ++_argv; + if (!hex->skip) + return(1); + } + /* NOTREACHED */ +} + +static void +doskip(const char *fname, int statok, struct hexdump *hex) +{ + struct stat sbuf; + + if (statok) { + if (fstat(fileno(stdin), &sbuf)) + err(EXIT_FAILURE, "%s", fname); + if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) { + /* If size valid and skip >= size */ + hex->skip -= sbuf.st_size; + address += sbuf.st_size; + return; + } + } + /* sbuf may be undefined here - do not test it */ + if (fseek(stdin, hex->skip, SEEK_SET)) + err(EXIT_FAILURE, "%s", fname); + address += hex->skip; + hex->skip = 0; +} |