blob: 04651d3e9415c7983784a91be5ef59754305f9fa [file] [log] [blame]
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -08001#include "vterm_internal.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <stdarg.h>
6#include <string.h>
7
8/*****************
9 * API functions *
10 *****************/
11
12static void *default_malloc(size_t size, void *allocdata)
13{
14 void *ptr = malloc(size);
15 if(ptr)
16 memset(ptr, 0, size);
17 return ptr;
18}
19
20static void default_free(void *ptr, void *allocdata)
21{
22 free(ptr);
23}
24
25static VTermAllocatorFunctions default_allocator = {
26 .malloc = &default_malloc,
27 .free = &default_free,
28};
29
30VTerm *vterm_new(int rows, int cols)
31{
32 return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);
33}
34
35VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata)
36{
37 /* Need to bootstrap using the allocator function directly */
38 VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);
39
40 vt->allocator = funcs;
41 vt->allocdata = allocdata;
42
43 vt->rows = rows;
44 vt->cols = cols;
45
46 vt->parser_state = NORMAL;
47
48 vt->strbuffer_len = 64;
49 vt->strbuffer_cur = 0;
50 vt->strbuffer = vterm_allocator_malloc(vt, vt->strbuffer_len);
51
52 vt->outbuffer_len = 64;
53 vt->outbuffer_cur = 0;
54 vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
55
56 return vt;
57}
58
59void vterm_free(VTerm *vt)
60{
61 if(vt->screen)
62 vterm_screen_free(vt->screen);
63
64 if(vt->state)
65 vterm_state_free(vt->state);
66
67 vterm_allocator_free(vt, vt->strbuffer);
68 vterm_allocator_free(vt, vt->outbuffer);
69
70 vterm_allocator_free(vt, vt);
71}
72
Elliott Hughes6d78f362014-12-04 19:52:44 -080073INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -080074{
75 return (*vt->allocator->malloc)(size, vt->allocdata);
76}
77
Elliott Hughes6d78f362014-12-04 19:52:44 -080078INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -080079{
80 (*vt->allocator->free)(ptr, vt->allocdata);
81}
82
83void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
84{
85 if(rowsp)
86 *rowsp = vt->rows;
87 if(colsp)
88 *colsp = vt->cols;
89}
90
91void vterm_set_size(VTerm *vt, int rows, int cols)
92{
93 vt->rows = rows;
94 vt->cols = cols;
95
96 if(vt->parser_callbacks && vt->parser_callbacks->resize)
97 (*vt->parser_callbacks->resize)(rows, cols, vt->cbdata);
98}
99
100void vterm_set_parser_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
101{
102 vt->parser_callbacks = callbacks;
103 vt->cbdata = user;
104}
105
106void vterm_parser_set_utf8(VTerm *vt, int is_utf8)
107{
108 vt->mode.utf8 = is_utf8;
109}
110
Elliott Hughes6d78f362014-12-04 19:52:44 -0800111INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -0800112{
113 if(len > vt->outbuffer_len - vt->outbuffer_cur) {
114 fprintf(stderr, "vterm_push_output(): buffer overflow; truncating output\n");
115 len = vt->outbuffer_len - vt->outbuffer_cur;
116 }
117
118 memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);
119 vt->outbuffer_cur += len;
120}
121
Elliott Hughes6d78f362014-12-04 19:52:44 -0800122INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -0800123{
124 int written = vsnprintf(vt->outbuffer + vt->outbuffer_cur,
125 vt->outbuffer_len - vt->outbuffer_cur,
126 format, args);
127 vt->outbuffer_cur += written;
128}
129
Elliott Hughes6d78f362014-12-04 19:52:44 -0800130INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -0800131{
132 va_list args;
133 va_start(args, format);
134 vterm_push_output_vsprintf(vt, format, args);
135 va_end(args);
136}
137
Elliott Hughes6d78f362014-12-04 19:52:44 -0800138INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -0800139{
140 if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
141 vterm_push_output_sprintf(vt, "\e%c", ctrl - 0x40);
142 else
143 vterm_push_output_sprintf(vt, "%c", ctrl);
144
145 va_list args;
146 va_start(args, fmt);
147 vterm_push_output_vsprintf(vt, fmt, args);
148 va_end(args);
Jeff Sharkey73fbfc32013-04-23 10:34:06 -0700149}
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -0800150
Elliott Hughes6d78f362014-12-04 19:52:44 -0800151INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
Jeff Sharkey73fbfc32013-04-23 10:34:06 -0700152{
153 if(!vt->mode.ctrl8bit)
154 vterm_push_output_sprintf(vt, "\e%c", C1_DCS - 0x40);
155 else
156 vterm_push_output_sprintf(vt, "%c", C1_DCS);
157
158 va_list args;
159 va_start(args, fmt);
160 vterm_push_output_vsprintf(vt, fmt, args);
161 va_end(args);
162
163 vterm_push_output_sprintf_ctrl(vt, C1_ST, "");
Jeff Sharkey5b78a3a2013-02-19 17:28:10 -0800164}
165
166size_t vterm_output_bufferlen(VTerm *vt)
167{
168 return vterm_output_get_buffer_current(vt);
169}
170
171size_t vterm_output_get_buffer_size(const VTerm *vt)
172{
173 return vt->outbuffer_len;
174}
175
176size_t vterm_output_get_buffer_current(const VTerm *vt)
177{
178 return vt->outbuffer_cur;
179}
180
181size_t vterm_output_get_buffer_remaining(const VTerm *vt)
182{
183 return vt->outbuffer_len - vt->outbuffer_cur;
184}
185
186size_t vterm_output_bufferread(VTerm *vt, char *buffer, size_t len)
187{
188 if(len > vt->outbuffer_cur)
189 len = vt->outbuffer_cur;
190
191 memcpy(buffer, vt->outbuffer, len);
192
193 if(len < vt->outbuffer_cur)
194 memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len);
195
196 vt->outbuffer_cur -= len;
197
198 return len;
199}
200
201VTermValueType vterm_get_attr_type(VTermAttr attr)
202{
203 switch(attr) {
204 case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL;
205 case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT;
206 case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL;
207 case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL;
208 case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL;
209 case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL;
210 case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT;
211 case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
212 case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
213 }
214 return 0; /* UNREACHABLE */
215}
216
217VTermValueType vterm_get_prop_type(VTermProp prop)
218{
219 switch(prop) {
220 case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL;
221 case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL;
222 case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL;
223 case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING;
224 case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING;
225 case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL;
226 case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT;
227 }
228 return 0; /* UNREACHABLE */
229}
230
231void vterm_scroll_rect(VTermRect rect,
232 int downward,
233 int rightward,
234 int (*moverect)(VTermRect src, VTermRect dest, void *user),
235 int (*eraserect)(VTermRect rect, int selective, void *user),
236 void *user)
237{
238 VTermRect src;
239 VTermRect dest;
240
241 if(abs(downward) >= rect.end_row - rect.start_row ||
242 abs(rightward) >= rect.end_col - rect.start_col) {
243 /* Scroll more than area; just erase the lot */
244 (*eraserect)(rect, 0, user);
245 return;
246 }
247
248 if(rightward >= 0) {
249 /* rect: [XXX................]
250 * src: [----------------]
251 * dest: [----------------]
252 */
253 dest.start_col = rect.start_col;
254 dest.end_col = rect.end_col - rightward;
255 src.start_col = rect.start_col + rightward;
256 src.end_col = rect.end_col;
257 }
258 else {
259 /* rect: [................XXX]
260 * src: [----------------]
261 * dest: [----------------]
262 */
263 int leftward = -rightward;
264 dest.start_col = rect.start_col + leftward;
265 dest.end_col = rect.end_col;
266 src.start_col = rect.start_col;
267 src.end_col = rect.end_col - leftward;
268 }
269
270 if(downward >= 0) {
271 dest.start_row = rect.start_row;
272 dest.end_row = rect.end_row - downward;
273 src.start_row = rect.start_row + downward;
274 src.end_row = rect.end_row;
275 }
276 else {
277 int upward = -downward;
278 dest.start_row = rect.start_row + upward;
279 dest.end_row = rect.end_row;
280 src.start_row = rect.start_row;
281 src.end_row = rect.end_row - upward;
282 }
283
284 if(moverect)
285 (*moverect)(dest, src, user);
286
287 if(downward > 0)
288 rect.start_row = rect.end_row - downward;
289 else if(downward < 0)
290 rect.end_row = rect.start_row - downward;
291
292 if(rightward > 0)
293 rect.start_col = rect.end_col - rightward;
294 else if(rightward < 0)
295 rect.end_col = rect.start_col - rightward;
296
297 (*eraserect)(rect, 0, user);
298}
299
300void vterm_copy_cells(VTermRect dest,
301 VTermRect src,
302 void (*copycell)(VTermPos dest, VTermPos src, void *user),
303 void *user)
304{
305 int downward = src.start_row - dest.start_row;
306 int rightward = src.start_col - dest.start_col;
307
308 int init_row, test_row, init_col, test_col;
309 int inc_row, inc_col;
310
311 if(downward < 0) {
312 init_row = dest.end_row - 1;
313 test_row = dest.start_row - 1;
314 inc_row = -1;
315 }
316 else /* downward >= 0 */ {
317 init_row = dest.start_row;
318 test_row = dest.end_row;
319 inc_row = +1;
320 }
321
322 if(rightward < 0) {
323 init_col = dest.end_col - 1;
324 test_col = dest.start_col - 1;
325 inc_col = -1;
326 }
327 else /* rightward >= 0 */ {
328 init_col = dest.start_col;
329 test_col = dest.end_col;
330 inc_col = +1;
331 }
332
333 VTermPos pos;
334 for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)
335 for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {
336 VTermPos srcpos = { pos.row + downward, pos.col + rightward };
337 (*copycell)(pos, srcpos, user);
338 }
339}