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