1 /* $Header: /src/pub/tcsh/ed.screen.c,v 3.49 2002/03/08 17:36:45 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.49 2002/03/08 17:36:45 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 #ifndef WINNT_NATIVE 1116 if (del > 0) { 1117 while (del > 0) { 1118 if ((T_Margin & MARGIN_AUTO) && Display[CursorV][0] != '\0') { 1119 /* move without newline */ 1120 MoveToChar(TermH - 1); 1121 so_write(&Display[CursorV][CursorH], 1); /* updates CursorH/V*/ 1122 del--; 1123 } 1124 else { 1125 if ((del > 1) && GoodStr(T_DO)) { 1126 (void) tputs(tgoto(Str(T_DO), del, del), del, PUTPURE); 1127 del = 0; 1128 } 1129 else { 1130 for ( ; del > 0; del--) 1131 (void) putraw('\n'); 1132 CursorH = 0; /* because the \n will become \r\n */ 1133 } 1134 } 1135 } 1136 } 1137 else { /* del < 0 */ 1138 if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) 1139 (void) tputs(tgoto(Str(T_UP), -del, -del), -del, PUTPURE); 1140 else { 1141 int i; 1142 if (GoodStr(T_up)) 1143 for (i = 0; i < -del; i++) 1144 (void) tputs(Str(T_up), 1, PUTPURE); 1145 } 1146 } 1147 #else /* WINNT_NATIVE */ 1148 NT_MoveToLineOrChar(del, 1); 1149 #endif /* !WINNT_NATIVE */ 1150 CursorV = where; /* now where is here */ 1151 } 1152 1153 void 1154 MoveToChar(where) /* move to character position (where) */ 1155 int where; 1156 { /* as efficiently as possible */ 1157 #ifndef WINNT_NATIVE 1158 int del; 1159 1160 mc_again: 1161 #endif /* WINNT_NATIVE */ 1162 if (where == CursorH) 1163 return; 1164 1165 if (where >= TermH) { 1166 #ifdef DEBUG_SCREEN 1167 xprintf("MoveToChar: where is riduculous: %d\r\n", where); 1168 flush(); 1169 #endif /* DEBUG_SCREEN */ 1170 return; 1171 } 1172 1173 if (!where) { /* if where is first column */ 1174 (void) putraw('\r'); /* do a CR */ 1175 CursorH = 0; 1176 return; 1177 } 1178 1179 #ifndef WINNT_NATIVE 1180 del = where - CursorH; 1181 1182 if ((del < -4 || del > 4) && GoodStr(T_ch)) 1183 /* go there directly */ 1184 (void) tputs(tgoto(Str(T_ch), where, where), where, PUTPURE); 1185 else { 1186 int i; 1187 if (del > 0) { /* moving forward */ 1188 if ((del > 4) && GoodStr(T_RI)) 1189 (void) tputs(tgoto(Str(T_RI), del, del), del, PUTPURE); 1190 else { 1191 /* if I can do tabs, use them */ 1192 if (T_Tabs 1193 #ifdef DSPMBYTE 1194 && !_enable_mbdisp 1195 #endif /* DSPMBYTE */ 1196 ) { 1197 if ((CursorH & 0370) != (where & 0370)) { 1198 /* if not within tab stop */ 1199 for (i = (CursorH & 0370); i < (where & 0370); i += 8) 1200 (void) putraw('\t'); /* then tab over */ 1201 CursorH = where & 0370; 1202 /* Note: considering that we often want to go to 1203 TermH - 1 for the wrapping, it would be nice to 1204 optimize this case by tabbing to the last column 1205 - but this doesn't work for all terminals! */ 1206 } 1207 } 1208 /* it's usually cheaper to just write the chars, so we do. */ 1209 1210 /* NOTE THAT so_write() WILL CHANGE CursorH!!! */ 1211 so_write(&Display[CursorV][CursorH], where - CursorH); 1212 1213 } 1214 } 1215 else { /* del < 0 := moving backward */ 1216 if ((-del > 4) && GoodStr(T_LE)) 1217 (void) tputs(tgoto(Str(T_LE), -del, -del), -del, PUTPURE); 1218 else { /* can't go directly there */ 1219 /* if the "cost" is greater than the "cost" from col 0 */ 1220 if (T_Tabs ? (-del > ((where >> 3) + (where & 07))) 1221 : (-del > where)) { 1222 (void) putraw('\r'); /* do a CR */ 1223 CursorH = 0; 1224 goto mc_again; /* and try again */ 1225 } 1226 for (i = 0; i < -del; i++) 1227 (void) putraw('\b'); 1228 } 1229 } 1230 } 1231 #else /* WINNT_NATIVE */ 1232 NT_MoveToLineOrChar(where, 0); 1233 #endif /* !WINNT_NATIVE */ 1234 CursorH = where; /* now where is here */ 1235 } 1236 1237 void 1238 so_write(cp, n) 1239 register Char *cp; 1240 register int n; 1241 { 1242 if (n <= 0) 1243 return; /* catch bugs */ 1244 1245 if (n > TermH) { 1246 #ifdef DEBUG_SCREEN 1247 xprintf("so_write: n is riduculous: %d\r\n", n); 1248 flush(); 1249 #endif /* DEBUG_SCREEN */ 1250 return; 1251 } 1252 1253 do { 1254 if (*cp & LITERAL) { 1255 extern Char *litptr[]; 1256 Char *d; 1257 1258 #ifdef DEBUG_LITERAL 1259 xprintf("so: litnum %d, litptr %x\r\n", 1260 *cp & CHAR, litptr[*cp & CHAR]); 1261 #endif /* DEBUG_LITERAL */ 1262 #if defined(WINNT_NATIVE) && !defined(COLOR_LS_F) 1263 { 1264 char buf[256], *ptr = &buf[0]; 1265 for (d = litptr[*cp++ & CHAR]; *d & LITERAL; d++) 1266 *ptr++ = (*d & CHAR); 1267 flush(); 1268 set_cons_attr(buf); 1269 } 1270 #else /* !WINNT_NATIVE || COLOR_LS_F */ 1271 for (d = litptr[*cp++ & CHAR]; *d & LITERAL; d++) 1272 (void) putraw(*d & CHAR); 1273 #endif /* WINNT_NATIVE && !COLOR_LS_F */ 1274 (void) putraw(*d); 1275 1276 } 1277 else 1278 (void) putraw(*cp++); 1279 CursorH++; 1280 } while (--n); 1281 1282 if (CursorH >= TermH) { /* wrap? */ 1283 if (T_Margin & MARGIN_AUTO) { /* yes */ 1284 CursorH = 0; 1285 CursorV++; 1286 if (T_Margin & MARGIN_MAGIC) { 1287 /* force the wrap to avoid the "magic" situation */ 1288 Char c; 1289 if ((c = Display[CursorV][CursorH]) != '\0') 1290 so_write(&c, 1); 1291 else 1292 (void) putraw(' '); 1293 CursorH = 1; 1294 } 1295 } 1296 else /* no wrap, but cursor stays on screen */ 1297 CursorH = TermH - 1; 1298 } 1299 } 1300 1301 1302 void 1303 DeleteChars(num) /* deletes <num> characters */ 1304 int num; 1305 { 1306 if (num <= 0) 1307 return; 1308 1309 if (!T_CanDel) { 1310 #ifdef DEBUG_EDIT 1311 xprintf(CGETS(7, 16, "ERROR: cannot delete\r\n")); 1312 #endif /* DEBUG_EDIT */ 1313 flush(); 1314 return; 1315 } 1316 1317 if (num > TermH) { 1318 #ifdef DEBUG_SCREEN 1319 xprintf(CGETS(7, 17, "DeleteChars: num is riduculous: %d\r\n"), num); 1320 flush(); 1321 #endif /* DEBUG_SCREEN */ 1322 return; 1323 } 1324 1325 if (GoodStr(T_DC)) /* if I have multiple delete */ 1326 if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more expen. */ 1327 (void) tputs(tgoto(Str(T_DC), num, num), num, PUTPURE); 1328 return; 1329 } 1330 1331 if (GoodStr(T_dm)) /* if I have delete mode */ 1332 (void) tputs(Str(T_dm), 1, PUTPURE); 1333 1334 if (GoodStr(T_dc)) /* else do one at a time */ 1335 while (num--) 1336 (void) tputs(Str(T_dc), 1, PUTPURE); 1337 1338 if (GoodStr(T_ed)) /* if I have delete mode */ 1339 (void) tputs(Str(T_ed), 1, PUTPURE); 1340 } 1341 1342 void 1343 Insert_write(cp, num) /* Puts terminal in insert character mode, */ 1344 register Char *cp; 1345 register int num; /* or inserts num characters in the line */ 1346 { 1347 if (num <= 0) 1348 return; 1349 if (!T_CanIns) { 1350 #ifdef DEBUG_EDIT 1351 xprintf(CGETS(7, 18, "ERROR: cannot insert\r\n")); 1352 #endif /* DEBUG_EDIT */ 1353 flush(); 1354 return; 1355 } 1356 1357 if (num > TermH) { 1358 #ifdef DEBUG_SCREEN 1359 xprintf(CGETS(7, 19, "StartInsert: num is riduculous: %d\r\n"), num); 1360 flush(); 1361 #endif /* DEBUG_SCREEN */ 1362 return; 1363 } 1364 1365 if (GoodStr(T_IC)) /* if I have multiple insert */ 1366 if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expen. */ 1367 (void) tputs(tgoto(Str(T_IC), num, num), num, PUTPURE); 1368 so_write(cp, num); /* this updates CursorH/V */ 1369 return; 1370 } 1371 1372 if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ 1373 (void) tputs(Str(T_im), 1, PUTPURE); 1374 1375 CursorH += num; 1376 do 1377 (void) putraw(*cp++); 1378 while (--num); 1379 1380 if (GoodStr(T_ip)) /* have to make num chars insert */ 1381 (void) tputs(Str(T_ip), 1, PUTPURE); 1382 1383 (void) tputs(Str(T_ei), 1, PUTPURE); 1384 return; 1385 } 1386 1387 do { 1388 if (GoodStr(T_ic)) /* have to make num chars insert */ 1389 (void) tputs(Str(T_ic), 1, PUTPURE); /* insert a char */ 1390 1391 (void) putraw(*cp++); 1392 1393 CursorH++; 1394 1395 if (GoodStr(T_ip)) /* have to make num chars insert */ 1396 (void) tputs(Str(T_ip), 1, PUTPURE);/* pad the inserted char */ 1397 1398 } while (--num); 1399 1400 } 1401 1402 void 1403 ClearEOL(num) /* clear to end of line. There are num */ 1404 int num; /* characters to clear */ 1405 { 1406 register int i; 1407 1408 if (num <= 0) 1409 return; 1410 1411 if (T_CanCEOL && GoodStr(T_ce)) 1412 (void) tputs(Str(T_ce), 1, PUTPURE); 1413 else { 1414 for (i = 0; i < num; i++) 1415 (void) putraw(' '); 1416 CursorH += num; /* have written num spaces */ 1417 } 1418 } 1419 1420 void 1421 ClearScreen() 1422 { /* clear the whole screen and home */ 1423 if (GoodStr(T_cl)) 1424 /* send the clear screen code */ 1425 (void) tputs(Str(T_cl), Val(T_li), PUTPURE); 1426 else if (GoodStr(T_ho) && GoodStr(T_cd)) { 1427 (void) tputs(Str(T_ho), Val(T_li), PUTPURE); /* home */ 1428 /* clear to bottom of screen */ 1429 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1430 } 1431 else { 1432 (void) putraw('\r'); 1433 (void) putraw('\n'); 1434 } 1435 } 1436 1437 void 1438 SoundBeep() 1439 { /* produce a sound */ 1440 beep_cmd (); 1441 if (adrof(STRnobeep)) 1442 return; 1443 1444 if (GoodStr(T_vb) && adrof(STRvisiblebell)) 1445 (void) tputs(Str(T_vb), 1, PUTPURE); /* visible bell */ 1446 else if (GoodStr(T_bl)) 1447 /* what termcap says we should use */ 1448 (void) tputs(Str(T_bl), 1, PUTPURE); 1449 else 1450 #ifndef WINNT_NATIVE 1451 (void) putraw(CTL_ESC('\007')); /* an ASCII bell; ^G */ 1452 #else /* WINNT_NATIVE */ 1453 MessageBeep(MB_ICONQUESTION); 1454 #endif /* !WINNT_NATIVE */ 1455 } 1456 1457 void 1458 ClearToBottom() 1459 { /* clear to the bottom of the screen */ 1460 if (GoodStr(T_cd)) 1461 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1462 else if (GoodStr(T_ce)) 1463 (void) tputs(Str(T_ce), Val(T_li), PUTPURE); 1464 } 1465 1466 void 1467 GetTermCaps() 1468 { /* read in the needed terminal capabilites */ 1469 register int i; 1470 char *ptr; 1471 char buf[TC_BUFSIZE]; 1472 static char bp[TC_BUFSIZE]; 1473 char *area; 1474 struct termcapstr *t; 1475 1476 1477 #ifdef SIG_WINDOW 1478 # ifdef BSDSIGS 1479 sigmask_t omask; 1480 # endif /* BSDSIGS */ 1481 int lins, cols; 1482 1483 /* don't want to confuse things here */ 1484 # ifdef BSDSIGS 1485 omask = sigblock(sigmask(SIG_WINDOW)) & ~sigmask(SIG_WINDOW); 1486 # else /* BSDSIGS */ 1487 (void) sighold(SIG_WINDOW); 1488 # endif /* BSDSIGS */ 1489 #endif /* SIG_WINDOW */ 1490 area = buf; 1491 1492 GotTermCaps = 1; 1493 1494 setname("gettermcaps"); 1495 ptr = getenv("TERM"); 1496 1497 #ifdef apollo 1498 /* 1499 * If we are on a pad, we pretend that we are dumb. Otherwise the termcap 1500 * library will put us in a weird screen mode, thinking that we are going 1501 * to use curses 1502 */ 1503 if (isapad()) 1504 ptr = "dumb"; 1505 #endif /* apollo */ 1506 1507 if (!ptr || !ptr[0] || !strcmp(ptr, "wm") || !strcmp(ptr,"dmx")) 1508 ptr = "dumb"; 1509 1510 setzero(bp, TC_BUFSIZE); 1511 1512 i = tgetent(bp, ptr); 1513 if (i <= 0) { 1514 if (i == -1) { 1515 #if (SYSVREL == 0) || defined(IRIS3D) 1516 xprintf(CGETS(7, 20, "%s: Cannot open /etc/termcap.\n"), progname); 1517 } 1518 else if (i == 0) { 1519 #endif /* SYSVREL */ 1520 xprintf(CGETS(7, 21, 1521 "%s: No entry for terminal type \"%s\"\n"), progname, 1522 getenv("TERM")); 1523 } 1524 xprintf(CGETS(7, 22, "%s: using dumb terminal settings.\n"), progname); 1525 Val(T_co) = 80; /* do a dumb terminal */ 1526 Val(T_pt) = Val(T_km) = Val(T_li) = 0; 1527 for (t = tstr; t->name != NULL; t++) 1528 TCalloc(t, NULL); 1529 } 1530 else { 1531 /* Can we tab */ 1532 Val(T_pt) = tgetflag("pt") && !tgetflag("xt"); 1533 /* do we have a meta? */ 1534 Val(T_km) = (tgetflag("km") || tgetflag("MT")); 1535 Val(T_am) = tgetflag("am"); 1536 Val(T_xn) = tgetflag("xn"); 1537 Val(T_co) = tgetnum("co"); 1538 Val(T_li) = tgetnum("li"); 1539 for (t = tstr; t->name != NULL; t++) 1540 TCalloc(t, tgetstr(t->name, &area)); 1541 } 1542 if (Val(T_co) < 2) 1543 Val(T_co) = 80; /* just in case */ 1544 if (Val(T_li) < 1) 1545 Val(T_li) = 24; 1546 1547 T_Cols = (Char) Val(T_co); 1548 T_Lines = (Char) Val(T_li); 1549 if (T_Tabs) 1550 T_Tabs = (Char) Val(T_pt); 1551 T_HasMeta = (Char) Val(T_km); 1552 T_Margin = (Char) Val(T_am) ? MARGIN_AUTO : 0; 1553 T_Margin |= (Char) Val(T_xn) ? MARGIN_MAGIC : 0; 1554 T_CanCEOL = GoodStr(T_ce); 1555 T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 1556 T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 1557 T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 1558 if (GoodStr(T_me) && GoodStr(T_ue)) 1559 me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 1560 else 1561 me_all = 0; 1562 if (GoodStr(T_me) && GoodStr(T_se)) 1563 me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 1564 1565 1566 #ifdef DEBUG_SCREEN 1567 if (!T_CanUP) { 1568 xprintf(CGETS(7, 23, "%s: WARNING: Your terminal cannot move up.\n", 1569 progname)); 1570 xprintf(CGETS(7, 24, "Editing may be odd for long lines.\n")); 1571 } 1572 if (!T_CanCEOL) 1573 xprintf(CGETS(7, 25, "no clear EOL capability.\n")); 1574 if (!T_CanDel) 1575 xprintf(CGETS(7, 26, "no delete char capability.\n")); 1576 if (!T_CanIns) 1577 xprintf(CGETS(7, 27, "no insert char capability.\n")); 1578 #endif /* DEBUG_SCREEN */ 1579 1580 1581 1582 #ifdef SIG_WINDOW 1583 (void) GetSize(&lins, &cols); /* get the correct window size */ 1584 ChangeSize(lins, cols); 1585 1586 # ifdef BSDSIGS 1587 (void) sigsetmask(omask); /* can change it again */ 1588 # else /* BSDSIGS */ 1589 (void) sigrelse(SIG_WINDOW); 1590 # endif /* BSDSIGS */ 1591 #else /* SIG_WINDOW */ 1592 ChangeSize(Val(T_li), Val(T_co)); 1593 #endif /* SIG_WINDOW */ 1594 1595 BindArrowKeys(); 1596 } 1597 1598 #ifdef SIG_WINDOW 1599 /* GetSize(): 1600 * Return the new window size in lines and cols, and 1601 * true if the size was changed. This can fail if SHIN 1602 * is not a tty, but it will work in most cases. 1603 */ 1604 int 1605 GetSize(lins, cols) 1606 int *lins, *cols; 1607 { 1608 *cols = Val(T_co); 1609 *lins = Val(T_li); 1610 1611 #ifdef TIOCGWINSZ 1612 # define KNOWsize 1613 # ifndef lint 1614 { 1615 struct winsize ws; /* from 4.3 */ 1616 1617 if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) { 1618 if (ws.ws_col) 1619 *cols = ws.ws_col; 1620 if (ws.ws_row) 1621 *lins = ws.ws_row; 1622 } 1623 } 1624 # endif /* !lint */ 1625 #else /* TIOCGWINSZ */ 1626 # ifdef TIOCGSIZE 1627 # define KNOWsize 1628 { 1629 struct ttysize ts; /* from Sun */ 1630 1631 if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) { 1632 if (ts.ts_cols) 1633 *cols = ts.ts_cols; 1634 if (ts.ts_lines) 1635 *lins = ts.ts_lines; 1636 } 1637 } 1638 # endif /* TIOCGSIZE */ 1639 #endif /* TIOCGWINSZ */ 1640 1641 return (Val(T_co) != *cols || Val(T_li) != *lins); 1642 } 1643 1644 #endif /* SIGWINDOW */ 1645 1646 void 1647 ChangeSize(lins, cols) 1648 int lins, cols; 1649 { 1650 /* 1651 * Just in case 1652 */ 1653 Val(T_co) = (cols < 2) ? 80 : cols; 1654 Val(T_li) = (lins < 1) ? 24 : lins; 1655 1656 #ifdef WINNT_NATIVE 1657 nt_set_size(lins,cols); 1658 #endif /* WINNT_NATIVE */ 1659 #ifdef KNOWsize 1660 /* 1661 * We want to affect the environment only when we have a valid 1662 * setup, not when we get bad settings. Consider the following scenario: 1663 * We just logged in, and we have not initialized the editor yet. 1664 * We reset termcap with tset, and not $TERMCAP has the right 1665 * terminal size. But since the editor is not initialized yet, and 1666 * the kernel's notion of the terminal size might be wrong we arrive 1667 * here with lines = columns = 0. If we reset the environment we lose 1668 * our only chance to get the window size right. 1669 */ 1670 if (Val(T_co) == cols && Val(T_li) == lins) { 1671 Char buf[10]; 1672 char *tptr; 1673 1674 if (getenv("COLUMNS")) { 1675 (void) Itoa(Val(T_co), buf, 0, 0); 1676 tsetenv(STRCOLUMNS, buf); 1677 } 1678 1679 if (getenv("LINES")) { 1680 (void) Itoa(Val(T_li), buf, 0, 0); 1681 tsetenv(STRLINES, buf); 1682 } 1683 1684 if ((tptr = getenv("TERMCAP")) != NULL) { 1685 /* Leave 64 characters slop in case we enlarge the termcap string */ 1686 Char termcap[1024+64], backup[1024+64], *ptr; 1687 int i; 1688 1689 ptr = str2short(tptr); 1690 (void) Strncpy(termcap, ptr, 1024); 1691 termcap[1023] = '\0'; 1692 1693 /* update termcap string; first do columns */ 1694 buf[0] = 'c'; 1695 buf[1] = 'o'; 1696 buf[2] = '#'; 1697 buf[3] = '\0'; 1698 if ((ptr = Strstr(termcap, buf)) == NULL) { 1699 (void) Strcpy(backup, termcap); 1700 } 1701 else { 1702 i = (int) (ptr - termcap + Strlen(buf)); 1703 (void) Strncpy(backup, termcap, (size_t) i); 1704 backup[i] = '\0'; 1705 (void) Itoa(Val(T_co), buf, 0, 0); 1706 (void) Strcat(backup + i, buf); 1707 ptr = Strchr(ptr, ':'); 1708 (void) Strcat(backup, ptr); 1709 } 1710 1711 /* now do lines */ 1712 buf[0] = 'l'; 1713 buf[1] = 'i'; 1714 buf[2] = '#'; 1715 buf[3] = '\0'; 1716 if ((ptr = Strstr(backup, buf)) == NULL) { 1717 (void) Strcpy(termcap, backup); 1718 } 1719 else { 1720 i = (int) (ptr - backup + Strlen(buf)); 1721 (void) Strncpy(termcap, backup, (size_t) i); 1722 termcap[i] = '\0'; 1723 (void) Itoa(Val(T_li), buf, 0, 0); 1724 (void) Strcat(termcap, buf); 1725 ptr = Strchr(ptr, ':'); 1726 (void) Strcat(termcap, ptr); 1727 } 1728 /* 1729 * Chop the termcap string at 1024 characters to avoid core-dumps 1730 * in the termcap routines 1731 */ 1732 termcap[1023] = '\0'; 1733 tsetenv(STRTERMCAP, termcap); 1734 } 1735 } 1736 #endif /* KNOWsize */ 1737 1738 ReBufferDisplay(); /* re-make display buffers */ 1739 ClearDisp(); 1740 } 1741