1 #include "vterm.h" 2 #include "../src/vterm_internal.h" /* We pull in some internal bits too */ 3 4 #include <stdio.h> 5 #include <string.h> 6 7 #define streq(a,b) (!strcmp(a,b)) 8 #define strstartswith(a,b) (!strncmp(a,b,strlen(b))) 9 10 static size_t inplace_hex2bytes(char *s) 11 { 12 char *inpos = s, *outpos = s; 13 14 while(*inpos) { 15 unsigned int ch; 16 sscanf(inpos, "%2x", &ch); 17 *outpos = ch; 18 outpos += 1; inpos += 2; 19 } 20 21 return outpos - s; 22 } 23 24 static VTermModifier strpe_modifiers(char **strp) 25 { 26 VTermModifier state = 0; 27 28 while((*strp)[0]) { 29 switch(((*strp)++)[0]) { 30 case 'S': state |= VTERM_MOD_SHIFT; break; 31 case 'C': state |= VTERM_MOD_CTRL; break; 32 case 'A': state |= VTERM_MOD_ALT; break; 33 default: return state; 34 } 35 } 36 37 return state; 38 } 39 40 static VTermKey strp_key(char *str) 41 { 42 static struct { 43 char *name; 44 VTermKey key; 45 } keys[] = { 46 { "Up", VTERM_KEY_UP }, 47 { "Tab", VTERM_KEY_TAB }, 48 { "Enter", VTERM_KEY_ENTER }, 49 { "KP0", VTERM_KEY_KP_0 }, 50 { NULL, VTERM_KEY_NONE }, 51 }; 52 int i; 53 54 for(i = 0; keys[i].name; i++) { 55 if(streq(str, keys[i].name)) 56 return keys[i].key; 57 } 58 59 return VTERM_KEY_NONE; 60 } 61 62 static VTerm *vt; 63 static VTermState *state; 64 static VTermScreen *screen; 65 66 static VTermEncodingInstance encoding; 67 68 static int parser_text(const char bytes[], size_t len, void *user) 69 { 70 int i; 71 72 printf("text "); 73 for(i = 0; i < len; i++) { 74 unsigned char b = bytes[i]; 75 if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0)) 76 break; 77 printf(i ? ",%x" : "%x", b); 78 } 79 printf("\n"); 80 81 return i; 82 } 83 84 static int parser_control(unsigned char control, void *user) 85 { 86 printf("control %02x\n", control); 87 88 return 1; 89 } 90 91 static int parser_escape(const char bytes[], size_t len, void *user) 92 { 93 int i; 94 95 if(bytes[0] >= 0x20 && bytes[0] < 0x30) { 96 if(len < 2) 97 return -1; 98 len = 2; 99 } 100 else { 101 len = 1; 102 } 103 104 printf("escape "); 105 for(i = 0; i < len; i++) 106 printf("%02x", bytes[i]); 107 printf("\n"); 108 109 return len; 110 } 111 112 static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) 113 { 114 int i; 115 printf("csi %02x", command); 116 117 if(leader && leader[0]) { 118 printf(" L="); 119 for(i = 0; leader[i]; i++) 120 printf("%02x", leader[i]); 121 } 122 123 for(i = 0; i < argcount; i++) { 124 char sep = i ? ',' : ' '; 125 126 if(args[i] == CSI_ARG_MISSING) 127 printf("%c*", sep); 128 else 129 printf("%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : ""); 130 } 131 132 if(intermed && intermed[0]) { 133 printf(" I="); 134 for(i = 0; intermed[i]; i++) 135 printf("%02x", intermed[i]); 136 } 137 138 printf("\n"); 139 140 return 1; 141 } 142 143 static int parser_osc(const char *command, size_t cmdlen, void *user) 144 { 145 int i; 146 printf("osc "); 147 for(i = 0; i < cmdlen; i++) 148 printf("%02x", command[i]); 149 printf("\n"); 150 151 return 1; 152 } 153 154 static int parser_dcs(const char *command, size_t cmdlen, void *user) 155 { 156 int i; 157 printf("dcs "); 158 for(i = 0; i < cmdlen; i++) 159 printf("%02x", command[i]); 160 printf("\n"); 161 162 return 1; 163 } 164 165 static VTermParserCallbacks parser_cbs = { 166 parser_text, /* text */ 167 parser_control, /* control */ 168 parser_escape, /* escape */ 169 parser_csi, /* csi */ 170 parser_osc, /* osc */ 171 parser_dcs, /* dcs */ 172 NULL /* resize */ 173 }; 174 175 /* These callbacks are shared by State and Screen */ 176 177 static int want_movecursor = 0; 178 static VTermPos state_pos; 179 static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) 180 { 181 state_pos = pos; 182 183 if(want_movecursor) 184 printf("movecursor %d,%d\n", pos.row, pos.col); 185 186 return 1; 187 } 188 189 static int want_scrollrect = 0; 190 static int scrollrect(VTermRect rect, int downward, int rightward, void *user) 191 { 192 if(!want_scrollrect) 193 return 0; 194 195 printf("scrollrect %d..%d,%d..%d => %+d,%+d\n", 196 rect.start_row, rect.end_row, rect.start_col, rect.end_col, 197 downward, rightward); 198 199 return 1; 200 } 201 202 static int want_moverect = 0; 203 static int moverect(VTermRect dest, VTermRect src, void *user) 204 { 205 if(!want_moverect) 206 return 0; 207 208 printf("moverect %d..%d,%d..%d -> %d..%d,%d..%d\n", 209 src.start_row, src.end_row, src.start_col, src.end_col, 210 dest.start_row, dest.end_row, dest.start_col, dest.end_col); 211 212 return 1; 213 } 214 215 static int want_settermprop = 0; 216 static int settermprop(VTermProp prop, VTermValue *val, void *user) 217 { 218 VTermValueType type; 219 if(!want_settermprop) 220 return 1; 221 222 type = vterm_get_prop_type(prop); 223 switch(type) { 224 case VTERM_VALUETYPE_BOOL: 225 printf("settermprop %d %s\n", prop, val->boolean ? "true" : "false"); 226 return 1; 227 case VTERM_VALUETYPE_INT: 228 printf("settermprop %d %d\n", prop, val->number); 229 return 1; 230 case VTERM_VALUETYPE_STRING: 231 printf("settermprop %d \"%s\"\n", prop, val->string); 232 return 1; 233 case VTERM_VALUETYPE_COLOR: 234 printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue); 235 return 1; 236 237 case VTERM_N_VALUETYPES: 238 return 0; 239 } 240 241 return 0; 242 } 243 244 /* These callbacks are for State */ 245 246 static int want_state_putglyph = 0; 247 static int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) 248 { 249 int i; 250 if(!want_state_putglyph) 251 return 1; 252 253 printf("putglyph "); 254 for(i = 0; info->chars[i]; i++) 255 printf(i ? ",%x" : "%x", info->chars[i]); 256 printf(" %d %d,%d", info->width, pos.row, pos.col); 257 if(info->protected_cell) 258 printf(" prot"); 259 if(info->dwl) 260 printf(" dwl"); 261 if(info->dhl) 262 printf(" dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" ); 263 printf("\n"); 264 265 return 1; 266 } 267 268 static int want_state_erase = 0; 269 static int state_erase(VTermRect rect, int selective, void *user) 270 { 271 if(!want_state_erase) 272 return 1; 273 274 printf("erase %d..%d,%d..%d%s\n", 275 rect.start_row, rect.end_row, rect.start_col, rect.end_col, 276 selective ? " selective" : ""); 277 278 return 1; 279 } 280 281 static struct { 282 int bold; 283 int underline; 284 int italic; 285 int blink; 286 int reverse; 287 int strike; 288 int font; 289 VTermColor foreground; 290 VTermColor background; 291 } state_pen; 292 static int state_setpenattr(VTermAttr attr, VTermValue *val, void *user) 293 { 294 switch(attr) { 295 case VTERM_ATTR_BOLD: 296 state_pen.bold = val->boolean; 297 break; 298 case VTERM_ATTR_UNDERLINE: 299 state_pen.underline = val->number; 300 break; 301 case VTERM_ATTR_ITALIC: 302 state_pen.italic = val->boolean; 303 break; 304 case VTERM_ATTR_BLINK: 305 state_pen.blink = val->boolean; 306 break; 307 case VTERM_ATTR_REVERSE: 308 state_pen.reverse = val->boolean; 309 break; 310 case VTERM_ATTR_STRIKE: 311 state_pen.strike = val->boolean; 312 break; 313 case VTERM_ATTR_FONT: 314 state_pen.font = val->number; 315 break; 316 case VTERM_ATTR_FOREGROUND: 317 state_pen.foreground = val->color; 318 break; 319 case VTERM_ATTR_BACKGROUND: 320 state_pen.background = val->color; 321 break; 322 323 case VTERM_N_ATTRS: 324 return 0; 325 } 326 327 return 1; 328 } 329 330 static int state_setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) 331 { 332 return 1; 333 } 334 335 VTermStateCallbacks state_cbs = { 336 state_putglyph, /* putglyph */ 337 movecursor, /* movecursor */ 338 scrollrect, /* scrollrect */ 339 moverect, /* moverect */ 340 state_erase, /* erase */ 341 NULL, /* initpen */ 342 state_setpenattr, /* setpenattr */ 343 settermprop, /* settermprop */ 344 NULL, /* bell */ 345 NULL, /* resize */ 346 state_setlineinfo, /* setlineinfo */ 347 }; 348 349 static int want_screen_damage = 0; 350 static int want_screen_damage_cells = 0; 351 static int screen_damage(VTermRect rect, void *user) 352 { 353 if(!want_screen_damage) 354 return 1; 355 356 printf("damage %d..%d,%d..%d", 357 rect.start_row, rect.end_row, rect.start_col, rect.end_col); 358 359 if(want_screen_damage_cells) { 360 int equals = FALSE; 361 int row; 362 int col; 363 364 for(row = rect.start_row; row < rect.end_row; row++) { 365 int eol = rect.end_col; 366 while(eol > rect.start_col) { 367 VTermScreenCell cell; 368 VTermPos pos; 369 pos.row = row; 370 pos.col = eol-1; 371 vterm_screen_get_cell(screen, pos, &cell); 372 if(cell.chars[0]) 373 break; 374 375 eol--; 376 } 377 378 if(eol == rect.start_col) 379 break; 380 381 if(!equals) 382 printf(" ="), equals = TRUE; 383 384 printf(" %d<", row); 385 for(col = rect.start_col; col < eol; col++) { 386 VTermScreenCell cell; 387 VTermPos pos; 388 pos.row = row; 389 pos.col = col; 390 vterm_screen_get_cell(screen, pos, &cell); 391 printf(col == rect.start_col ? "%02X" : " %02X", cell.chars[0]); 392 } 393 printf(">"); 394 } 395 } 396 397 printf("\n"); 398 399 return 1; 400 } 401 402 static int want_screen_scrollback = 0; 403 static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user) 404 { 405 int eol; 406 int c; 407 408 if(!want_screen_scrollback) 409 return 1; 410 411 eol = cols; 412 while(eol && !cells[eol-1].chars[0]) 413 eol--; 414 415 printf("sb_pushline %d =", cols); 416 for(c = 0; c < eol; c++) 417 printf(" %02X", cells[c].chars[0]); 418 printf("\n"); 419 420 return 1; 421 } 422 423 static int screen_sb_popline(int cols, VTermScreenCell *cells, void *user) 424 { 425 int col; 426 427 if(!want_screen_scrollback) 428 return 0; 429 430 /* All lines of scrollback contain "ABCDE" */ 431 for(col = 0; col < cols; col++) { 432 if(col < 5) 433 cells[col].chars[0] = 'A' + col; 434 else 435 cells[col].chars[0] = 0; 436 437 cells[col].width = 1; 438 } 439 440 printf("sb_popline %d\n", cols); 441 return 1; 442 } 443 444 VTermScreenCallbacks screen_cbs = { 445 screen_damage, /* damage */ 446 moverect, /* moverect */ 447 movecursor, /* movecursor */ 448 settermprop, /* settermprop */ 449 NULL, /* bell */ 450 NULL, /* resize */ 451 screen_sb_pushline, /* sb_pushline */ 452 screen_sb_popline /* sb_popline */ 453 }; 454 455 int main(int argc, char **argv) 456 { 457 char line[1024] = {0}; 458 int flag; 459 460 int err; 461 462 setvbuf(stdout, NULL, _IONBF, 0); 463 464 while(fgets(line, sizeof line, stdin)) { 465 char *nl; 466 size_t outlen; 467 err = 0; 468 469 if((nl = strchr(line, '\n'))) 470 *nl = '\0'; 471 472 if(streq(line, "INIT")) { 473 if(!vt) 474 vt = vterm_new(25, 80); 475 } 476 477 else if(streq(line, "WANTPARSER")) { 478 vterm_parser_set_callbacks(vt, &parser_cbs, NULL); 479 } 480 481 else if(strstartswith(line, "WANTSTATE") && (line[9] == '\0' || line[9] == ' ')) { 482 int i = 9; 483 int sense = 1; 484 if(!state) { 485 state = vterm_obtain_state(vt); 486 vterm_state_set_callbacks(state, &state_cbs, NULL); 487 vterm_state_set_bold_highbright(state, 1); 488 vterm_state_reset(state, 1); 489 } 490 491 while(line[i] == ' ') 492 i++; 493 for( ; line[i]; i++) 494 switch(line[i]) { 495 case '+': 496 sense = 1; 497 break; 498 case '-': 499 sense = 0; 500 break; 501 case 'g': 502 want_state_putglyph = sense; 503 break; 504 case 's': 505 want_scrollrect = sense; 506 break; 507 case 'm': 508 want_moverect = sense; 509 break; 510 case 'e': 511 want_state_erase = sense; 512 break; 513 case 'p': 514 want_settermprop = sense; 515 break; 516 case 'f': 517 vterm_state_set_unrecognised_fallbacks(state, sense ? &parser_cbs : NULL, NULL); 518 break; 519 default: 520 fprintf(stderr, "Unrecognised WANTSTATE flag '%c'\n", line[i]); 521 } 522 } 523 524 else if(strstartswith(line, "WANTSCREEN") && (line[10] == '\0' || line[10] == ' ')) { 525 int i = 10; 526 int sense = 1; 527 if(!screen) 528 screen = vterm_obtain_screen(vt); 529 vterm_screen_enable_altscreen(screen, 1); 530 vterm_screen_set_callbacks(screen, &screen_cbs, NULL); 531 532 while(line[i] == ' ') 533 i++; 534 for( ; line[i]; i++) 535 switch(line[i]) { 536 case '-': 537 sense = 0; 538 break; 539 case 'd': 540 want_screen_damage = sense; 541 break; 542 case 'D': 543 want_screen_damage = sense; 544 want_screen_damage_cells = sense; 545 break; 546 case 'm': 547 want_moverect = sense; 548 break; 549 case 'c': 550 want_movecursor = sense; 551 break; 552 case 'p': 553 want_settermprop = 1; 554 break; 555 case 'b': 556 want_screen_scrollback = sense; 557 break; 558 default: 559 fprintf(stderr, "Unrecognised WANTSCREEN flag '%c'\n", line[i]); 560 } 561 } 562 563 else if(sscanf(line, "UTF8 %d", &flag)) { 564 vterm_set_utf8(vt, flag); 565 } 566 567 else if(streq(line, "RESET")) { 568 if(state) { 569 vterm_state_reset(state, 1); 570 vterm_state_get_cursorpos(state, &state_pos); 571 } 572 if(screen) { 573 vterm_screen_reset(screen, 1); 574 } 575 } 576 577 else if(strstartswith(line, "RESIZE ")) { 578 int rows, cols; 579 char *linep = line + 7; 580 while(linep[0] == ' ') 581 linep++; 582 sscanf(linep, "%d, %d", &rows, &cols); 583 vterm_set_size(vt, rows, cols); 584 } 585 586 else if(strstartswith(line, "PUSH ")) { 587 char *bytes = line + 5; 588 size_t len = inplace_hex2bytes(bytes); 589 size_t written = vterm_input_write(vt, bytes, len); 590 if(written < len) 591 fprintf(stderr, "! short write\n"); 592 } 593 594 else if(streq(line, "WANTENCODING")) { 595 /* This isn't really external API but it's hard to get this out any 596 * other way 597 */ 598 encoding.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); 599 if(encoding.enc->init) 600 (*encoding.enc->init)(encoding.enc, encoding.data); 601 } 602 603 else if(strstartswith(line, "ENCIN ")) { 604 char *bytes = line + 6; 605 size_t len = inplace_hex2bytes(bytes); 606 607 uint32_t cp[1024]; 608 int cpi = 0; 609 size_t pos = 0; 610 611 (*encoding.enc->decode)(encoding.enc, encoding.data, 612 cp, &cpi, len, bytes, &pos, len); 613 614 if(cpi > 0) { 615 int i; 616 printf("encout "); 617 for(i = 0; i < cpi; i++) { 618 printf(i ? ",%x" : "%x", cp[i]); 619 } 620 printf("\n"); 621 } 622 } 623 624 else if(strstartswith(line, "INCHAR ")) { 625 char *linep = line + 7; 626 unsigned int c = 0; 627 VTermModifier mod; 628 while(linep[0] == ' ') 629 linep++; 630 mod = strpe_modifiers(&linep); 631 sscanf(linep, " %x", &c); 632 633 vterm_keyboard_unichar(vt, c, mod); 634 } 635 636 else if(strstartswith(line, "INKEY ")) { 637 VTermModifier mod; 638 VTermKey key; 639 char *linep = line + 6; 640 while(linep[0] == ' ') 641 linep++; 642 mod = strpe_modifiers(&linep); 643 while(linep[0] == ' ') 644 linep++; 645 key = strp_key(linep); 646 647 vterm_keyboard_key(vt, key, mod); 648 } 649 650 else if(strstartswith(line, "PASTE ")) { 651 char *linep = line + 6; 652 if(streq(linep, "START")) 653 vterm_keyboard_start_paste(vt); 654 else if(streq(linep, "END")) 655 vterm_keyboard_end_paste(vt); 656 else 657 goto abort_line; 658 } 659 660 else if(strstartswith(line, "FOCUS ")) { 661 char *linep = line + 6; 662 if(streq(linep, "IN")) 663 vterm_state_focus_in(state); 664 else if(streq(linep, "OUT")) 665 vterm_state_focus_out(state); 666 else 667 goto abort_line; 668 } 669 670 else if(strstartswith(line, "MOUSEMOVE ")) { 671 char *linep = line + 10; 672 int row, col, len; 673 VTermModifier mod; 674 while(linep[0] == ' ') 675 linep++; 676 sscanf(linep, "%d,%d%n", &row, &col, &len); 677 linep += len; 678 while(linep[0] == ' ') 679 linep++; 680 mod = strpe_modifiers(&linep); 681 vterm_mouse_move(vt, row, col, mod); 682 } 683 684 else if(strstartswith(line, "MOUSEBTN ")) { 685 char *linep = line + 9; 686 char press; 687 int button, len; 688 VTermModifier mod; 689 while(linep[0] == ' ') 690 linep++; 691 sscanf(linep, "%c %d%n", &press, &button, &len); 692 linep += len; 693 while(linep[0] == ' ') 694 linep++; 695 mod = strpe_modifiers(&linep); 696 vterm_mouse_button(vt, button, (press == 'd' || press == 'D'), mod); 697 } 698 699 else if(strstartswith(line, "DAMAGEMERGE ")) { 700 char *linep = line + 12; 701 while(linep[0] == ' ') 702 linep++; 703 if(streq(linep, "CELL")) 704 vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_CELL); 705 else if(streq(linep, "ROW")) 706 vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_ROW); 707 else if(streq(linep, "SCREEN")) 708 vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCREEN); 709 else if(streq(linep, "SCROLL")) 710 vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCROLL); 711 } 712 713 else if(strstartswith(line, "DAMAGEFLUSH")) { 714 vterm_screen_flush_damage(screen); 715 } 716 717 else if(line[0] == '?') { 718 if(streq(line, "?cursor")) { 719 VTermPos pos; 720 vterm_state_get_cursorpos(state, &pos); 721 if(pos.row != state_pos.row) 722 printf("! row mismatch: state=%d,%d event=%d,%d\n", 723 pos.row, pos.col, state_pos.row, state_pos.col); 724 else if(pos.col != state_pos.col) 725 printf("! col mismatch: state=%d,%d event=%d,%d\n", 726 pos.row, pos.col, state_pos.row, state_pos.col); 727 else 728 printf("%d,%d\n", state_pos.row, state_pos.col); 729 } 730 else if(strstartswith(line, "?pen ")) { 731 VTermValue val; 732 char *linep = line + 5; 733 while(linep[0] == ' ') 734 linep++; 735 736 #define BOOLSTR(v) ((v) ? "on" : "off") 737 738 if(streq(linep, "bold")) { 739 vterm_state_get_penattr(state, VTERM_ATTR_BOLD, &val); 740 if(val.boolean != state_pen.bold) 741 printf("! pen bold mismatch; state=%s, event=%s\n", 742 BOOLSTR(val.boolean), BOOLSTR(state_pen.bold)); 743 else 744 printf("%s\n", BOOLSTR(state_pen.bold)); 745 } 746 else if(streq(linep, "underline")) { 747 vterm_state_get_penattr(state, VTERM_ATTR_UNDERLINE, &val); 748 if(val.boolean != state_pen.underline) 749 printf("! pen underline mismatch; state=%d, event=%d\n", 750 val.boolean, state_pen.underline); 751 else 752 printf("%d\n", state_pen.underline); 753 } 754 else if(streq(linep, "italic")) { 755 vterm_state_get_penattr(state, VTERM_ATTR_ITALIC, &val); 756 if(val.boolean != state_pen.italic) 757 printf("! pen italic mismatch; state=%s, event=%s\n", 758 BOOLSTR(val.boolean), BOOLSTR(state_pen.italic)); 759 else 760 printf("%s\n", BOOLSTR(state_pen.italic)); 761 } 762 else if(streq(linep, "blink")) { 763 vterm_state_get_penattr(state, VTERM_ATTR_BLINK, &val); 764 if(val.boolean != state_pen.blink) 765 printf("! pen blink mismatch; state=%s, event=%s\n", 766 BOOLSTR(val.boolean), BOOLSTR(state_pen.blink)); 767 else 768 printf("%s\n", BOOLSTR(state_pen.blink)); 769 } 770 else if(streq(linep, "reverse")) { 771 vterm_state_get_penattr(state, VTERM_ATTR_REVERSE, &val); 772 if(val.boolean != state_pen.reverse) 773 printf("! pen reverse mismatch; state=%s, event=%s\n", 774 BOOLSTR(val.boolean), BOOLSTR(state_pen.reverse)); 775 else 776 printf("%s\n", BOOLSTR(state_pen.reverse)); 777 } 778 else if(streq(linep, "font")) { 779 vterm_state_get_penattr(state, VTERM_ATTR_FONT, &val); 780 if(val.boolean != state_pen.font) 781 printf("! pen font mismatch; state=%d, event=%d\n", 782 val.boolean, state_pen.font); 783 else 784 printf("%d\n", state_pen.font); 785 } 786 else if(streq(linep, "foreground")) { 787 printf("rgb(%d,%d,%d)\n", state_pen.foreground.red, state_pen.foreground.green, state_pen.foreground.blue); 788 } 789 else if(streq(linep, "background")) { 790 printf("rgb(%d,%d,%d)\n", state_pen.background.red, state_pen.background.green, state_pen.background.blue); 791 } 792 else 793 printf("?\n"); 794 } 795 else if(strstartswith(line, "?screen_chars ")) { 796 char *linep = line + 13; 797 VTermRect rect; 798 size_t len; 799 while(linep[0] == ' ') 800 linep++; 801 if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) { 802 printf("! screen_chars unrecognised input\n"); 803 goto abort_line; 804 } 805 len = vterm_screen_get_chars(screen, NULL, 0, rect); 806 if(len == (size_t)-1) 807 printf("! screen_chars error\n"); 808 else if(len == 0) 809 printf("\n"); 810 else { 811 uint32_t *chars = malloc(sizeof(uint32_t) * len); 812 size_t i; 813 vterm_screen_get_chars(screen, chars, len, rect); 814 for(i = 0; i < len; i++) { 815 printf("0x%02x%s", chars[i], i < len-1 ? "," : "\n"); 816 } 817 free(chars); 818 } 819 } 820 else if(strstartswith(line, "?screen_text ")) { 821 char *linep = line + 12; 822 VTermRect rect; 823 size_t len; 824 while(linep[0] == ' ') 825 linep++; 826 if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) { 827 printf("! screen_text unrecognised input\n"); 828 goto abort_line; 829 } 830 len = vterm_screen_get_text(screen, NULL, 0, rect); 831 if(len == (size_t)-1) 832 printf("! screen_text error\n"); 833 else if(len == 0) 834 printf("\n"); 835 else { 836 /* Put an overwrite guard at both ends of the buffer */ 837 unsigned char *buffer = malloc(len + 4); 838 unsigned char *text = buffer + 2; 839 text[-2] = 0x55; text[-1] = 0xAA; 840 text[len] = 0x55; text[len+1] = 0xAA; 841 842 vterm_screen_get_text(screen, (char *)text, len, rect); 843 844 if(text[-2] != 0x55 || text[-1] != 0xAA) 845 printf("! screen_get_text buffer overrun left [%02x,%02x]\n", text[-2], text[-1]); 846 else if(text[len] != 0x55 || text[len+1] != 0xAA) 847 printf("! screen_get_text buffer overrun right [%02x,%02x]\n", text[len], text[len+1]); 848 else 849 { 850 size_t i; 851 for(i = 0; i < len; i++) { 852 printf("0x%02x%s", text[i], i < len-1 ? "," : "\n"); 853 } 854 } 855 856 free(buffer); 857 } 858 } 859 else if(strstartswith(line, "?screen_cell ")) { 860 char *linep = line + 12; 861 int i; 862 VTermPos pos; 863 VTermScreenCell cell; 864 while(linep[0] == ' ') 865 linep++; 866 if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) { 867 printf("! screen_cell unrecognised input\n"); 868 goto abort_line; 869 } 870 if(!vterm_screen_get_cell(screen, pos, &cell)) 871 goto abort_line; 872 printf("{"); 873 for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell.chars[i]; i++) { 874 printf("%s0x%x", i ? "," : "", cell.chars[i]); 875 } 876 printf("} width=%d attrs={", cell.width); 877 if(cell.attrs.bold) printf("B"); 878 if(cell.attrs.underline) printf("U%d", cell.attrs.underline); 879 if(cell.attrs.italic) printf("I"); 880 if(cell.attrs.blink) printf("K"); 881 if(cell.attrs.reverse) printf("R"); 882 if(cell.attrs.font) printf("F%d", cell.attrs.font); 883 printf("} "); 884 if(cell.attrs.dwl) printf("dwl "); 885 if(cell.attrs.dhl) printf("dhl-%s ", cell.attrs.dhl == 2 ? "bottom" : "top"); 886 printf("fg=rgb(%d,%d,%d) ", cell.fg.red, cell.fg.green, cell.fg.blue); 887 printf("bg=rgb(%d,%d,%d)\n", cell.bg.red, cell.bg.green, cell.bg.blue); 888 } 889 else if(strstartswith(line, "?screen_eol ")) { 890 VTermPos pos; 891 char *linep = line + 12; 892 while(linep[0] == ' ') 893 linep++; 894 if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) { 895 printf("! screen_eol unrecognised input\n"); 896 goto abort_line; 897 } 898 printf("%d\n", vterm_screen_is_eol(screen, pos)); 899 } 900 else if(strstartswith(line, "?screen_attrs_extent ")) { 901 VTermPos pos; 902 VTermRect rect; 903 char *linep = line + 21; 904 while(linep[0] == ' ') 905 linep++; 906 if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) { 907 printf("! screen_attrs_extent unrecognised input\n"); 908 goto abort_line; 909 } 910 rect.start_col = 0; 911 rect.end_col = -1; 912 if(!vterm_screen_get_attrs_extent(screen, &rect, pos, ~0)) { 913 printf("! screen_attrs_extent failed\n"); 914 goto abort_line; 915 } 916 printf("%d,%d-%d,%d\n", rect.start_row, rect.start_col, rect.end_row, rect.end_col); 917 } 918 else 919 printf("?\n"); 920 921 memset(line, 0, sizeof line); 922 continue; 923 } 924 925 else 926 abort_line: err = 1; 927 928 outlen = vterm_output_get_buffer_current(vt); 929 if(outlen > 0) { 930 int i; 931 char outbuff[1024]; 932 vterm_output_read(vt, outbuff, outlen); 933 934 printf("output "); 935 for(i = 0; i < outlen; i++) 936 printf("%x%s", (unsigned char)outbuff[i], i < outlen-1 ? "," : "\n"); 937 } 938 939 printf(err ? "?\n" : "DONE\n"); 940 } 941 942 vterm_free(vt); 943 944 return 0; 945 } 946