1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/ed.screen.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ 2: /* 3: * ed.screen.c: Editor/t_c_-curses interface 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: #if !defined(lint) && !defined(pdp11) 39: static char *rcsid() 40: { return "$Id: ed.screen.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } 41: #endif 42: 43: #include "sh.h" 44: #include "ed.h" 45: #include "ed.defns.h" 46: 47: /* 48: * We don't prototype these, cause some systems have them wrong! 49: */ 50: extern char *tgoto(); 51: extern char *tgetstr(); 52: extern char *tputs(); 53: extern int tgetent(); 54: extern int tgetflag(); 55: extern int tgetnum(); 56: 57: 58: /* #define DEBUG_LITERAL */ 59: 60: /* 61: * IMPORTANT NOTE: these routines are allowed to look at the current screen 62: * and the current possition assuming that it is correct. If this is not 63: * true, then the update will be WRONG! This is (should be) a valid 64: * assumption... 65: */ 66: 67: #ifndef TC_BUFSIZ 68: # ifdef pdp11 69: # define TC_BUFSIZ 1024 70: # else 71: # define TC_BUFSIZ 2048 72: # endif /* pdp11 */ 73: #endif 74: 75: #define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0') 76: #define Str(a) tstr[a].str 77: #define Val(a) tval[a].val 78: 79: static struct { 80: char *b_name; 81: int b_rate; 82: } baud_rate[] = { 83: 84: #ifdef B0 85: { "0", B0 }, 86: #endif 87: #ifdef B50 88: { "50", B50 }, 89: #endif 90: #ifdef B75 91: { "75", B75 }, 92: #endif 93: #ifdef B110 94: { "110", B110 }, 95: #endif 96: #ifdef B134 97: { "134", B134 }, 98: #endif 99: #ifdef B150 100: { "150", B150 }, 101: #endif 102: #ifdef B200 103: { "200", B200 }, 104: #endif 105: #ifdef B300 106: { "300", B300 }, 107: #endif 108: #ifdef B600 109: { "600", B600 }, 110: #endif 111: #ifdef B900 112: { "900", B900 }, 113: #endif 114: #ifdef B1200 115: { "1200", B1200 }, 116: #endif 117: #ifdef B1800 118: { "1800", B1800 }, 119: #endif 120: #ifdef B2400 121: { "2400", B2400 }, 122: #endif 123: #ifdef B3600 124: { "3600", B3600 }, 125: #endif 126: #ifdef B4800 127: { "4800", B4800 }, 128: #endif 129: #ifdef B7200 130: { "7200", B7200 }, 131: #endif 132: #ifdef B9600 133: { "9600", B9600 }, 134: #endif 135: #ifdef EXTA 136: { "19200", EXTA }, 137: #endif 138: #ifdef B19200 139: { "19200", B19200 }, 140: #endif 141: #ifdef EXTB 142: { "38400", EXTB }, 143: #endif 144: #ifdef B38400 145: { "38400", B38400 }, 146: #endif 147: { NULL, 0 } 148: }; 149: 150: static struct t_c_str { 151: char *name; 152: #ifdef TCLONGNAME 153: char *long_name; 154: #endif 155: char *str; 156: } tstr[] = { 157: 158: #define T_al 0 159: { "al", 160: #ifdef TCLONGNAME 161: "add new blank line", 162: #endif 163: NULL }, 164: #define T_bl 1 165: { "bl", 166: #ifdef TCLONGNAME 167: "audible bell", 168: #endif 169: NULL }, 170: #define T_cd 2 171: { "cd", 172: #ifdef TCLONGNAME 173: "clear to bottom", 174: #endif 175: NULL }, 176: #define T_ce 3 177: { "ce", 178: #ifdef TCLONGNAME 179: "clear to end of line", 180: #endif 181: NULL }, 182: #define T_ch 4 183: { "ch", 184: #ifdef TCLONGNAME 185: "cursor to horiz pos", 186: #endif 187: NULL }, 188: #define T_cl 5 189: { "cl", 190: #ifdef TCLONGNAME 191: "clear screen", 192: #endif 193: NULL }, 194: #define T_dc 6 195: { "dc", 196: #ifdef TCLONGNAME 197: "delete a character", 198: #endif 199: NULL }, 200: #define T_dl 7 201: { "dl", 202: #ifdef TCLONGNAME 203: "delete a line", 204: #endif 205: NULL }, 206: #define T_dm 8 207: { "dm", 208: #ifdef TCLONGNAME 209: "start delete mode", 210: #endif 211: NULL }, 212: #define T_ed 9 213: { "ed", 214: #ifdef TCLONGNAME 215: "end delete mode", 216: #endif 217: NULL }, 218: #define T_ei 10 219: { "ei", 220: #ifdef TCLONGNAME 221: "end insert mode", 222: #endif 223: NULL }, 224: #define T_fs 11 225: { "fs", 226: #ifdef TCLONGNAME 227: "cursor from status line", 228: #endif 229: NULL }, 230: #define T_ho 12 231: { "ho", 232: #ifdef TCLONGNAME 233: "home cursor", 234: #endif 235: NULL }, 236: #define T_ic 13 237: { "ic", 238: #ifdef TCLONGNAME 239: "insert character", 240: #endif 241: NULL }, 242: #define T_im 14 243: { "im", 244: #ifdef TCLONGNAME 245: "start insert mode", 246: #endif 247: NULL }, 248: #define T_ip 15 249: { "ip", 250: #ifdef TCLONGNAME 251: "insert padding", 252: #endif 253: NULL }, 254: #define T_kd 16 255: { "kd", 256: #ifdef TCLONGNAME 257: "sends cursor down", 258: #endif 259: NULL }, 260: #define T_kl 17 261: { "kl", 262: #ifdef TCLONGNAME 263: "sends cursor left", 264: #endif 265: NULL }, 266: #define T_kr 18 267: { "kr", 268: #ifdef TCLONGNAME 269: "sends cursor right", 270: #endif 271: NULL }, 272: #define T_ku 19 273: { "ku", 274: #ifdef TCLONGNAME 275: "sends cursor up", 276: #endif 277: NULL }, 278: #define T_md 20 279: { "md", 280: #ifdef TCLONGNAME 281: "begin bold", 282: #endif 283: NULL }, 284: #define T_me 21 285: { "me", 286: #ifdef TCLONGNAME 287: "end attributes", 288: #endif 289: NULL }, 290: #define T_nd 22 291: { "nd", 292: #ifdef TCLONGNAME 293: "non destructive space", 294: #endif 295: NULL }, 296: #define T_se 23 297: { "se", 298: #ifdef TCLONGNAME 299: "end standout", 300: #endif 301: NULL }, 302: #define T_so 24 303: { "so", 304: #ifdef TCLONGNAME 305: "begin standout", 306: #endif 307: NULL }, 308: #define T_ts 25 309: { "ts", 310: #ifdef TCLONGNAME 311: "cursor to status line", 312: #endif 313: NULL }, 314: #define T_up 26 315: { "up", 316: #ifdef TCLONGNAME 317: "cursor up one", 318: #endif 319: NULL }, 320: #define T_us 27 321: { "us", 322: #ifdef TCLONGNAME 323: "begin underline", 324: #endif 325: NULL }, 326: #define T_ue 28 327: { "ue", 328: #ifdef TCLONGNAME 329: "end underline", 330: #endif 331: NULL }, 332: #define T_vb 29 333: { "vb", 334: #ifdef TCLONGNAME 335: "visible bell", 336: #endif 337: NULL }, 338: #define T_DC 30 339: { "DC", 340: #ifdef TCLONGNAME 341: "delete multiple chars", 342: #endif 343: NULL }, 344: #define T_DO 31 345: { "DO", 346: #ifdef TCLONGNAME 347: "cursor down multiple", 348: #endif 349: NULL }, 350: #define T_IC 32 351: { "IC", 352: #ifdef TCLONGNAME 353: "insert multiple chars", 354: #endif 355: NULL }, 356: #define T_LE 33 357: { "LE", 358: #ifdef TCLONGNAME 359: "cursor left multiple", 360: #endif 361: NULL }, 362: #define T_RI 34 363: { "RI", 364: #ifdef TCLONGNAME 365: "cursor right multiple", 366: #endif 367: NULL }, 368: #define T_UP 35 369: { "UP", 370: #ifdef TCLONGNAME 371: "cursor up multiple", 372: #endif 373: NULL }, 374: #define T_str 36 375: { NULL, 376: #ifdef TCLONGNAME 377: NULL, 378: #endif 379: NULL } 380: }; 381: 382: static struct t_c_val { 383: char *name; 384: #ifdef TCLONGNAME 385: char *long_name; 386: #endif 387: int val; 388: } tval[] = { 389: #define T_pt 0 390: { "pt", 391: #ifdef TCLONGNAME 392: "can use physical tabs", 393: #endif 394: 0 }, 395: #define T_li 1 396: { "li", 397: #ifdef TCLONGNAME 398: "Number of lines", 399: #endif 400: 0 }, 401: #define T_co 2 402: { "co", 403: #ifdef TCLONGNAME 404: "Number of columns", 405: #endif 406: 0 }, 407: #define T_km 3 408: { "km", 409: #ifdef TCLONGNAME 410: "Has meta key", 411: #endif 412: 0 }, 413: #define T_val 4 414: { NULL, 415: #ifdef TCLONGNAME 416: NULL, 417: #endif 418: 0 } 419: }; 420: 421: static bool me_all = 0; /* does two or more of the attributes use me */ 422: 423: static void ReBufferDisplay __P((void)); 424: static void TCalloc __P((struct t_c_str *, char *)); 425: 426: 427: static void 428: TCalloc(t, cap) 429: struct t_c_str *t; 430: char *cap; 431: { 432: static char t_c__alloc[TC_BUFSIZ]; 433: char termbuf[TC_BUFSIZ]; 434: struct t_c_str *ts; 435: static int tloc = 0; 436: int tlen, clen; 437: 438: if (cap == NULL || *cap == '\0') { 439: t->str = NULL; 440: return; 441: } 442: else 443: clen = strlen(cap); 444: 445: if (t->str == NULL) 446: tlen = 0; 447: else 448: tlen = strlen(t->str); 449: 450: /* 451: * New string is shorter; no need to allocate space 452: */ 453: if (clen <= tlen) { 454: (void) strcpy(t->str, cap); 455: return; 456: } 457: 458: /* 459: * New string is longer; see if we have enough space to append 460: */ 461: if (tloc + 3 < TC_BUFSIZ) { 462: (void) strcpy(t->str = &t_c__alloc[tloc], cap); 463: tloc += clen + 1; /* one for \0 */ 464: return; 465: } 466: 467: /* 468: * Compact our buffer; no need to check compaction, cause we know it 469: * fits... 470: */ 471: tlen = 0; 472: for (ts = tstr; ts->name != NULL; ts++) 473: if (t != ts && ts->str != NULL && ts->str[0] != '\0') { 474: char *ptr; 475: 476: for (ptr = ts->str; *ptr != '\0'; termbuf[tlen++] = *ptr++); 477: termbuf[tlen++] = '\0'; 478: } 479: copy(t_c__alloc, termbuf, TC_BUFSIZ); 480: tloc = tlen; 481: if (tloc + 3 >= TC_BUFSIZ) { 482: stderror(ERR_NAME | ERR_TCNOSTR); 483: return; 484: } 485: (void) strcpy(t->str = &t_c__alloc[tloc], cap); 486: tloc += clen + 1; /* one for \0 */ 487: return; 488: } 489: 490: 491: /*ARGSUSED*/ 492: void 493: TellTC(what) 494: char *what; 495: { 496: struct t_c_str *t; 497: 498: xprintf("\n\tTcsh thinks your terminal has the\n"); 499: xprintf("\tfollowing characteristics:\n\n"); 500: xprintf("\tIt has %d columns and %d lines\n", 501: Val(T_co), Val(T_li)); 502: xprintf("\tIt has %s meta key\n", T_HasMeta ? "a" : "no"); 503: xprintf("\tIt can%suse tabs\n", T_Tabs ? " " : "not "); 504: 505: for (t = tstr; t->name != NULL; t++) 506: #ifdef TCLONGNAME 507: xprintf("\t%25s (%s) == %s\n", t->long_name, t->name, 508: t->str && *t->str ? t->str : "(empty)"); 509: #else 510: xprintf("\t(%s) == %s\n", t->name, 511: t->str && *t->str ? t->str : "(empty)"); 512: #endif 513: xprintf("\n"); 514: } 515: 516: 517: static void 518: ReBufferDisplay() 519: { 520: register int i; 521: Char **b; 522: Char **bufp; 523: 524: b = Display; 525: Display = NULL; 526: if (b != NULL) { 527: for (bufp = b; *bufp != NULL; bufp++) 528: xfree((ptr_t) * bufp); 529: xfree((ptr_t) b); 530: } 531: b = Vdisplay; 532: Vdisplay = NULL; 533: if (b != NULL) { 534: for (bufp = b; *bufp != NULL; bufp++) 535: xfree((ptr_t) * bufp); 536: xfree((ptr_t) b); 537: } 538: /* make this public, -1 to avoid wraps */ 539: TermH = Val(T_co) - 1; 540: TermV = (INBUFSIZ * 4) / TermH + 1; 541: b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1))); 542: for (i = 0; i < TermV; i++) 543: b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1))); 544: b[TermV] = NULL; 545: Display = b; 546: b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1))); 547: for (i = 0; i < TermV; i++) 548: b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1))); 549: b[TermV] = NULL; 550: Vdisplay = b; 551: } 552: 553: void 554: SetTC(what, how) 555: char *what, *how; 556: { 557: struct t_c_str *ts; 558: struct t_c_val *tv; 559: 560: /* 561: * Do the strings first 562: */ 563: setname("settc"); 564: for (ts = tstr; ts->name != NULL; ts++) 565: if (strcmp(ts->name, what) == 0) 566: break; 567: if (ts->name != NULL) { 568: TCalloc(ts, how); 569: /* 570: * Reset variables 571: */ 572: if (GoodStr(T_me) && GoodStr(T_ue)) 573: me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 574: else 575: me_all = 0; 576: if (GoodStr(T_me) && GoodStr(T_se)) 577: me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 578: 579: T_CanCEOL = GoodStr(T_ce); 580: T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 581: T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 582: T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 583: return; 584: } 585: 586: /* 587: * Do the numeric ones second 588: */ 589: for (tv = tval; tv->name != NULL; tv++) 590: if (strcmp(tv->name, what) == 0) 591: break; 592: 593: if (tv->name != NULL) { 594: if (tv == &tval[T_pt] || tv == &tval[T_km]) { 595: if (strcmp(how, "yes") == 0) 596: tv->val = 1; 597: else if (strcmp(how, "no") == 0) 598: tv->val = 0; 599: else { 600: stderror(ERR_SETTCUS, tv->name); 601: return; 602: } 603: T_Tabs = Val(T_pt); 604: T_HasMeta = Val(T_km); 605: return; 606: } 607: else { 608: tv->val = atoi(how); 609: T_Cols = Val(T_co); 610: T_Lines = Val(T_li); 611: if (tv == &tval[T_co]) 612: ReBufferDisplay(); 613: return; 614: } 615: } 616: stderror(ERR_NAME | ERR_TCCAP, what); 617: return; 618: } 619: 620: 621: /* 622: * Print the t_c_ string out with variable substitution 623: */ 624: void 625: EchoTC(v) 626: Char **v; 627: { 628: char *cap, *scap, cv[BUFSIZ]; 629: int arg_need, arg_cols, arg_rows; 630: int verbose = 0, silent = 0; 631: char *area; 632: static char *fmts = "%s\n", *fmtd = "%d\n"; 633: char buf[TC_BUFSIZ]; 634: 635: area = buf; 636: 637: setname("echotc"); 638: if (!*v || *v[0] == '\0') 639: return; 640: if (v[0][0] == '-') { 641: switch (v[0][1]) { 642: case 'v': 643: verbose = 1; 644: break; 645: case 's': 646: silent = 1; 647: break; 648: default: 649: stderror(ERR_NAME | ERR_TCUSAGE); 650: break; 651: } 652: v++; 653: } 654: (void) strcpy(cv, short2str(*v)); 655: if (strcmp(cv, "tabs") == 0) { 656: xprintf(fmts, T_Tabs ? "yes" : "no"); 657: flush(); 658: return; 659: } 660: else if (strcmp(cv, "meta") == 0) { 661: xprintf(fmts, Val(T_km) ? "yes" : "no"); 662: flush(); 663: return; 664: } 665: else if (strcmp(cv, "baud") == 0) { 666: int i; 667: 668: for (i = 0; baud_rate[i].b_name != NULL; i++) 669: if (T_Speed == baud_rate[i].b_rate) { 670: xprintf(fmts, baud_rate[i].b_name); 671: flush(); 672: return; 673: } 674: xprintf(fmtd, 0); 675: flush(); 676: return; 677: } 678: else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0) { 679: xprintf(fmtd, Val(T_li)); 680: flush(); 681: return; 682: } 683: else if (strcmp(cv, "cols") == 0) { 684: xprintf(fmtd, Val(T_co)); 685: flush(); 686: return; 687: } 688: 689: /* 690: * Count home many values we need for this capability. 691: */ 692: scap = tgetstr(cv, &area); 693: if (!scap || scap[0] == '\0') 694: stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCCAP), cv); 695: 696: for (cap = scap, arg_need = 0; *cap; cap++) 697: if (*cap == '%') 698: switch (*++cap) { 699: case 'd': 700: case '2': 701: case '3': 702: case '.': 703: case '+': 704: arg_need++; 705: break; 706: case '%': 707: case '>': 708: case 'i': 709: case 'r': 710: case 'n': 711: case 'B': 712: case 'D': 713: break; 714: default: 715: /* 716: * hpux has lot's of them... 717: */ 718: if (verbose) 719: stderror(ERR_NAME | ERR_TCPARM, *cap); 720: /* This is bad, but I won't complain */ 721: break; 722: } 723: 724: switch (arg_need) { 725: case 0: 726: v++; 727: if (*v && *v[0]) 728: stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCARGS), 729: cv, arg_need); 730: (void) tputs(scap, 1, putraw); 731: break; 732: case 1: 733: v++; 734: if (!*v || *v[0] == '\0') 735: stderror(ERR_NAME | ERR_TCNARGS, cv, 1); 736: arg_rows = 0; 737: arg_cols = atoi(short2str(*v)); 738: v++; 739: if (*v && *v[0]) 740: stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCARGS), 741: cv, arg_need); 742: (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, putraw); 743: break; 744: default: 745: /* This is wrong, but I will ignore it... */ 746: if (verbose) 747: stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 748: case 2: 749: v++; 750: if (!*v || *v[0] == '\0') 751: stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCNARGS), cv, 2); 752: arg_cols = atoi(short2str(*v)); 753: v++; 754: if (!*v || *v[0] == '\0') 755: stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCNARGS), cv, 2); 756: arg_rows = atoi(short2str(*v)); 757: v++; 758: if (*v && *v[0]) 759: stderror(silent ? ERR_SILENT : (ERR_NAME | ERR_TCARGS), 760: cv, arg_need); 761: (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, putraw); 762: break; 763: } 764: flush(); 765: } 766: 767: bool GotTermCaps = 0; 768: 769: void 770: BindArrowKeys() 771: { 772: KEYCMD *map; 773: int i; 774: char *p; 775: static struct { 776: int key, fun; 777: } ar[] = 778: { 779: { T_kd, F_DOWN_HIST }, 780: { T_ku, F_UP_HIST }, 781: { T_kl, F_CHARBACK }, 782: { T_kr, F_CHARFWD } 783: }; 784: 785: if (!GotTermCaps) 786: return; 787: map = VImode ? CcAltMap : CcKeyMap; 788: 789: for (i = 0; i < 4; i++) { 790: p = tstr[ar[i].key].str; 791: if (p && *p) { 792: if (p[1]) { 793: AddXKeyCmd(str2short(p), ar[i].fun); 794: map[(unsigned char) *p] = F_XKEY; 795: } 796: else if (map[(unsigned char) *p] == F_UNASSIGNED) { 797: ClearXkey(map, str2short(p)); 798: map[(unsigned char) *p] = ar[i].fun; 799: } 800: } 801: } 802: } 803: 804: static Char cur_atr = 0; /* current attributes */ 805: 806: void 807: SetAttributes(atr) 808: int atr; 809: { 810: atr &= ATTRIBUTES; 811: if (atr != cur_atr) { 812: if (me_all && GoodStr(T_me)) { 813: if ((cur_atr & BOLD) && !(atr & BOLD) || 814: (cur_atr & UNDER) && !(atr & UNDER) || 815: (cur_atr & STANDOUT) && !(atr & STANDOUT)) { 816: (void) tputs(Str(T_me), 1, putpure); 817: cur_atr = 0; 818: } 819: } 820: if ((atr & BOLD) != (cur_atr & BOLD)) { 821: if (atr & BOLD) { 822: if (GoodStr(T_md) && GoodStr(T_me)) { 823: (void) tputs(Str(T_md), 1, putpure); 824: cur_atr |= BOLD; 825: } 826: } 827: else { 828: if (GoodStr(T_md) && GoodStr(T_me)) { 829: (void) tputs(Str(T_me), 1, putpure); 830: if ((cur_atr & STANDOUT) && GoodStr(T_se)) { 831: (void) tputs(Str(T_se), 1, putpure); 832: cur_atr &= ~STANDOUT; 833: } 834: if ((cur_atr & UNDER) && GoodStr(T_ue)) { 835: (void) tputs(Str(T_ue), 1, putpure); 836: cur_atr &= ~UNDER; 837: } 838: cur_atr &= ~BOLD; 839: } 840: } 841: } 842: if ((atr & STANDOUT) != (cur_atr & STANDOUT)) { 843: if (atr & STANDOUT) { 844: if (GoodStr(T_so) && GoodStr(T_se)) { 845: (void) tputs(Str(T_so), 1, putpure); 846: cur_atr |= STANDOUT; 847: } 848: } 849: else { 850: if (GoodStr(T_se)) { 851: (void) tputs(Str(T_se), 1, putpure); 852: cur_atr &= ~STANDOUT; 853: } 854: } 855: } 856: if ((atr & UNDER) != (cur_atr & UNDER)) { 857: if (atr & UNDER) { 858: if (GoodStr(T_us) && GoodStr(T_ue)) { 859: (void) tputs(Str(T_us), 1, putpure); 860: cur_atr |= UNDER; 861: } 862: } 863: else { 864: if (GoodStr(T_ue)) { 865: (void) tputs(Str(T_ue), 1, putpure); 866: cur_atr &= ~UNDER; 867: } 868: } 869: } 870: } 871: } 872: 873: /* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask t_c_ */ 874: int 875: CanWeTab() 876: { 877: return (Val(T_pt)); 878: } 879: 880: void 881: MoveToLine(where) /* move to line <where> (first line == 0) */ 882: int where; /* as efficiently as possible; */ 883: { 884: int del, i; 885: 886: if (where == CursorV) 887: return; 888: 889: if (where > TermV) { 890: #ifdef DEBUG_SCREEN 891: xprintf("MoveToLine: where is ridiculous: %d\r\n", where); 892: flush(); 893: #endif 894: return; 895: } 896: 897: if ((del = where - CursorV) > 0) { 898: if ((del > 1) && GoodStr(T_DO)) 899: (void) tputs(tgoto(Str(T_DO), del, del), del, putpure); 900: else { 901: for (i = 0; i < del; i++) 902: (void) putraw('\n'); 903: CursorH = 0; /* because the \n will become \r\n */ 904: } 905: } 906: else { /* del < 0 */ 907: if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) 908: (void) tputs(tgoto(Str(T_UP), -del, -del), -del, putpure); 909: else { 910: if (GoodStr(T_up)) 911: for (i = 0; i < -del; i++) 912: (void) tputs(Str(T_up), 1, putpure); 913: } 914: } 915: CursorV = where; /* now where is here */ 916: } 917: 918: void 919: MoveToChar(where) /* move to character position (where) */ 920: int where; 921: { /* as efficiently as possible */ 922: int del, i; 923: 924: mc_again: 925: if (where == CursorH) 926: return; 927: 928: if (where > (TermH + 1)) { 929: #ifdef DEBUG_SCREEN 930: xprintf("MoveToChar: where is riduculous: %d\r\n", where); 931: flush(); 932: #endif 933: return; 934: } 935: 936: if (!where) { /* if where is first column */ 937: (void) putraw('\r'); /* do a CR */ 938: CursorH = 0; 939: return; 940: } 941: 942: del = where - CursorH; 943: 944: if ((del < -4 || del > 4) && GoodStr(T_ch)) 945: /* go there directly */ 946: (void) tputs(tgoto(Str(T_ch), where, where), where, putpure); 947: else { 948: if (del > 0) { /* moving forward */ 949: if ((del > 4) && GoodStr(T_RI)) 950: (void) tputs(tgoto(Str(T_RI), del, del), del, putpure); 951: else { 952: if (T_Tabs) { /* if I can do tabs, use them */ 953: if ((CursorH & 0370) != (where & 0370)) { 954: /* if not within tab stop */ 955: for (i = (CursorH & 0370); i < (where & 0370); i += 8) 956: (void) putraw('\t'); /* then tab over */ 957: CursorH = where & 0370; 958: } 959: } 960: /* it's usually cheaper to just write the chars, so we do. */ 961: 962: /* NOTE THAT so_write() WILL CHANGE CursorH!!! */ 963: so_write(&Display[CursorV][CursorH], where - CursorH); 964: 965: } 966: } 967: else { /* del < 0 := moving backward */ 968: if ((-del > 4) && GoodStr(T_LE)) 969: (void) tputs(tgoto(Str(T_LE), -del, -del), -del, putpure); 970: else { /* can't go directly there */ 971: /* if the "cost" is greater than the "cost" from col 0 */ 972: if (T_Tabs ? (-del > ((where >> 3) + (where & 07))) 973: : (-del > where)) { 974: (void) putraw('\r'); /* do a CR */ 975: CursorH = 0; 976: goto mc_again; /* and try again */ 977: } 978: for (i = 0; i < -del; i++) 979: (void) putraw('\b'); 980: } 981: } 982: } 983: CursorH = where; /* now where is here */ 984: } 985: 986: void 987: so_write(cp, n) 988: register Char *cp; 989: register int n; 990: { 991: if (n <= 0) 992: return; /* catch bugs */ 993: 994: if (n > (TermH + 1)) { 995: #ifdef DEBUG_SCREEN 996: xprintf("so_write: n is riduculous: %d\r\n", n); 997: flush(); 998: #endif 999: return; 1000: } 1001: 1002: do { 1003: if (*cp & LITERAL) { 1004: extern Char *litptr[]; 1005: Char *d; 1006: 1007: #ifdef DEBUG_LITERAL 1008: xprintf("so: litnum %d, litptr %x\r\n", 1009: *cp & CHAR, litptr[*cp & CHAR]); 1010: #endif 1011: for (d = litptr[*cp++ & CHAR]; *d & LITERAL; d++) 1012: (void) putraw(*d & CHAR); 1013: (void) putraw(*d); 1014: 1015: } 1016: else 1017: (void) putraw(*cp++); 1018: CursorH++; 1019: } while (--n); 1020: } 1021: 1022: 1023: void 1024: DeleteChars(num) /* deletes <num> characters */ 1025: int num; 1026: { 1027: if (num <= 0) 1028: return; 1029: 1030: if (!T_CanDel) { 1031: #ifdef DEBUG_EDIT 1032: xprintf(" ERROR: cannot delete \n"); 1033: #endif 1034: flush(); 1035: return; 1036: } 1037: 1038: if (num > TermH) { 1039: #ifdef DEBUG_SCREEN 1040: xprintf("DeleteChars: num is riduculous: %d\r\n", num); 1041: flush(); 1042: #endif 1043: return; 1044: } 1045: 1046: if (GoodStr(T_DC)) /* if I have multiple delete */ 1047: if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more expen. */ 1048: (void) tputs(tgoto(Str(T_DC), num, num), num, putpure); 1049: return; 1050: } 1051: 1052: if (GoodStr(T_dm)) /* if I have delete mode */ 1053: (void) tputs(Str(T_dm), 1, putpure); 1054: 1055: if (GoodStr(T_dc)) /* else do one at a time */ 1056: while (num--) 1057: (void) tputs(Str(T_dc), 1, putpure); 1058: 1059: if (GoodStr(T_ed)) /* if I have delete mode */ 1060: (void) tputs(Str(T_ed), 1, putpure); 1061: } 1062: 1063: void 1064: Insert_write(cp, num) /* Puts terminal in insert character mode, */ 1065: register Char *cp; 1066: register int num; /* or inserts num characters in the line */ 1067: { 1068: if (num <= 0) 1069: return; 1070: 1071: if (!T_CanIns) { 1072: #ifdef DEBUG_EDIT 1073: xprintf(" ERROR: cannot insert \n"); 1074: #endif 1075: flush(); 1076: return; 1077: } 1078: 1079: if (num > TermH) { 1080: #ifdef DEBUG_SCREEN 1081: xprintf("StartInsert: num is riduculous: %d\r\n", num); 1082: flush(); 1083: #endif 1084: return; 1085: } 1086: 1087: if (GoodStr(T_IC)) /* if I have multiple insert */ 1088: if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expen. */ 1089: (void) tputs(tgoto(Str(T_IC), num, num), num, putpure); 1090: so_write(cp, num); /* this updates CursorH */ 1091: return; 1092: } 1093: 1094: if (GoodStr(T_im)) /* if I have insert mode */ 1095: (void) tputs(Str(T_im), 1, putpure); 1096: 1097: do { 1098: if (GoodStr(T_ic)) /* have to make num chars insert */ 1099: (void) tputs(Str(T_ic), 1, putpure); /* insert a char */ 1100: 1101: (void) putraw(*cp++); 1102: 1103: CursorH++; 1104: 1105: if (GoodStr(T_ip)) /* have to make num chars insert */ 1106: (void) tputs(Str(T_ip), 1, putpure);/* pad the inserted char */ 1107: 1108: } while (--num); 1109: 1110: if (GoodStr(T_ei)) 1111: (void) tputs(Str(T_ei), 1, putpure); 1112: } 1113: 1114: void 1115: ClearEOL(num) /* clear to end of line. There are num */ 1116: int num; /* characters to clear */ 1117: { 1118: register int i; 1119: 1120: if (T_CanCEOL && GoodStr(T_ce)) 1121: (void) tputs(Str(T_ce), 1, putpure); 1122: else { 1123: for (i = 0; i < num; i++) 1124: (void) putraw(' '); 1125: CursorH += num; /* have written num spaces */ 1126: } 1127: } 1128: 1129: void 1130: ClearScreen() 1131: { /* clear the whole screen and home */ 1132: if (GoodStr(T_cl)) 1133: /* send the clear screen code */ 1134: (void) tputs(Str(T_cl), Val(T_li), putpure); 1135: else if (GoodStr(T_ho) && GoodStr(T_cd)) { 1136: (void) tputs(Str(T_ho), Val(T_li), putpure); /* home */ 1137: /* clear to bottom of screen */ 1138: (void) tputs(Str(T_cd), Val(T_li), putpure); 1139: } 1140: else { 1141: (void) putraw('\r'); 1142: (void) putraw('\n'); 1143: } 1144: } 1145: 1146: void 1147: Beep() 1148: { /* produce a sound */ 1149: if (adrof(STRnobeep)) 1150: return; 1151: 1152: if (GoodStr(T_vb) && adrof(STRvisiblebell)) 1153: (void) tputs(Str(T_vb), 1, putpure); /* visible bell */ 1154: else if (GoodStr(T_bl)) 1155: /* what t_c_ says we should use */ 1156: (void) tputs(Str(T_bl), 1, putpure); 1157: else 1158: (void) putraw('\007'); /* an ASCII bell; ^G */ 1159: } 1160: 1161: void 1162: ClearToBottom() 1163: { /* clear to the bottom of the screen */ 1164: if (GoodStr(T_cd)) 1165: (void) tputs(Str(T_cd), Val(T_li), putpure); 1166: else if (GoodStr(T_ce)) 1167: (void) tputs(Str(T_ce), Val(T_li), putpure); 1168: } 1169: 1170: void 1171: GetTermCaps() 1172: { /* read in the needed terminal capabilites */ 1173: register int i; 1174: char *ptr; 1175: char buf[TC_BUFSIZ]; 1176: static char bp[TC_BUFSIZ]; 1177: char *area; 1178: extern char *getenv(); 1179: struct t_c_str *t; 1180: 1181: 1182: #ifdef SIG_WINDOW 1183: #ifdef BSDSIGS 1184: sigmask_t omask; 1185: #endif /* BSDSIGS */ 1186: int lins, cols; 1187: 1188: /* don't want to confuse things here */ 1189: #ifdef BSDSIGS 1190: omask = sigblock(sigmask(SIG_WINDOW)) & ~sigmask(SIG_WINDOW); 1191: #else /* BSDSIGS */ 1192: (void) sighold(SIG_WINDOW); 1193: #endif /* BSDSIGS */ 1194: #endif /* SIG_WINDOW */ 1195: area = buf; 1196: 1197: GotTermCaps = 1; 1198: 1199: setname("gett_c_s"); 1200: ptr = getenv("TERM"); 1201: #ifdef apollo 1202: /* 1203: * If we are on a pad, we pretend that we are dumb. Otherwise the t_c_ 1204: * library will put us in a weird screen mode, thinking that we are going 1205: * to use curses 1206: */ 1207: if (isapad()) 1208: ptr = "dumb"; 1209: #endif 1210: if (!ptr || !ptr[0]) 1211: ptr = "dumb"; 1212: 1213: setzero(bp, TC_BUFSIZ); 1214: 1215: i = tgetent(bp, ptr); 1216: if (i <= 0) { 1217: if (i == -1) { 1218: #if SVID == 0 1219: xprintf("tcsh: Cannot open /etc/t_c_.\n"); 1220: } 1221: else if (i == 0) { 1222: #endif /* SVID */ 1223: xprintf("tcsh: No entry for terminal type \"%s\"\n", 1224: getenv("TERM")); 1225: } 1226: xprintf("tcsh: using dumb terminal settings.\n"); 1227: Val(T_co) = 80; /* do a dumb terminal */ 1228: Val(T_pt) = Val(T_km) = Val(T_li) = 0; 1229: for (t = tstr; t->name != NULL; t++) 1230: TCalloc(t, NULL); 1231: } 1232: else { 1233: /* Can we tab */ 1234: Val(T_pt) = tgetflag("pt") && !tgetflag("xt"); 1235: /* do we have a meta? */ 1236: Val(T_km) = (tgetflag("km") || tgetflag("MT")); 1237: Val(T_co) = tgetnum("co"); 1238: Val(T_li) = tgetnum("li"); 1239: for (t = tstr; t->name != NULL; t++) 1240: TCalloc(t, tgetstr(t->name, &area)); 1241: } 1242: if (Val(T_co) < 2) 1243: Val(T_co) = 80; /* just in case */ 1244: if (Val(T_li) < 1) 1245: Val(T_li) = 24; 1246: 1247: T_Cols = Val(T_co); 1248: T_Lines = Val(T_li); 1249: if (T_Tabs) 1250: T_Tabs = Val(T_pt); 1251: T_HasMeta = Val(T_km); 1252: T_CanCEOL = GoodStr(T_ce); 1253: T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 1254: T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 1255: T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 1256: if (GoodStr(T_me) && GoodStr(T_ue)) 1257: me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 1258: else 1259: me_all = 0; 1260: if (GoodStr(T_me) && GoodStr(T_se)) 1261: me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 1262: 1263: 1264: #ifdef DEBUG_SCREEN 1265: if (!T_CanUP) { 1266: xprintf("tcsh: WARNING: Your terminal cannot move up.\n"); 1267: xprintf("Editing may be odd for long lines.\n"); 1268: } 1269: if (!T_CanCEOL) 1270: xprintf("no clear EOL capability.\n"); 1271: if (!T_CanDel) 1272: xprintf("no delete char capability.\n"); 1273: if (!T_CanIns) 1274: xprintf("no insert char capability.\n"); 1275: #endif /* DEBUG_SCREEN */ 1276: 1277: 1278: 1279: #ifdef SIG_WINDOW 1280: (void) GetSize(&lins, &cols); /* get the correct window size */ 1281: ChangeSize(lins, cols); 1282: 1283: # ifdef BSDSIGS 1284: (void) sigsetmask(omask); /* can change it again */ 1285: # else /* BSDSIGS */ 1286: (void) sigrelse(SIG_WINDOW); 1287: # endif /* BSDSIGS */ 1288: #else /* SIG_WINDOW */ 1289: ChangeSize(Val(T_li), Val(T_co)); 1290: #endif /* SIG_WINDOW */ 1291: 1292: BindArrowKeys(); 1293: } 1294: 1295: #ifdef SIG_WINDOW 1296: /* GetSize(): 1297: * Return the new window size in lines and cols, and 1298: * true if the size was changed. 1299: */ 1300: int 1301: GetSize(lins, cols) 1302: int *lins, *cols; 1303: { 1304: *cols = Val(T_co); 1305: *lins = Val(T_li); 1306: 1307: #ifdef TIOCGWINSZ 1308: # ifndef lint 1309: { 1310: struct winsize ws; /* from 4.3 */ 1311: 1312: if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & ws) < 0) 1313: return (0); 1314: 1315: if (ws.ws_col) 1316: *cols = ws.ws_col; 1317: if (ws.ws_row) 1318: *lins = ws.ws_row; 1319: } 1320: # endif 1321: #else /* TIOCGWINSZ */ 1322: # ifdef TIOCGSIZE 1323: { 1324: struct ttysize ts; /* from Sun */ 1325: 1326: if (ioctl(SHOUT, TIOCGSIZE, (ioctl_t) & ts) < 0) 1327: return; 1328: 1329: if (ts.ts_cols) 1330: *cols = ts.ts_cols; 1331: if (ts.ts_lines) 1332: *lins = ts.ts_lines; 1333: } 1334: # endif /* TIOCGSIZE */ 1335: #endif /* TIOCGWINSZ */ 1336: 1337: if (*cols < 2) 1338: *cols = 80; /* just in case */ 1339: if (*lins < 1) 1340: *lins = 24; 1341: 1342: return (Val(T_co) != *cols || Val(T_li) != *lins); 1343: } 1344: 1345: #endif /* SIGWINDOW */ 1346: 1347: void 1348: ChangeSize(lins, cols) 1349: int lins, cols; 1350: { 1351: 1352: Val(T_co) = cols; 1353: Val(T_li) = lins; 1354: 1355: #ifdef SIG_WINDOW 1356: { 1357: Char buf[10]; 1358: char *tptr; 1359: 1360: if (getenv("COLUMNS")) { 1361: Itoa(Val(T_co), buf); 1362: Setenv(STRCOLUMNS, buf); 1363: } 1364: 1365: if (getenv("LINES")) { 1366: Itoa(Val(T_li), buf); 1367: Setenv(STRLINES, buf); 1368: } 1369: 1370: if (tptr = getenv("TERMCAP")) { 1371: Char t_c_[1024], backup[1024], *ptr; 1372: int i; 1373: 1374: ptr = str2short(tptr); 1375: (void) Strncpy(t_c_, ptr, 1024); 1376: t_c_[1023] = '\0'; 1377: 1378: /* update t_c_ string; first do columns */ 1379: buf[0] = 'c'; 1380: buf[1] = 'o'; 1381: buf[2] = '#'; 1382: buf[3] = '\0'; 1383: if ((ptr = Strstr(t_c_, buf)) == NULL) { 1384: (void) Strcpy(backup, t_c_); 1385: } 1386: else { 1387: i = ptr - t_c_ + Strlen(buf); 1388: (void) Strncpy(backup, t_c_, i); 1389: backup[i] = '\0'; 1390: Itoa(Val(T_co), buf); 1391: (void) Strcat(backup + i, buf); 1392: ptr = Strchr(ptr, ':'); 1393: (void) Strcat(backup, ptr); 1394: } 1395: 1396: /* now do lines */ 1397: buf[0] = 'l'; 1398: buf[1] = 'i'; 1399: buf[2] = '#'; 1400: buf[3] = '\0'; 1401: if ((ptr = Strstr(backup, buf)) == NULL) { 1402: (void) Strcpy(t_c_, backup); 1403: } 1404: else { 1405: i = ptr - backup + Strlen(buf); 1406: (void) Strncpy(t_c_, backup, i); 1407: t_c_[i] = '\0'; 1408: Itoa(Val(T_li), buf); 1409: (void) Strcat(t_c_, buf); 1410: ptr = Strchr(ptr, ':'); 1411: (void) Strcat(t_c_, ptr); 1412: } 1413: Setenv(STRTRMCAP, t_c_); 1414: } 1415: } 1416: #endif /* SIG_WINDOW */ 1417: 1418: ReBufferDisplay(); /* re-make display buffers */ 1419: ClearDisp(); 1420: }