diff options
Diffstat (limited to 'src/libvterm/bin/vterm-dump.c')
-rw-r--r-- | src/libvterm/bin/vterm-dump.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/libvterm/bin/vterm-dump.c b/src/libvterm/bin/vterm-dump.c new file mode 100644 index 0000000..a299d9c --- /dev/null +++ b/src/libvterm/bin/vterm-dump.c @@ -0,0 +1,232 @@ +// Require getopt(3) +#define _XOPEN_SOURCE + +#include <stdio.h> +#include <string.h> +#define streq(a,b) (strcmp(a,b)==0) + +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "vterm.h" + +static const char *special_begin = "{"; +static const char *special_end = "}"; + +static int parser_text(const char bytes[], size_t len, void *user) +{ + unsigned char *b = (unsigned char *)bytes; + + int i; + for(i = 0; i < len; /* none */) { + if(b[i] < 0x20) // C0 + break; + else if(b[i] < 0x80) // ASCII + i++; + else if(b[i] < 0xa0) // C1 + break; + else if(b[i] < 0xc0) // UTF-8 continuation + break; + else if(b[i] < 0xe0) { // UTF-8 2-byte + // 2-byte UTF-8 + if(len < i+2) break; + i += 2; + } + else if(b[i] < 0xf0) { // UTF-8 3-byte + if(len < i+3) break; + i += 3; + } + else if(b[i] < 0xf8) { // UTF-8 4-byte + if(len < i+4) break; + i += 4; + } + else // otherwise invalid + break; + } + + printf("%.*s", i, b); + return i; +} + +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +static const char *name_c0[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "LS0", "LS1", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US", +}; +static const char *name_c1[] = { + NULL, NULL, "BPH", "NBH", NULL, "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3", + "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", NULL, "SCI", "CSI", "ST", "OSC", "PM", "APC", +}; + +static int parser_control(unsigned char control, void *user) +{ + if(control < 0x20) + printf("%s%s%s", special_begin, name_c0[control], special_end); + else if(control >= 0x80 && control < 0xa0 && name_c1[control - 0x80]) + printf("%s%s%s", special_begin, name_c1[control - 0x80], special_end); + else + printf("%sCONTROL 0x%02x%s", special_begin, control, special_end); + + if(control == 0x0a) + printf("\n"); + return 1; +} + +static int parser_escape(const char bytes[], size_t len, void *user) +{ + if(bytes[0] >= 0x20 && bytes[0] < 0x30) { + if(len < 2) + return -1; + len = 2; + } + else { + len = 1; + } + + printf("%sESC %.*s%s", special_begin, (int)len, bytes, special_end); + + return len; +} + +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +static const char *name_csi_plain[] = { + "ICH", "CUU", "CUD", "CUF", "CUB", "CNL", "CPL", "CHA", "CUP", "CHT", "ED", "EL", "IL", "DL", "EF", "EA", + "DCH", "SSE", "CPR", "SU", "SD", "NP", "PP", "CTC", "ECH", "CVT", "CBT", "SRS", "PTX", "SDS", "SIMD",NULL, + "HPA", "HPR", "REP", "DA", "VPA", "VPR", "HVP", "TBC", "SM", "MC", "HPB", "VPB", "RM", "SGR", "DSR", "DAQ", +}; + +/*0 4 8 B */ +static const int newline_csi_plain[] = { + 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, +}; + +static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) +{ + const char *name = NULL; + if(!leader && !intermed && command < 0x70) + name = name_csi_plain[command - 0x40]; + else if(leader && streq(leader, "?") && !intermed) { + /* DEC */ + switch(command) { + case 'h': name = "DECSM"; break; + case 'l': name = "DECRM"; break; + } + if(name) + leader = NULL; + } + + if(!leader && !intermed && command < 0x70 && newline_csi_plain[command - 0x40]) + printf("\n"); + + if(name) + printf("%s%s", special_begin, name); + else + printf("%sCSI", special_begin); + + if(leader && leader[0]) + printf(" %s", leader); + + { + int i; + for(i = 0; i < argcount; i++) { + printf(i ? "," : " "); + } + + if(args[i] == CSI_ARG_MISSING) + printf("*"); + else { + while(CSI_ARG_HAS_MORE(args[i])) + printf("%ld+", CSI_ARG(args[i++])); + printf("%ld", CSI_ARG(args[i])); + } + } + + if(intermed && intermed[0]) + printf(" %s", intermed); + + if(name) + printf("%s", special_end); + else + printf(" %c%s", command, special_end); + + return 1; +} + +static int parser_osc(const char *command, size_t cmdlen, void *user) +{ + printf("%sOSC %.*s%s", special_begin, (int)cmdlen, command, special_end); + + return 1; +} + +static int parser_dcs(const char *command, size_t cmdlen, void *user) +{ + printf("%sDCS %.*s%s", special_begin, (int)cmdlen, command, special_end); + + return 1; +} + +static VTermParserCallbacks parser_cbs = { + &parser_text, /* text */ + &parser_control, /* control */ + &parser_escape, /* escape */ + &parser_csi, /* csi */ + &parser_osc, /* osc */ + &parser_dcs, /* dcs */ + NULL /* resize */ +}; + +int main(int argc, char *argv[]) +{ + int use_colour = isatty(1); + const char *file; + int fd; + VTerm *vt; + int len; + char buffer[1024]; + + int opt; + while((opt = getopt(argc, argv, "c")) != -1) { + switch(opt) { + case 'c': use_colour = 1; break; + } + } + + file = argv[optind++]; + + if(!file || streq(file, "-")) + fd = 0; // stdin + else { + fd = open(file, O_RDONLY); + if(fd == -1) { + fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno)); + exit(1); + } + } + + if(use_colour) { + special_begin = "\x1b[7m{"; + special_end = "}\x1b[m"; + } + + /* Size matters not for the parser */ + vt = vterm_new(25, 80); + vterm_set_utf8(vt, 1); + vterm_parser_set_callbacks(vt, &parser_cbs, NULL); + + while((len = read(fd, buffer, sizeof(buffer))) > 0) { + vterm_input_write(vt, buffer, len); + } + + printf("\n"); + + close(fd); + vterm_free(vt); + + return 0; +} |