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 73INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size) 74{ 75 return (*vt->allocator->malloc)(size, vt->allocdata); 76} 77 78INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr) 79{ 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 111INTERNAL 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 122INTERNAL 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 130INTERNAL 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 138INTERNAL 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 152INTERNAL 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 168size_t vterm_output_bufferlen(VTerm *vt) 169{ 170 return vterm_output_get_buffer_current(vt); 171} 172 173size_t vterm_output_get_buffer_size(const VTerm *vt) 174{ 175 return vt->outbuffer_len; 176} 177 178size_t vterm_output_get_buffer_current(const VTerm *vt) 179{ 180 return vt->outbuffer_cur; 181} 182 183size_t vterm_output_get_buffer_remaining(const VTerm *vt) 184{ 185 return vt->outbuffer_len - vt->outbuffer_cur; 186} 187 188size_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 203VTermValueType 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 219VTermValueType 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 233void 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 302void 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