blob: a299d9c93893e5d98a7c419783264f7820368f69 [file] [log] [blame]
Bram Moolenaarb691de02018-04-24 18:39:14 +02001// Require getopt(3)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02002#define _XOPEN_SOURCE
3
4#include <stdio.h>
5#include <string.h>
6#define streq(a,b) (strcmp(a,b)==0)
7
8#include <errno.h>
9#include <fcntl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <unistd.h>
13
14#include "vterm.h"
15
16static const char *special_begin = "{";
17static const char *special_end = "}";
18
19static int parser_text(const char bytes[], size_t len, void *user)
20{
21 unsigned char *b = (unsigned char *)bytes;
22
23 int i;
24 for(i = 0; i < len; /* none */) {
Bram Moolenaarb691de02018-04-24 18:39:14 +020025 if(b[i] < 0x20) // C0
Bram Moolenaare4f25e42017-07-07 11:54:15 +020026 break;
Bram Moolenaarb691de02018-04-24 18:39:14 +020027 else if(b[i] < 0x80) // ASCII
Bram Moolenaare4f25e42017-07-07 11:54:15 +020028 i++;
Bram Moolenaarb691de02018-04-24 18:39:14 +020029 else if(b[i] < 0xa0) // C1
Bram Moolenaare4f25e42017-07-07 11:54:15 +020030 break;
Bram Moolenaarb691de02018-04-24 18:39:14 +020031 else if(b[i] < 0xc0) // UTF-8 continuation
Bram Moolenaare4f25e42017-07-07 11:54:15 +020032 break;
Bram Moolenaarb691de02018-04-24 18:39:14 +020033 else if(b[i] < 0xe0) { // UTF-8 2-byte
34 // 2-byte UTF-8
Bram Moolenaare4f25e42017-07-07 11:54:15 +020035 if(len < i+2) break;
36 i += 2;
37 }
Bram Moolenaarb691de02018-04-24 18:39:14 +020038 else if(b[i] < 0xf0) { // UTF-8 3-byte
Bram Moolenaare4f25e42017-07-07 11:54:15 +020039 if(len < i+3) break;
40 i += 3;
41 }
Bram Moolenaarb691de02018-04-24 18:39:14 +020042 else if(b[i] < 0xf8) { // UTF-8 4-byte
Bram Moolenaare4f25e42017-07-07 11:54:15 +020043 if(len < i+4) break;
44 i += 4;
45 }
Bram Moolenaarb691de02018-04-24 18:39:14 +020046 else // otherwise invalid
Bram Moolenaare4f25e42017-07-07 11:54:15 +020047 break;
48 }
49
50 printf("%.*s", i, b);
51 return i;
52}
53
54/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
55static const char *name_c0[] = {
56 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "LS0", "LS1",
57 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US",
58};
59static const char *name_c1[] = {
60 NULL, NULL, "BPH", "NBH", NULL, "NEL", "SSA", "ESA", "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
61 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA", "SOS", NULL, "SCI", "CSI", "ST", "OSC", "PM", "APC",
62};
63
64static int parser_control(unsigned char control, void *user)
65{
66 if(control < 0x20)
67 printf("%s%s%s", special_begin, name_c0[control], special_end);
68 else if(control >= 0x80 && control < 0xa0 && name_c1[control - 0x80])
69 printf("%s%s%s", special_begin, name_c1[control - 0x80], special_end);
70 else
71 printf("%sCONTROL 0x%02x%s", special_begin, control, special_end);
72
73 if(control == 0x0a)
74 printf("\n");
75 return 1;
76}
77
78static int parser_escape(const char bytes[], size_t len, void *user)
79{
80 if(bytes[0] >= 0x20 && bytes[0] < 0x30) {
81 if(len < 2)
82 return -1;
83 len = 2;
84 }
85 else {
86 len = 1;
87 }
88
89 printf("%sESC %.*s%s", special_begin, (int)len, bytes, special_end);
90
91 return len;
92}
93
94/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
95static const char *name_csi_plain[] = {
96 "ICH", "CUU", "CUD", "CUF", "CUB", "CNL", "CPL", "CHA", "CUP", "CHT", "ED", "EL", "IL", "DL", "EF", "EA",
97 "DCH", "SSE", "CPR", "SU", "SD", "NP", "PP", "CTC", "ECH", "CVT", "CBT", "SRS", "PTX", "SDS", "SIMD",NULL,
98 "HPA", "HPR", "REP", "DA", "VPA", "VPR", "HVP", "TBC", "SM", "MC", "HPB", "VPB", "RM", "SGR", "DSR", "DAQ",
99};
100
101/*0 4 8 B */
102static const int newline_csi_plain[] = {
103 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
105 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
106};
107
108static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
109{
110 const char *name = NULL;
111 if(!leader && !intermed && command < 0x70)
112 name = name_csi_plain[command - 0x40];
113 else if(leader && streq(leader, "?") && !intermed) {
114 /* DEC */
115 switch(command) {
116 case 'h': name = "DECSM"; break;
117 case 'l': name = "DECRM"; break;
118 }
119 if(name)
120 leader = NULL;
121 }
122
123 if(!leader && !intermed && command < 0x70 && newline_csi_plain[command - 0x40])
124 printf("\n");
125
126 if(name)
127 printf("%s%s", special_begin, name);
128 else
129 printf("%sCSI", special_begin);
130
131 if(leader && leader[0])
132 printf(" %s", leader);
133
134 {
135 int i;
136 for(i = 0; i < argcount; i++) {
137 printf(i ? "," : " ");
138 }
139
140 if(args[i] == CSI_ARG_MISSING)
141 printf("*");
142 else {
143 while(CSI_ARG_HAS_MORE(args[i]))
144 printf("%ld+", CSI_ARG(args[i++]));
145 printf("%ld", CSI_ARG(args[i]));
146 }
147 }
148
149 if(intermed && intermed[0])
150 printf(" %s", intermed);
151
152 if(name)
153 printf("%s", special_end);
154 else
155 printf(" %c%s", command, special_end);
156
157 return 1;
158}
159
160static int parser_osc(const char *command, size_t cmdlen, void *user)
161{
162 printf("%sOSC %.*s%s", special_begin, (int)cmdlen, command, special_end);
163
164 return 1;
165}
166
167static int parser_dcs(const char *command, size_t cmdlen, void *user)
168{
169 printf("%sDCS %.*s%s", special_begin, (int)cmdlen, command, special_end);
170
171 return 1;
172}
173
174static VTermParserCallbacks parser_cbs = {
175 &parser_text, /* text */
176 &parser_control, /* control */
177 &parser_escape, /* escape */
178 &parser_csi, /* csi */
179 &parser_osc, /* osc */
180 &parser_dcs, /* dcs */
181 NULL /* resize */
182};
183
184int main(int argc, char *argv[])
185{
186 int use_colour = isatty(1);
187 const char *file;
188 int fd;
189 VTerm *vt;
190 int len;
191 char buffer[1024];
192
193 int opt;
194 while((opt = getopt(argc, argv, "c")) != -1) {
195 switch(opt) {
196 case 'c': use_colour = 1; break;
197 }
198 }
199
200 file = argv[optind++];
201
202 if(!file || streq(file, "-"))
Bram Moolenaarb691de02018-04-24 18:39:14 +0200203 fd = 0; // stdin
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200204 else {
205 fd = open(file, O_RDONLY);
206 if(fd == -1) {
207 fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
208 exit(1);
209 }
210 }
211
212 if(use_colour) {
213 special_begin = "\x1b[7m{";
214 special_end = "}\x1b[m";
215 }
216
217 /* Size matters not for the parser */
218 vt = vterm_new(25, 80);
219 vterm_set_utf8(vt, 1);
220 vterm_parser_set_callbacks(vt, &parser_cbs, NULL);
221
222 while((len = read(fd, buffer, sizeof(buffer))) > 0) {
223 vterm_input_write(vt, buffer, len);
224 }
225
226 printf("\n");
227
228 close(fd);
229 vterm_free(vt);
Bram Moolenaarb5b49a32018-03-25 16:20:37 +0200230
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200231 return 0;
232}