diff options
-rw-r--r-- | uxd.1 | 11 | ||||
-rw-r--r-- | uxd.c | 123 | ||||
-rw-r--r-- | uxd.rst | 9 |
3 files changed, 100 insertions, 43 deletions
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UXD" 1 "2024-12-15" "0.1.0" "Urchlay's Utilities" +.TH "UXD" 1 "2024-12-16" "0.1.0" "Urchlay's Utilities" .SH NAME uxd \- UTF-8 hex dumper .SH SYNOPSIS @@ -89,8 +89,8 @@ will be dumped. .B \-m Monochrome mode. Uses underline, bold, reverse video instead of color. Use this if you have trouble distinguishing the colors, or if they -look too much like angry fruit salad. -NOT IMPLEMENTED YET. +look too much like angry fruit salad. Disables prior \fB\-b\fP, \fB\-c\fP +options. .TP .B \-n Ignore \fBUXD_OPTS\fP environment variable. This option should not be @@ -118,7 +118,7 @@ position after seeking. \fB\-S 100\fP is the same as \fB\-s 100 \-o \-100\fP\&. Works with negative \fIpos\fP, too. .TP .B \-u -Use uppercase hex digits A\-F. Default is lowercase. +Use uppercase hex digits \fIA\-F\fP\&. Default is lowercase. .TP .B \-v\fP,\fB \-\-version Print version number and exit. @@ -266,7 +266,8 @@ any files other than standard output. There\(aqs no config file. .TP .B \fBUXD_OPTS\fP If this is set, its value is treated as a set of options, which -get applied before any command\-line options. +get applied before any command\-line options (unless the command\-line +options inclue \fB\-n\fP). .TP .B \fBNO_COLOR\fP If this is set (to any value), \fBuxd\fP runs in monochrome mode, just @@ -65,9 +65,13 @@ extern int optind; #define BAD_FG BLACK #define BAD_BG bad_color +#define HL_NORMAL 0 +#define HL_NORM_INV 1 +#define HL_SPECIAL 2 +#define HL_BAD 3 + int normal_colors[] = { GREEN, YELLOW }; -int cur_normal_color = 0; -int dump_color; +int cur_normal_hilite = 1; int bad_color = RED; int special_color = SPECIAL; @@ -305,13 +309,33 @@ void print_line(void) { dump_column = 0; } -void next_normal_color() { - cur_normal_color++; - cur_normal_color %= (sizeof(normal_colors) / sizeof(int)); +void next_normal_hilite() { + cur_normal_hilite = !cur_normal_hilite; } -void append_color(char *buf, int fgcolor, int bgcolor) { +void append_color(char *buf, int hl_type) { char tmpbuf[100]; + int fgcolor, bgcolor; + + switch(hl_type) { + case HL_NORMAL: + fgcolor = normal_colors[cur_normal_hilite]; + bgcolor = 0; + break; + case HL_NORM_INV: + fgcolor = 0; + bgcolor = normal_colors[cur_normal_hilite]; + break; + case HL_SPECIAL: + fgcolor = special_color; + bgcolor = 0; + break; + default: + case HL_BAD: + fgcolor = BAD_FG; + bgcolor = bad_color; + break; + } sprintf(tmpbuf, "\x1b[%d;3%d", bold, fgcolor); strcat(buf, tmpbuf); @@ -323,7 +347,36 @@ void append_color(char *buf, int fgcolor, int bgcolor) { strcat(buf, tmpbuf); } -void append_color_off(char *buf) { +void append_mono(char *buf, int hl_type) { + char tmpbuf[100]; + int code; + + switch(hl_type) { + case HL_NORMAL: + case HL_NORM_INV: + code = cur_normal_hilite ? 4 : 0; /* underline : normal */ + break; + case HL_SPECIAL: + code = 1; /* bold */ + break; + default: + case HL_BAD: + code = 7; /* reverse video */ + break; + } + + sprintf(tmpbuf, "\x1b[%dm", code); + strcat(buf, tmpbuf); +} + +void append_hilite(char *buf, int hl_type) { + if(mono) + append_mono(buf, hl_type); + else + append_color(buf, hl_type); +} + +void append_hilite_off(char *buf) { strcat(buf, "\x1b[0m"); } @@ -331,13 +384,13 @@ void append_right(char *str) { strcat(right_buf, str); } -void append_left(unsigned char byte, int dash, int fgcolor, int bgcolor) { +void append_left(unsigned char byte, int dash, int hl_type) { char tmpbuf[100]; if(!dump_column) sprintf(left_buf, hex_word_fmt, filepos + display_offset); - append_color(left_buf, fgcolor, bgcolor); + append_hilite(left_buf, hl_type); sprintf(tmpbuf, hex_byte_fmt, byte); strcat(left_buf, tmpbuf); @@ -347,9 +400,9 @@ void append_left(unsigned char byte, int dash, int fgcolor, int bgcolor) { strcat(left_buf, "-"); if(dump_column == (MAX_DUMP_COLS / 2)) strcat(left_buf, "-"); - append_color_off(left_buf); + append_hilite_off(left_buf); } else { - append_color_off(left_buf); + append_hilite_off(left_buf); strcat(left_buf, " "); if(dump_column == (MAX_DUMP_COLS / 2)) strcat(left_buf, " "); @@ -397,8 +450,8 @@ int dump_utf8_char(void) { unsigned char bytes[] = { 0, 0, 0, 0, 0 }; unsigned char *cont_bytes = bytes + 1; char *printable; - int bad = 0, special = 0; - int c, cont_count, i, fg, bg; + int bad = 0, special = 0, hl_type; + int c, cont_count, i; static int byte0; c = fgetc(input); @@ -415,28 +468,33 @@ int dump_utf8_char(void) { check_utf16(byte0, c); } + /* look at 1st byte to find out how long the sequence is */ if(c < 0x7f) { ascii_count++; cont_count = 0; if(c <= ' ' || c == 0x7f) special = 1; - } else if((c & 0xe0) == 0xc0) /* 110xxxxx */ + } else if((c & 0xe0) == 0xc0) { /* 110xxxxx */ cont_count = 1; - else if((c & 0xf0) == 0xe0) /* 1110xxxx */ + } else if((c & 0xf0) == 0xe0) { /* 1110xxxx */ cont_count = 2; - else if((c & 0xf8) == 0xf0) /* 11110xxx */ + } else if((c & 0xf8) == 0xf0) { /* 11110xxx */ cont_count = 3; - else { + } else { + /* high bit set, but not a valid sequence-starter */ cont_count = 0; bad = 1; } + /* read and validate the continuation bytes, if any */ for(i = 0; i < cont_count; i++) { int cb; c = fgetc(input); if(c == EOF) { - /* EOF in mid-sequence */ + /* EOF in mid-sequence. Don't return 0 here, since we still + have to dump the partial sequence. The next call will + give us EOF again. */ cont_count = i; bad = 1; break; @@ -465,36 +523,33 @@ int dump_utf8_char(void) { multi_count++; } + /* decide how to highlight the current character */ if(bad) { - fg = BAD_FG; - bg = BAD_BG; + hl_type = HL_BAD; /* replacement character � is U+FFFD */ printable = "�"; } else if(special) { - fg = special_color; - bg = 0; + hl_type = HL_SPECIAL; printable = get_special(bytes[0]); } else if(cont_count == 2 && is_bom(bytes)) { - fg = special_color; - bg = 0; + hl_type = HL_SPECIAL; printable = "B"; } else { - fg = normal_colors[cur_normal_color]; - bg = 0; + hl_type = HL_NORMAL; printable = (char *)bytes; - next_normal_color(); + next_normal_hilite(); } - append_color(right_buf, fg, bg); + /* human-readable (right) column: */ + append_hilite(right_buf, hl_type); append_right(printable); - append_color_off(right_buf); - - if(hilite_multi && cont_count) { - c = bg; bg = fg; fg = c; - } + append_hilite_off(right_buf); + /* hex columns: */ + if(hilite_multi && cont_count) + hl_type = HL_NORM_INV; for(i = 0; i <= cont_count; i++) { - append_left(bytes[i], (i != cont_count), fg, bg); + append_left(bytes[i], (i != cont_count), hl_type); } return 1; @@ -78,8 +78,8 @@ by itself. -m Monochrome mode. Uses underline, bold, reverse video instead of color. Use this if you have trouble distinguishing the colors, or if they - look too much like angry fruit salad. - NOT IMPLEMENTED YET. + look too much like angry fruit salad. Disables prior **-b**, **-c** + options. -n Ignore **UXD_OPTS** environment variable. This option should not be @@ -107,7 +107,7 @@ by itself. Works with negative *pos*, too. -u - Use uppercase hex digits A-F. Default is lowercase. + Use uppercase hex digits *A-F*. Default is lowercase. -v, --version Print version number and exit. @@ -251,7 +251,8 @@ ENVIRONMENT **UXD_OPTS** If this is set, its value is treated as a set of options, which - get applied before any command-line options. + get applied before any command-line options (unless the command-line + options inclue **-n**). **NO_COLOR** If this is set (to any value), **uxd** runs in monochrome mode, just |