• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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->parser.callbacks = NULL;
49   vt->parser.cbdata    = NULL;
50 
51   vt->parser.strbuffer_len = 64;
52   vt->parser.strbuffer_cur = 0;
53   vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);
54 
55   vt->outbuffer_len = 64;
56   vt->outbuffer_cur = 0;
57   vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
58 
59   return vt;
60 }
61 
vterm_free(VTerm * vt)62 void vterm_free(VTerm *vt)
63 {
64   if(vt->screen)
65     vterm_screen_free(vt->screen);
66 
67   if(vt->state)
68     vterm_state_free(vt->state);
69 
70   vterm_allocator_free(vt, vt->parser.strbuffer);
71   vterm_allocator_free(vt, vt->outbuffer);
72 
73   vterm_allocator_free(vt, vt);
74 }
75 
vterm_allocator_malloc(VTerm * vt,size_t size)76 INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
77 {
78   return (*vt->allocator->malloc)(size, vt->allocdata);
79 }
80 
vterm_allocator_free(VTerm * vt,void * ptr)81 INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
82 {
83   (*vt->allocator->free)(ptr, vt->allocdata);
84 }
85 
vterm_get_size(const VTerm * vt,int * rowsp,int * colsp)86 void vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)
87 {
88   if(rowsp)
89     *rowsp = vt->rows;
90   if(colsp)
91     *colsp = vt->cols;
92 }
93 
vterm_set_size(VTerm * vt,int rows,int cols)94 void vterm_set_size(VTerm *vt, int rows, int cols)
95 {
96   vt->rows = rows;
97   vt->cols = cols;
98 
99   if(vt->parser.callbacks && vt->parser.callbacks->resize)
100     (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata);
101 }
102 
vterm_get_utf8(const VTerm * vt)103 int vterm_get_utf8(const VTerm *vt)
104 {
105   return vt->mode.utf8;
106 }
107 
vterm_set_utf8(VTerm * vt,int is_utf8)108 void vterm_set_utf8(VTerm *vt, int is_utf8)
109 {
110   vt->mode.utf8 = is_utf8;
111 }
112 
vterm_push_output_bytes(VTerm * vt,const char * bytes,size_t len)113 INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)
114 {
115   if(len > vt->outbuffer_len - vt->outbuffer_cur) {
116     DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n");
117     len = vt->outbuffer_len - vt->outbuffer_cur;
118   }
119 
120   memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);
121   vt->outbuffer_cur += len;
122 }
123 
outbuffer_is_full(VTerm * vt)124 static int outbuffer_is_full(VTerm *vt)
125 {
126   return vt->outbuffer_cur >= vt->outbuffer_len - 1;
127 }
128 
vterm_push_output_vsprintf(VTerm * vt,const char * format,va_list args)129 INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)
130 {
131   if(outbuffer_is_full(vt)) {
132     DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n");
133     return;
134   }
135 
136   int written = vsnprintf(vt->outbuffer + vt->outbuffer_cur,
137       vt->outbuffer_len - vt->outbuffer_cur,
138       format, args);
139 
140   if(written == vt->outbuffer_len - vt->outbuffer_cur) {
141     /* output was truncated */
142     vt->outbuffer_cur = vt->outbuffer_len - 1;
143   }
144   else
145     vt->outbuffer_cur += written;
146 }
147 
vterm_push_output_sprintf(VTerm * vt,const char * format,...)148 INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)
149 {
150   va_list args;
151   va_start(args, format);
152   vterm_push_output_vsprintf(vt, format, args);
153   va_end(args);
154 }
155 
vterm_push_output_sprintf_ctrl(VTerm * vt,unsigned char ctrl,const char * fmt,...)156 INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
157 {
158   size_t orig_cur = vt->outbuffer_cur;
159 
160   if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
161     vterm_push_output_sprintf(vt, ESC_S "%c", ctrl - 0x40);
162   else
163     vterm_push_output_sprintf(vt, "%c", ctrl);
164 
165   va_list args;
166   va_start(args, fmt);
167   vterm_push_output_vsprintf(vt, fmt, args);
168   va_end(args);
169 
170   if(outbuffer_is_full(vt))
171     vt->outbuffer_cur = orig_cur;
172 }
173 
vterm_push_output_sprintf_dcs(VTerm * vt,const char * fmt,...)174 INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
175 {
176   size_t orig_cur = vt->outbuffer_cur;
177 
178   if(!vt->mode.ctrl8bit)
179     vterm_push_output_sprintf(vt, ESC_S "%c", C1_DCS - 0x40);
180   else
181     vterm_push_output_sprintf(vt, "%c", C1_DCS);
182 
183   va_list args;
184   va_start(args, fmt);
185   vterm_push_output_vsprintf(vt, fmt, args);
186   va_end(args);
187 
188   vterm_push_output_sprintf_ctrl(vt, C1_ST, "");
189 
190   if(outbuffer_is_full(vt))
191     vt->outbuffer_cur = orig_cur;
192 }
193 
vterm_output_get_buffer_size(const VTerm * vt)194 size_t vterm_output_get_buffer_size(const VTerm *vt)
195 {
196   return vt->outbuffer_len;
197 }
198 
vterm_output_get_buffer_current(const VTerm * vt)199 size_t vterm_output_get_buffer_current(const VTerm *vt)
200 {
201   return vt->outbuffer_cur;
202 }
203 
vterm_output_get_buffer_remaining(const VTerm * vt)204 size_t vterm_output_get_buffer_remaining(const VTerm *vt)
205 {
206   return vt->outbuffer_len - vt->outbuffer_cur;
207 }
208 
vterm_output_read(VTerm * vt,char * buffer,size_t len)209 size_t vterm_output_read(VTerm *vt, char *buffer, size_t len)
210 {
211   if(len > vt->outbuffer_cur)
212     len = vt->outbuffer_cur;
213 
214   memcpy(buffer, vt->outbuffer, len);
215 
216   if(len < vt->outbuffer_cur)
217     memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len);
218 
219   vt->outbuffer_cur -= len;
220 
221   return len;
222 }
223 
vterm_get_attr_type(VTermAttr attr)224 VTermValueType vterm_get_attr_type(VTermAttr attr)
225 {
226   switch(attr) {
227     case VTERM_ATTR_BOLD:       return VTERM_VALUETYPE_BOOL;
228     case VTERM_ATTR_UNDERLINE:  return VTERM_VALUETYPE_INT;
229     case VTERM_ATTR_ITALIC:     return VTERM_VALUETYPE_BOOL;
230     case VTERM_ATTR_BLINK:      return VTERM_VALUETYPE_BOOL;
231     case VTERM_ATTR_REVERSE:    return VTERM_VALUETYPE_BOOL;
232     case VTERM_ATTR_STRIKE:     return VTERM_VALUETYPE_BOOL;
233     case VTERM_ATTR_FONT:       return VTERM_VALUETYPE_INT;
234     case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
235     case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
236 
237     case VTERM_N_ATTRS: return 0;
238   }
239   return 0; /* UNREACHABLE */
240 }
241 
vterm_get_prop_type(VTermProp prop)242 VTermValueType vterm_get_prop_type(VTermProp prop)
243 {
244   switch(prop) {
245     case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL;
246     case VTERM_PROP_CURSORBLINK:   return VTERM_VALUETYPE_BOOL;
247     case VTERM_PROP_ALTSCREEN:     return VTERM_VALUETYPE_BOOL;
248     case VTERM_PROP_TITLE:         return VTERM_VALUETYPE_STRING;
249     case VTERM_PROP_ICONNAME:      return VTERM_VALUETYPE_STRING;
250     case VTERM_PROP_REVERSE:       return VTERM_VALUETYPE_BOOL;
251     case VTERM_PROP_CURSORSHAPE:   return VTERM_VALUETYPE_INT;
252     case VTERM_PROP_MOUSE:         return VTERM_VALUETYPE_INT;
253 
254     case VTERM_N_PROPS: return 0;
255   }
256   return 0; /* UNREACHABLE */
257 }
258 
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)259 void vterm_scroll_rect(VTermRect rect,
260     int downward,
261     int rightward,
262     int (*moverect)(VTermRect src, VTermRect dest, void *user),
263     int (*eraserect)(VTermRect rect, int selective, void *user),
264     void *user)
265 {
266   VTermRect src;
267   VTermRect dest;
268 
269   if(abs(downward)  >= rect.end_row - rect.start_row ||
270      abs(rightward) >= rect.end_col - rect.start_col) {
271     /* Scroll more than area; just erase the lot */
272     (*eraserect)(rect, 0, user);
273     return;
274   }
275 
276   if(rightward >= 0) {
277     /* rect: [XXX................]
278      * src:     [----------------]
279      * dest: [----------------]
280      */
281     dest.start_col = rect.start_col;
282     dest.end_col   = rect.end_col   - rightward;
283     src.start_col  = rect.start_col + rightward;
284     src.end_col    = rect.end_col;
285   }
286   else {
287     /* rect: [................XXX]
288      * src:  [----------------]
289      * dest:    [----------------]
290      */
291     int leftward = -rightward;
292     dest.start_col = rect.start_col + leftward;
293     dest.end_col   = rect.end_col;
294     src.start_col  = rect.start_col;
295     src.end_col    = rect.end_col - leftward;
296   }
297 
298   if(downward >= 0) {
299     dest.start_row = rect.start_row;
300     dest.end_row   = rect.end_row   - downward;
301     src.start_row  = rect.start_row + downward;
302     src.end_row    = rect.end_row;
303   }
304   else {
305     int upward = -downward;
306     dest.start_row = rect.start_row + upward;
307     dest.end_row   = rect.end_row;
308     src.start_row  = rect.start_row;
309     src.end_row    = rect.end_row - upward;
310   }
311 
312   if(moverect)
313     (*moverect)(dest, src, user);
314 
315   if(downward > 0)
316     rect.start_row = rect.end_row - downward;
317   else if(downward < 0)
318     rect.end_row = rect.start_row - downward;
319 
320   if(rightward > 0)
321     rect.start_col = rect.end_col - rightward;
322   else if(rightward < 0)
323     rect.end_col = rect.start_col - rightward;
324 
325   (*eraserect)(rect, 0, user);
326 }
327 
vterm_copy_cells(VTermRect dest,VTermRect src,void (* copycell)(VTermPos dest,VTermPos src,void * user),void * user)328 void vterm_copy_cells(VTermRect dest,
329     VTermRect src,
330     void (*copycell)(VTermPos dest, VTermPos src, void *user),
331     void *user)
332 {
333   int downward  = src.start_row - dest.start_row;
334   int rightward = src.start_col - dest.start_col;
335 
336   int init_row, test_row, init_col, test_col;
337   int inc_row, inc_col;
338 
339   if(downward < 0) {
340     init_row = dest.end_row - 1;
341     test_row = dest.start_row - 1;
342     inc_row = -1;
343   }
344   else /* downward >= 0 */ {
345     init_row = dest.start_row;
346     test_row = dest.end_row;
347     inc_row = +1;
348   }
349 
350   if(rightward < 0) {
351     init_col = dest.end_col - 1;
352     test_col = dest.start_col - 1;
353     inc_col = -1;
354   }
355   else /* rightward >= 0 */ {
356     init_col = dest.start_col;
357     test_col = dest.end_col;
358     inc_col = +1;
359   }
360 
361   VTermPos pos;
362   for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)
363     for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {
364       VTermPos srcpos = { pos.row + downward, pos.col + rightward };
365       (*copycell)(pos, srcpos, user);
366     }
367 }
368