Home | History | Annotate | Download | only in src
      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 
     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 
     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 
     30 VTerm *vterm_new(int rows, int cols)
     31 {
     32   return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);
     33 }
     34 
     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 
     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 
     73 INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)
     74 {
     75   return (*vt->allocator->malloc)(size, vt->allocdata);
     76 }
     77 
     78 INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)
     79 {
     80   (*vt->allocator->free)(ptr, vt->allocdata);
     81 }
     82 
     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 
     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 
    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 
    106 void vterm_parser_set_utf8(VTerm *vt, int is_utf8)
    107 {
    108   vt->mode.utf8 = is_utf8;
    109 }
    110 
    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 
    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 
    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 
    138 INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)
    139 {
    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);
    149 }
    150 
    151 INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)
    152 {
    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, "");
    164 }
    165 
    166 size_t vterm_output_bufferlen(VTerm *vt)
    167 {
    168   return vterm_output_get_buffer_current(vt);
    169 }
    170 
    171 size_t vterm_output_get_buffer_size(const VTerm *vt)
    172 {
    173   return vt->outbuffer_len;
    174 }
    175 
    176 size_t vterm_output_get_buffer_current(const VTerm *vt)
    177 {
    178   return vt->outbuffer_cur;
    179 }
    180 
    181 size_t vterm_output_get_buffer_remaining(const VTerm *vt)
    182 {
    183   return vt->outbuffer_len - vt->outbuffer_cur;
    184 }
    185 
    186 size_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 
    201 VTermValueType 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 
    217 VTermValueType 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 
    231 void 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 
    300 void 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 }
    340