From cc51d35cd4d57f7d08b9a0ce1e43d832dd8c5055 Mon Sep 17 00:00:00 2001 From: PQCraft <58464017+PQCraft@users.noreply.github.com> Date: Tue, 25 Jan 2022 23:20:54 -0500 Subject: [PATCH] 2.1 Added color support (uses escape codes so R.I.P. Windows users without escape code support or escape codes enabled) --- qhd.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 156 insertions(+), 15 deletions(-) diff --git a/qhd.c b/qhd.c index ad680bc..40c19ee 100644 --- a/qhd.c +++ b/qhd.c @@ -8,7 +8,7 @@ /* */ /* ---------------------------------------------------------------- */ -const char* VER = "2.0"; +const char* VER = "2.1"; #ifndef QHD_ASCII #define QHD_ASCII 0 // Enable/disable 7-bit ASCII mode @@ -25,6 +25,16 @@ const char* VER = "2.0"; int argc; char** argv; +char* fname = NULL; + +bool opt_bar = false; +bool opt_emptyln = false; +bool opt_showpos = true; +bool opt_showhex = true; +bool opt_showchr = true; +bool opt_onlyfile = false; +bool opt_color = false; + void aperror(char* str) { fprintf(stderr, "%s: ", argv[0]); perror(str); @@ -34,7 +44,45 @@ void cperror(char* str) { fprintf(stderr, "%s: %s\n", argv[0], str); } +void replacestr(char** ptr, char* str) { + free(*ptr); + *ptr = strdup(str); +} + +int eqstrcmp(char* str1, char* str2) { + char* ostr1 = str1; + while (*str1 && *str2 && *str1 != '=' && *str2 != '=') { + if (*str1 != *str2) {return -1;} + ++str1; + ++str2; + } + if ((!*str1 && *str2 && *str2 != '=') || (!*str2 && *str1 && *str1 != '=')) return -1; + if (*str1 == '=') ++str1; + return str1 - ostr1; +} + +enum { + COLOR_NORM, + COLOR_DIV, + COLOR_POS, + COLOR_HEX, + COLOR_HEXH, + COLOR_HEXZ, + COLOR_CHR, + COLOR_CHRN, + COLORCODE_LIST_SIZE, +}; + +char* colorcodes[COLORCODE_LIST_SIZE]; + +void setcolor(int code) { + if (!opt_color) return; + if (code != COLOR_NORM) printf("\e[%sm", colorcodes[COLOR_NORM]); + printf("\e[%sm", colorcodes[code]); +} + void putdiv() { + setcolor(COLOR_DIV); #if defined(QHD_ASCII) && QHD_ASCII putchar('|'); #else @@ -42,7 +90,54 @@ void putdiv() { #endif } +void parsecolors(char* instr) { + if (!instr || !*instr) return; + char* newstr = strdup(instr); + char* str = newstr; + char* oldstr = newstr; + char** list; + int listlen = 1; + for (; *str; ++str) {if (*str == ':') ++listlen;} + list = malloc(listlen * sizeof(char*)); + int listindex = 0; + str = oldstr; + while (1) { + if (*str == ':' || !*str) { + bool brk = !*str; + *str = 0; + list[listindex] = oldstr; + oldstr = str + 1; + ++listindex; + if (brk) break; + } + ++str; + } + for (int i = 0; i < listlen; ++i) { + int offset = 0; + if ((offset = eqstrcmp(list[i], "div")) > -1) { + replacestr(&colorcodes[COLOR_DIV], &list[i][offset]); + } else if ((offset = eqstrcmp(list[i], "pos")) > -1) { + replacestr(&colorcodes[COLOR_POS], &list[i][offset]); + } else if ((offset = eqstrcmp(list[i], "hex")) > -1) { + replacestr(&colorcodes[COLOR_HEX], &list[i][offset]); + } else if ((offset = eqstrcmp(list[i], "hexh")) > -1) { + replacestr(&colorcodes[COLOR_HEXH], &list[i][offset]); + } else if ((offset = eqstrcmp(list[i], "hexz")) > -1) { + replacestr(&colorcodes[COLOR_HEXZ], &list[i][offset]); + } else if ((offset = eqstrcmp(list[i], "chr")) > -1) { + replacestr(&colorcodes[COLOR_CHR], &list[i][offset]); + } else if ((offset = eqstrcmp(list[i], "chrn")) > -1) { + replacestr(&colorcodes[COLOR_CHRN], &list[i][offset]); + } + } + free(newstr); + free(list); +} + void puthelp() { + printf("Quick HexDump version %s\n\n", VER); + printf("USAGE: %s [OPTION]... FILE\n\n", argv[0]); + puts("OPTIONS:"); puts(" --help Display help text and exit"); puts(" --version Display version info and exit"); puts(" -b, --bar Display a column bar"); @@ -50,6 +145,19 @@ void puthelp() { puts(" -p, --hide-pos Hide the position column"); puts(" -h, --hide-hex Hide the hexadecimal column"); puts(" -c, --hide-chr Hide the character column"); + puts(" -C, --color Enable color escape codes\n"); + puts("ENVIRONMENT:"); + puts(" QHD_COLORS: Sets the pallette to use when color escape codes are enabled"); + puts(" Format is key=value separated by colons"); + puts(" Values are the middle parts of a color escape code (put between \"\\e[\" and \"m\")"); + puts(" Valid keys:"); + puts(" div: Divider color"); + puts(" pos: Position column color"); + puts(" hex: Hexadecimal column color"); + puts(" hexh: Hexadecimal value over 7F color"); + puts(" hexz: Hexadecimal value of zero color"); + puts(" chr: Character column color"); + puts(" chrn: Non-printable character color"); exit(0); } @@ -62,15 +170,6 @@ void putver() { exit(0); } -char* fname = NULL; - -bool opt_bar = false; -bool opt_emptyln = false; -bool opt_showpos = true; -bool opt_showhex = true; -bool opt_showchr = true; -bool opt_onlyfile = false; - bool readopt() { bool setfile = false; for (int i = 1; i < argc; ++i) { @@ -93,6 +192,8 @@ bool readopt() { opt_showhex = false; } else if (!strcmp(opt, "hide-chr")) { opt_showchr = false; + } else if (!strcmp(opt, "color")) { + opt_color = true; } else { errno = EINVAL; aperror(argv[i]); @@ -111,6 +212,8 @@ bool readopt() { opt_showhex = false; } else if (opt == 'c') { opt_showchr = false; + } else if (opt == 'C') { + opt_color = true; } else { char tmp[3] = {'-', 0, 0}; tmp[1] = opt; @@ -132,7 +235,20 @@ bool readopt() { int main(int _argc, char** _argv) { argc = _argc; argv = _argv; - if (!readopt()) return 1; + uint8_t retval = 0; + #define _return(x) {retval = x; goto _ret;} + if (!readopt()) _return(1); + if (opt_color) { + colorcodes[COLOR_NORM] = strdup("0"); + colorcodes[COLOR_DIV] = strdup("1"); + colorcodes[COLOR_POS] = strdup("32"); + colorcodes[COLOR_HEX] = strdup("34"); + colorcodes[COLOR_HEXH] = strdup("35"); + colorcodes[COLOR_HEXZ] = strdup("90"); + colorcodes[COLOR_CHR] = strdup("36"); + colorcodes[COLOR_CHRN] = strdup("90"); + parsecolors(getenv("QHD_COLORS")); + } char posfmt[] = " %016lX "; if (sizeof(long) == 4) { posfmt[3] = '0'; @@ -143,7 +259,7 @@ int main(int _argc, char** _argv) { fp = fopen(fname, "rb"); if (!fp) { aperror(fname); - return 1; + _return(1); } int fd = fileno(fp); struct stat statinfo; @@ -153,7 +269,7 @@ int main(int _argc, char** _argv) { fclose(fp); errno = EISDIR; aperror(fname); - return 1; + _return(1); } } else { fp = stdin; @@ -170,20 +286,35 @@ int main(int _argc, char** _argv) { fputs(" ", stdout); } putdiv(); + setcolor(COLOR_POS); fputs(" 0 1 2 3 4 5 6 7 8 9 A B C D E F ", stdout); putdiv(); + setcolor(COLOR_NORM); putchar('\n'); } size_t i = 0; if (opt_showpos) { putdiv(); + setcolor(COLOR_POS); printf(posfmt, pos); } if (opt_showhex) { putdiv(); + setcolor(COLOR_HEX); putchar(' '); for (; i < bread; ++i) { - printf("%02X ", buf[i]); + if (!buf[i] || buf[i] > 0x7F) { + if (!buf[i]) { + setcolor(COLOR_HEXZ); + } else { + setcolor(COLOR_HEXH); + } + printf("%02X", buf[i]); + setcolor(COLOR_HEX); + putchar(' '); + } else { + printf("%02X ", buf[i]); + } } for (; i < 16; ++i) { buf[i] = 0; @@ -192,11 +323,13 @@ int main(int _argc, char** _argv) { } if (opt_showchr) { putdiv(); + setcolor(COLOR_CHR); putchar(' '); for (size_t i = 0; i < 16; ++i) { if (buf[i] >= 32 && buf[i] <= 126) { putchar(buf[i]); } else { + setcolor(COLOR_CHRN); if (i < bread) { #if defined(QHD_ASCII) && QHD_ASCII putchar('.'); @@ -206,14 +339,22 @@ int main(int _argc, char** _argv) { } else { putchar(' '); } + setcolor(COLOR_CHR); } } putchar(' '); } putdiv(); pos += 16; + setcolor(COLOR_NORM); putchar('\n'); } if (fname) fclose(fp); - return 0; + _ret:; + if (opt_color) { + for (int i = 0; i < COLORCODE_LIST_SIZE; ++i) { + free(colorcodes[i]); + } + } + return retval; }