LF OS
Hobby operating system for amd64 with high ambitions
Loading...
Searching...
No Matches
unterm.c
Go to the documentation of this file.
1#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#include "../src/utf8.h" // fill_utf8
12
13/*
14 * unterm [OPTIONS] SCRIPTFILE
15 *
16 * Interprets terminal sequences in SCRIPTFILE and outputs the final state of
17 * the terminal buffer at the end.
18 *
19 * OPTIONS:
20 * -f FORMAT -- set the output format: ["plain" | "sgr"]
21 * -l LINES,
22 * -c COLS -- set the size of the emulated terminal
23 */
24
25#define streq(a,b) (!strcmp(a,b))
26
27static VTerm *vt;
29
30static int cols;
31static int rows;
32
33static enum {
37
38static int dump_cell_color(const VTermColor *col, int sgri, int sgr[], int fg)
39{
40 /* Reset the color if the given color is the default color */
41 if (fg && VTERM_COLOR_IS_DEFAULT_FG(col)) {
42 sgr[sgri++] = 39;
43 return sgri;
44 }
45 if (!fg && VTERM_COLOR_IS_DEFAULT_BG(col)) {
46 sgr[sgri++] = 49;
47 return sgri;
48 }
49
50 /* Decide whether to send an indexed color or an RGB color */
51 if (VTERM_COLOR_IS_INDEXED(col)) {
52 const uint8_t idx = col->indexed.idx;
53 if (idx < 8) {
54 sgr[sgri++] = (idx + (fg ? 30 : 40));
55 }
56 else if (idx < 16) {
57 sgr[sgri++] = (idx - 8 + (fg ? 90 : 100));
58 }
59 else {
60 sgr[sgri++] = (fg ? 38 : 48);
61 sgr[sgri++] = 5;
62 sgr[sgri++] = idx;
63 }
64 }
65 else if (VTERM_COLOR_IS_RGB(col)) {
66 sgr[sgri++] = (fg ? 38 : 48);
67 sgr[sgri++] = 2;
68 sgr[sgri++] = col->rgb.red;
69 sgr[sgri++] = col->rgb.green;
70 sgr[sgri++] = col->rgb.blue;
71 }
72 return sgri;
73}
74
75static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell)
76{
77 switch(format) {
78 case FORMAT_PLAIN:
79 break;
80 case FORMAT_SGR:
81 {
82 // If all 7 attributes change, that means 7 SGRs max
83 // Each colour could consume up to 5 entries
84 int sgr[7 + 2*5]; int sgri = 0;
85
86 if(!prevcell->attrs.bold && cell->attrs.bold)
87 sgr[sgri++] = 1;
88 if(prevcell->attrs.bold && !cell->attrs.bold)
89 sgr[sgri++] = 22;
90
91 if(!prevcell->attrs.underline && cell->attrs.underline)
92 sgr[sgri++] = 4;
93 if(prevcell->attrs.underline && !cell->attrs.underline)
94 sgr[sgri++] = 24;
95
96 if(!prevcell->attrs.italic && cell->attrs.italic)
97 sgr[sgri++] = 3;
98 if(prevcell->attrs.italic && !cell->attrs.italic)
99 sgr[sgri++] = 23;
100
101 if(!prevcell->attrs.blink && cell->attrs.blink)
102 sgr[sgri++] = 5;
103 if(prevcell->attrs.blink && !cell->attrs.blink)
104 sgr[sgri++] = 25;
105
106 if(!prevcell->attrs.reverse && cell->attrs.reverse)
107 sgr[sgri++] = 7;
108 if(prevcell->attrs.reverse && !cell->attrs.reverse)
109 sgr[sgri++] = 27;
110
111 if(!prevcell->attrs.conceal && cell->attrs.conceal)
112 sgr[sgri++] = 8;
113 if(prevcell->attrs.conceal && !cell->attrs.conceal)
114 sgr[sgri++] = 28;
115
116 if(!prevcell->attrs.strike && cell->attrs.strike)
117 sgr[sgri++] = 9;
118 if(prevcell->attrs.strike && !cell->attrs.strike)
119 sgr[sgri++] = 29;
120
121 if(!prevcell->attrs.font && cell->attrs.font)
122 sgr[sgri++] = 10 + cell->attrs.font;
123 if(prevcell->attrs.font && !cell->attrs.font)
124 sgr[sgri++] = 10;
125
126 if(!vterm_color_is_equal(&prevcell->fg, &cell->fg)) {
127 sgri = dump_cell_color(&cell->fg, sgri, sgr, 1);
128 }
129
130 if(!vterm_color_is_equal(&prevcell->bg, &cell->bg)) {
131 sgri = dump_cell_color(&cell->bg, sgri, sgr, 0);
132 }
133
134 if(!sgri)
135 break;
136
137 printf("\x1b[");
138 for(int i = 0; i < sgri; i++)
139 printf(!i ? "%d" :
140 CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" :
141 ";%d",
142 CSI_ARG(sgr[i]));
143 printf("m");
144 }
145 break;
146 }
147
148 for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
149 char bytes[6];
150 bytes[fill_utf8(cell->chars[i], bytes)] = 0;
151 printf("%s", bytes);
152 }
153}
154
155static void dump_eol(const VTermScreenCell *prevcell)
156{
157 switch(format) {
158 case FORMAT_PLAIN:
159 break;
160 case FORMAT_SGR:
161 if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic ||
162 prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike ||
163 prevcell->attrs.conceal || prevcell->attrs.font)
164 printf("\x1b[m");
165 break;
166 }
167
168 printf("\n");
169}
170
171void dump_row(int row)
172{
173 VTermPos pos = { .row = row, .col = 0 };
174 VTermScreenCell prevcell = { 0 };
176
177 while(pos.col < cols) {
178 VTermScreenCell cell;
179 vterm_screen_get_cell(vts, pos, &cell);
180
181 dump_cell(&cell, &prevcell);
182
183 pos.col += cell.width;
184 prevcell = cell;
185 }
186
187 dump_eol(&prevcell);
188}
189
190static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
191{
192 VTermScreenCell prevcell = { 0 };
194
195 for(int col = 0; col < cols; col++) {
196 dump_cell(cells + col, &prevcell);
197 prevcell = cells[col];
198 }
199
200 dump_eol(&prevcell);
201
202 return 1;
203}
204
205static int screen_resize(int new_rows, int new_cols, void *user)
206{
207 rows = new_rows;
208 cols = new_cols;
209 return 1;
210}
211
216
217int main(int argc, char *argv[])
218{
219 rows = 25;
220 cols = 80;
221
222 int opt;
223 while((opt = getopt(argc, argv, "f:l:c:")) != -1) {
224 switch(opt) {
225 case 'f':
226 if(streq(optarg, "plain"))
228 else if(streq(optarg, "sgr"))
230 else {
231 fprintf(stderr, "Unrecognised format '%s'\n", optarg);
232 exit(1);
233 }
234 break;
235
236 case 'l':
237 rows = atoi(optarg);
238 if(!rows)
239 rows = 25;
240 break;
241
242 case 'c':
243 cols = atoi(optarg);
244 if(!cols)
245 cols = 80;
246 break;
247 }
248 }
249
250 const char *file = argv[optind++];
251 int fd = open(file, O_RDONLY);
252 if(fd == -1) {
253 fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno));
254 exit(1);
255 }
256
257 vt = vterm_new(rows, cols);
258 vterm_set_utf8(vt, true);
259
262
264
265 int len;
266 char buffer[1024];
267 while((len = read(fd, buffer, sizeof(buffer))) > 0) {
268 vterm_input_write(vt, buffer, len);
269 }
270
271 for(int row = 0; row < rows; row++) {
272 dump_row(row);
273 }
274
275 close(fd);
276
277 vterm_free(vt);
278
279 return 0;
280}
unsigned char uint8_t
Definition arch.h:5
int read(int file, char *ptr, int len)
Definition rw_hook.c:4
int(* sb_pushline)(int cols, const VTermScreenCell *cells, void *user)
Definition vterm.h:541
static int rows
Definition unterm.c:31
static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
Definition unterm.c:190
int main(int argc, char *argv[])
Definition unterm.c:217
void dump_row(int row)
Definition unterm.c:171
#define streq(a, b)
Definition unterm.c:25
static int cols
Definition unterm.c:30
static void dump_eol(const VTermScreenCell *prevcell)
Definition unterm.c:155
@ FORMAT_SGR
Definition unterm.c:35
@ FORMAT_PLAIN
Definition unterm.c:34
static VTermScreen * vts
Definition unterm.c:28
static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell)
Definition unterm.c:75
static VTerm * vt
Definition unterm.c:27
static int dump_cell_color(const VTermColor *col, int sgri, int sgr[], int fg)
Definition unterm.c:38
static enum @5 format
static int screen_resize(int new_rows, int new_cols, void *user)
Definition unterm.c:205
static VTermScreenCallbacks cb_screen
Definition unterm.c:212
static int fill_utf8(long codepoint, char *str)
Definition utf8.h:16
void vterm_set_utf8(VTerm *vt, int is_utf8)
Definition vterm.c:133
#define VTERM_MAX_CHARS_PER_CELL
Definition vterm.h:24
struct VTermColor::@11 indexed
unsigned int underline
Definition vterm.h:501
unsigned int bold
Definition vterm.h:500
unsigned int italic
Definition vterm.h:502
VTermColor fg
Definition vterm.h:531
void vterm_screen_reset(VTermScreen *screen, int hard)
Definition screen.c:902
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg)
Definition pen.c:231
#define VTERM_COLOR_IS_INDEXED(col)
Definition vterm.h:109
VTermColor bg
Definition vterm.h:531
#define CSI_ARG_HAS_MORE(a)
Definition vterm.h:392
int col
Definition vterm.h:32
uint32_t chars[VTERM_MAX_CHARS_PER_CELL]
Definition vterm.h:528
#define VTERM_COLOR_IS_DEFAULT_FG(col)
Definition vterm.h:124
int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)
Definition screen.c:971
#define VTERM_COLOR_IS_RGB(col)
Definition vterm.h:116
unsigned int font
Definition vterm.h:507
int row
Definition vterm.h:31
void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user)
Definition screen.c:1053
VTermScreenCellAttrs attrs
Definition vterm.h:530
VTermState * vterm_obtain_state(VTerm *vt)
Definition state.c:2059
VTermScreen * vterm_obtain_screen(VTerm *vt)
Definition screen.c:1021
#define CSI_ARG(a)
Definition vterm.h:393
unsigned int conceal
Definition vterm.h:505
unsigned int strike
Definition vterm.h:506
unsigned int reverse
Definition vterm.h:504
#define VTERM_COLOR_IS_DEFAULT_BG(col)
Definition vterm.h:132
void vterm_free(VTerm *vt)
Definition vterm.c:84
int vterm_color_is_equal(const VTermColor *a, const VTermColor *b)
Definition pen.c:211
VTerm * vterm_new(int rows, int cols)
Definition vterm.c:30
unsigned int blink
Definition vterm.h:503
size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
Definition parser.c:111
struct VTermColor::@10 rgb