1 /* $Header: /src/pub/tcsh/ed.screen.c,v 3.50 2003/02/08 20:03:25 christos Exp $ */ 2 /* 3 * ed.screen.c: Editor/termcap-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. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 #include "sh.h" 34 35 RCSID("$Id: ed.screen.c,v 3.50 2003/02/08 20:03:25 christos Exp $") 36 37 #include "ed.h" 38 #include "tc.h" 39 #include "ed.defns.h" 40 41 #ifndef POSIX 42 /* 43 * We don't prototype these, cause some systems have them wrong! 44 */ 45 extern int tgetent __P(()); 46 extern char *tgetstr __P(()); 47 extern int tgetflag __P(()); 48 extern int tgetnum __P(()); 49 extern char *tgoto __P(()); 50 # define PUTPURE putpure 51 # define PUTRAW putraw 52 #else 53 extern int tgetent __P((char *, char *)); 54 extern char *tgetstr __P((char *, char **)); 55 extern int tgetflag __P((char *)); 56 extern int tgetnum __P((char *)); 57 extern char *tgoto __P((char *, int, int)); 58 extern void tputs __P((char *, int, void (*)(int))); 59 # define PUTPURE ((void (*)__P((int))) putpure) 60 # define PUTRAW ((void (*)__P((int))) putraw) 61 #endif 62 63 64 /* #define DEBUG_LITERAL */ 65 66 /* 67 * IMPORTANT NOTE: these routines are allowed to look at the current screen 68 * and the current possition assuming that it is correct. If this is not 69 * true, then the update will be WRONG! This is (should be) a valid 70 * assumption... 71 */ 72 73 #define TC_BUFSIZE 2048 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 #define T_al 0 151 #define T_bl 1 152 #define T_cd 2 153 #define T_ce 3 154 #define T_ch 4 155 #define T_cl 5 156 #define T_dc 6 157 #define T_dl 7 158 #define T_dm 8 159 #define T_ed 9 160 #define T_ei 10 161 #define T_fs 11 162 #define T_ho 12 163 #define T_ic 13 164 #define T_im 14 165 #define T_ip 15 166 #define T_kd 16 167 #define T_kl 17 168 #define T_kr 18 169 #define T_ku 19 170 #define T_md 20 171 #define T_me 21 172 #define T_nd 22 173 #define T_se 23 174 #define T_so 24 175 #define T_ts 25 176 #define T_up 26 177 #define T_us 27 178 #define T_ue 28 179 #define T_vb 29 180 #define T_DC 30 181 #define T_DO 31 182 #define T_IC 32 183 #define T_LE 33 184 #define T_RI 34 185 #define T_UP 35 186 #define T_kh 36 187 #define T_at7 37 188 #define T_str 38 189 static struct termcapstr { 190 char *name; 191 char *long_name; 192 char *str; 193 } tstr[T_str + 1]; 194 195 196 #define T_am 0 197 #define T_pt 1 198 #define T_li 2 199 #define T_co 3 200 #define T_km 4 201 #define T_xn 5 202 #define T_val 6 203 static struct termcapval { 204 char *name; 205 char *long_name; 206 int val; 207 } tval[T_val + 1]; 208 209 void 210 terminit() 211 { 212 #ifdef NLS_CATALOGS 213 int i; 214 215 for (i = 0; i < T_str + 1; i++) 216 xfree((ptr_t) tstr[i].long_name); 217 218 for (i = 0; i < T_val + 1; i++) 219 xfree((ptr_t) tval[i].long_name); 220 #endif 221 222 tstr[T_al].name = "al"; 223 tstr[T_al].long_name = CSAVS(4, 1, "add new blank line"); 224 225 tstr[T_bl].name = "bl"; 226 tstr[T_bl].long_name = CSAVS(4, 2, "audible bell"); 227 228 tstr[T_cd].name = "cd"; 229 tstr[T_cd].long_name = CSAVS(4, 3, "clear to bottom"); 230 231 tstr[T_ce].name = "ce"; 232 tstr[T_ce].long_name = CSAVS(4, 4, "clear to end of line"); 233 234 tstr[T_ch].name = "ch"; 235 tstr[T_ch].long_name = CSAVS(4, 5, "cursor to horiz pos"); 236 237 tstr[T_cl].name = "cl"; 238 tstr[T_cl].long_name = CSAVS(4, 6, "clear screen"); 239 240 tstr[T_dc].name = "dc"; 241 tstr[T_dc].long_name = CSAVS(4, 7, "delete a character"); 242 243 tstr[T_dl].name = "dl"; 244 tstr[T_dl].long_name = CSAVS(4, 8, "delete a line"); 245 246 tstr[T_dm].name = "dm"; 247 tstr[T_dm].long_name = CSAVS(4, 9, "start delete mode"); 248 249 tstr[T_ed].name = "ed"; 250 tstr[T_ed].long_name = CSAVS(4, 10, "end delete mode"); 251 252 tstr[T_ei].name = "ei"; 253 tstr[T_ei].long_name = CSAVS(4, 11, "end insert mode"); 254 255 tstr[T_fs].name = "fs"; 256 tstr[T_fs].long_name = CSAVS(4, 12, "cursor from status line"); 257 258 tstr[T_ho].name = "ho"; 259 tstr[T_ho].long_name = CSAVS(4, 13, "home cursor"); 260 261 tstr[T_ic].name = "ic"; 262 tstr[T_ic].long_name = CSAVS(4, 14, "insert character"); 263 264 tstr[T_im].name = "im"; 265 tstr[T_im].long_name = CSAVS(4, 15, "start insert mode"); 266 267 tstr[T_ip].name = "ip"; 268 tstr[T_ip].long_name = CSAVS(4, 16, "insert padding"); 269 270 tstr[T_kd].name = "kd"; 271 tstr[T_kd].long_name = CSAVS(4, 17, "sends cursor down"); 272 273 tstr[T_kl].name = "kl"; 274 tstr[T_kl].long_name = CSAVS(4, 18, "sends cursor left"); 275 276 tstr[T_kr].name = "kr"; 277 tstr[T_kr].long_name = CSAVS(4, 19, "sends cursor right"); 278 279 tstr[T_ku].name = "ku"; 280 tstr[T_ku].long_name = CSAVS(4, 20, "sends cursor up"); 281 282 tstr[T_md].name = "md"; 283 tstr[T_md].long_name = CSAVS(4, 21, "begin bold"); 284 285 tstr[T_me].name = "me"; 286 tstr[T_me].long_name = CSAVS(4, 22, "end attributes"); 287 288 tstr[T_nd].name = "nd"; 289 tstr[T_nd].long_name = CSAVS(4, 23, "non destructive space"); 290 291 tstr[T_se].name = "se"; 292 tstr[T_se].long_name = CSAVS(4, 24, "end standout"); 293 294 tstr[T_so].name = "so"; 295 tstr[T_so].long_name = CSAVS(4, 25, "begin standout"); 296 297 tstr[T_ts].name = "ts"; 298 tstr[T_ts].long_name = CSAVS(4, 26, "cursor to status line"); 299 300 tstr[T_up].name = "up"; 301 tstr[T_up].long_name = CSAVS(4, 27, "cursor up one"); 302 303 tstr[T_us].name = "us"; 304 tstr[T_us].long_name = CSAVS(4, 28, "begin underline"); 305 306 tstr[T_ue].name = "ue"; 307 tstr[T_ue].long_name = CSAVS(4, 29, "end underline"); 308 309 tstr[T_vb].name = "vb"; 310 tstr[T_vb].long_name = CSAVS(4, 30, "visible bell"); 311 312 tstr[T_DC].name = "DC"; 313 tstr[T_DC].long_name = CSAVS(4, 31, "delete multiple chars"); 314 315 tstr[T_DO].name = "DO"; 316 tstr[T_DO].long_name = CSAVS(4, 32, "cursor down multiple"); 317 318 tstr[T_IC].name = "IC"; 319 tstr[T_IC].long_name = CSAVS(4, 33, "insert multiple chars"); 320 321 tstr[T_LE].name = "LE"; 322 tstr[T_LE].long_name = CSAVS(4, 34, "cursor left multiple"); 323 324 tstr[T_RI].name = "RI"; 325 tstr[T_RI].long_name = CSAVS(4, 35, "cursor right multiple"); 326 327 tstr[T_UP].name = "UP"; 328 tstr[T_UP].long_name = CSAVS(4, 36, "cursor up multiple"); 329 330 tstr[T_kh].name = "kh"; 331 tstr[T_kh].long_name = CSAVS(4, 37, "send cursor home"); 332 333 tstr[T_at7].name = "@7"; 334 tstr[T_at7].long_name = CSAVS(4, 38, "send cursor end"); 335 336 tstr[T_str].name = NULL; 337 tstr[T_str].long_name = NULL; 338 339 340 tval[T_am].name = "am"; 341 tval[T_am].long_name = CSAVS(4, 37, "Has automatic margins"); 342 343 tval[T_pt].name = "pt"; 344 tval[T_pt].long_name = CSAVS(4, 38, "Can use physical tabs"); 345 346 tval[T_li].name = "li"; 347 tval[T_li].long_name = CSAVS(4, 39, "Number of lines"); 348 349 tval[T_co].name = "co"; 350 tval[T_co].long_name = CSAVS(4, 40, "Number of columns"); 351 352 tval[T_km].name = "km"; 353 tval[T_km].long_name = CSAVS(4, 41, "Has meta key"); 354 355 tval[T_xn].name = "xn"; 356 tval[T_xn].long_name = CSAVS(4, 42, "Newline ignored at right margin"); 357 358 tval[T_val].name = NULL; 359 tval[T_val].long_name = NULL; 360 } 361 362 /* 363 * A very useful table from justin@crim.ca (Justin Bur) :-) 364 * (Modified by per@erix.ericsson.se (Per Hedeland) 365 * - first (and second:-) case fixed) 366 * 367 * Description Termcap variables tcsh behavior 368 * am xn UseRightmost SendCRLF 369 * -------------- ------- ------- ------------ ------------ 370 * Automargins yes no yes no 371 * Magic Margins yes yes yes no 372 * No Wrap no -- yes yes 373 */ 374 375 static bool me_all = 0; /* does two or more of the attributes use me */ 376 377 static void ReBufferDisplay __P((void)); 378 static void TCalloc __P((struct termcapstr *, char *)); 379 380 381 static void 382 TCalloc(t, cap) 383 struct termcapstr *t; 384 char *cap; 385 { 386 static char termcap_alloc[TC_BUFSIZE]; 387 char termbuf[TC_BUFSIZE]; 388 struct termcapstr *ts; 389 static int tloc = 0; 390 int tlen, clen; 391 392 if (cap == NULL || *cap == '\0') { 393 t->str = NULL; 394 return; 395 } 396 else 397 clen = strlen(cap); 398 399 if (t->str == NULL) 400 tlen = 0; 401 else 402 tlen = strlen(t->str); 403 404 /* 405 * New string is shorter; no need to allocate space 406 */ 407 if (clen <= tlen) { 408 (void) strcpy(t->str, cap); 409 return; 410 } 411 412 /* 413 * New string is longer; see if we have enough space to append 414 */ 415 if (tloc + 3 < TC_BUFSIZE) { 416 (void) strcpy(t->str = &termcap_alloc[tloc], cap); 417 tloc += clen + 1; /* one for \0 */ 418 return; 419 } 420 421 /* 422 * Compact our buffer; no need to check compaction, cause we know it 423 * fits... 424 */ 425 tlen = 0; 426 for (ts = tstr; ts->name != NULL; ts++) 427 if (t != ts && ts->str != NULL && ts->str[0] != '\0') { 428 char *ptr; 429 430 for (ptr = ts->str; *ptr != '\0'; termbuf[tlen++] = *ptr++) 431 continue; 432 termbuf[tlen++] = '\0'; 433 } 434 (void) memmove((ptr_t) termcap_alloc, (ptr_t) termbuf, (size_t) TC_BUFSIZE); 435 tloc = tlen; 436 if (tloc + 3 >= TC_BUFSIZE) { 437 stderror(ERR_NAME | ERR_TCNOSTR); 438 return; 439 } 440 (void) strcpy(t->str = &termcap_alloc[tloc], cap); 441 tloc += clen + 1; /* one for \0 */ 442 return; 443 } 444 445 446 /*ARGSUSED*/ 447 void 448 TellTC(what) 449 char *what; 450 { 451 struct termcapstr *t; 452 453 USE(what); 454 xprintf(CGETS(7, 1, "\n\tTcsh thinks your terminal has the\n")); 455 xprintf(CGETS(7, 2, "\tfollowing characteristics:\n\n")); 456 xprintf(CGETS(7, 3, "\tIt has %d columns and %d lines\n"), 457 Val(T_co), Val(T_li)); 458 xprintf(CGETS(7, 4, "\tIt has %s meta key\n"), T_HasMeta ? 459 CGETS(7, 5, "a") : CGETS(7, 6, "no")); 460 xprintf(CGETS(7, 7, "\tIt can%s use tabs\n"), T_Tabs ? 461 "" : CGETS(7, 8, " not")); 462 xprintf(CGETS(7, 9, "\tIt %s automatic margins\n"), 463 (T_Margin&MARGIN_AUTO)? 464 CGETS(7, 10, "has"): 465 CGETS(7, 11, "does not have")); 466 if (T_Margin & MARGIN_AUTO) 467 xprintf(CGETS(7, 12, "\tIt %s magic margins\n"), 468 (T_Margin & MARGIN_MAGIC) ? 469 CGETS(7, 10, "has"): 470 CGETS(7, 11, "does not have")); 471 472 for (t = tstr; t->name != NULL; t++) 473 xprintf("\t%36s (%s) == %s\n", t->long_name, t->name, 474 t->str && *t->str ? t->str : CGETS(7, 13, "(empty)")); 475 xputchar('\n'); 476 } 477 478 479 static void 480 ReBufferDisplay() 481 { 482 register int i; 483 Char **b; 484 Char **bufp; 485 486 b = Display; 487 Display = NULL; 488 if (b != NULL) { 489 for (bufp = b; *bufp != NULL; bufp++) 490 xfree((ptr_t) * bufp); 491 xfree((ptr_t) b); 492 } 493 b = Vdisplay; 494 Vdisplay = NULL; 495 if (b != NULL) { 496 for (bufp = b; *bufp != NULL; bufp++) 497 xfree((ptr_t) * bufp); 498 xfree((ptr_t) b); 499 } 500 TermH = Val(T_co); 501 TermV = (INBUFSIZE * 4) / TermH + 1; 502 b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1))); 503 for (i = 0; i < TermV; i++) 504 b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1))); 505 b[TermV] = NULL; 506 Display = b; 507 b = (Char **) xmalloc((size_t) (sizeof(Char *) * (TermV + 1))); 508 for (i = 0; i < TermV; i++) 509 b[i] = (Char *) xmalloc((size_t) (sizeof(Char) * (TermH + 1))); 510 b[TermV] = NULL; 511 Vdisplay = b; 512 } 513 514 void 515 SetTC(what, how) 516 char *what, *how; 517 { 518 struct termcapstr *ts; 519 struct termcapval *tv; 520 521 /* 522 * Do the strings first 523 */ 524 setname("settc"); 525 for (ts = tstr; ts->name != NULL; ts++) 526 if (strcmp(ts->name, what) == 0) 527 break; 528 if (ts->name != NULL) { 529 TCalloc(ts, how); 530 /* 531 * Reset variables 532 */ 533 if (GoodStr(T_me) && GoodStr(T_ue)) 534 me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 535 else 536 me_all = 0; 537 if (GoodStr(T_me) && GoodStr(T_se)) 538 me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 539 540 T_CanCEOL = GoodStr(T_ce); 541 T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 542 T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 543 T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 544 return; 545 } 546 547 /* 548 * Do the numeric ones second 549 */ 550 for (tv = tval; tv->name != NULL; tv++) 551 if (strcmp(tv->name, what) == 0) 552 break; 553 554 if (tv->name != NULL) { 555 if (tv == &tval[T_pt] || tv == &tval[T_km] || 556 tv == &tval[T_am] || tv == &tval[T_xn]) { 557 if (strcmp(how, "yes") == 0) 558 tv->val = 1; 559 else if (strcmp(how, "no") == 0) 560 tv->val = 0; 561 else { 562 stderror(ERR_SETTCUS, tv->name); 563 return; 564 } 565 T_Tabs = (Char) Val(T_pt); 566 T_HasMeta = (Char) Val(T_km); 567 T_Margin = (Char) Val(T_am) ? MARGIN_AUTO : 0; 568 T_Margin |= (Char) Val(T_xn) ? MARGIN_MAGIC : 0; 569 if (tv == &tval[T_am] || tv == &tval[T_xn]) 570 ChangeSize(Val(T_li), Val(T_co)); 571 return; 572 } 573 else { 574 tv->val = atoi(how); 575 T_Cols = (Char) Val(T_co); 576 T_Lines = (Char) Val(T_li); 577 if (tv == &tval[T_co] || tv == &tval[T_li]) 578 ChangeSize(Val(T_li), Val(T_co)); 579 return; 580 } 581 } 582 stderror(ERR_NAME | ERR_TCCAP, what); 583 return; 584 } 585 586 587 /* 588 * Print the termcap string out with variable substitution 589 */ 590 void 591 EchoTC(v) 592 Char **v; 593 { 594 char *cap, *scap, cv[BUFSIZE]; 595 int arg_need, arg_cols, arg_rows; 596 int verbose = 0, silent = 0; 597 char *area; 598 static char *fmts = "%s\n", *fmtd = "%d\n"; 599 struct termcapstr *t; 600 char buf[TC_BUFSIZE]; 601 602 area = buf; 603 604 setname("echotc"); 605 606 tglob(v); 607 if (gflag) { 608 v = globall(v); 609 if (v == 0) 610 stderror(ERR_NAME | ERR_NOMATCH); 611 } 612 else 613 v = gargv = saveblk(v); 614 trim(v); 615 616 if (!*v || *v[0] == '\0') 617 return; 618 if (v[0][0] == '-') { 619 switch (v[0][1]) { 620 case 'v': 621 verbose = 1; 622 break; 623 case 's': 624 silent = 1; 625 break; 626 default: 627 stderror(ERR_NAME | ERR_TCUSAGE); 628 break; 629 } 630 v++; 631 } 632 if (!*v || *v[0] == '\0') 633 return; 634 (void) strcpy(cv, short2str(*v)); 635 if (strcmp(cv, "tabs") == 0) { 636 xprintf(fmts, T_Tabs ? CGETS(7, 14, "yes") : 637 CGETS(7, 15, "no")); 638 flush(); 639 return; 640 } 641 else if (strcmp(cv, "meta") == 0) { 642 xprintf(fmts, Val(T_km) ? CGETS(7, 14, "yes") : 643 CGETS(7, 15, "no")); 644 flush(); 645 return; 646 } 647 else if (strcmp(cv, "xn") == 0) { 648 xprintf(fmts, T_Margin & MARGIN_MAGIC ? CGETS(7, 14, "yes") : 649 CGETS(7, 15, "no")); 650 flush(); 651 return; 652 } 653 else if (strcmp(cv, "am") == 0) { 654 xprintf(fmts, T_Margin & MARGIN_AUTO ? CGETS(7, 14, "yes") : 655 CGETS(7, 15, "no")); 656 flush(); 657 return; 658 } 659 else if (strcmp(cv, "baud") == 0) { 660 int i; 661 662 for (i = 0; baud_rate[i].b_name != NULL; i++) 663 if (T_Speed == baud_rate[i].b_rate) { 664 xprintf(fmts, baud_rate[i].b_name); 665 flush(); 666 return; 667 } 668 xprintf(fmtd, 0); 669 flush(); 670 return; 671 } 672 else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0) { 673 xprintf(fmtd, Val(T_li)); 674 flush(); 675 return; 676 } 677 else if (strcmp(cv, "cols") == 0) { 678 xprintf(fmtd, Val(T_co)); 679 flush(); 680 return; 681 } 682 683 /* 684 * Try to use our local definition first 685 */ 686 scap = NULL; 687 for (t = tstr; t->name != NULL; t++) 688 if (strcmp(t->name, cv) == 0) { 689 scap = t->str; 690 break; 691 } 692 if (t->name == NULL) 693 scap = tgetstr(cv, &area); 694 if (!scap || scap[0] == '\0') { 695 if (tgetflag(cv)) { 696 xprintf(CGETS(7, 14, "yes\n")); 697 return; 698 } 699 if (silent) 700 return; 701 else 702 stderror(ERR_NAME | ERR_TCCAP, cv); 703 } 704 705 /* 706 * Count home many values we need for this capability. 707 */ 708 for (cap = scap, arg_need = 0; *cap; cap++) 709 if (*cap == '%') 710 switch (*++cap) { 711 case 'd': 712 case '2': 713 case '3': 714 case '.': 715 case '+': 716 arg_need++; 717 break; 718 case '%': 719 case '>': 720 case 'i': 721 case 'r': 722 case 'n': 723 case 'B': 724 case 'D': 725 break; 726 default: 727 /* 728 * hpux has lot's of them... 729 */ 730 if (verbose) 731 stderror(ERR_NAME | ERR_TCPARM, *cap); 732 /* This is bad, but I won't complain */ 733 break; 734 } 735 736 switch (arg_need) { 737 case 0: 738 v++; 739 if (*v && *v[0]) { 740 if (silent) 741 return; 742 else 743 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 744 } 745 (void) tputs(scap, 1, PUTRAW); 746 break; 747 case 1: 748 v++; 749 if (!*v || *v[0] == '\0') 750 stderror(ERR_NAME | ERR_TCNARGS, cv, 1); 751 arg_cols = 0; 752 arg_rows = atoi(short2str(*v)); 753 v++; 754 if (*v && *v[0]) { 755 if (silent) 756 return; 757 else 758 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 759 } 760 (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, PUTRAW); 761 break; 762 default: 763 /* This is wrong, but I will ignore it... */ 764 if (verbose) 765 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 766 /*FALLTHROUGH*/ 767 case 2: 768 v++; 769 if (!*v || *v[0] == '\0') { 770 if (silent) 771 return; 772 else 773 stderror(ERR_NAME | ERR_TCNARGS, cv, 2); 774 } 775 arg_cols = atoi(short2str(*v)); 776 v++; 777 if (!*v || *v[0] == '\0') { 778 if (silent) 779 return; 780 else 781 stderror(ERR_NAME | ERR_TCNARGS, cv, 2); 782 } 783 arg_rows = atoi(short2str(*v)); 784 v++; 785 if (*v && *v[0]) { 786 if (silent) 787 return; 788 else 789 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 790 } 791 (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, PUTRAW); 792 break; 793 } 794 flush(); 795 if (gargv) { 796 blkfree(gargv); 797 gargv = 0; 798 } 799 } 800 801 bool GotTermCaps = 0; 802 803 static struct { 804 Char *name; 805 int key; 806 XmapVal fun; 807 int type; 808 } arrow[] = { 809 #define A_K_DN 0 810 { STRdown, T_kd }, 811 #define A_K_UP 1 812 { STRup, T_ku }, 813 #define A_K_LT 2 814 { STRleft, T_kl }, 815 #define A_K_RT 3 816 { STRright, T_kr }, 817 #define A_K_HO 4 818 { STRhome, T_kh }, 819 #define A_K_EN 5 820 { STRend, T_at7} 821 }; 822 #define A_K_NKEYS 6 823 824 void 825 ResetArrowKeys() 826 { 827 arrow[A_K_DN].fun.cmd = F_DOWN_HIST; 828 arrow[A_K_DN].type = XK_CMD; 829 830 arrow[A_K_UP].fun.cmd = F_UP_HIST; 831 arrow[A_K_UP].type = XK_CMD; 832 833 arrow[A_K_LT].fun.cmd = F_CHARBACK; 834 arrow[A_K_LT].type = XK_CMD; 835 836 arrow[A_K_RT].fun.cmd = F_CHARFWD; 837 arrow[A_K_RT].type = XK_CMD; 838 839 arrow[A_K_HO].fun.cmd = F_TOBEG; 840 arrow[A_K_HO].type = XK_CMD; 841 842 arrow[A_K_EN].fun.cmd = F_TOEND; 843 arrow[A_K_EN].type = XK_CMD; 844 } 845 846 void 847 DefaultArrowKeys() 848 { 849 static Char strA[] = {033, '[', 'A', '\0'}; 850 static Char strB[] = {033, '[', 'B', '\0'}; 851 static Char strC[] = {033, '[', 'C', '\0'}; 852 static Char strD[] = {033, '[', 'D', '\0'}; 853 static Char strH[] = {033, '[', 'H', '\0'}; 854 static Char strF[] = {033, '[', 'F', '\0'}; 855 static Char stOA[] = {033, 'O', 'A', '\0'}; 856 static Char stOB[] = {033, 'O', 'B', '\0'}; 857 static Char stOC[] = {033, 'O', 'C', '\0'}; 858 static Char stOD[] = {033, 'O', 'D', '\0'}; 859 static Char stOH[] = {033, 'O', 'H', '\0'}; 860 static Char stOF[] = {033, 'O', 'F', '\0'}; 861 862 CStr cs; 863 #ifndef IS_ASCII 864 if (strA[0] == 033) 865 { 866 strA[0] = CTL_ESC('\033'); 867 strB[0] = CTL_ESC('\033'); 868 strC[0] = CTL_ESC('\033'); 869 strD[0] = CTL_ESC('\033'); 870 strH[0] = CTL_ESC('\033'); 871 strF[0] = CTL_ESC('\033'); 872 stOA[0] = CTL_ESC('\033'); 873 stOB[0] = CTL_ESC('\033'); 874 stOC[0] = CTL_ESC('\033'); 875 stOD[0] = CTL_ESC('\033'); 876 stOH[0] = CTL_ESC('\033'); 877 stOF[0] = CTL_ESC('\033'); 878 } 879 #endif 880 881 cs.len = 3; 882 883 cs.buf = strA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 884 cs.buf = strB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 885 cs.buf = strC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 886 cs.buf = strD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 887 cs.buf = strH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 888 cs.buf = strF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 889 cs.buf = stOA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 890 cs.buf = stOB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 891 cs.buf = stOC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 892 cs.buf = stOD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 893 cs.buf = stOH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 894 cs.buf = stOF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 895 896 if (VImode) { 897 cs.len = 2; 898 cs.buf = &strA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 899 cs.buf = &strB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 900 cs.buf = &strC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 901 cs.buf = &strD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 902 cs.buf = &strH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 903 cs.buf = &strF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 904 cs.buf = &stOA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 905 cs.buf = &stOB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 906 cs.buf = &stOC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 907 cs.buf = &stOD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 908 cs.buf = &stOH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 909 cs.buf = &stOF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 910 } 911 } 912 913 914 int 915 SetArrowKeys(name, fun, type) 916 CStr *name; 917 XmapVal *fun; 918 int type; 919 { 920 int i; 921 for (i = 0; i < A_K_NKEYS; i++) 922 if (Strcmp(name->buf, arrow[i].name) == 0) { 923 arrow[i].fun = *fun; 924 arrow[i].type = type; 925 return 0; 926 } 927 return -1; 928 } 929 930 int 931 IsArrowKey(name) 932 Char *name; 933 { 934 int i; 935 for (i = 0; i < A_K_NKEYS; i++) 936 if (Strcmp(name, arrow[i].name) == 0) 937 return 1; 938 return 0; 939 } 940 941 int 942 ClearArrowKeys(name) 943 CStr *name; 944 { 945 int i; 946 for (i = 0; i < A_K_NKEYS; i++) 947 if (Strcmp(name->buf, arrow[i].name) == 0) { 948 arrow[i].type = XK_NOD; 949 return 0; 950 } 951 return -1; 952 } 953 954 void 955 PrintArrowKeys(name) 956 CStr *name; 957 { 958 int i; 959 960 for (i = 0; i < A_K_NKEYS; i++) 961 if (name->len == 0 || Strcmp(name->buf, arrow[i].name) == 0) 962 if (arrow[i].type != XK_NOD) { 963 CStr cs; 964 cs.buf = arrow[i].name; 965 cs.len = Strlen(cs.buf); 966 (void) printOne(&cs, &arrow[i].fun, arrow[i].type); 967 } 968 } 969 970 971 void 972 BindArrowKeys() 973 { 974 KEYCMD *map, *dmap; 975 int i, j; 976 char *p; 977 CStr cs; 978 979 if (!GotTermCaps) 980 return; 981 map = VImode ? CcAltMap : CcKeyMap; 982 dmap = VImode ? CcViCmdMap : CcEmacsMap; 983 984 DefaultArrowKeys(); 985 986 for (i = 0; i < A_K_NKEYS; i++) { 987 p = tstr[arrow[i].key].str; 988 if (p && *p) { 989 j = (unsigned char) *p; 990 cs.buf = str2short(p); 991 cs.len = Strlen(cs.buf); 992 /* 993 * Assign the arrow keys only if: 994 * 995 * 1. They are multi-character arrow keys and the user 996 * has not re-assigned the leading character, or 997 * has re-assigned the leading character to be F_XKEY 998 * 2. They are single arrow keys pointing to an unassigned key. 999 */ 1000 if (arrow[i].type == XK_NOD) { 1001 ClearXkey(map, &cs); 1002 } 1003 else { 1004 if (p[1] && (dmap[j] == map[j] || map[j] == F_XKEY)) { 1005 AddXkey(&cs, &arrow[i].fun, arrow[i].type); 1006 map[j] = F_XKEY; 1007 } 1008 else if (map[j] == F_UNASSIGNED) { 1009 ClearXkey(map, &cs); 1010 if (arrow[i].type == XK_CMD) 1011 map[j] = arrow[i].fun.cmd; 1012 else 1013 AddXkey(&cs, &arrow[i].fun, arrow[i].type); 1014 } 1015 } 1016 } 1017 } 1018 } 1019 1020 static Char cur_atr = 0; /* current attributes */ 1021 1022 void 1023 SetAttributes(atr) 1024 int atr; 1025 { 1026 atr &= ATTRIBUTES; 1027 if (atr != cur_atr) { 1028 if (me_all && GoodStr(T_me)) { 1029 if (((cur_atr & BOLD) && !(atr & BOLD)) || 1030 ((cur_atr & UNDER) && !(atr & UNDER)) || 1031 ((cur_atr & STANDOUT) && !(atr & STANDOUT))) { 1032 (void) tputs(Str(T_me), 1, PUTPURE); 1033 cur_atr = 0; 1034 } 1035 } 1036 if ((atr & BOLD) != (cur_atr & BOLD)) { 1037 if (atr & BOLD) { 1038 if (GoodStr(T_md) && GoodStr(T_me)) { 1039 (void) tputs(Str(T_md), 1, PUTPURE); 1040 cur_atr |= BOLD; 1041 } 1042 } 1043 else { 1044 if (GoodStr(T_md) && GoodStr(T_me)) { 1045 (void) tputs(Str(T_me), 1, PUTPURE); 1046 if ((cur_atr & STANDOUT) && GoodStr(T_se)) { 1047 (void) tputs(Str(T_se), 1, PUTPURE); 1048 cur_atr &= ~STANDOUT; 1049 } 1050 if ((cur_atr & UNDER) && GoodStr(T_ue)) { 1051 (void) tputs(Str(T_ue), 1, PUTPURE); 1052 cur_atr &= ~UNDER; 1053 } 1054 cur_atr &= ~BOLD; 1055 } 1056 } 1057 } 1058 if ((atr & STANDOUT) != (cur_atr & STANDOUT)) { 1059 if (atr & STANDOUT) { 1060 if (GoodStr(T_so) && GoodStr(T_se)) { 1061 (void) tputs(Str(T_so), 1, PUTPURE); 1062 cur_atr |= STANDOUT; 1063 } 1064 } 1065 else { 1066 if (GoodStr(T_se)) { 1067 (void) tputs(Str(T_se), 1, PUTPURE); 1068 cur_atr &= ~STANDOUT; 1069 } 1070 } 1071 } 1072 if ((atr & UNDER) != (cur_atr & UNDER)) { 1073 if (atr & UNDER) { 1074 if (GoodStr(T_us) && GoodStr(T_ue)) { 1075 (void) tputs(Str(T_us), 1, PUTPURE); 1076 cur_atr |= UNDER; 1077 } 1078 } 1079 else { 1080 if (GoodStr(T_ue)) { 1081 (void) tputs(Str(T_ue), 1, PUTPURE); 1082 cur_atr &= ~UNDER; 1083 } 1084 } 1085 } 1086 } 1087 } 1088 1089 /* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */ 1090 int 1091 CanWeTab() 1092 { 1093 return (Val(T_pt)); 1094 } 1095 1096 void 1097 MoveToLine(where) /* move to line <where> (first line == 0) */ 1098 int where; /* as efficiently as possible; */ 1099 { 1100 int del; 1101 1102 if (where == CursorV) 1103 return; 1104 1105 if (where > TermV) { 1106 #ifdef DEBUG_SCREEN 1107 xprintf("MoveToLine: where is ridiculous: %d\r\n", where); 1108 flush(); 1109 #endif /* DEBUG_SCREEN */ 1110 return; 1111 } 1112 1113 del = where - CursorV; 1114 1115 if (del > 0) { 1116 while (del > 0) { 1117 if ((T_Margin & MARGIN_AUTO) && Display[CursorV][0] != '\0') { 1118 /* move without newline */ 1119 MoveToChar(TermH - 1); 1120 so_write(&Display[CursorV][CursorH], 1); /* updates CursorH/V*/ 1121 del--; 1122 } 1123 else { 1124 if ((del > 1) && GoodStr(T_DO)) { 1125 (void) tputs(tgoto(Str(T_DO), del, del), del, PUTPURE); 1126 del = 0; 1127 } 1128 else { 1129 for ( ; del > 0; del--) 1130 (void) putraw('\n'); 1131 CursorH = 0; /* because the \n will become \r\n */ 1132 } 1133 } 1134 } 1135 } 1136 else { /* del < 0 */ 1137 if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) 1138 (void) tputs(tgoto(Str(T_UP), -del, -del), -del, PUTPURE); 1139 else { 1140 int i; 1141 if (GoodStr(T_up)) 1142 for (i = 0; i < -del; i++) 1143 (void) tputs(Str(T_up), 1, PUTPURE); 1144 } 1145 } 1146 CursorV = where; /* now where is here */ 1147 } 1148 1149 void 1150 MoveToChar(where) /* move to character position (where) */ 1151 int where; 1152 { /* as efficiently as possible */ 1153 int del; 1154 1155 mc_again: 1156 if (where == CursorH) 1157 return; 1158 1159 if (where >= TermH) { 1160 #ifdef DEBUG_SCREEN 1161 xprintf("MoveToChar: where is riduculous: %d\r\n", where); 1162 flush(); 1163 #endif /* DEBUG_SCREEN */ 1164 return; 1165 } 1166 1167 if (!where) { /* if where is first column */ 1168 (void) putraw('\r'); /* do a CR */ 1169 CursorH = 0; 1170 return; 1171 } 1172 1173 del = where - CursorH; 1174 1175 if ((del < -4 || del > 4) && GoodStr(T_ch)) 1176 /* go there directly */ 1177 (void) tputs(tgoto(Str(T_ch), where, where), where, PUTPURE); 1178 else { 1179 int i; 1180 if (del > 0) { /* moving forward */ 1181 if ((del > 4) && GoodStr(T_RI)) 1182 (void) tputs(tgoto(Str(T_RI), del, del), del, PUTPURE); 1183 else { 1184 /* if I can do tabs, use them */ 1185 if (T_Tabs 1186 #ifdef DSPMBYTE 1187 && !_enable_mbdisp 1188 #endif /* DSPMBYTE */ 1189 ) { 1190 if ((CursorH & 0370) != (where & 0370)) { 1191 /* if not within tab stop */ 1192 for (i = (CursorH & 0370); i < (where & 0370); i += 8) 1193 (void) putraw('\t'); /* then tab over */ 1194 CursorH = where & 0370; 1195 /* Note: considering that we often want to go to 1196 TermH - 1 for the wrapping, it would be nice to 1197 optimize this case by tabbing to the last column 1198 - but this doesn't work for all terminals! */ 1199 } 1200 } 1201 /* it's usually cheaper to just write the chars, so we do. */ 1202 1203 /* NOTE THAT so_write() WILL CHANGE CursorH!!! */ 1204 so_write(&Display[CursorV][CursorH], where - CursorH); 1205 1206 } 1207 } 1208 else { /* del < 0 := moving backward */ 1209 if ((-del > 4) && GoodStr(T_LE)) 1210 (void) tputs(tgoto(Str(T_LE), -del, -del), -del, PUTPURE); 1211 else { /* can't go directly there */ 1212 /* if the "cost" is greater than the "cost" from col 0 */ 1213 if (T_Tabs ? (-del > ((where >> 3) + (where & 07))) 1214 : (-del > where)) { 1215 (void) putraw('\r'); /* do a CR */ 1216 CursorH = 0; 1217 goto mc_again; /* and try again */ 1218 } 1219 for (i = 0; i < -del; i++) 1220 (void) putraw('\b'); 1221 } 1222 } 1223 } 1224 CursorH = where; /* now where is here */ 1225 } 1226 1227 void 1228 so_write(cp, n) 1229 register Char *cp; 1230 register int n; 1231 { 1232 if (n <= 0) 1233 return; /* catch bugs */ 1234 1235 if (n > TermH) { 1236 #ifdef DEBUG_SCREEN 1237 xprintf("so_write: n is riduculous: %d\r\n", n); 1238 flush(); 1239 #endif /* DEBUG_SCREEN */ 1240 return; 1241 } 1242 1243 do { 1244 if (*cp & LITERAL) { 1245 extern Char *litptr[]; 1246 Char *d; 1247 1248 #ifdef DEBUG_LITERAL 1249 xprintf("so: litnum %d, litptr %x\r\n", 1250 *cp & CHAR, litptr[*cp & CHAR]); 1251 #endif /* DEBUG_LITERAL */ 1252 for (d = litptr[*cp++ & CHAR]; *d & LITERAL; d++) 1253 (void) putraw(*d & CHAR); 1254 (void) putraw(*d); 1255 1256 } 1257 else 1258 (void) putraw(*cp++); 1259 CursorH++; 1260 } while (--n); 1261 1262 if (CursorH >= TermH) { /* wrap? */ 1263 if (T_Margin & MARGIN_AUTO) { /* yes */ 1264 CursorH = 0; 1265 CursorV++; 1266 if (T_Margin & MARGIN_MAGIC) { 1267 /* force the wrap to avoid the "magic" situation */ 1268 Char c; 1269 if ((c = Display[CursorV][CursorH]) != '\0') 1270 so_write(&c, 1); 1271 else 1272 (void) putraw(' '); 1273 CursorH = 1; 1274 } 1275 } 1276 else /* no wrap, but cursor stays on screen */ 1277 CursorH = TermH - 1; 1278 } 1279 } 1280 1281 1282 void 1283 DeleteChars(num) /* deletes <num> characters */ 1284 int num; 1285 { 1286 if (num <= 0) 1287 return; 1288 1289 if (!T_CanDel) { 1290 #ifdef DEBUG_EDIT 1291 xprintf(CGETS(7, 16, "ERROR: cannot delete\r\n")); 1292 #endif /* DEBUG_EDIT */ 1293 flush(); 1294 return; 1295 } 1296 1297 if (num > TermH) { 1298 #ifdef DEBUG_SCREEN 1299 xprintf(CGETS(7, 17, "DeleteChars: num is riduculous: %d\r\n"), num); 1300 flush(); 1301 #endif /* DEBUG_SCREEN */ 1302 return; 1303 } 1304 1305 if (GoodStr(T_DC)) /* if I have multiple delete */ 1306 if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more expen. */ 1307 (void) tputs(tgoto(Str(T_DC), num, num), num, PUTPURE); 1308 return; 1309 } 1310 1311 if (GoodStr(T_dm)) /* if I have delete mode */ 1312 (void) tputs(Str(T_dm), 1, PUTPURE); 1313 1314 if (GoodStr(T_dc)) /* else do one at a time */ 1315 while (num--) 1316 (void) tputs(Str(T_dc), 1, PUTPURE); 1317 1318 if (GoodStr(T_ed)) /* if I have delete mode */ 1319 (void) tputs(Str(T_ed), 1, PUTPURE); 1320 } 1321 1322 void 1323 Insert_write(cp, num) /* Puts terminal in insert character mode, */ 1324 register Char *cp; 1325 register int num; /* or inserts num characters in the line */ 1326 { 1327 if (num <= 0) 1328 return; 1329 if (!T_CanIns) { 1330 #ifdef DEBUG_EDIT 1331 xprintf(CGETS(7, 18, "ERROR: cannot insert\r\n")); 1332 #endif /* DEBUG_EDIT */ 1333 flush(); 1334 return; 1335 } 1336 1337 if (num > TermH) { 1338 #ifdef DEBUG_SCREEN 1339 xprintf(CGETS(7, 19, "StartInsert: num is riduculous: %d\r\n"), num); 1340 flush(); 1341 #endif /* DEBUG_SCREEN */ 1342 return; 1343 } 1344 1345 if (GoodStr(T_IC)) /* if I have multiple insert */ 1346 if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expen. */ 1347 (void) tputs(tgoto(Str(T_IC), num, num), num, PUTPURE); 1348 so_write(cp, num); /* this updates CursorH/V */ 1349 return; 1350 } 1351 1352 if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ 1353 (void) tputs(Str(T_im), 1, PUTPURE); 1354 1355 CursorH += num; 1356 do 1357 (void) putraw(*cp++); 1358 while (--num); 1359 1360 if (GoodStr(T_ip)) /* have to make num chars insert */ 1361 (void) tputs(Str(T_ip), 1, PUTPURE); 1362 1363 (void) tputs(Str(T_ei), 1, PUTPURE); 1364 return; 1365 } 1366 1367 do { 1368 if (GoodStr(T_ic)) /* have to make num chars insert */ 1369 (void) tputs(Str(T_ic), 1, PUTPURE); /* insert a char */ 1370 1371 (void) putraw(*cp++); 1372 1373 CursorH++; 1374 1375 if (GoodStr(T_ip)) /* have to make num chars insert */ 1376 (void) tputs(Str(T_ip), 1, PUTPURE);/* pad the inserted char */ 1377 1378 } while (--num); 1379 1380 } 1381 1382 void 1383 ClearEOL(num) /* clear to end of line. There are num */ 1384 int num; /* characters to clear */ 1385 { 1386 register int i; 1387 1388 if (num <= 0) 1389 return; 1390 1391 if (T_CanCEOL && GoodStr(T_ce)) 1392 (void) tputs(Str(T_ce), 1, PUTPURE); 1393 else { 1394 for (i = 0; i < num; i++) 1395 (void) putraw(' '); 1396 CursorH += num; /* have written num spaces */ 1397 } 1398 } 1399 1400 void 1401 ClearScreen() 1402 { /* clear the whole screen and home */ 1403 if (GoodStr(T_cl)) 1404 /* send the clear screen code */ 1405 (void) tputs(Str(T_cl), Val(T_li), PUTPURE); 1406 else if (GoodStr(T_ho) && GoodStr(T_cd)) { 1407 (void) tputs(Str(T_ho), Val(T_li), PUTPURE); /* home */ 1408 /* clear to bottom of screen */ 1409 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1410 } 1411 else { 1412 (void) putraw('\r'); 1413 (void) putraw('\n'); 1414 } 1415 } 1416 1417 void 1418 SoundBeep() 1419 { /* produce a sound */ 1420 beep_cmd (); 1421 if (adrof(STRnobeep)) 1422 return; 1423 1424 if (GoodStr(T_vb) && adrof(STRvisiblebell)) 1425 (void) tputs(Str(T_vb), 1, PUTPURE); /* visible bell */ 1426 else if (GoodStr(T_bl)) 1427 /* what termcap says we should use */ 1428 (void) tputs(Str(T_bl), 1, PUTPURE); 1429 else 1430 (void) putraw(CTL_ESC('\007')); /* an ASCII bell; ^G */ 1431 } 1432 1433 void 1434 ClearToBottom() 1435 { /* clear to the bottom of the screen */ 1436 if (GoodStr(T_cd)) 1437 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1438 else if (GoodStr(T_ce)) 1439 (void) tputs(Str(T_ce), Val(T_li), PUTPURE); 1440 } 1441 1442 void 1443 GetTermCaps() 1444 { /* read in the needed terminal capabilites */ 1445 register int i; 1446 char *ptr; 1447 char buf[TC_BUFSIZE]; 1448 static char bp[TC_BUFSIZE]; 1449 char *area; 1450 struct termcapstr *t; 1451 1452 1453 #ifdef SIG_WINDOW 1454 # ifdef BSDSIGS 1455 sigmask_t omask; 1456 # endif /* BSDSIGS */ 1457 int lins, cols; 1458 1459 /* don't want to confuse things here */ 1460 # ifdef BSDSIGS 1461 omask = sigblock(sigmask(SIG_WINDOW)) & ~sigmask(SIG_WINDOW); 1462 # else /* BSDSIGS */ 1463 (void) sighold(SIG_WINDOW); 1464 # endif /* BSDSIGS */ 1465 #endif /* SIG_WINDOW */ 1466 area = buf; 1467 1468 GotTermCaps = 1; 1469 1470 setname("gettermcaps"); 1471 ptr = getenv("TERM"); 1472 1473 #ifdef apollo 1474 /* 1475 * If we are on a pad, we pretend that we are dumb. Otherwise the termcap 1476 * library will put us in a weird screen mode, thinking that we are going 1477 * to use curses 1478 */ 1479 if (isapad()) 1480 ptr = "dumb"; 1481 #endif /* apollo */ 1482 1483 if (!ptr || !ptr[0] || !strcmp(ptr, "wm") || !strcmp(ptr,"dmx")) 1484 ptr = "dumb"; 1485 1486 setzero(bp, TC_BUFSIZE); 1487 1488 i = tgetent(bp, ptr); 1489 if (i <= 0) { 1490 if (i == -1) { 1491 #if (SYSVREL == 0) || defined(IRIS3D) 1492 xprintf(CGETS(7, 20, "%s: Cannot open /etc/termcap.\n"), progname); 1493 } 1494 else if (i == 0) { 1495 #endif /* SYSVREL */ 1496 xprintf(CGETS(7, 21, 1497 "%s: No entry for terminal type \"%s\"\n"), progname, 1498 getenv("TERM")); 1499 } 1500 xprintf(CGETS(7, 22, "%s: using dumb terminal settings.\n"), progname); 1501 Val(T_co) = 80; /* do a dumb terminal */ 1502 Val(T_pt) = Val(T_km) = Val(T_li) = 0; 1503 for (t = tstr; t->name != NULL; t++) 1504 TCalloc(t, NULL); 1505 } 1506 else { 1507 /* Can we tab */ 1508 Val(T_pt) = tgetflag("pt") && !tgetflag("xt"); 1509 /* do we have a meta? */ 1510 Val(T_km) = (tgetflag("km") || tgetflag("MT")); 1511 Val(T_am) = tgetflag("am"); 1512 Val(T_xn) = tgetflag("xn"); 1513 Val(T_co) = tgetnum("co"); 1514 Val(T_li) = tgetnum("li"); 1515 for (t = tstr; t->name != NULL; t++) 1516 TCalloc(t, tgetstr(t->name, &area)); 1517 } 1518 if (Val(T_co) < 2) 1519 Val(T_co) = 80; /* just in case */ 1520 if (Val(T_li) < 1) 1521 Val(T_li) = 24; 1522 1523 T_Cols = (Char) Val(T_co); 1524 T_Lines = (Char) Val(T_li); 1525 if (T_Tabs) 1526 T_Tabs = (Char) Val(T_pt); 1527 T_HasMeta = (Char) Val(T_km); 1528 T_Margin = (Char) Val(T_am) ? MARGIN_AUTO : 0; 1529 T_Margin |= (Char) Val(T_xn) ? MARGIN_MAGIC : 0; 1530 T_CanCEOL = GoodStr(T_ce); 1531 T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 1532 T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 1533 T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 1534 if (GoodStr(T_me) && GoodStr(T_ue)) 1535 me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 1536 else 1537 me_all = 0; 1538 if (GoodStr(T_me) && GoodStr(T_se)) 1539 me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 1540 1541 1542 #ifdef DEBUG_SCREEN 1543 if (!T_CanUP) { 1544 xprintf(CGETS(7, 23, "%s: WARNING: Your terminal cannot move up.\n", 1545 progname)); 1546 xprintf(CGETS(7, 24, "Editing may be odd for long lines.\n")); 1547 } 1548 if (!T_CanCEOL) 1549 xprintf(CGETS(7, 25, "no clear EOL capability.\n")); 1550 if (!T_CanDel) 1551 xprintf(CGETS(7, 26, "no delete char capability.\n")); 1552 if (!T_CanIns) 1553 xprintf(CGETS(7, 27, "no insert char capability.\n")); 1554 #endif /* DEBUG_SCREEN */ 1555 1556 1557 1558 #ifdef SIG_WINDOW 1559 (void) GetSize(&lins, &cols); /* get the correct window size */ 1560 ChangeSize(lins, cols); 1561 1562 # ifdef BSDSIGS 1563 (void) sigsetmask(omask); /* can change it again */ 1564 # else /* BSDSIGS */ 1565 (void) sigrelse(SIG_WINDOW); 1566 # endif /* BSDSIGS */ 1567 #else /* SIG_WINDOW */ 1568 ChangeSize(Val(T_li), Val(T_co)); 1569 #endif /* SIG_WINDOW */ 1570 1571 BindArrowKeys(); 1572 } 1573 1574 #ifdef SIG_WINDOW 1575 /* GetSize(): 1576 * Return the new window size in lines and cols, and 1577 * true if the size was changed. This can fail if SHIN 1578 * is not a tty, but it will work in most cases. 1579 */ 1580 int 1581 GetSize(lins, cols) 1582 int *lins, *cols; 1583 { 1584 *cols = Val(T_co); 1585 *lins = Val(T_li); 1586 1587 #ifdef TIOCGWINSZ 1588 # define KNOWsize 1589 # ifndef lint 1590 { 1591 struct winsize ws; /* from 4.3 */ 1592 1593 if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) { 1594 if (ws.ws_col) 1595 *cols = ws.ws_col; 1596 if (ws.ws_row) 1597 *lins = ws.ws_row; 1598 } 1599 } 1600 # endif /* !lint */ 1601 #else /* TIOCGWINSZ */ 1602 # ifdef TIOCGSIZE 1603 # define KNOWsize 1604 { 1605 struct ttysize ts; /* from Sun */ 1606 1607 if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) { 1608 if (ts.ts_cols) 1609 *cols = ts.ts_cols; 1610 if (ts.ts_lines) 1611 *lins = ts.ts_lines; 1612 } 1613 } 1614 # endif /* TIOCGSIZE */ 1615 #endif /* TIOCGWINSZ */ 1616 1617 return (Val(T_co) != *cols || Val(T_li) != *lins); 1618 } 1619 1620 #endif /* SIGWINDOW */ 1621 1622 void 1623 ChangeSize(lins, cols) 1624 int lins, cols; 1625 { 1626 /* 1627 * Just in case 1628 */ 1629 Val(T_co) = (cols < 2) ? 80 : cols; 1630 Val(T_li) = (lins < 1) ? 24 : lins; 1631 1632 #ifdef KNOWsize 1633 /* 1634 * We want to affect the environment only when we have a valid 1635 * setup, not when we get bad settings. Consider the following scenario: 1636 * We just logged in, and we have not initialized the editor yet. 1637 * We reset termcap with tset, and not $TERMCAP has the right 1638 * terminal size. But since the editor is not initialized yet, and 1639 * the kernel's notion of the terminal size might be wrong we arrive 1640 * here with lines = columns = 0. If we reset the environment we lose 1641 * our only chance to get the window size right. 1642 */ 1643 if (Val(T_co) == cols && Val(T_li) == lins) { 1644 Char buf[10]; 1645 char *tptr; 1646 1647 if (getenv("COLUMNS")) { 1648 (void) Itoa(Val(T_co), buf, 0, 0); 1649 tsetenv(STRCOLUMNS, buf); 1650 } 1651 1652 if (getenv("LINES")) { 1653 (void) Itoa(Val(T_li), buf, 0, 0); 1654 tsetenv(STRLINES, buf); 1655 } 1656 1657 if ((tptr = getenv("TERMCAP")) != NULL) { 1658 /* Leave 64 characters slop in case we enlarge the termcap string */ 1659 Char termcap[1024+64], backup[1024+64], *ptr; 1660 int i; 1661 1662 ptr = str2short(tptr); 1663 (void) Strncpy(termcap, ptr, 1024); 1664 termcap[1023] = '\0'; 1665 1666 /* update termcap string; first do columns */ 1667 buf[0] = 'c'; 1668 buf[1] = 'o'; 1669 buf[2] = '#'; 1670 buf[3] = '\0'; 1671 if ((ptr = Strstr(termcap, buf)) == NULL) { 1672 (void) Strcpy(backup, termcap); 1673 } 1674 else { 1675 i = (int) (ptr - termcap + Strlen(buf)); 1676 (void) Strncpy(backup, termcap, (size_t) i); 1677 backup[i] = '\0'; 1678 (void) Itoa(Val(T_co), buf, 0, 0); 1679 (void) Strcat(backup + i, buf); 1680 ptr = Strchr(ptr, ':'); 1681 (void) Strcat(backup, ptr); 1682 } 1683 1684 /* now do lines */ 1685 buf[0] = 'l'; 1686 buf[1] = 'i'; 1687 buf[2] = '#'; 1688 buf[3] = '\0'; 1689 if ((ptr = Strstr(backup, buf)) == NULL) { 1690 (void) Strcpy(termcap, backup); 1691 } 1692 else { 1693 i = (int) (ptr - backup + Strlen(buf)); 1694 (void) Strncpy(termcap, backup, (size_t) i); 1695 termcap[i] = '\0'; 1696 (void) Itoa(Val(T_li), buf, 0, 0); 1697 (void) Strcat(termcap, buf); 1698 ptr = Strchr(ptr, ':'); 1699 (void) Strcat(termcap, ptr); 1700 } 1701 /* 1702 * Chop the termcap string at 1024 characters to avoid core-dumps 1703 * in the termcap routines 1704 */ 1705 termcap[1023] = '\0'; 1706 tsetenv(STRTERMCAP, termcap); 1707 } 1708 } 1709 #endif /* KNOWsize */ 1710 1711 ReBufferDisplay(); /* re-make display buffers */ 1712 ClearDisp(); 1713 } 1714