xref: /haiku/src/apps/serialconnect/libvterm/src/vterm.c (revision 6a545a8eb1e3dd624c7a473fe9965a4c08e5a54f)
1 #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 
default_malloc(size_t size,void * allocdata)12 static 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 
default_free(void * ptr,void * allocdata)20 static void default_free(void *ptr, void *allocdata)
21 {
22   free(ptr);
23 }
24 
25 static VTermAllocatorFunctions default_allocator = {
26   .malloc = &default_malloc,
27   .free   = &default_free,
28 };
29 
vterm_new(int rows,int cols)30 VTerm *vterm_new(int rows, int cols)
31 {
32   return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);
33 }
34 
vterm_new_with_allocator(int rows,int cols,VTermAllocatorFunctions * funcs,void * allocdata)35 VTerm *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 
vterm_free(VTerm * vt)59 void 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 
vterm_allocator_malloc(VTerm * vt,size_t size)73 INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
74 {
75   return (*vt->allocator->malloc)(size, vt->allocdata);
76 }
77 
vterm_allocator_free(VTerm * vt,void * ptr)78 INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
79 {
80   (*vt->allocator->free)(ptr, vt->allocdata);
81 }
82 
vterm_get_size(const VTerm * vt,int * rowsp,int * colsp)83 void 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 
vterm_set_size(VTerm * vt,int rows,int cols)91 void 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 
vterm_set_parser_callbacks(VTerm * vt,const VTermParserCallbacks * callbacks,void * user)100 void vterm_set_parser_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
101 {
102   vt->parser_callbacks = callbacks;
103   vt->cbdata = user;
104 }
105 
vterm_parser_set_utf8(VTerm * vt,int is_utf8)106 void vterm_parser_set_utf8(VTerm *vt, int is_utf8)
107 {
108   vt->mode.utf8 = is_utf8;
109 }
110 
vterm_push_output_bytes(VTerm * vt,const char * bytes,size_t len)111 INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
112 {
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 
vterm_push_output_vsprintf(VTerm * vt,const char * format,va_list args)122 INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
123 {
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 
vterm_push_output_sprintf(VTerm * vt,const char * format,...)130 INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
131 {
132   va_list args;
133   va_start(args, format);
134   vterm_push_output_vsprintf(vt, format, args);
135   va_end(args);
136 }
137 
vterm_push_output_sprintf_ctrl(VTerm * vt,unsigned char ctrl,const char * fmt,...)138 INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
139 {
140   va_list args;
141 
142   if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
143     vterm_push_output_sprintf(vt, "\e%c", ctrl - 0x40);
144   else
145     vterm_push_output_sprintf(vt, "%c", ctrl);
146 
147   va_start(args, fmt);
148   vterm_push_output_vsprintf(vt, fmt, args);
149   va_end(args);
150 }
151 
vterm_push_output_sprintf_dcs(VTerm * vt,const char * fmt,...)152 INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
153 {
154   va_list args;
155 
156   if(!vt->mode.ctrl8bit)
157     vterm_push_output_sprintf(vt, "\e%c", C1_DCS - 0x40);
158   else
159     vterm_push_output_sprintf(vt, "%c", C1_DCS);
160 
161   va_start(args, fmt);
162   vterm_push_output_vsprintf(vt, fmt, args);
163   va_end(args);
164 
165   vterm_push_output_sprintf_ctrl(vt, C1_ST, "");
166 }
167 
vterm_output_bufferlen(VTerm * vt)168 size_t vterm_output_bufferlen(VTerm *vt)
169 {
170   return vterm_output_get_buffer_current(vt);
171 }
172 
vterm_output_get_buffer_size(const VTerm * vt)173 size_t vterm_output_get_buffer_size(const VTerm *vt)
174 {
175   return vt->outbuffer_len;
176 }
177 
vterm_output_get_buffer_current(const VTerm * vt)178 size_t vterm_output_get_buffer_current(const VTerm *vt)
179 {
180   return vt->outbuffer_cur;
181 }
182 
vterm_output_get_buffer_remaining(const VTerm * vt)183 size_t vterm_output_get_buffer_remaining(const VTerm *vt)
184 {
185   return vt->outbuffer_len - vt->outbuffer_cur;
186 }
187 
vterm_output_bufferread(VTerm * vt,char * buffer,size_t len)188 size_t vterm_output_bufferread(VTerm *vt, char *buffer, size_t len)
189 {
190   if(len > vt->outbuffer_cur)
191     len = vt->outbuffer_cur;
192 
193   memcpy(buffer, vt->outbuffer, len);
194 
195   if(len < vt->outbuffer_cur)
196     memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len);
197 
198   vt->outbuffer_cur -= len;
199 
200   return len;
201 }
202 
vterm_get_attr_type(VTermAttr attr)203 VTermValueType vterm_get_attr_type(VTermAttr attr)
204 {
205   switch(attr) {
206     case VTERM_ATTR_BOLD:       return VTERM_VALUETYPE_BOOL;
207     case VTERM_ATTR_UNDERLINE:  return VTERM_VALUETYPE_INT;
208     case VTERM_ATTR_ITALIC:     return VTERM_VALUETYPE_BOOL;
209     case VTERM_ATTR_BLINK:      return VTERM_VALUETYPE_BOOL;
210     case VTERM_ATTR_REVERSE:    return VTERM_VALUETYPE_BOOL;
211     case VTERM_ATTR_STRIKE:     return VTERM_VALUETYPE_BOOL;
212     case VTERM_ATTR_FONT:       return VTERM_VALUETYPE_INT;
213     case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
214     case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
215   }
216   return 0; /* UNREACHABLE */
217 }
218 
vterm_get_prop_type(VTermProp prop)219 VTermValueType vterm_get_prop_type(VTermProp prop)
220 {
221   switch(prop) {
222     case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL;
223     case VTERM_PROP_CURSORBLINK:   return VTERM_VALUETYPE_BOOL;
224     case VTERM_PROP_ALTSCREEN:     return VTERM_VALUETYPE_BOOL;
225     case VTERM_PROP_TITLE:         return VTERM_VALUETYPE_STRING;
226     case VTERM_PROP_ICONNAME:      return VTERM_VALUETYPE_STRING;
227     case VTERM_PROP_REVERSE:       return VTERM_VALUETYPE_BOOL;
228     case VTERM_PROP_CURSORSHAPE:   return VTERM_VALUETYPE_INT;
229   }
230   return 0; /* UNREACHABLE */
231 }
232 
vterm_scroll_rect(VTermRect rect,int downward,int rightward,int (* moverect)(VTermRect src,VTermRect dest,void * user),int (* eraserect)(VTermRect rect,int selective,void * user),void * user)233 void vterm_scroll_rect(VTermRect rect,
234     int downward,
235     int rightward,
236     int (*moverect)(VTermRect src, VTermRect dest, void *user),
237     int (*eraserect)(VTermRect rect, int selective, void *user),
238     void *user)
239 {
240   VTermRect src;
241   VTermRect dest;
242 
243   if(abs(downward)  >= rect.end_row - rect.start_row ||
244      abs(rightward) >= rect.end_col - rect.start_col) {
245     /* Scroll more than area; just erase the lot */
246     (*eraserect)(rect, 0, user);
247     return;
248   }
249 
250   if(rightward >= 0) {
251     /* rect: [XXX................]
252      * src:     [----------------]
253      * dest: [----------------]
254      */
255     dest.start_col = rect.start_col;
256     dest.end_col   = rect.end_col   - rightward;
257     src.start_col  = rect.start_col + rightward;
258     src.end_col    = rect.end_col;
259   }
260   else {
261     /* rect: [................XXX]
262      * src:  [----------------]
263      * dest:    [----------------]
264      */
265     int leftward = -rightward;
266     dest.start_col = rect.start_col + leftward;
267     dest.end_col   = rect.end_col;
268     src.start_col  = rect.start_col;
269     src.end_col    = rect.end_col - leftward;
270   }
271 
272   if(downward >= 0) {
273     dest.start_row = rect.start_row;
274     dest.end_row   = rect.end_row   - downward;
275     src.start_row  = rect.start_row + downward;
276     src.end_row    = rect.end_row;
277   }
278   else {
279     int upward = -downward;
280     dest.start_row = rect.start_row + upward;
281     dest.end_row   = rect.end_row;
282     src.start_row  = rect.start_row;
283     src.end_row    = rect.end_row - upward;
284   }
285 
286   if(moverect)
287     (*moverect)(dest, src, user);
288 
289   if(downward > 0)
290     rect.start_row = rect.end_row - downward;
291   else if(downward < 0)
292     rect.end_row = rect.start_row - downward;
293 
294   if(rightward > 0)
295     rect.start_col = rect.end_col - rightward;
296   else if(rightward < 0)
297     rect.end_col = rect.start_col - rightward;
298 
299   (*eraserect)(rect, 0, user);
300 }
301 
vterm_copy_cells(VTermRect dest,VTermRect src,void (* copycell)(VTermPos dest,VTermPos src,void * user),void * user)302 void vterm_copy_cells(VTermRect dest,
303     VTermRect src,
304     void (*copycell)(VTermPos dest, VTermPos src, void *user),
305     void *user)
306 {
307   int downward  = src.start_row - dest.start_row;
308   int rightward = src.start_col - dest.start_col;
309 
310   int init_row, test_row, init_col, test_col;
311   int inc_row, inc_col;
312 
313   VTermPos pos;
314 
315   if(downward < 0) {
316     init_row = dest.end_row - 1;
317     test_row = dest.start_row - 1;
318     inc_row = -1;
319   }
320   else /* downward >= 0 */ {
321     init_row = dest.start_row;
322     test_row = dest.end_row;
323     inc_row = +1;
324   }
325 
326   if(rightward < 0) {
327     init_col = dest.end_col - 1;
328     test_col = dest.start_col - 1;
329     inc_col = -1;
330   }
331   else /* rightward >= 0 */ {
332     init_col = dest.start_col;
333     test_col = dest.end_col;
334     inc_col = +1;
335   }
336 
337   for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)
338     for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {
339       VTermPos srcpos = { pos.row + downward, pos.col + rightward };
340       (*copycell)(pos, srcpos, user);
341     }
342 }
343