Skip to content

Commit

Permalink
2.1
Browse files Browse the repository at this point in the history
Added color support (uses escape codes so R.I.P. Windows users without escape code support or escape codes enabled)
  • Loading branch information
PQCraft authored Jan 26, 2022
1 parent 6cb5c28 commit cc51d35
Showing 1 changed file with 156 additions and 15 deletions.
171 changes: 156 additions & 15 deletions qhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -34,22 +44,120 @@ 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
printf("│");
#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");
puts(" -e, --emptyline Display an empty line if the file size is zero");
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);
}

Expand All @@ -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) {
Expand All @@ -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]);
Expand All @@ -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;
Expand All @@ -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';
Expand All @@ -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;
Expand All @@ -153,7 +269,7 @@ int main(int _argc, char** _argv) {
fclose(fp);
errno = EISDIR;
aperror(fname);
return 1;
_return(1);
}
} else {
fp = stdin;
Expand All @@ -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;
Expand All @@ -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('.');
Expand All @@ -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;
}

0 comments on commit cc51d35

Please sign in to comment.