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