summaryrefslogtreecommitdiffstats
path: root/text-utils/hexdump-parse.c
diff options
context:
space:
mode:
authorOndrej Oprala2014-01-21 17:13:56 +0100
committerKarel Zak2014-02-10 16:01:37 +0100
commit098ab0778f5a46ab4519c8404fd4ba8ec137368b (patch)
tree62e319ce561e1b9e725312ae66d7f4d7d28824ea /text-utils/hexdump-parse.c
parentlib/color: add colorscheme parser (diff)
downloadkernel-qcow2-util-linux-098ab0778f5a46ab4519c8404fd4ba8ec137368b.tar.gz
kernel-qcow2-util-linux-098ab0778f5a46ab4519c8404fd4ba8ec137368b.tar.xz
kernel-qcow2-util-linux-098ab0778f5a46ab4519c8404fd4ba8ec137368b.zip
hexdump: add highlighting support
[kzak@redhat.com: - fix coding style, - use xalloc in all code, - fix strtol usage] Signed-off-by: Ondrej Oprala <ooprala@redhat.com> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'text-utils/hexdump-parse.c')
-rw-r--r--text-utils/hexdump-parse.c140
1 files changed, 140 insertions, 0 deletions
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)
{