summaryrefslogtreecommitdiffstats
path: root/text-utils
diff options
context:
space:
mode:
Diffstat (limited to 'text-utils')
-rw-r--r--text-utils/hexdump-display.c70
-rw-r--r--text-utils/hexdump-parse.c140
-rw-r--r--text-utils/hexdump.138
-rw-r--r--text-utils/hexdump.c23
-rw-r--r--text-utils/hexdump.h11
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 */
};