diff options
Diffstat (limited to 'text-utils')
-rw-r--r-- | text-utils/hexdump-display.c | 70 | ||||
-rw-r--r-- | text-utils/hexdump-parse.c | 140 | ||||
-rw-r--r-- | text-utils/hexdump.1 | 38 | ||||
-rw-r--r-- | text-utils/hexdump.c | 23 | ||||
-rw-r--r-- | text-utils/hexdump.h | 11 |
5 files changed, 281 insertions, 1 deletions
diff --git a/text-utils/hexdump-display.c b/text-utils/hexdump-display.c index b195a01ae..ce714f68c 100644 --- a/text-utils/hexdump-display.c +++ b/text-utils/hexdump-display.c @@ -44,6 +44,7 @@ #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 *); @@ -53,9 +54,67 @@ 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; + continue; + } + + /* 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); @@ -148,6 +207,8 @@ print(struct hexdump_pr *pr, unsigned char *bp) { break; } } + if (color) /* did we colorize something? */ + color_disable(); } static void bpad(struct hexdump_pr *pr) @@ -239,6 +300,13 @@ void display(struct hexdump *hex) } list_for_each (p, &endfu->prlist) { pr = list_entry(p, struct hexdump_pr, prlist); + + const char *color = NULL; + 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); @@ -247,6 +315,8 @@ void display(struct hexdump *hex) printf("%s", pr->fmt); break; } + if (color) /* did we highlight something? */ + color_disable(); } } } diff --git a/text-utils/hexdump-parse.c b/text-utils/hexdump-parse.c index 17dd77343..660dcce31 100644 --- a/text-utils/hexdump-parse.c +++ b/text-utils/hexdump-parse.c @@ -45,8 +45,10 @@ #include "nls.h" #include "xalloc.h" #include "strutils.h" +#include "colors.h" static void escape(char *p1); +static struct list_head *color_fmt(char *cfmt, int bcnt); static void __attribute__ ((__noreturn__)) badcnt(const char *s) { @@ -391,6 +393,28 @@ isint: cs[2] = '\0'; badconv(p1); } + /* Color unit(s) specified */ + if (*p2 == '_' && p2[1] == 'L') { + if (colors_wanted()) { + char *a; + + /* "cut out" the color_unit(s) */ + a = strchr(p2, '['); + p2 = strrchr(p2, ']'); + if (a++ && p2) + pr->colorlist = color_fmt(xstrndup(a, p2++ - a), pr->bcnt); + else + badconv(p2); + } + /* we don't want colors, quietly skip over them */ + else { + p2 = strrchr(p2, ']'); + /* be a bit louder if we don't know how to skip over them */ + if (!p2) + badconv("_L"); + ++p2; + } + } /* * Copy to hexdump_pr format string, set conversion character * pointer, update original. @@ -447,6 +471,122 @@ isint: cs[2] = '\0'; } } +/* [!]color[:string|:hex_number|:oct_number][@offt|@offt_start-offt_end],... */ +static struct list_head *color_fmt(char *cfmt, int bcnt) +{ + struct hexdump_clr *hc, *hcnext; + struct list_head *ret_head; + char *clr, *fmt; + + ret_head = xmalloc(sizeof(struct list_head)); + hcnext = hc = xcalloc(1, sizeof(struct hexdump_clr)); + + INIT_LIST_HEAD(&hc->colorlist); + INIT_LIST_HEAD(ret_head); + list_add_tail(&hc->colorlist, ret_head); + + fmt = cfmt; + while (cfmt && *cfmt) { + char *end; + /* invert this condition */ + if (*cfmt == '!') { + hcnext->invert = 1; + ++cfmt; + } + + clr = xstrndup(cfmt, strcspn(cfmt, ":@,")); + cfmt += strlen(clr); + hcnext->fmt = colorscheme_from_string(clr); + free(clr); + + if (!hcnext->fmt) + return NULL; + + /* only colorize this specific value */ + if (*cfmt == ':') { + ++cfmt; + /* a hex or oct value */ + if (*cfmt == '0') { + /* hex */ + errno = 0; + end = NULL; + if (cfmt[1] == 'x' || cfmt[1] == 'X') + hcnext->val = strtoul(cfmt + 2, &end, 16); + else + hcnext->val = strtoul(cfmt, &end, 8); + if (errno || end == cfmt) + badfmt(fmt); + cfmt = end; + /* a string */ + } else { + off_t fmt_end; + char endchar; + char *endstr; + + hcnext->val = -1; + /* temporarily null-delimit the format, so we can reverse-search + * for the start of an offset specifier */ + fmt_end = strcspn(cfmt, ","); + endchar = cfmt[fmt_end]; + cfmt[fmt_end] = '\0'; + endstr = strrchr(cfmt, '@'); + + if (endstr) { + if (endstr[1] != '\0') + --endstr; + hcnext->str = xstrndup(cfmt, endstr - cfmt + 1); + } else + hcnext->str = xstrndup(cfmt, fmt_end); + + /* restore the character */ + cfmt[fmt_end] = endchar; + cfmt += strlen(hcnext->str); + } + + /* no specific value */ + } else + hcnext->val = -1; + + /* only colorize at this offset */ + hcnext->range = bcnt; + if (cfmt && *cfmt == '@') { + errno = 0; + hcnext->offt = strtoul(++cfmt, &cfmt, 10); + if (errno) + badfmt(fmt); + + /* offset range */ + if (*cfmt == '-') { + ++cfmt; + errno = 0; + + hcnext->range = + strtoul(cfmt, &cfmt, 10) - hcnext->offt + 1; + if (errno) + badfmt(fmt); + /* offset range must be between 0 and format byte count */ + if (!(hcnext->range >= 0 && hcnext->range <= bcnt)) + badcnt("_L"); + } + /* no specific offset */ + } else + hcnext->offt = (off_t)-1; + + /* check if the string we're looking for is the same length as the range */ + if (hcnext->str && (int)strlen(hcnext->str) != hcnext->range) + badcnt("_L"); + + /* link in another condition */ + if (cfmt && *cfmt == ',') { + ++cfmt; + + hcnext = xcalloc(1, sizeof(struct hexdump_clr)); + INIT_LIST_HEAD(&hcnext->colorlist); + list_add_tail(&hcnext->colorlist, ret_head); + } + } + return ret_head; +} static void escape(char *p1) { diff --git a/text-utils/hexdump.1 b/text-utils/hexdump.1 index e8afdbac8..8b4bf275d 100644 --- a/text-utils/hexdump.1 +++ b/text-utils/hexdump.1 @@ -235,6 +235,37 @@ displayed using the following, lower-case, names. Characters greater than 018 can 019 em 01A sub 01B esc 01C fs 01D gs 01E rs 01F us 0FF del .nf +.SS Colors +When put at the end of a format specifier, hexdump highlights the respective +string with the color specified. Conditions, if present, are evaluated +prior to highlighting. +.TP +.B \&_L[color_unit_1,color_unit_2,...,color_unit_n] +.TP +The full syntax of a color unit is as follows: +.TP +.B [!]COLOR[:HEX_VAL|:OCT_VAL|:STRING][@DEC_OFFT|@DEC_OFFT_START-DEC_OFFT_END] +.TP +.B ! +Negate the condition. Please note that it only makes sense to negate +a unit if both a value/string and an offset are specified. In that case +the respective output string will be highlighted if and only if the value/string +does not match the one at the offset. +.PP +.BR COLOR +One of the 8 basic shell colors. +.PP +.BR HEX_VAL , OCT_VAL +A value to be matched specified in hexadecimal or octal base. +.PP +.BR STRING +A string to be matched. Please note that the usual C escape sequences +are not interpreted by hexdump inside the color_units. +.PP +.BR DEC_OFFT , DEC_OFFT_START , DEC_OFFT_END +An offset or an offset range at which +to check for a match. Please note that DEC_OFFT is equal to DEC_OFFT-DEC_OFFT. +Also, the range may not be larger than the respective format byte count. .SS Counters The default and supported byte counts for the conversion characters are as follows: @@ -313,6 +344,13 @@ Implement the \-x option: "%07.7_Ax\en" "%07.7_ax " 8/2 "%04x " "\en" .nf +.PP +MBR Boot Signature example: +Highlight the addresses cyan and the bytes at offsets 510 and 511 green if their value is 0xAA55, red otherwise. +.nf + "%07.7_Ax_L[cyan]\en" + "%07.7_ax_L[cyan] " 8/2 " %04x_L[green:0xAA55@510-511,!red:0xAA55@510-511] " "\en" +.nf .SH STANDARDS The .B hexdump diff --git a/text-utils/hexdump.c b/text-utils/hexdump.c index ac7778229..19e67f46d 100644 --- a/text-utils/hexdump.c +++ b/text-utils/hexdump.c @@ -49,6 +49,7 @@ #include "list.h" #include "nls.h" #include "c.h" +#include "colors.h" #include "strutils.h" #include "xalloc.h" #include "closestream.h" @@ -59,8 +60,10 @@ int parse_args(int argc, char **argv, struct hexdump *hex) { int ch; + int colormode = UL_COLORMODE_NEVER; char *hex_offt = "\"%07.7_Ax\n\""; + static const struct option longopts[] = { {"one-byte-octal", no_argument, NULL, 'b'}, {"one-byte-char", required_argument, NULL, 'c'}, @@ -70,6 +73,7 @@ parse_args(int argc, char **argv, struct hexdump *hex) {"two-bytes-hex", no_argument, NULL, 'x'}, {"format", required_argument, NULL, 'e'}, {"format-file", required_argument, NULL, 'f'}, + {"color", optional_argument, NULL, 'L'}, {"length", required_argument, NULL, 'n'}, {"skip", required_argument, NULL, 's'}, {"no-squeezing", no_argument, NULL, 'v'}, @@ -103,6 +107,12 @@ parse_args(int argc, char **argv, struct hexdump *hex) case 'f': addfile(optarg, hex); break; + case 'L': + colormode = UL_COLORMODE_AUTO; + if (optarg) + colormode = colormode_or_err(optarg, + _("unsupported color mode")); + break; case 'n': hex->length = strtosize_or_err(optarg, _("failed to parse length")); break; @@ -135,6 +145,7 @@ parse_args(int argc, char **argv, struct hexdump *hex) add_fmt(hex_offt, hex); add_fmt("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"", hex); } + colors_init (colormode); return optind; } @@ -149,6 +160,7 @@ void __attribute__((__noreturn__)) usage(FILE *out) fputs(_(" -d, --two-bytes-decimal two-byte decimal display\n"), out); fputs(_(" -o, --two-bytes-octal two-byte octal display\n"), out); fputs(_(" -x, --two-bytes-hex two-byte hexadecimal display\n"), out); + fputs(_(" -L, --color[=<mode>] interpret color formatting specifiers\n"), out); fputs(_(" -e, --format <format> format string to be used for displaying data\n"), out); fputs(_(" -f, --format-file <file> file that contains format strings\n"), out); fputs(_(" -n, --length <length> interpret only length bytes of input\n"), out); @@ -207,16 +219,25 @@ int main(int argc, char **argv) void hex_free(struct hexdump *hex) { - struct list_head *p, *pn, *q, *qn, *r, *rn; + struct list_head *p, *pn, *q, *qn, *r, *rn, *s, *sn; struct hexdump_fs *fs; struct hexdump_fu *fu; struct hexdump_pr *pr; + struct hexdump_clr *clr; + list_for_each_safe(p, pn, &hex->fshead) { fs = list_entry(p, struct hexdump_fs, fslist); list_for_each_safe(q, qn, &fs->fulist) { fu = list_entry(q, struct hexdump_fu, fulist); list_for_each_safe(r, rn, &fu->prlist) { pr = list_entry(r, struct hexdump_pr, prlist); + if (pr->colorlist) { + list_for_each_safe(s, sn, pr->colorlist) { + clr = list_entry (s, struct hexdump_clr, colorlist); + free(clr->str); + free(clr); + } + } free(pr->fmt); free(pr); } diff --git a/text-utils/hexdump.h b/text-utils/hexdump.h index 56f5dc55a..741a57ad2 100644 --- a/text-utils/hexdump.h +++ b/text-utils/hexdump.h @@ -35,6 +35,16 @@ #include "c.h" #include "list.h" +struct hexdump_clr { + struct list_head colorlist; /* next color unit */ + const char *fmt; /* the color, UL_COLOR_* */ + off_t offt; /* offset where unit is valid... */ + int range; /* ... and it's range */ + int val; /* value ... */ + char *str; /* ... or string to match */ + int invert; /* invert condition? */ +}; + struct hexdump_pr { struct list_head prlist; /* next print unit */ #define F_ADDRESS 0x001 /* print offset */ @@ -51,6 +61,7 @@ struct hexdump_pr { unsigned int flags; /* flag values */ int bcnt; /* byte count */ char *cchar; /* conversion character */ + struct list_head *colorlist; /* color settings */ char *fmt; /* printf format */ char *nospace; /* no whitespace version */ }; |