1 2 3 /* This version of microEmacs is based on the public domain C 4 * version written by Dave G. Conroy. 5 * The D programming language version is written by Walter Bright. 6 * http://www.digitalmars.com/d/ 7 * This program is in the public domain. 8 */ 9 10 11 module tcap; 12 13 version (none) 14 { 15 import ed; 16 17 import std.c.stdio; 18 import core.stdc.stdlib; 19 import std.c..string; 20 import std.c.time; 21 import core.sys.posix.termios; 22 23 extern (C) void cfmakeraw(in termios*); 24 25 termios ostate; /* saved tty state */ 26 termios nstate; /* values for editor mode */ 27 28 29 /* Termcap library functions 30 * See: http://www.gnu.org/software/termutils/manual/termcap-1.3/html_node/termcap_toc.html 31 */ 32 33 extern (C) 34 { 35 int tgetent(char *buffer, const char *termtype); 36 int tgetnum (const char *name); 37 int tgetflag (const char *name); 38 const(char) *tgetstr (const char *name, const(char) **area); 39 const(char) *tgoto (const(char) *cstring, int hpos, int vpos); 40 const(char) *tparam (const(char) *ctlstring, char *buffer, int size, int parm1,...); 41 char PC; 42 short ospeed; 43 int tputs (const(char) *string, int nlines, int function(int) outfun); 44 } 45 46 enum 47 { 48 NROW = 24, 49 NCOL = 80, 50 BEL = 0x07, 51 ESC = 0x1B, 52 } 53 54 char[2048] tcapbuf; 55 static const(char) *p; /* roving pointer into tcapbuf[] */ 56 const(char)* 57 CM, 58 CL, 59 CE, 60 UP, 61 CD, 62 KU, /* up arrow key */ 63 KD, /* down arrow key */ 64 KL, /* left arrow key */ 65 KR, /* right arrow key */ 66 K1, /* second meta key */ 67 SO, /* start standout mode */ 68 SE, /* end standout mode */ 69 VB, /* visible bell */ 70 CS, /* scrolling region */ 71 SR, /* scroll reverse */ 72 SF, /* scroll forward */ 73 DO, /* move down (alt for scroll forward) */ 74 AL, /* add a line */ 75 DL; /* delete a line */ 76 77 /* 78 * The LONGKEY structures are used to map the keys that produce 79 * escape sequences to single return values. Each LONGKEY element 80 * is allocated as an array of LONGKEY structures. lk[0].key is 81 * the number of structure-1, lk[0].ptr is a backpointer. lk[1] is 82 * the first entry, etc. These structures are dynamcially allocated 83 * and linked at initialize time. See tcapgetc() to see how they 84 * are used. 85 */ 86 87 int LONGFINAL(char C) { return C & 0x80; } 88 int LONGCHAR(char C) { return C & 0x7F; } 89 90 struct LONGKEY 91 { 92 char key; 93 union { 94 LONGKEY *ptr; 95 int keyv; 96 } 97 } 98 LONGKEY *lkroot = null; 99 100 struct TERM 101 { 102 short t_nrow; /* Number of rows. */ 103 short t_ncol; /* Number of columns. */ 104 bool t_canscroll = true; 105 106 void t_open() /* Open terminal at the start. */ 107 { 108 auto tv_stype = getenv("TERM"); 109 if (tv_stype == null) 110 { 111 puts("environment variable TERM not defined\n"); 112 exit(1); 113 } 114 115 char[2048] tcbuf = void; 116 auto success = tgetent(tcbuf.ptr, tv_stype); 117 if (success < 0) 118 { 119 printf("cannot access termcap database\n"); 120 exit(1); 121 } 122 if (success == 0) 123 { 124 printf("unknown terminal type %s\n", tv_stype); 125 exit(1); 126 } 127 128 p = tcapbuf.ptr; 129 auto t = tgetstr("pc", &p); 130 if (t) 131 PC = *t; // set "padding capabilities" 132 133 term.t_ncol = cast(short)tgetnum("co"); 134 term.t_nrow = cast(short)tgetnum("li"); 135 CD = tgetstr("cd", &p); 136 CM = tgetstr("cm", &p); 137 CE = tgetstr("ce", &p); 138 UP = tgetstr("up", &p); 139 //printf("UP=%p,%02x,%02x,%02x '%s'\n\n\n\n",UP,*UP,UP[1],UP[2],UP); fflush(stdout); sleep(1); 140 VB = tgetstr("vb", &p); 141 KU = tgetstr("ku", &p); 142 //printf("KU=%p,%02x,%02x,%02x '%s'\n\n\n\n",KU,*KU,KU[1],KU[2],KU); fflush(stdout); sleep(3); 143 KD = tgetstr("kd", &p); 144 KL = tgetstr("kl", &p); 145 KR = tgetstr("kr", &p); 146 K1 = tgetstr("k1", &p); 147 SO = tgetstr("so", &p); 148 SE = tgetstr("se", &p); 149 CS = tgetstr("cs", &p); 150 SR = tgetstr("sr", &p); 151 SF = tgetstr("sf", &p); 152 DO = tgetstr("do", &p); 153 AL = tgetstr("al", &p); 154 DL = tgetstr("dl", &p); 155 build_long_keys( tv_stype ); 156 157 if (CD == null || CM == null || CE == null || UP == null 158 || term.t_ncol < 1 || term.t_nrow < 1 ) 159 { 160 puts("Incomplete termcap entry\n"); 161 exit(1); 162 } 163 164 if (p >= tcapbuf.ptr + tcapbuf.length) 165 { 166 puts("Terminal description too big!\n"); 167 exit(1); 168 } 169 170 if (AL && DL) 171 { 172 scroll_type = 0; 173 } 174 else if (CS && SR && (SF || DO)) 175 { 176 scroll_type = 1; 177 if (!SF) 178 SF = DO; 179 } 180 else 181 { 182 t_canscroll = false; 183 } 184 185 /* Adjust output channel */ 186 tcgetattr(1, &ostate); /* save old state */ 187 tcgetattr(1, &nstate); /* get base of new state */ 188 cfmakeraw(&nstate); 189 tcsetattr(1, TCSADRAIN, &nstate); /* set mode */ 190 191 if( strcmp(tv_stype,"vt100") == 0 ) 192 fputs("\033=",stdout); /* turn on the keypad */ 193 } 194 195 void t_close() /* Close terminal at end. */ 196 { 197 if( strcmp(getenv("TERM"),"vt100") == 0 ) 198 fputs("\033[?7h",stdout); /* turn on autowrap */ 199 200 tcsetattr(1, TCSADRAIN, &ostate); // return to original mode 201 } 202 203 int t_getchar() /* Get character from keyboard. */ 204 { 205 int c,i; 206 LONGKEY* lkp,tmpp; 207 208 __gshared int backlen; 209 __gshared char[16] backc; 210 211 /* 212 * If there was a previously almost complete LONGKEY sequence 213 * that failed, then we have to send the characters as if they 214 * were pressed individually. 215 */ 216 start: 217 if( backlen ) 218 return( backc[--backlen] ); 219 220 /* 221 * Continue following the LONGKEY structure sequence until 222 * either there is a complete match, or there is a complete 223 * failure to match. 224 */ 225 lkp = lkroot; 226 loop: 227 c = fgetc(stdin); 228 for(i=1; i<=lkp[0].key; i++) 229 { 230 if( LONGCHAR(lkp[i].key) == c ) 231 { 232 //static int x; 233 //printf("\nmatch %d\n",++x); fflush(stdout); sleep(2); 234 if( LONGFINAL(lkp[i].key) ) 235 return( lkp[i].keyv ); 236 lkp = lkp[i].ptr; 237 goto loop; 238 } 239 } 240 241 /+ 242 for(i=1; i<=lkp[0].key; i++) 243 { 244 printf("\nLONGCHAR[%d] = x%02x\n",i,lkp[i].key); 245 } 246 printf("no match for x%02x of %d entries\n",c,i); fflush(stdout); sleep(10); 247 +/ 248 249 /* 250 * Upon a complete failure to match, we fill up the backc[] 251 * array with the ASCII characters that have been entered 252 * so that future calls to tcapgetc() can return these 253 * characters is the correct order. 254 */ 255 backc[backlen++] = cast(char)c; 256 while( lkp[0].ptr != null ) 257 { 258 tmpp = lkp; 259 lkp = lkp[0].ptr; 260 for(i=1; i<=lkp[0].key; i++) 261 if( lkp[i].ptr == tmpp ) break; 262 backc[backlen++] = lkp[i].key; 263 } 264 goto start; 265 } 266 267 extern (C) static int t_putchar(int c) /* Put character to display. */ 268 { 269 return fputc(c, stdout); 270 } 271 272 void t_flush() /* Flush output buffers. */ 273 { 274 fflush(stdout); 275 } 276 277 void t_move(int row, int col) /* Move the cursor, origin 0. */ 278 { 279 putpad(tgoto(CM, col, row)); 280 } 281 282 void t_eeol() /* Erase to end of line. */ 283 { 284 putpad(CE); 285 } 286 287 void t_eeop() /* Erase to end of page. */ 288 { 289 putpad(CD); 290 } 291 292 void t_beep() /* Beep. */ 293 { 294 if (VB) 295 putpad(VB); 296 else 297 t_putchar(BEL); 298 } 299 300 void t_standout() /* Start standout mode */ 301 { 302 if (SO) 303 putpad( SO ); 304 } 305 306 void t_standend() /* End standout mode */ 307 { 308 if (SE) 309 putpad( SE ); 310 } 311 312 void setColorBright(bool bright) 313 { 314 //fprintf(_fp, "\033[%dm", bright); 315 } 316 317 void setColor(Color color) 318 { 319 //fprintf(_fp, "\033[%d;%dm", color & Color.bright ? 1 : 0, 30 + (color & ~Color.bright)); 320 } 321 322 void resetColor() 323 { 324 //fputs("\033[m", _fp); 325 } 326 327 void t_scrollup(int first, int last) /* Scroll the screen up */ 328 { 329 if (scroll_type) 330 { 331 tpstr( CS, first, last ); 332 t_move( last, 0 ); 333 putpad( SF ); 334 tpstr( CS, 0, term.t_nrow - 1 ); 335 t_move( last, 0 ); 336 } 337 else 338 { 339 t_move( first, 0 ); 340 putpad( DL ); 341 t_move( last, 0 ); 342 putpad( AL ); 343 } 344 } 345 346 void t_scrolldn(int first, int last) /* Scroll the screen down */ 347 /* Note: scrolling routines do */ 348 /* not save cursor position. */ 349 { 350 if (scroll_type) 351 { 352 tpstr( CS, first, last ); 353 t_move( first, 0 ); 354 putpad( SR ); 355 tpstr( CS, 0, term.t_nrow - 1 ); 356 t_move( first, 0 ); 357 } 358 else 359 { 360 t_move( last, 0 ); 361 putpad( DL ); 362 t_move( first, 0 ); 363 putpad( AL ); 364 } 365 } 366 367 void t_setcursor(int insertmode) 368 { 369 } 370 } 371 372 373 TERM term; 374 375 static int scroll_type; /* type of scrolling region (used in tcapscr{up|dn}) */ 376 377 378 void putpad(const(char)* str) 379 { 380 tputs(str, 1, &TERM.t_putchar); 381 } 382 383 void putnpad(const(char)* str, int n) 384 { 385 tputs(str, n, &TERM.t_putchar); 386 } 387 388 static void build_long_keys(const(char)* term ) 389 { 390 lkroot = cast(LONGKEY *)malloc(LONGKEY.sizeof); 391 lkroot.key = 0; 392 lkroot.ptr = null; 393 394 version (Posix) 395 { 396 build_one_long("\033[A", UPKEY); 397 build_one_long("\033[B", DNKEY); 398 build_one_long("\033[C", RTKEY); 399 build_one_long("\033[D", LTKEY); 400 build_one_long( "\033\x4F\x50", F1KEY ); 401 build_one_long( "\033\x4F\x51", F2KEY ); 402 build_one_long( "\033\x4F\x52", F3KEY ); 403 build_one_long( "\033\x4F\x53", F4KEY ); 404 build_one_long( "\033\x5B\x31\x31\x7E", F1KEY ); 405 build_one_long( "\033\x5B\x31\x32\x7E", F2KEY ); 406 build_one_long( "\033\x5B\x31\x33\x7E", F3KEY ); 407 build_one_long( "\033\x5B\x31\x34\x7E", F4KEY ); 408 build_one_long( "\033\x5B\x31\x35\x7E", F5KEY ); 409 build_one_long( "\033\x5B\x31\x37\x7E", F6KEY ); 410 build_one_long( "\033\x5B\x31\x38\x7E", F7KEY ); 411 build_one_long( "\033\x5B\x31\x39\x7E", F8KEY ); 412 build_one_long( "\033\x5B\x32\x30\x7E", F9KEY ); 413 build_one_long( "\033\x5B\x32\x31\x7E", F10KEY ); 414 415 416 build_one_long("\033\x62", ALTB ); 417 build_one_long("\033\x63", ALTC ); 418 build_one_long("\033\x64", ALTD ); 419 build_one_long("\033\x64", ALTE ); 420 build_one_long("\033\x66", ALTF ); 421 build_one_long("\033\x68", ALTH ); 422 build_one_long("\033\x6D", ALTM ); 423 build_one_long("\033\x78", ALTX ); 424 build_one_long("\033\x7A", ALTZ ); 425 426 build_one_long("\033\x5B\x32\x7E", InsKEY ); 427 build_one_long("\033\x5B\x33\x7E", DelKEY ); 428 build_one_long("\033\x5B\x31\x7E", HOMEKEY ); 429 build_one_long("\033\x5B\x34\x7E", ENDKEY ); 430 build_one_long("\033\x5B\x35\x7E", PgUpKEY ); 431 build_one_long("\033\x5B\x36\x7E", PgDnKEY ); 432 } 433 else 434 { 435 build_one_long( KU, UPKEY ); 436 build_one_long( KD, DNKEY ); 437 build_one_long( KR, RTKEY ); 438 build_one_long( KL, LTKEY ); 439 build_one_long( K1, GOLDKEY ); 440 build_one_long( tgetstr("kR",&p), SCROLLUPKEY ); /* scroll back */ 441 build_one_long( tgetstr("kF",&p), SCROLLDNKEY ); /* scroll forw */ 442 build_one_long( tgetstr("kP",&p), PAGEUPKEY ); /* prev page */ 443 build_one_long( tgetstr("kN",&p), PAGEDNKEY ); /* next page */ 444 if( strcmp(term,"vt100") == 0 ) 445 { 446 build_one_long( "\033OQ", PF2KEY ); 447 build_one_long( "\033OR", PF3KEY ); 448 build_one_long( "\033OS", PF4KEY ); 449 build_one_long( "\033Op", F0KEY ); 450 build_one_long( "\033Oq", F1KEY ); 451 build_one_long( "\033Or", F2KEY ); 452 build_one_long( "\033Os", F3KEY ); 453 build_one_long( "\033Ot", F4KEY ); 454 build_one_long( "\033Ou", F5KEY ); 455 build_one_long( "\033Ov", F6KEY ); 456 build_one_long( "\033Ow", F7KEY ); 457 build_one_long( "\033Ox", F8KEY ); 458 build_one_long( "\033Oy", F9KEY ); 459 build_one_long( "\033Om", FMINUSKEY ); 460 build_one_long( "\033Ol", FCOMMAKEY ); 461 build_one_long( "\033On", FDOTKEY ); 462 build_one_long( "\033OM", FENTERKEY ); 463 } 464 else 465 { 466 build_one_long( tgetstr("k2",&p), PF2KEY ); 467 build_one_long( tgetstr("k3",&p), PF3KEY ); 468 build_one_long( tgetstr("k4",&p), PF4KEY ); 469 build_one_long( tgetstr("k5",&p), F5KEY ); 470 build_one_long( tgetstr("k6",&p), F6KEY ); 471 build_one_long( tgetstr("k7",&p), F7KEY ); 472 build_one_long( tgetstr("k8",&p), F8KEY ); 473 build_one_long( tgetstr("k9",&p), F9KEY ); 474 build_one_long( "\033Op", F0KEY ); 475 build_one_long( "\033Oq", F1KEY ); 476 build_one_long( "\033Or", F2KEY ); 477 build_one_long( "\033Os", F3KEY ); 478 build_one_long( "\033Ot", F4KEY ); 479 build_one_long( "\033Om", FMINUSKEY ); 480 build_one_long( "\033[229z", FCOMMAKEY ); 481 build_one_long( "\033Ol", FCOMMAKEY ); 482 build_one_long( "\033OM", FENTERKEY ); 483 } 484 } 485 } 486 487 static void build_one_long(const(char)* s, int keyval) 488 { 489 int i; 490 LONGKEY* lkp,tmpp,tmpq; 491 492 if (!s) 493 return; 494 lkp = lkroot; 495 while( *s ) 496 { 497 for(i=1; i<=lkp[0].key; i++) 498 if( lkp[i].key == *s ) break; 499 if( i != lkp[0].key+1 ) 500 { 501 lkp = lkp[i].ptr; 502 s++; 503 } 504 else 505 { 506 tmpp = cast(LONGKEY *)malloc( 507 LONGKEY.sizeof * ++i ); 508 while( i-- ) 509 { 510 tmpp[i].key = lkp[i].key; 511 tmpp[i].ptr = lkp[i].ptr; 512 } 513 if( lkp[0].ptr ) 514 { 515 tmpq = lkp[0].ptr; 516 for(i=1; i<=tmpq[0].key; i++) 517 if( tmpq[i].ptr == lkp ) 518 tmpq[i].ptr = tmpp; 519 } 520 else 521 lkroot = tmpp; 522 free( lkp ); 523 lkp = tmpp; 524 for(i=1; i<=lkp[0].key; i++) 525 if( !LONGFINAL(lkp[i].key) ) 526 lkp[i].ptr.ptr = lkp; 527 lkp[0].key++; 528 lkp[lkp[0].key].key = *s++; 529 if( !*s ) 530 { 531 lkp[lkp[0].key].keyv = keyval; 532 lkp[lkp[0].key].key |= 0x80; 533 } 534 else 535 { 536 tmpp = lkp; 537 lkp = lkp[lkp[0].key].ptr = cast(LONGKEY *) 538 malloc( LONGKEY.sizeof ); 539 lkp[0].key = 0; 540 lkp[0].ptr = tmpp; 541 } 542 } 543 } 544 } 545 546 void tpstr(const(char)* str, int p1, int p2) 547 { 548 char[128] buf = '\0'; 549 char* pt = buf.ptr; 550 int pi; 551 552 pi = p1; 553 while( *str >= '0' && *str <= '9' ) *pt++ = *str++; 554 if( *str == '*' ) *pt++ = *str++; 555 while( *str ) 556 { 557 if( *str == '%' ) 558 { str++; 559 switch( *str++ ) 560 { 561 case 'd': 562 sprintf(pt,"%d",pi); 563 pi = p2; break; 564 case '2': 565 sprintf(pt,"%2d",pi); 566 pi = p2; break; 567 case '3': 568 sprintf(pt,"%3d",pi); 569 pi = p2; break; 570 case '.': 571 sprintf(pt,"%c",pi); 572 pi = p2; break; 573 case 'r': 574 pi = p2; 575 p2 = p1; 576 p1 = pi; 577 break; 578 case 'i': 579 p1++; p2++; pi++; break; 580 case '%': 581 *pt++ = '%'; break; 582 default: 583 strcpy(pt,"\nTERMCAP Error\n"); 584 break; 585 } 586 pt = buf.ptr + strlen(buf.ptr); 587 } 588 else 589 *pt++ = *str++; 590 } 591 *pt = '\0'; 592 putpad( buf.ptr ); 593 } 594 595 debug 596 { 597 void dump_longs() 598 { 599 printf("__dump__\n"); 600 dump_one_long( 0, lkroot, null ); 601 printf("________\n"); 602 } 603 604 int backcheck = 0; 605 606 void dump_one_long( int offset, LONGKEY* lkp, LONGKEY* lkprev ) 607 { 608 int i,j; 609 if( backcheck ) 610 { 611 for(j=0; j<offset; j++) printf(" "); 612 printf( (lkprev == lkp[0].ptr) ? "TRUE\n" : "FALSE\n" ); 613 } 614 for(i=1; i<=lkp[0].key; i++) 615 { 616 for(j=0; j<offset; j++) printf(" "); 617 printf("%d (%c) ", 618 LONGCHAR(lkp[i].key), LONGCHAR(lkp[i].key)); 619 if( LONGFINAL(lkp[i].key) ) 620 printf("return( %d )\n", lkp[i].keyv ); 621 else 622 { printf("\n"); 623 dump_one_long( offset+1, lkp[i].ptr, lkp ); 624 } 625 } 626 } 627 } 628 629 /************************** 630 * Return true if there are unread chars ready in the input. 631 */ 632 633 bool ttkeysininput() 634 { 635 return false; 636 } 637 638 /************************** 639 * Return when there are unread chars ready in the input. 640 */ 641 642 void ttwaitkeys() 643 { 644 } 645 646 /****************************** 647 */ 648 649 void ttyield() 650 { 651 } 652 653 /****************************** 654 */ 655 656 int msm_init() 657 { 658 return FALSE; // no mouse support 659 } 660 661 int mouse_command() 662 { 663 return 0; // no mouse input 664 } 665 }