blob: 84a957a68205c491d2f34097108f93ad214027c0 [file] [log] [blame]
Bram Moolenaare4f25e42017-07-07 11:54:15 +02001/* Require getopt(3) */
2#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 */) {
25 if(b[i] < 0x20) /* C0 */
26 break;
27 else if(b[i] < 0x80) /* ASCII */
28 i++;
29 else if(b[i] < 0xa0) /* C1 */
30 break;
31 else if(b[i] < 0xc0) /* UTF-8 continuation */
32 break;
33 else if(b[i] < 0xe0) { /* UTF-8 2-byte */
34 /* 2-byte UTF-8 */
35 if(len < i+2) break;
36 i += 2;
37 }
38 else if(b[i] < 0xf0) { /* UTF-8 3-byte */
39 if(len < i+3) break;
40 i += 3;
41 }
42 else if(b[i] < 0xf8) { /* UTF-8 4-byte */
43 if(len < i+4) break;
44 i += 4;
45 }
46 else /* otherwise invalid */
47 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, "-"))
203 fd = 0; /* stdin */
204 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);
230 return 0;
231}