blob: 3af2ecf51a071324fb04807c3c5e60721d1a99f5 [file] [log] [blame]
Bram Moolenaare4f25e42017-07-07 11:54:15 +02001#include <stdio.h>
2#include <string.h>
3
4#include <errno.h>
5#include <fcntl.h>
6#include <getopt.h>
7#include <unistd.h>
8
9#include "vterm.h"
10
11#define DEFINE_INLINES
12#include "../src/utf8.h" /* fill_utf8 */
13
14#define streq(a,b) (!strcmp(a,b))
15
16static VTerm *vt;
17static VTermScreen *vts;
18
19static int cols;
20static int rows;
21
22static enum {
23 FORMAT_PLAIN,
24 FORMAT_SGR
25} format = FORMAT_PLAIN;
26
27static int col2index(VTermColor target)
28{
29 int index;
30
31 for(index = 0; index < 256; index++) {
32 VTermColor col;
33 vterm_state_get_palette_color(NULL, index, &col);
34 if(col.red == target.red && col.green == target.green && col.blue == target.blue)
35 return index;
36 }
37 return -1;
38}
39
40static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell)
41{
42 switch(format) {
43 case FORMAT_PLAIN:
44 break;
45 case FORMAT_SGR:
46 {
47 /* If all 7 attributes change, that means 7 SGRs max */
48 /* Each colour could consume up to 3 */
49 int sgr[7 + 2*3]; int sgri = 0;
50
51 if(!prevcell->attrs.bold && cell->attrs.bold)
52 sgr[sgri++] = 1;
53 if(prevcell->attrs.bold && !cell->attrs.bold)
54 sgr[sgri++] = 22;
55
56 if(!prevcell->attrs.underline && cell->attrs.underline)
57 sgr[sgri++] = 4;
58 if(prevcell->attrs.underline && !cell->attrs.underline)
59 sgr[sgri++] = 24;
60
61 if(!prevcell->attrs.italic && cell->attrs.italic)
62 sgr[sgri++] = 3;
63 if(prevcell->attrs.italic && !cell->attrs.italic)
64 sgr[sgri++] = 23;
65
66 if(!prevcell->attrs.blink && cell->attrs.blink)
67 sgr[sgri++] = 5;
68 if(prevcell->attrs.blink && !cell->attrs.blink)
69 sgr[sgri++] = 25;
70
71 if(!prevcell->attrs.reverse && cell->attrs.reverse)
72 sgr[sgri++] = 7;
73 if(prevcell->attrs.reverse && !cell->attrs.reverse)
74 sgr[sgri++] = 27;
75
76 if(!prevcell->attrs.strike && cell->attrs.strike)
77 sgr[sgri++] = 9;
78 if(prevcell->attrs.strike && !cell->attrs.strike)
79 sgr[sgri++] = 29;
80
81 if(!prevcell->attrs.font && cell->attrs.font)
82 sgr[sgri++] = 10 + cell->attrs.font;
83 if(prevcell->attrs.font && !cell->attrs.font)
84 sgr[sgri++] = 10;
85
86 if(prevcell->fg.red != cell->fg.red ||
87 prevcell->fg.green != cell->fg.green ||
88 prevcell->fg.blue != cell->fg.blue) {
89 int index = col2index(cell->fg);
90 if(index == -1)
91 sgr[sgri++] = 39;
92 else if(index < 8)
93 sgr[sgri++] = 30 + index;
94 else if(index < 16)
95 sgr[sgri++] = 90 + (index - 8);
96 else {
97 sgr[sgri++] = 38;
Bram Moolenaarb5b49a32018-03-25 16:20:37 +020098 sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
99 sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200100 }
101 }
102
103 if(prevcell->bg.red != cell->bg.red ||
104 prevcell->bg.green != cell->bg.green ||
105 prevcell->bg.blue != cell->bg.blue) {
106 int index = col2index(cell->bg);
107 if(index == -1)
108 sgr[sgri++] = 49;
109 else if(index < 8)
110 sgr[sgri++] = 40 + index;
111 else if(index < 16)
112 sgr[sgri++] = 100 + (index - 8);
113 else {
114 sgr[sgri++] = 48;
Bram Moolenaarb5b49a32018-03-25 16:20:37 +0200115 sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
116 sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200117 }
118 }
119
120 if(!sgri)
121 break;
122
123 printf("\x1b[");
124 {
125 int i;
126 for(i = 0; i < sgri; i++)
127 printf(!i ? "%d" :
Bram Moolenaarb5b49a32018-03-25 16:20:37 +0200128 CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" :
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200129 ";%d",
Bram Moolenaarb5b49a32018-03-25 16:20:37 +0200130 CSI_ARG(sgr[i]));
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200131 }
132 printf("m");
133 }
134 break;
135 }
136
137 {
138 int i;
139 for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
140 char bytes[6];
141 bytes[fill_utf8(cell->chars[i], bytes)] = 0;
142 printf("%s", bytes);
143 }
144 }
145}
146
147static void dump_eol(const VTermScreenCell *prevcell)
148{
149 switch(format) {
150 case FORMAT_PLAIN:
151 break;
152 case FORMAT_SGR:
153 if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic ||
154 prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike ||
155 prevcell->attrs.font)
156 printf("\x1b[m");
157 break;
158 }
159
160 printf("\n");
161}
162
163void dump_row(int row)
164{
165 VTermPos pos;
166 VTermScreenCell prevcell;
167 pos.row = row;
168 pos.col = 0;
169 memset(&prevcell, 0, sizeof(prevcell));
170 vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
171
172 while(pos.col < cols) {
173 VTermScreenCell cell;
174 vterm_screen_get_cell(vts, pos, &cell);
175
176 dump_cell(&cell, &prevcell);
177
178 pos.col += cell.width;
179 prevcell = cell;
180 }
181
182 dump_eol(&prevcell);
183}
184
185static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
186{
187 VTermScreenCell prevcell;
188 int col;
189
190 memset(&prevcell, 0, sizeof(prevcell));
191 vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg);
192
193 for(col = 0; col < cols; col++) {
194 dump_cell(cells + col, &prevcell);
195 prevcell = cells[col];
196 }
197
198 dump_eol(&prevcell);
199
200 return 1;
201}
202
203static int screen_resize(int new_rows, int new_cols, void *user)
204{
205 rows = new_rows;
206 cols = new_cols;
207 return 1;
208}
209
210static VTermScreenCallbacks cb_screen = {
211 NULL, /* damage */
212 NULL, /* moverect */
213 NULL, /* movecursor */
214 NULL, /* settermprop */
215 NULL, /* bell */
216 &screen_resize, /* resize */
217 &screen_sb_pushline, /* sb_pushline */
218 NULL, /* popline */
219};
220
221int main(int argc, char *argv[])
222{
223 int opt;
224 const char *file;
225 int fd;
226 int len;
227 char buffer[1024];
228 int row;
229
230 rows = 25;
231 cols = 80;
232
233 while((opt = getopt(argc, argv, "f:l:c:")) != -1) {
234 switch(opt) {
235 case 'f':
236 if(streq(optarg, "plain"))
237 format = FORMAT_PLAIN;
238 else if(streq(optarg, "sgr"))
239 format = FORMAT_SGR;
240 else {
241 fprintf(stderr, "Unrecognised format '%s'\n", optarg);
242 exit(1);
243 }
244 break;
245
246 case 'l':
247 rows = atoi(optarg);
248 if(!rows)
249 rows = 25;
250 break;
251
252 case 'c':
253 cols = atoi(optarg);
254 if(!cols)
255 cols = 80;
256 break;
257 }
258 }
259
260 file = argv[optind++];
261 fd = open(file, O_RDONLY);
262 if(fd == -1) {
263 fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
264 exit(1);
265 }
266
267 vt = vterm_new(rows, cols);
Bram Moolenaarb2a76ec2017-07-25 21:34:46 +0200268 vterm_set_utf8(vt, TRUE);
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200269
270 vts = vterm_obtain_screen(vt);
271 vterm_screen_set_callbacks(vts, &cb_screen, NULL);
272
273 vterm_screen_reset(vts, 1);
274
275 while((len = read(fd, buffer, sizeof(buffer))) > 0) {
276 vterm_input_write(vt, buffer, len);
277 }
278
279 for(row = 0; row < rows; row++) {
280 dump_row(row);
281 }
282
283 close(fd);
284
285 vterm_free(vt);
Bram Moolenaarb5b49a32018-03-25 16:20:37 +0200286
Bram Moolenaare4f25e42017-07-07 11:54:15 +0200287 return 0;
288}