1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program (see the file COPYING); if not, write to the 18 * Free Software Foundation, Inc., 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 * 21 **************************************************************** 22 */ 23 24#include <sys/types.h> 25#include "config.h" 26#include "screen.h" 27#include "extern.h" 28 29#undef DEBUGG 30 31extern struct display *display, *displays; 32extern int real_uid, real_gid, eff_uid, eff_gid; 33extern struct term term[]; /* terminal capabilities */ 34extern struct NewWindow nwin_undef, nwin_default, nwin_options; 35extern int force_vt; 36extern int Z0width, Z1width; 37extern int hardstatusemu; 38#ifdef MAPKEYS 39extern struct action umtab[]; 40extern struct action mmtab[]; 41extern struct action dmtab[]; 42extern struct kmap_ext *kmap_exts; 43extern int kmap_extn; 44extern int DefaultEsc; 45#endif 46 47 48static void AddCap __P((char *)); 49static void MakeString __P((char *, char *, int, char *)); 50static char *findcap __P((char *, char **, int)); 51static int copyarg __P((char **, char *)); 52static int e_tgetent __P((char *, char *)); 53static char *e_tgetstr __P((char *, char **)); 54static int e_tgetflag __P((char *)); 55static int e_tgetnum __P((char *)); 56#ifdef MAPKEYS 57static int findseq_ge __P((char *, int, unsigned char **)); 58static void setseqoff __P((unsigned char *, int, int)); 59static int addmapseq __P((char *, int, int)); 60static int remmapseq __P((char *, int)); 61#ifdef DEBUGG 62static void dumpmap __P((void)); 63#endif 64#endif 65 66 67char Termcap[TERMCAP_BUFSIZE + 8]; /* new termcap +8:"TERMCAP=" */ 68static int Termcaplen; 69static int tcLineLen; 70char Term[MAXSTR+5]; /* +5: "TERM=" */ 71char screenterm[20]; /* new $TERM, usually "screen" */ 72 73char *extra_incap, *extra_outcap; 74 75static const char TermcapConst[] = "\\\n\ 76\t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\ 77\t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\ 78\t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\ 79\t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:"; 80 81char * 82gettermcapstring(s) 83char *s; 84{ 85 int i; 86 87 if (display == 0 || s == 0) 88 return 0; 89 for (i = 0; i < T_N; i++) 90 { 91 if (term[i].type != T_STR) 92 continue; 93 if (strcmp(term[i].tcname, s) == 0) 94 return D_tcs[i].str; 95 } 96 return 0; 97} 98 99/* 100 * Compile the terminal capabilities for a display. 101 * Input: tgetent(, D_termname) extra_incap, extra_outcap. 102 * Effect: display initialisation. 103 */ 104int 105InitTermcap(wi, he) 106int wi; 107int he; 108{ 109 register char *s; 110 int i; 111 char tbuf[TERMCAP_BUFSIZE], *tp; 112 int t, xue, xse, xme; 113 114 ASSERT(display); 115 bzero(tbuf, sizeof(tbuf)); 116 debug1("InitTermcap: looking for tgetent('%s')\n", D_termname); 117 if (*D_termname == 0 || e_tgetent(tbuf, D_termname) != 1) 118 { 119#ifdef TERMINFO 120 Msg(0, "Cannot find terminfo entry for '%s'.", D_termname); 121#else 122 Msg(0, "Cannot find termcap entry for '%s'.", D_termname); 123#endif 124 return -1; 125 } 126 debug1("got it:\n%s\n", tbuf); 127#ifdef DEBUG 128 if (extra_incap) 129 debug1("Extra incap: %s\n", extra_incap); 130 if (extra_outcap) 131 debug1("Extra outcap: %s\n", extra_outcap); 132#endif 133 134 if ((D_tentry = (char *)malloc(TERMCAP_BUFSIZE + (extra_incap ? strlen(extra_incap) + 1 : 0))) == 0) 135 { 136 Msg(0, strnomem); 137 return -1; 138 } 139 140 /* 141 * loop through all needed capabilities, record their values in the display 142 */ 143 tp = D_tentry; 144 for (i = 0; i < T_N; i++) 145 { 146 switch(term[i].type) 147 { 148 case T_FLG: 149 D_tcs[i].flg = e_tgetflag(term[i].tcname); 150 break; 151 case T_NUM: 152 D_tcs[i].num = e_tgetnum(term[i].tcname); 153 break; 154 case T_STR: 155 D_tcs[i].str = e_tgetstr(term[i].tcname, &tp); 156 /* no empty strings, please */ 157 if (D_tcs[i].str && *D_tcs[i].str == 0) 158 D_tcs[i].str = 0; 159 break; 160 default: 161 Panic(0, "Illegal tc type in entry #%d", i); 162 /*NOTREACHED*/ 163 } 164 } 165 166 /* 167 * Now a good deal of sanity checks on the retrieved capabilities. 168 */ 169 if (D_HC) 170 { 171 Msg(0, "You can't run screen on a hardcopy terminal."); 172 return -1; 173 } 174 if (D_OS) 175 { 176 Msg(0, "You can't run screen on a terminal that overstrikes."); 177 return -1; 178 } 179 if (!D_CL) 180 { 181 Msg(0, "Clear screen capability required."); 182 return -1; 183 } 184 if (!D_CM) 185 { 186 Msg(0, "Addressable cursor capability required."); 187 return -1; 188 } 189 if ((s = getenv("COLUMNS")) && (i = atoi(s)) > 0) 190 D_CO = i; 191 if ((s = getenv("LINES")) && (i = atoi(s)) > 0) 192 D_LI = i; 193 if (wi) 194 D_CO = wi; 195 if (he) 196 D_LI = he; 197 if (D_CO <= 0) 198 D_CO = 80; 199 if (D_LI <= 0) 200 D_LI = 24; 201 202 if (D_CTF) 203 { 204 /* standard fixes for xterms etc */ 205 /* assume color for everything that looks ansi-compatible */ 206 if (!D_CAF && D_ME && (InStr(D_ME, "\033[m") || InStr(D_ME, "\033[0m"))) 207 { 208#ifdef TERMINFO 209 D_CAF = "\033[3%p1%dm"; 210 D_CAB = "\033[4%p1%dm"; 211#else 212 D_CAF = "\033[3%dm"; 213 D_CAB = "\033[4%dm"; 214#endif 215 } 216 if (D_OP && InStr(D_OP, "\033[39;49m")) 217 D_CAX = 1; 218 if (D_OP && (InStr(D_OP, "\033[m") || InStr(D_OP, "\033[0m"))) 219 D_OP = 0; 220 /* ISO2022 */ 221 if ((D_EA && InStr(D_EA, "\033(B")) || (D_AS && InStr(D_AS, "\033(0"))) 222 D_CG0 = 1; 223 if (InStr(D_termname, "xterm") || InStr(D_termname, "rxvt")) 224 D_CXT = 1; 225 /* "be" seems to be standard for xterms... */ 226 if (D_CXT) 227 D_BE = 1; 228 } 229 if (nwin_options.flowflag == nwin_undef.flowflag) 230 nwin_default.flowflag = D_CNF ? FLOW_NOW * 0 : 231 D_NX ? FLOW_NOW * 1 : 232 FLOW_AUTOFLAG; 233 D_CLP |= (!D_AM || D_XV || D_XN); 234 if (!D_BL) 235 D_BL = "\007"; 236 if (!D_BC) 237 { 238 if (D_BS) 239 D_BC = "\b"; 240 else 241 D_BC = D_LE; 242 } 243 if (!D_CR) 244 D_CR = "\r"; 245 if (!D_NL) 246 D_NL = "\n"; 247 248 /* 249 * Set up attribute handling. 250 * This is rather complicated because termcap has different 251 * attribute groups. 252 */ 253 254 if (D_UG > 0) 255 D_US = D_UE = 0; 256 if (D_SG > 0) 257 D_SO = D_SE = 0; 258 /* Unfortunatelly there is no 'mg' capability. 259 * For now we think that mg > 0 if sg and ug > 0. 260 */ 261 if (D_UG > 0 && D_SG > 0) 262 D_MH = D_MD = D_MR = D_MB = D_ME = 0; 263 264 xue = ATYP_U; 265 xse = ATYP_S; 266 xme = ATYP_M; 267 268 if (D_SO && D_SE == 0) 269 { 270 Msg(0, "Warning: 'so' but no 'se' capability."); 271 if (D_ME) 272 xse = xme; 273 else 274 D_SO = 0; 275 } 276 if (D_US && D_UE == 0) 277 { 278 Msg(0, "Warning: 'us' but no 'ue' capability."); 279 if (D_ME) 280 xue = xme; 281 else 282 D_US = 0; 283 } 284 if ((D_MH || D_MD || D_MR || D_MB) && D_ME == 0) 285 { 286 Msg(0, "Warning: 'm?' but no 'me' capability."); 287 D_MH = D_MD = D_MR = D_MB = 0; 288 } 289 /* 290 * Does ME also reverse the effect of SO and/or US? This is not 291 * clearly specified by the termcap manual. Anyway, we should at 292 * least look whether ME and SE/UE are equal: 293 */ 294 if (D_UE && D_SE && strcmp(D_SE, D_UE) == 0) 295 xse = xue; 296 if (D_SE && D_ME && strcmp(D_ME, D_SE) == 0) 297 xse = xme; 298 if (D_UE && D_ME && strcmp(D_ME, D_UE) == 0) 299 xue = xme; 300 301 for (i = 0; i < NATTR; i++) 302 { 303 D_attrtab[i] = D_tcs[T_ATTR + i].str; 304 D_attrtyp[i] = i == ATTR_SO ? xse : (i == ATTR_US ? xue : xme); 305 } 306 307 /* Set up missing entries (attributes are priority ordered) */ 308 s = 0; 309 t = 0; 310 for (i = 0; i < NATTR; i++) 311 if ((s = D_attrtab[i])) 312 { 313 t = D_attrtyp[i]; 314 break; 315 } 316 for (i = 0; i < NATTR; i++) 317 { 318 if (D_attrtab[i] == 0) 319 { 320 D_attrtab[i] = s; 321 D_attrtyp[i] = t; 322 } 323 else 324 { 325 s = D_attrtab[i]; 326 t = D_attrtyp[i]; 327 } 328 } 329 if (D_CAF || D_CAB || D_CSF || D_CSB) 330 D_hascolor = 1; 331 if (D_UT) 332 D_BE = 1; /* screen erased with background color */ 333 334 if (!D_DO) 335 D_DO = D_NL; 336 if (!D_SF) 337 D_SF = D_NL; 338 if (D_IN) 339 D_IC = D_IM = 0; 340 if (D_EI == 0) 341 D_IM = 0; 342 /* some strange termcap entries have IC == IM */ 343 if (D_IC && D_IM && strcmp(D_IC, D_IM) == 0) 344 D_IC = 0; 345 if (D_KE == 0) 346 D_KS = 0; 347 if (D_CVN == 0) 348 D_CVR = 0; 349 if (D_VE == 0) 350 D_VI = D_VS = 0; 351 if (D_CCE == 0) 352 D_CCS = 0; 353 354#ifdef FONT 355 if (D_CG0) 356 { 357 if (D_CS0 == 0) 358#ifdef TERMINFO 359 D_CS0 = "\033(%p1%c"; 360#else 361 D_CS0 = "\033(%."; 362#endif 363 if (D_CE0 == 0) 364 D_CE0 = "\033(B"; 365 D_AC = 0; 366 D_EA = 0; 367 } 368 else if (D_AC || (D_AS && D_AE)) /* some kind of graphics */ 369 { 370 D_CS0 = (D_AS && D_AE) ? D_AS : ""; 371 D_CE0 = (D_AS && D_AE) ? D_AE : ""; 372 D_CC0 = D_AC; 373 } 374 else 375 { 376 D_CS0 = D_CE0 = ""; 377 D_CC0 = 0; 378 D_AC = ""; /* enable default string */ 379 } 380 381 for (i = 0; i < 256; i++) 382 D_c0_tab[i] = i; 383 if (D_AC) 384 { 385 /* init with default string first */ 386 s = "l+m+k+j+u+t+v+w+q-x|n+o~s_p\"r#`+a:f'g#~o.v-^+<,>h#I#0#y<z>"; 387 for (i = strlen(s) & ~1; i >= 0; i -= 2) 388 D_c0_tab[(int)(unsigned char)s[i]] = s[i + 1]; 389 } 390 if (D_CC0) 391 for (i = strlen(D_CC0) & ~1; i >= 0; i -= 2) 392 D_c0_tab[(int)(unsigned char)D_CC0[i]] = D_CC0[i + 1]; 393 debug1("ISO2022 = %d\n", D_CG0); 394#endif /* FONT */ 395 if (D_PF == 0) 396 D_PO = 0; 397 debug2("terminal size is %d, %d (says TERMCAP)\n", D_CO, D_LI); 398 399#ifdef FONT 400 if (D_CXC) 401 if (CreateTransTable(D_CXC)) 402 return -1; 403#endif 404 405 /* Termcap fields Z0 & Z1 contain width-changing sequences. */ 406 if (D_CZ1 == 0) 407 D_CZ0 = 0; 408 Z0width = 132; 409 Z1width = 80; 410 411 CheckScreenSize(0); 412 413 if (D_TS == 0 || D_FS == 0 || D_DS == 0) 414 D_HS = 0; 415 if (D_HS) 416 { 417 debug("oy! we have a hardware status line, says termcap\n"); 418 if (D_WS < 0) 419 D_WS = 0; 420 } 421 D_has_hstatus = hardstatusemu & ~HSTATUS_ALWAYS; 422 if (D_HS && !(hardstatusemu & HSTATUS_ALWAYS)) 423 D_has_hstatus = HSTATUS_HS; 424 425#ifdef ENCODINGS 426 if (D_CKJ) 427 { 428 int enc = FindEncoding(D_CKJ); 429 if (enc != -1) 430 D_encoding = enc; 431 } 432#endif 433 if (!D_tcs[T_NAVIGATE].str && D_tcs[T_NAVIGATE + 1].str) 434 D_tcs[T_NAVIGATE].str = D_tcs[T_NAVIGATE + 1].str; /* kh = @1 */ 435 if (!D_tcs[T_NAVIGATE + 2].str && D_tcs[T_NAVIGATE + 3].str) 436 D_tcs[T_NAVIGATE + 2].str = D_tcs[T_NAVIGATE + 3].str; /* kH = @7 */ 437 438 D_UPcost = CalcCost(D_UP); 439 D_DOcost = CalcCost(D_DO); 440 D_NLcost = CalcCost(D_NL); 441 D_LEcost = CalcCost(D_BC); 442 D_NDcost = CalcCost(D_ND); 443 D_CRcost = CalcCost(D_CR); 444 D_IMcost = CalcCost(D_IM); 445 D_EIcost = CalcCost(D_EI); 446 447#ifdef AUTO_NUKE 448 if (D_CAN) 449 { 450 debug("termcap has AN, setting autonuke\n"); 451 D_auto_nuke = 1; 452 } 453#endif 454 if (D_COL > 0) 455 { 456 debug1("termcap has OL (%d), setting limit\n", D_COL); 457 D_obufmax = D_COL; 458 D_obuflenmax = D_obuflen - D_obufmax; 459 } 460 461 /* Some xterm entries set F0 and F10 to the same string. Nuke F0. */ 462 if (D_tcs[T_CAPS].str && D_tcs[T_CAPS + 10].str && !strcmp(D_tcs[T_CAPS].str, D_tcs[T_CAPS + 10].str)) 463 D_tcs[T_CAPS].str = 0; 464 /* Some xterm entries set kD to ^?. Nuke it. */ 465 if (D_tcs[T_NAVIGATE_DELETE].str && !strcmp(D_tcs[T_NAVIGATE_DELETE].str, "\0177")) 466 D_tcs[T_NAVIGATE_DELETE].str = 0; 467 /* wyse52 entries have kcub1 == kb == ^H. Nuke... */ 468 if (D_tcs[T_CURSOR + 3].str && !strcmp(D_tcs[T_CURSOR + 3].str, "\008")) 469 D_tcs[T_CURSOR + 3].str = 0; 470 471#ifdef MAPKEYS 472 D_nseqs = 0; 473 for (i = 0; i < T_OCAPS - T_CAPS; i++) 474 remap(i, 1); 475 for (i = 0; i < kmap_extn; i++) 476 remap(i + (KMAP_KEYS+KMAP_AKEYS), 1); 477 D_seqp = D_kmaps + 3; 478 D_seql = 0; 479 D_seqh = 0; 480#endif 481 482 D_tcinited = 1; 483 MakeTermcap(0); 484#ifdef MAPKEYS 485 CheckEscape(); 486#endif 487 return 0; 488} 489 490#ifdef MAPKEYS 491 492int 493remap(n, map) 494int n; 495int map; 496{ 497 char *s = 0; 498 int fl = 0, domap = 0; 499 struct action *a1, *a2, *tab; 500 int l = 0; 501 struct kmap_ext *kme = 0; 502 503 a1 = 0; 504 if (n >= KMAP_KEYS+KMAP_AKEYS) 505 { 506 kme = kmap_exts + (n - (KMAP_KEYS+KMAP_AKEYS)); 507 s = kme->str; 508 l = kme->fl & ~KMAP_NOTIMEOUT; 509 fl = kme->fl & KMAP_NOTIMEOUT; 510 a1 = &kme->um; 511 } 512 tab = umtab; 513 for (;;) 514 { 515 a2 = 0; 516 if (n < KMAP_KEYS+KMAP_AKEYS) 517 { 518 a1 = &tab[n]; 519 if (n >= KMAP_KEYS) 520 n -= T_OCAPS-T_CURSOR; 521 s = D_tcs[n + T_CAPS].str; 522 l = s ? strlen(s) : 0; 523 if (n >= T_CURSOR-T_CAPS) 524 a2 = &tab[n + (T_OCAPS-T_CURSOR)]; 525 } 526 if (s == 0 || l == 0) 527 return 0; 528 if (a1 && a1->nr == RC_ILLEGAL) 529 a1 = 0; 530 if (a2 && a2->nr == RC_ILLEGAL) 531 a2 = 0; 532 if (a1 && a1->nr == RC_STUFF && strcmp(a1->args[0], s) == 0) 533 a1 = 0; 534 if (a2 && a2->nr == RC_STUFF && strcmp(a2->args[0], s) == 0) 535 a2 = 0; 536 domap |= (a1 || a2); 537 if (tab == umtab) 538 { 539 tab = dmtab; 540 a1 = kme ? &kme->dm : 0; 541 } 542 else if (tab == dmtab) 543 { 544 tab = mmtab; 545 a1 = kme ? &kme->mm : 0; 546 } 547 else 548 break; 549 } 550 551 if (map == 0 && domap) 552 return 0; 553 if (map && !domap) 554 return 0; 555 debug3("%smapping %s %#x\n", map? "" :"un",s,n); 556 if (map) 557 return addmapseq(s, l, n | fl); 558 else 559 return remmapseq(s, l); 560} 561 562void 563CheckEscape() 564{ 565 struct display *odisplay; 566 int i, nr; 567 568 if (DefaultEsc >= 0) 569 return; 570 571 odisplay = display; 572 for (display = displays; display; display = display->d_next) 573 { 574 for (i = 0; i < D_nseqs; i += D_kmaps[i + 2] * 2 + 4) 575 { 576 nr = (D_kmaps[i] << 8 | D_kmaps[i + 1]) & ~KMAP_NOTIMEOUT; 577 if (nr < KMAP_KEYS+KMAP_AKEYS) 578 { 579 if (umtab[nr].nr == RC_COMMAND) 580 break; 581 if (umtab[nr].nr == RC_ILLEGAL && dmtab[nr].nr == RC_COMMAND) 582 break; 583 } 584 else 585 { 586 struct kmap_ext *kme = kmap_exts + nr - (KMAP_KEYS+KMAP_AKEYS); 587 if (kme->um.nr == RC_COMMAND) 588 break; 589 if (kme->um.nr == RC_ILLEGAL && kme->dm.nr == RC_COMMAND) 590 break; 591 } 592 } 593 } 594 if (display == 0) 595 { 596 display = odisplay; 597 return; 598 } 599 SetEscape((struct acluser *)0, Ctrl('a'), 'a'); 600 if (odisplay->d_user->u_Esc == -1) 601 odisplay->d_user->u_Esc = DefaultEsc; 602 if (odisplay->d_user->u_MetaEsc == -1) 603 odisplay->d_user->u_MetaEsc = DefaultMetaEsc; 604 display = 0; 605 Msg(0, "Warning: escape char set back to ^A"); 606 display = odisplay; 607} 608 609static int 610findseq_ge(seq, k, sp) 611char *seq; 612int k; 613unsigned char **sp; 614{ 615 unsigned char *p; 616 int j, l; 617 618 p = D_kmaps; 619 while (p - D_kmaps < D_nseqs) 620 { 621 l = p[2]; 622 p += 3; 623 for (j = 0; ; j++) 624 { 625 if (j == k || j == l) 626 j = l - k; 627 else if (p[j] != ((unsigned char *)seq)[j]) 628 j = p[j] - ((unsigned char *)seq)[j]; 629 else 630 continue; 631 break; 632 } 633 if (j >= 0) 634 { 635 *sp = p - 3; 636 return j; 637 } 638 p += 2 * l + 1; 639 } 640 *sp = p; 641 return -1; 642} 643 644static void 645setseqoff(p, i, o) 646unsigned char *p; 647int i; 648int o; 649{ 650 unsigned char *q; 651 int l, k; 652 653 k = p[2]; 654 if (o < 256) 655 { 656 p[k + 4 + i] = o; 657 return; 658 } 659 /* go for the biggest offset */ 660 for (q = p + k * 2 + 4; ; q += l * 2 + 4) 661 { 662 l = q[2]; 663 if ((q + l * 2 - p) / 2 >= 256) 664 { 665 p[k + 4 + i] = (q - p - 4) / 2; 666 return; 667 } 668 } 669} 670 671static int 672addmapseq(seq, k, nr) 673char *seq; 674int k; 675int nr; 676{ 677 int i, j, l, mo, m; 678 unsigned char *p, *q; 679 680 if (k >= 254) 681 return -1; 682 j = findseq_ge(seq, k, &p); 683 if (j == 0) 684 { 685 p[0] = nr >> 8; 686 p[1] = nr; 687 return 0; 688 } 689 i = p - D_kmaps; 690 if (D_nseqs + 2 * k + 4 >= D_aseqs) 691 { 692 D_kmaps = (unsigned char *)xrealloc((char *)D_kmaps, D_aseqs + 256); 693 D_aseqs += 256; 694 p = D_kmaps + i; 695 } 696 D_seqp = D_kmaps + 3; 697 D_seql = 0; 698 D_seqh = 0; 699 evdeq(&D_mapev); 700 if (j > 0) 701 bcopy((char *)p, (char *)p + 2 * k + 4, D_nseqs - i); 702 p[0] = nr >> 8; 703 p[1] = nr; 704 p[2] = k; 705 bcopy(seq, (char *)p + 3, k); 706 bzero(p + k + 3, k + 1); 707 D_nseqs += 2 * k + 4; 708 if (j > 0) 709 { 710 q = p + 2 * k + 4; 711 l = q[2]; 712 for (i = 0; i < k; i++) 713 { 714 if (p[3 + i] != q[3 + i]) 715 { 716 p[k + 4 + i] = k; 717 break; 718 } 719 setseqoff(p, i, q[l + 4 + i] ? q[l + 4 + i] + k + 2: 0); 720 } 721 } 722 for (q = D_kmaps; q < p; q += 2 * l + 4) 723 { 724 l = q[2]; 725 for (m = j = 0; j < l; j++) 726 { 727 mo = m; 728 if (!m && q[3 + j] != seq[j]) 729 m = 1; 730 if (q[l + 4 + j] == 0) 731 { 732 if (!mo && m) 733 setseqoff(q, j, (p - q - 4) / 2); 734 } 735 else if (q + q[l + 4 + j] * 2 + 4 > p || (q + q[l + 4 + j] * 2 + 4 == p && !m)) 736 setseqoff(q, j, q[l + 4 + j] + k + 2); 737 } 738 } 739#ifdef DEBUGG 740 dumpmap(); 741#endif 742 return 0; 743} 744 745static int 746remmapseq(seq, k) 747char *seq; 748int k; 749{ 750 int j, l; 751 unsigned char *p, *q; 752 753 if (k >= 254 || (j = findseq_ge(seq, k, &p)) != 0) 754 return -1; 755 for (q = D_kmaps; q < p; q += 2 * l + 4) 756 { 757 l = q[2]; 758 for (j = 0; j < l; j++) 759 { 760 if (q + q[l + 4 + j] * 2 + 4 == p) 761 setseqoff(q, j, p[k + 4 + j] ? q[l + 4 + j] + p[k + 4 + j] - k : 0); 762 else if (q + q[l + 4 + j] * 2 + 4 > p) 763 q[l + 4 + j] -= k + 2; 764 } 765 } 766 if (D_kmaps + D_nseqs > p + 2 * k + 4) 767 bcopy((char *)p + 2 * k + 4, (char *)p, (D_kmaps + D_nseqs) - (p + 2 * k + 4)); 768 D_nseqs -= 2 * k + 4; 769 D_seqp = D_kmaps + 3; 770 D_seql = 0; 771 D_seqh = 0; 772 evdeq(&D_mapev); 773#ifdef DEBUGG 774 dumpmap(); 775#endif 776 return 0; 777} 778 779#ifdef DEBUGG 780static void 781dumpmap() 782{ 783 unsigned char *p; 784 int j, n, l, o, oo; 785 debug("Mappings:\n"); 786 p = D_kmaps; 787 if (!p) 788 return; 789 while (p < D_kmaps + D_nseqs) 790 { 791 l = p[2]; 792 debug1("%d: ", p - D_kmaps + 3); 793 for (j = 0; j < l; j++) 794 { 795 o = oo = p[l + 4 + j]; 796 if (o) 797 o = 2 * o + 4 + (p + 3 + j - D_kmaps); 798 if (p[j + 3] > ' ' && p[j + 3] < 0177) 799 { 800 debug3("%c[%d:%d] ", p[j + 3], oo, o); 801 } 802 else 803 debug3("\\%03o[%d:%d] ", p[j + 3], oo, o); 804 } 805 n = p[0] << 8 | p[1]; 806 debug2(" ==> %d%s\n", n & ~KMAP_NOTIMEOUT, (n & KMAP_NOTIMEOUT) ? " (no timeout)" : ""); 807 p += 2 * l + 4; 808 } 809} 810#endif /* DEBUGG */ 811 812#endif /* MAPKEYS */ 813 814/* 815 * Appends to the static variable Termcap 816 */ 817static void 818AddCap(s) 819char *s; 820{ 821 register int n; 822 823 if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < TERMCAP_BUFSIZE - 4 - 1) 824 { 825 strcpy(Termcap + Termcaplen, "\\\n\t:"); 826 Termcaplen += 4; 827 tcLineLen = 0; 828 } 829 if (Termcaplen + n < TERMCAP_BUFSIZE - 1) 830 { 831 strcpy(Termcap + Termcaplen, s); 832 Termcaplen += n; 833 tcLineLen += n; 834 } 835 else 836 Panic(0, "TERMCAP overflow - sorry."); 837} 838 839/* 840 * Reads a displays capabilities and reconstructs a termcap entry in the 841 * global buffer "Termcap". A pointer to this buffer is returned. 842 */ 843char * 844MakeTermcap(aflag) 845int aflag; 846{ 847 char buf[TERMCAP_BUFSIZE]; 848 register char *p, *cp, *s, ch, *tname; 849 int i, wi, he; 850#if 0 851 int found; 852#endif 853 854 if (display) 855 { 856 wi = D_width; 857 he = D_height; 858 tname = D_termname; 859 } 860 else 861 { 862 wi = 80; 863 he = 24; 864 tname = "vt100"; 865 } 866 debug1("MakeTermcap(%d)\n", aflag); 867 if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE) 868 { 869 sprintf(Termcap, "TERMCAP=%s", s); 870 strcpy(Term, "TERM=screen"); 871 debug("getenvSCREENCAP o.k.\n"); 872 return Termcap; 873 } 874 Termcaplen = 0; 875 debug1("MakeTermcap screenterm='%s'\n", screenterm); 876 debug1("MakeTermcap termname='%s'\n", tname); 877 if (*screenterm == '\0' || strlen(screenterm) > MAXSTR - 3) 878 { 879 debug("MakeTermcap sets screenterm=screen\n"); 880 strcpy(screenterm, "screen"); 881 } 882#if 0 883 found = 1; 884#endif 885 do 886 { 887 strcpy(Term, "TERM="); 888 p = Term + 5; 889 if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR-1) 890 { 891 sprintf(p, "%s.%s", screenterm, tname); 892 if (e_tgetent(buf, p) == 1) 893 break; 894 } 895#ifdef COLOR 896 if (nwin_default.bce) 897 { 898 sprintf(p, "%s-bce", screenterm); 899 if (e_tgetent(buf, p) == 1) 900 break; 901 } 902#endif 903#ifdef CHECK_SCREEN_W 904 if (wi >= 132) 905 { 906 sprintf(p, "%s-w", screenterm); 907 if (e_tgetent(buf, p) == 1) 908 break; 909 } 910#endif 911 strcpy(p, screenterm); 912 if (e_tgetent(buf, p) == 1) 913 break; 914 strcpy(p, "vt100"); 915#if 0 916 found = 0; 917#endif 918 } 919 while (0); /* Goto free programming... */ 920 921#if 0 922#ifndef TERMINFO 923 /* check for compatibility problems, displays == 0 after fork */ 924 if (found) 925 { 926 char xbuf[TERMCAP_BUFSIZE], *xbp = xbuf; 927 if (tgetstr("im", &xbp) && tgetstr("ic", &xbp) && displays) 928 { 929 Msg(0, "Warning: im and ic set in %s termcap entry", p); 930 } 931 } 932#endif 933#endif 934 935 tcLineLen = 100; /* Force NL */ 936 if (strlen(Term) > TERMCAP_BUFSIZE - 40) 937 strcpy(Term, "too_long"); 938 sprintf(Termcap, "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal:", Term + 5); 939 Termcaplen = strlen(Termcap); 940 debug1("MakeTermcap decided '%s'\n", p); 941 if (extra_outcap && *extra_outcap) 942 { 943 for (cp = extra_outcap; (p = index(cp, ':')); cp = p) 944 { 945 ch = *++p; 946 *p = '\0'; 947 AddCap(cp); 948 *p = ch; 949 } 950 tcLineLen = 100; /* Force NL */ 951 } 952 debug1("MakeTermcap after outcap '%s'\n", (char *)TermcapConst); 953 if (Termcaplen + strlen(TermcapConst) < TERMCAP_BUFSIZE) 954 { 955 strcpy(Termcap + Termcaplen, (char *)TermcapConst); 956 Termcaplen += strlen(TermcapConst); 957 } 958 sprintf(buf, "li#%d:co#%d:", he, wi); 959 AddCap(buf); 960 AddCap("am:"); 961 if (aflag || (force_vt && !D_COP) || D_CLP || !D_AM) 962 { 963 AddCap("xn:"); 964 AddCap("xv:"); 965 AddCap("LP:"); 966 } 967 if (aflag || (D_CS && D_SR) || D_AL || D_CAL) 968 { 969 AddCap("sr=\\EM:"); 970 AddCap("al=\\E[L:"); 971 AddCap("AL=\\E[%dL:"); 972 } 973 else if (D_SR) 974 AddCap("sr=\\EM:"); 975 if (aflag || D_CS) 976 AddCap("cs=\\E[%i%d;%dr:"); 977 if (aflag || D_CS || D_DL || D_CDL) 978 { 979 AddCap("dl=\\E[M:"); 980 AddCap("DL=\\E[%dM:"); 981 } 982 if (aflag || D_DC || D_CDC) 983 { 984 AddCap("dc=\\E[P:"); 985 AddCap("DC=\\E[%dP:"); 986 } 987 if (aflag || D_CIC || D_IC || D_IM) 988 { 989 AddCap("im=\\E[4h:"); 990 AddCap("ei=\\E[4l:"); 991 AddCap("mi:"); 992 AddCap("IC=\\E[%d@:"); 993 } 994#ifdef MAPKEYS 995 AddCap("ks=\\E[?1h\\E=:"); 996 AddCap("ke=\\E[?1l\\E>:"); 997#endif 998 AddCap("vi=\\E[?25l:"); 999 AddCap("ve=\\E[34h\\E[?25h:"); 1000 AddCap("vs=\\E[34l:"); 1001 AddCap("ti=\\E[?1049h:"); 1002 AddCap("te=\\E[?1049l:"); 1003 if (display) 1004 { 1005 if (D_US) 1006 { 1007 AddCap("us=\\E[4m:"); 1008 AddCap("ue=\\E[24m:"); 1009 } 1010 if (D_SO) 1011 { 1012 AddCap("so=\\E[3m:"); 1013 AddCap("se=\\E[23m:"); 1014 } 1015 if (D_MB) 1016 AddCap("mb=\\E[5m:"); 1017 if (D_MD) 1018 AddCap("md=\\E[1m:"); 1019 if (D_MH) 1020 AddCap("mh=\\E[2m:"); 1021 if (D_MR) 1022 AddCap("mr=\\E[7m:"); 1023 if (D_MB || D_MD || D_MH || D_MR) 1024 AddCap("me=\\E[m:ms:"); 1025 if (D_hascolor) 1026 AddCap("Co#8:pa#64:AF=\\E[3%dm:AB=\\E[4%dm:op=\\E[39;49m:AX:"); 1027 if (D_VB) 1028 AddCap("vb=\\Eg:"); 1029#ifndef MAPKEYS 1030 if (D_KS) 1031 { 1032 AddCap("ks=\\E=:"); 1033 AddCap("ke=\\E>:"); 1034 } 1035 if (D_CCS) 1036 { 1037 AddCap("CS=\\E[?1h:"); 1038 AddCap("CE=\\E[?1l:"); 1039 } 1040#endif 1041 if (D_CG0) 1042 AddCap("G0:"); 1043 if (D_CC0 || (D_CS0 && *D_CS0)) 1044 { 1045 AddCap("as=\\E(0:"); 1046 AddCap("ae=\\E(B:"); 1047 /* avoid `` because some shells dump core... */ 1048 AddCap("ac=\\140\\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:"); 1049 } 1050 if (D_PO) 1051 { 1052 AddCap("po=\\E[5i:"); 1053 AddCap("pf=\\E[4i:"); 1054 } 1055 if (D_CZ0) 1056 { 1057 AddCap("Z0=\\E[?3h:"); 1058 AddCap("Z1=\\E[?3l:"); 1059 } 1060 if (D_CWS) 1061 AddCap("WS=\\E[8;%d;%dt:"); 1062 } 1063 for (i = T_CAPS; i < T_ECAPS; i++) 1064 { 1065#ifdef MAPKEYS 1066 struct action *act; 1067 if (i < T_OCAPS) 1068 { 1069 if (i >= T_KEYPAD) /* don't put keypad codes in TERMCAP */ 1070 continue; /* - makes it too big */ 1071 if (i >= T_CURSOR && i < T_OCAPS) 1072 { 1073 act = &umtab[i - (T_CURSOR - T_OCAPS + T_CAPS)]; 1074 if (act->nr == RC_ILLEGAL) 1075 act = &dmtab[i - (T_CURSOR - T_OCAPS + T_CAPS)]; 1076 } 1077 else 1078 { 1079 act = &umtab[i - T_CAPS]; 1080 if (act->nr == RC_ILLEGAL) 1081 act = &dmtab[i - T_CAPS]; 1082 } 1083 if (act->nr == RC_ILLEGAL && (i == T_NAVIGATE + 1 || i == T_NAVIGATE + 3)) 1084 { 1085 /* kh -> @1, kH -> @7 */ 1086 act = &umtab[i - T_CAPS - 1]; 1087 if (act->nr == RC_ILLEGAL) 1088 act = &dmtab[i - T_CAPS - 1]; 1089 } 1090 if (act->nr != RC_ILLEGAL) 1091 { 1092 if (act->nr == RC_STUFF) 1093 { 1094 MakeString(term[i].tcname, buf, sizeof(buf), act->args[0]); 1095 AddCap(buf); 1096 } 1097 continue; 1098 } 1099 } 1100#endif 1101 if (display == 0) 1102 continue; 1103 switch(term[i].type) 1104 { 1105 case T_STR: 1106 if (D_tcs[i].str == 0) 1107 break; 1108 MakeString(term[i].tcname, buf, sizeof(buf), D_tcs[i].str); 1109 AddCap(buf); 1110 break; 1111 case T_FLG: 1112 if (D_tcs[i].flg == 0) 1113 break; 1114 sprintf(buf, "%s:", term[i].tcname); 1115 AddCap(buf); 1116 break; 1117 default: 1118 break; 1119 } 1120 } 1121 debug("MakeTermcap: end\n"); 1122 return Termcap; 1123} 1124 1125static void 1126MakeString(cap, buf, buflen, s) 1127char *cap, *buf; 1128int buflen; 1129char *s; 1130{ 1131 register char *p, *pmax; 1132 register unsigned int c; 1133 1134 p = buf; 1135 pmax = p + buflen - (3+4+2); 1136 *p++ = *cap++; 1137 *p++ = *cap; 1138 *p++ = '='; 1139 while ((c = *s++) && (p < pmax)) 1140 { 1141 switch (c) 1142 { 1143 case '\033': 1144 *p++ = '\\'; 1145 *p++ = 'E'; 1146 break; 1147 case ':': 1148 strcpy(p, "\\072"); 1149 p += 4; 1150 break; 1151 case '^': 1152 case '\\': 1153 *p++ = '\\'; 1154 *p++ = c; 1155 break; 1156 default: 1157 if (c >= 200) 1158 { 1159 sprintf(p, "\\%03o", c & 0377); 1160 p += 4; 1161 } 1162 else if (c < ' ') 1163 { 1164 *p++ = '^'; 1165 *p++ = c + '@'; 1166 } 1167 else 1168 *p++ = c; 1169 } 1170 } 1171 *p++ = ':'; 1172 *p = '\0'; 1173} 1174 1175 1176#undef QUOTES 1177#define QUOTES(p) \ 1178 (*p == '\\' && (p[1] == '\\' || p[1] == ',' || p[1] == '%')) 1179 1180#ifdef FONT 1181int 1182CreateTransTable(s) 1183char *s; 1184{ 1185 int curchar; 1186 char *templ, *arg; 1187 int templlen; 1188 int templnsub; 1189 char *p, *sx; 1190 char **ctable; 1191 int l, c; 1192 1193 if ((D_xtable = (char ***)malloc(256 * sizeof(char **))) == 0) 1194 { 1195 Msg(0, strnomem); 1196 return -1; 1197 } 1198 bzero((char *)D_xtable, 256 * sizeof(char **)); 1199 1200 while (*s) 1201 { 1202 if (QUOTES(s)) 1203 s++; 1204 curchar = (unsigned char)*s++; 1205 if (curchar == 'B') 1206 curchar = 0; /* ASCII */ 1207 templ = s; 1208 templlen = 0; 1209 templnsub = 0; 1210 if (D_xtable[curchar] == 0) 1211 { 1212 if ((D_xtable[curchar] = (char **)malloc(257 * sizeof(char *))) == 0) 1213 { 1214 Msg(0, strnomem); 1215 FreeTransTable(); 1216 return -1; 1217 } 1218 bzero((char *)D_xtable[curchar], 257 * sizeof(char *)); 1219 } 1220 ctable = D_xtable[curchar]; 1221 for(; *s && *s != ','; s++) 1222 { 1223 if (QUOTES(s)) 1224 s++; 1225 else if (*s == '%') 1226 { 1227 templnsub++; 1228 continue; 1229 } 1230 templlen++; 1231 } 1232 if (*s++ == 0) 1233 break; 1234 while (*s && *s != ',') 1235 { 1236 c = (unsigned char)*s++; 1237 if (QUOTES((s - 1))) 1238 c = (unsigned char)*s++; 1239 else if (c == '%') 1240 c = 256; 1241 if (ctable[c]) 1242 free(ctable[c]); 1243 arg = s; 1244 l = copyarg(&s, (char *)0); 1245 if (c != 256) 1246 l = l * templnsub + templlen; 1247 if ((ctable[c] = (char *)malloc(l + 1)) == 0) 1248 { 1249 Msg(0, strnomem); 1250 FreeTransTable(); 1251 return -1; 1252 } 1253 sx = ctable[c]; 1254 for (p = ((c == 256) ? "%" : templ); *p && *p != ','; p++) 1255 { 1256 if (QUOTES(p)) 1257 p++; 1258 else if (*p == '%') 1259 { 1260 s = arg; 1261 sx += copyarg(&s, sx); 1262 continue; 1263 } 1264 *sx++ = *p; 1265 } 1266 *sx = 0; 1267 ASSERT(ctable[c] + l * templnsub + templlen == sx); 1268 debug3("XC: %c %c->%s\n", curchar, c, ctable[c]); 1269 } 1270 if (*s == ',') 1271 s++; 1272 } 1273 return 0; 1274} 1275 1276void 1277FreeTransTable() 1278{ 1279 char ***p, **q; 1280 int i, j; 1281 1282 if ((p = D_xtable) == 0) 1283 return; 1284 for (i = 0; i < 256; i++, p++) 1285 { 1286 if (*p == 0) 1287 continue; 1288 q = *p; 1289 for (j = 0; j < 257; j++, q++) 1290 if (*q) 1291 free(*q); 1292 free(*p); 1293 } 1294 free(D_xtable); 1295} 1296#endif /* FONT */ 1297 1298static int 1299copyarg(pp, s) 1300char **pp, *s; 1301{ 1302 int l; 1303 char *p; 1304 1305 for (l = 0, p = *pp; *p && *p != ','; p++) 1306 { 1307 if (QUOTES(p)) 1308 p++; 1309 if (s) 1310 *s++ = *p; 1311 l++; 1312 } 1313 if (*p == ',') 1314 p++; 1315 *pp = p; 1316 return l; 1317} 1318 1319 1320/* 1321** 1322** Termcap routines that use our extra_incap 1323** 1324*/ 1325 1326static int 1327e_tgetent(bp, name) 1328char *bp, *name; 1329{ 1330 int r; 1331 1332#ifdef USE_SETEUID 1333 xseteuid(real_uid); 1334 xsetegid(real_gid); 1335#endif 1336 r = tgetent(bp, name); 1337#ifdef USE_SETEUID 1338 xseteuid(eff_uid); 1339 xsetegid(eff_gid); 1340#endif 1341 return r; 1342} 1343 1344 1345/* findcap: 1346 * cap = capability we are looking for 1347 * tepp = pointer to bufferpointer 1348 * n = size of buffer (0 = infinity) 1349 */ 1350 1351static char * 1352findcap(cap, tepp, n) 1353char *cap; 1354char **tepp; 1355int n; 1356{ 1357 char *tep; 1358 char c, *p, *cp; 1359 int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */ 1360 int num = 0, capl; 1361 1362 if (!extra_incap) 1363 return 0; 1364 tep = *tepp; 1365 capl = strlen(cap); 1366 cp = 0; 1367 mode = 0; 1368 for (p = extra_incap; *p; ) 1369 { 1370 if (strncmp(p, cap, capl) == 0) 1371 { 1372 p += capl; 1373 c = *p; 1374 if (c && c != ':' && c != '@') 1375 p++; 1376 if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#') 1377 cp = tep; 1378 } 1379 while ((c = *p)) 1380 { 1381 p++; 1382 if (mode == 0) 1383 { 1384 if (c == ':') 1385 break; 1386 if (c == '^') 1387 mode = 1; 1388 if (c == '\\') 1389 mode = 2; 1390 } 1391 else if (mode == 1) 1392 { 1393 mode = 0; 1394 c = c & 0x1f; 1395 } 1396 else if (mode == 2) 1397 { 1398 mode = 0; 1399 switch(c) 1400 { 1401 case '0': 1402 case '1': 1403 case '2': 1404 case '3': 1405 case '4': 1406 case '5': 1407 case '6': 1408 case '7': 1409 case '8': 1410 case '9': 1411 mode = 3; 1412 num = 0; 1413 break; 1414 case 'E': 1415 c = 27; 1416 break; 1417 case 'n': 1418 c = '\n'; 1419 break; 1420 case 'r': 1421 c = '\r'; 1422 break; 1423 case 't': 1424 c = '\t'; 1425 break; 1426 case 'b': 1427 c = '\b'; 1428 break; 1429 case 'f': 1430 c = '\f'; 1431 break; 1432 } 1433 } 1434 if (mode > 2) 1435 { 1436 num = num * 8 + (c - '0'); 1437 if (mode++ == 5 || (*p < '0' || *p > '9')) 1438 { 1439 c = num; 1440 mode = 0; 1441 } 1442 } 1443 if (mode) 1444 continue; 1445 1446 if (cp && n != 1) 1447 { 1448 *cp++ = c; 1449 n--; 1450 } 1451 } 1452 if (cp) 1453 { 1454 *cp++ = 0; 1455 *tepp = cp; 1456 debug2("'%s' found in extra_incap -> %s\n", cap, tep); 1457 return tep; 1458 } 1459 } 1460 return 0; 1461} 1462 1463static char * 1464e_tgetstr(cap, tepp) 1465char *cap; 1466char **tepp; 1467{ 1468 char *tep; 1469 if ((tep = findcap(cap, tepp, 0))) 1470 return (*tep == '@') ? 0 : tep; 1471 return tgetstr(cap, tepp); 1472} 1473 1474static int 1475e_tgetflag(cap) 1476char *cap; 1477{ 1478 char buf[2], *bufp; 1479 char *tep; 1480 bufp = buf; 1481 if ((tep = findcap(cap, &bufp, 2))) 1482 return (*tep == '@') ? 0 : 1; 1483 return tgetflag(cap) > 0; 1484} 1485 1486static int 1487e_tgetnum(cap) 1488char *cap; 1489{ 1490 char buf[20], *bufp; 1491 char *tep, c; 1492 int res, base = 10; 1493 1494 bufp = buf; 1495 if ((tep = findcap(cap, &bufp, 20))) 1496 { 1497 c = *tep; 1498 if (c == '@') 1499 return -1; 1500 if (c == '0') 1501 base = 8; 1502 res = 0; 1503 while ((c = *tep++) >= '0' && c <= '9') 1504 res = res * base + (c - '0'); 1505 return res; 1506 } 1507 return tgetnum(cap); 1508} 1509 1510