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 void *vterm_allocator_malloc(VTerm *vt, size_t size) 74 { 75 return (*vt->allocator->malloc)(size, vt->allocdata); 76 } 77 78 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 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 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 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 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 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