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 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 73void *vterm_allocator_malloc(VTerm *vt, size_t size) 74{ 75 return (*vt->allocator->malloc)(size, vt->allocdata); 76} 77 78void vterm_allocator_free(VTerm *vt, void *ptr) 79{ 80 (*vt->allocator->free)(ptr, vt->allocdata); 81} 82 83void vterm_get_size(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->is_utf8 = is_utf8; 109} 110 111void 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 122void 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 130void 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 138size_t vterm_output_bufferlen(VTerm *vt) 139{ 140 return vterm_output_get_buffer_current(vt); 141} 142 143size_t vterm_output_get_buffer_size(VTerm *vt) 144{ 145 return vt->outbuffer_len; 146} 147 148size_t vterm_output_get_buffer_current(VTerm *vt) 149{ 150 return vt->outbuffer_cur; 151} 152 153size_t vterm_output_get_buffer_remaining(VTerm *vt) 154{ 155 return vt->outbuffer_len - vt->outbuffer_cur; 156} 157 158size_t vterm_output_bufferread(VTerm *vt, char *buffer, size_t len) 159{ 160 if(len > vt->outbuffer_cur) 161 len = vt->outbuffer_cur; 162 163 memcpy(buffer, vt->outbuffer, len); 164 165 if(len < vt->outbuffer_cur) 166 memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len); 167 168 vt->outbuffer_cur -= len; 169 170 return len; 171} 172 173VTermValueType vterm_get_attr_type(VTermAttr attr) 174{ 175 switch(attr) { 176 case VTERM_ATTR_BOLD: return VTERM_VALUETYPE_BOOL; 177 case VTERM_ATTR_UNDERLINE: return VTERM_VALUETYPE_INT; 178 case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL; 179 case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL; 180 case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL; 181 case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL; 182 case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT; 183 case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR; 184 case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR; 185 } 186 return 0; /* UNREACHABLE */ 187} 188 189VTermValueType vterm_get_prop_type(VTermProp prop) 190{ 191 switch(prop) { 192 case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL; 193 case VTERM_PROP_CURSORBLINK: return VTERM_VALUETYPE_BOOL; 194 case VTERM_PROP_ALTSCREEN: return VTERM_VALUETYPE_BOOL; 195 case VTERM_PROP_TITLE: return VTERM_VALUETYPE_STRING; 196 case VTERM_PROP_ICONNAME: return VTERM_VALUETYPE_STRING; 197 case VTERM_PROP_REVERSE: return VTERM_VALUETYPE_BOOL; 198 case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT; 199 } 200 return 0; /* UNREACHABLE */ 201} 202 203void vterm_scroll_rect(VTermRect rect, 204 int downward, 205 int rightward, 206 int (*moverect)(VTermRect src, VTermRect dest, void *user), 207 int (*eraserect)(VTermRect rect, void *user), 208 void *user) 209{ 210 VTermRect src; 211 VTermRect dest; 212 213 if(abs(downward) >= rect.end_row - rect.start_row || 214 abs(rightward) >= rect.end_col - rect.start_col) { 215 /* Scroll more than area; just erase the lot */ 216 (*eraserect)(rect, user); 217 return; 218 } 219 220 if(rightward >= 0) { 221 /* rect: [XXX................] 222 * src: [----------------] 223 * dest: [----------------] 224 */ 225 dest.start_col = rect.start_col; 226 dest.end_col = rect.end_col - rightward; 227 src.start_col = rect.start_col + rightward; 228 src.end_col = rect.end_col; 229 } 230 else { 231 /* rect: [................XXX] 232 * src: [----------------] 233 * dest: [----------------] 234 */ 235 int leftward = -rightward; 236 dest.start_col = rect.start_col + leftward; 237 dest.end_col = rect.end_col; 238 src.start_col = rect.start_col; 239 src.end_col = rect.end_col - leftward; 240 } 241 242 if(downward >= 0) { 243 dest.start_row = rect.start_row; 244 dest.end_row = rect.end_row - downward; 245 src.start_row = rect.start_row + downward; 246 src.end_row = rect.end_row; 247 } 248 else { 249 int upward = -downward; 250 dest.start_row = rect.start_row + upward; 251 dest.end_row = rect.end_row; 252 src.start_row = rect.start_row; 253 src.end_row = rect.end_row - upward; 254 } 255 256 if(moverect) 257 (*moverect)(dest, src, user); 258 259 if(downward > 0) 260 rect.start_row = rect.end_row - downward; 261 else if(downward < 0) 262 rect.end_row = rect.start_row - downward; 263 264 if(rightward > 0) 265 rect.start_col = rect.end_col - rightward; 266 else if(rightward < 0) 267 rect.end_col = rect.start_col - rightward; 268 269 (*eraserect)(rect, user); 270} 271 272void vterm_copy_cells(VTermRect dest, 273 VTermRect src, 274 void (*copycell)(VTermPos dest, VTermPos src, void *user), 275 void *user) 276{ 277 int downward = src.start_row - dest.start_row; 278 int rightward = src.start_col - dest.start_col; 279 280 int init_row, test_row, init_col, test_col; 281 int inc_row, inc_col; 282 283 VTermPos pos; 284 285 if(downward < 0) { 286 init_row = dest.end_row - 1; 287 test_row = dest.start_row - 1; 288 inc_row = -1; 289 } 290 else if(downward == 0) { 291 init_row = dest.start_row; 292 test_row = dest.end_row; 293 inc_row = +1; 294 } 295 else /* downward > 0 */ { 296 init_row = dest.start_row; 297 test_row = dest.end_row; 298 inc_row = +1; 299 } 300 301 if(rightward < 0) { 302 init_col = dest.end_col - 1; 303 test_col = dest.start_col - 1; 304 inc_col = -1; 305 } 306 else if(rightward == 0) { 307 init_col = dest.start_col; 308 test_col = dest.end_col; 309 inc_col = +1; 310 } 311 else /* rightward > 0 */ { 312 init_col = dest.start_col; 313 test_col = dest.end_col; 314 inc_col = +1; 315 } 316 317 for(pos.row = init_row; pos.row != test_row; pos.row += inc_row) 318 for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) { 319 VTermPos srcpos = { pos.row + downward, pos.col + rightward }; 320 (*copycell)(pos, srcpos, user); 321 } 322} 323