Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 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 | |
Elliott Hughes | 6d78f36 | 2014-12-04 19:52:44 -0800 | [diff] [blame^] | 73 | INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size) |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 74 | { |
| 75 | return (*vt->allocator->malloc)(size, vt->allocdata); |
| 76 | } |
| 77 | |
Elliott Hughes | 6d78f36 | 2014-12-04 19:52:44 -0800 | [diff] [blame^] | 78 | INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr) |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 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 | |
Elliott Hughes | 6d78f36 | 2014-12-04 19:52:44 -0800 | [diff] [blame^] | 111 | INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 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 | |
Elliott Hughes | 6d78f36 | 2014-12-04 19:52:44 -0800 | [diff] [blame^] | 122 | INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 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 | |
Elliott Hughes | 6d78f36 | 2014-12-04 19:52:44 -0800 | [diff] [blame^] | 130 | INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 131 | { |
| 132 | va_list args; |
| 133 | va_start(args, format); |
| 134 | vterm_push_output_vsprintf(vt, format, args); |
| 135 | va_end(args); |
| 136 | } |
| 137 | |
Elliott Hughes | 6d78f36 | 2014-12-04 19:52:44 -0800 | [diff] [blame^] | 138 | INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 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); |
Jeff Sharkey | 73fbfc3 | 2013-04-23 10:34:06 -0700 | [diff] [blame] | 149 | } |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 150 | |
Elliott Hughes | 6d78f36 | 2014-12-04 19:52:44 -0800 | [diff] [blame^] | 151 | INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) |
Jeff Sharkey | 73fbfc3 | 2013-04-23 10:34:06 -0700 | [diff] [blame] | 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, ""); |
Jeff Sharkey | 5b78a3a | 2013-02-19 17:28:10 -0800 | [diff] [blame] | 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 | } |