Start converting to GPL v3+ (ref: ticket #23900)
[screen-lua.git] / src / termcap.c
blob4689e76cf48be65f27a434f18f699eb3449d4302
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
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 3, or (at your option)
9 * any later version.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, see
18 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include "config.h"
26 #include "screen.h"
27 #include "extern.h"
29 #undef DEBUGG
31 extern struct display *display, *displays;
32 extern int real_uid, real_gid, eff_uid, eff_gid;
33 extern struct term term[]; /* terminal capabilities */
34 extern struct NewWindow nwin_undef, nwin_default, nwin_options;
35 extern int force_vt;
36 extern int Z0width, Z1width;
37 extern int hardstatusemu;
38 #ifdef MAPKEYS
39 extern struct action umtab[];
40 extern struct action mmtab[];
41 extern struct action dmtab[];
42 extern struct action ktab[];
43 extern struct kmap_ext *kmap_exts;
44 extern int kmap_extn;
45 extern int DefaultEsc;
46 #endif
49 static void AddCap __P((char *));
50 static void MakeString __P((char *, char *, int, char *));
51 static char *findcap __P((char *, char **, int));
52 static int copyarg __P((char **, char *));
53 static int e_tgetent __P((char *, char *));
54 static char *e_tgetstr __P((char *, char **));
55 static int e_tgetflag __P((char *));
56 static int e_tgetnum __P((char *));
57 #ifdef MAPKEYS
58 static int findseq_ge __P((char *, int, unsigned char **));
59 static void setseqoff __P((unsigned char *, int, int));
60 static int addmapseq __P((char *, int, int));
61 static int remmapseq __P((char *, int));
62 #ifdef DEBUGG
63 static void dumpmap __P((void));
64 #endif
65 #endif
68 char Termcap[TERMCAP_BUFSIZE + 8]; /* new termcap +8:"TERMCAP=" */
69 static int Termcaplen;
70 static int tcLineLen;
71 char Term[MAXSTR+5]; /* +5: "TERM=" */
72 char screenterm[20]; /* new $TERM, usually "screen" */
74 char *extra_incap, *extra_outcap;
76 static const char TermcapConst[] = "\\\n\
77 \t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
78 \t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
79 \t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\
80 \t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:";
82 char *
83 gettermcapstring(s)
84 char *s;
86 int i;
88 if (display == 0 || s == 0)
89 return 0;
90 for (i = 0; i < T_N; i++)
92 if (term[i].type != T_STR)
93 continue;
94 if (strcmp(term[i].tcname, s) == 0)
95 return D_tcs[i].str;
97 return 0;
101 * Compile the terminal capabilities for a display.
102 * Input: tgetent(, D_termname) extra_incap, extra_outcap.
103 * Effect: display initialisation.
106 InitTermcap(wi, he)
107 int wi;
108 int he;
110 register char *s;
111 int i;
112 char tbuf[TERMCAP_BUFSIZE], *tp;
113 int t, xue, xse, xme;
115 ASSERT(display);
116 bzero(tbuf, sizeof(tbuf));
117 debug1("InitTermcap: looking for tgetent('%s')\n", D_termname);
118 if (*D_termname == 0 || e_tgetent(tbuf, D_termname) != 1)
120 #ifdef TERMINFO
121 Msg(0, "Cannot find terminfo entry for '%s'.", D_termname);
122 #else
123 Msg(0, "Cannot find termcap entry for '%s'.", D_termname);
124 #endif
125 return -1;
127 debug1("got it:\n%s\n", tbuf);
128 #ifdef DEBUG
129 if (extra_incap)
130 debug1("Extra incap: %s\n", extra_incap);
131 if (extra_outcap)
132 debug1("Extra outcap: %s\n", extra_outcap);
133 #endif
135 if ((D_tentry = (char *)malloc(TERMCAP_BUFSIZE + (extra_incap ? strlen(extra_incap) + 1 : 0))) == 0)
137 Msg(0, strnomem);
138 return -1;
142 * loop through all needed capabilities, record their values in the display
144 tp = D_tentry;
145 for (i = 0; i < T_N; i++)
147 switch(term[i].type)
149 case T_FLG:
150 D_tcs[i].flg = e_tgetflag(term[i].tcname);
151 break;
152 case T_NUM:
153 D_tcs[i].num = e_tgetnum(term[i].tcname);
154 break;
155 case T_STR:
156 D_tcs[i].str = e_tgetstr(term[i].tcname, &tp);
157 /* no empty strings, please */
158 if (D_tcs[i].str && *D_tcs[i].str == 0)
159 D_tcs[i].str = 0;
160 break;
161 default:
162 Panic(0, "Illegal tc type in entry #%d", i);
163 /*NOTREACHED*/
168 * Now a good deal of sanity checks on the retrieved capabilities.
170 if (D_HC)
172 Msg(0, "You can't run screen on a hardcopy terminal.");
173 return -1;
175 if (D_OS)
177 Msg(0, "You can't run screen on a terminal that overstrikes.");
178 return -1;
180 if (!D_CL)
182 Msg(0, "Clear screen capability required.");
183 return -1;
185 if (!D_CM)
187 Msg(0, "Addressable cursor capability required.");
188 return -1;
190 if ((s = getenv("COLUMNS")) && (i = atoi(s)) > 0)
191 D_CO = i;
192 if ((s = getenv("LINES")) && (i = atoi(s)) > 0)
193 D_LI = i;
194 if (wi)
195 D_CO = wi;
196 if (he)
197 D_LI = he;
198 if (D_CO <= 0)
199 D_CO = 80;
200 if (D_LI <= 0)
201 D_LI = 24;
203 if (D_CTF)
205 /* standard fixes for xterms etc */
206 /* assume color for everything that looks ansi-compatible */
207 if (!D_CAF && D_ME && (InStr(D_ME, "\033[m") || InStr(D_ME, "\033[0m")))
209 #ifdef TERMINFO
210 D_CAF = "\033[3%p1%dm";
211 D_CAB = "\033[4%p1%dm";
212 #else
213 D_CAF = "\033[3%dm";
214 D_CAB = "\033[4%dm";
215 #endif
217 if (D_OP && InStr(D_OP, "\033[39;49m"))
218 D_CAX = 1;
219 if (D_OP && (InStr(D_OP, "\033[m") || InStr(D_OP, "\033[0m")))
220 D_OP = 0;
221 /* ISO2022 */
222 if ((D_EA && InStr(D_EA, "\033(B")) || (D_AS && InStr(D_AS, "\033(0")))
223 D_CG0 = 1;
224 if (InStr(D_termname, "xterm") || InStr(D_termname, "rxvt"))
225 D_CXT = 1;
226 /* "be" seems to be standard for xterms... */
227 if (D_CXT)
228 D_BE = 1;
230 if (nwin_options.flowflag == nwin_undef.flowflag)
231 nwin_default.flowflag = D_CNF ? FLOW_NOW * 0 :
232 D_NX ? FLOW_NOW * 1 :
233 FLOW_AUTOFLAG;
234 D_CLP |= (!D_AM || D_XV || D_XN);
235 if (!D_BL)
236 D_BL = "\007";
237 if (!D_BC)
239 if (D_BS)
240 D_BC = "\b";
241 else
242 D_BC = D_LE;
244 if (!D_CR)
245 D_CR = "\r";
246 if (!D_NL)
247 D_NL = "\n";
250 * Set up attribute handling.
251 * This is rather complicated because termcap has different
252 * attribute groups.
255 if (D_UG > 0)
256 D_US = D_UE = 0;
257 if (D_SG > 0)
258 D_SO = D_SE = 0;
259 /* Unfortunatelly there is no 'mg' capability.
260 * For now we think that mg > 0 if sg and ug > 0.
262 if (D_UG > 0 && D_SG > 0)
263 D_MH = D_MD = D_MR = D_MB = D_ME = 0;
265 xue = ATYP_U;
266 xse = ATYP_S;
267 xme = ATYP_M;
269 if (D_SO && D_SE == 0)
271 Msg(0, "Warning: 'so' but no 'se' capability.");
272 if (D_ME)
273 xse = xme;
274 else
275 D_SO = 0;
277 if (D_US && D_UE == 0)
279 Msg(0, "Warning: 'us' but no 'ue' capability.");
280 if (D_ME)
281 xue = xme;
282 else
283 D_US = 0;
285 if ((D_MH || D_MD || D_MR || D_MB) && D_ME == 0)
287 Msg(0, "Warning: 'm?' but no 'me' capability.");
288 D_MH = D_MD = D_MR = D_MB = 0;
291 * Does ME also reverse the effect of SO and/or US? This is not
292 * clearly specified by the termcap manual. Anyway, we should at
293 * least look whether ME and SE/UE are equal:
295 if (D_UE && D_SE && strcmp(D_SE, D_UE) == 0)
296 xse = xue;
297 if (D_SE && D_ME && strcmp(D_ME, D_SE) == 0)
298 xse = xme;
299 if (D_UE && D_ME && strcmp(D_ME, D_UE) == 0)
300 xue = xme;
302 for (i = 0; i < NATTR; i++)
304 D_attrtab[i] = D_tcs[T_ATTR + i].str;
305 D_attrtyp[i] = i == ATTR_SO ? xse : (i == ATTR_US ? xue : xme);
308 /* Set up missing entries (attributes are priority ordered) */
309 s = 0;
310 t = 0;
311 for (i = 0; i < NATTR; i++)
312 if ((s = D_attrtab[i]))
314 t = D_attrtyp[i];
315 break;
317 for (i = 0; i < NATTR; i++)
319 if (D_attrtab[i] == 0)
321 D_attrtab[i] = s;
322 D_attrtyp[i] = t;
324 else
326 s = D_attrtab[i];
327 t = D_attrtyp[i];
330 if (D_CAF || D_CAB || D_CSF || D_CSB)
331 D_hascolor = 1;
332 if (D_UT)
333 D_BE = 1; /* screen erased with background color */
335 if (!D_DO)
336 D_DO = D_NL;
337 if (!D_SF)
338 D_SF = D_NL;
339 if (D_IN)
340 D_IC = D_IM = 0;
341 if (D_EI == 0)
342 D_IM = 0;
343 /* some strange termcap entries have IC == IM */
344 if (D_IC && D_IM && strcmp(D_IC, D_IM) == 0)
345 D_IC = 0;
346 if (D_KE == 0)
347 D_KS = 0;
348 if (D_CVN == 0)
349 D_CVR = 0;
350 if (D_VE == 0)
351 D_VI = D_VS = 0;
352 if (D_CCE == 0)
353 D_CCS = 0;
355 #ifdef FONT
356 if (D_CG0)
358 if (D_CS0 == 0)
359 #ifdef TERMINFO
360 D_CS0 = "\033(%p1%c";
361 #else
362 D_CS0 = "\033(%.";
363 #endif
364 if (D_CE0 == 0)
365 D_CE0 = "\033(B";
366 D_AC = 0;
367 D_EA = 0;
369 else if (D_AC || (D_AS && D_AE)) /* some kind of graphics */
371 D_CS0 = (D_AS && D_AE) ? D_AS : "";
372 D_CE0 = (D_AS && D_AE) ? D_AE : "";
373 D_CC0 = D_AC;
375 else
377 D_CS0 = D_CE0 = "";
378 D_CC0 = 0;
379 D_AC = ""; /* enable default string */
382 for (i = 0; i < 256; i++)
383 D_c0_tab[i] = i;
384 if (D_AC)
386 /* init with default string first */
387 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>";
388 for (i = strlen(s) & ~1; i >= 0; i -= 2)
389 D_c0_tab[(int)(unsigned char)s[i]] = s[i + 1];
391 if (D_CC0)
392 for (i = strlen(D_CC0) & ~1; i >= 0; i -= 2)
393 D_c0_tab[(int)(unsigned char)D_CC0[i]] = D_CC0[i + 1];
394 debug1("ISO2022 = %d\n", D_CG0);
395 #endif /* FONT */
396 if (D_PF == 0)
397 D_PO = 0;
398 debug2("terminal size is %d, %d (says TERMCAP)\n", D_CO, D_LI);
400 #ifdef FONT
401 if (D_CXC)
402 if (CreateTransTable(D_CXC))
403 return -1;
404 #endif
406 /* Termcap fields Z0 & Z1 contain width-changing sequences. */
407 if (D_CZ1 == 0)
408 D_CZ0 = 0;
409 Z0width = 132;
410 Z1width = 80;
412 CheckScreenSize(0);
414 if (D_TS == 0 || D_FS == 0 || D_DS == 0)
415 D_HS = 0;
416 if (D_HS)
418 debug("oy! we have a hardware status line, says termcap\n");
419 if (D_WS < 0)
420 D_WS = 0;
422 D_has_hstatus = hardstatusemu & ~HSTATUS_ALWAYS;
423 if (D_HS && !(hardstatusemu & HSTATUS_ALWAYS))
424 D_has_hstatus = HSTATUS_HS;
426 #ifdef ENCODINGS
427 if (D_CKJ)
429 int enc = FindEncoding(D_CKJ);
430 if (enc != -1)
431 D_encoding = enc;
433 #endif
434 if (!D_tcs[T_NAVIGATE].str && D_tcs[T_NAVIGATE + 1].str)
435 D_tcs[T_NAVIGATE].str = D_tcs[T_NAVIGATE + 1].str; /* kh = @1 */
436 if (!D_tcs[T_NAVIGATE + 2].str && D_tcs[T_NAVIGATE + 3].str)
437 D_tcs[T_NAVIGATE + 2].str = D_tcs[T_NAVIGATE + 3].str; /* kH = @7 */
439 D_UPcost = CalcCost(D_UP);
440 D_DOcost = CalcCost(D_DO);
441 D_NLcost = CalcCost(D_NL);
442 D_LEcost = CalcCost(D_BC);
443 D_NDcost = CalcCost(D_ND);
444 D_CRcost = CalcCost(D_CR);
445 D_IMcost = CalcCost(D_IM);
446 D_EIcost = CalcCost(D_EI);
448 #ifdef AUTO_NUKE
449 if (D_CAN)
451 debug("termcap has AN, setting autonuke\n");
452 D_auto_nuke = 1;
454 #endif
455 if (D_COL > 0)
457 debug1("termcap has OL (%d), setting limit\n", D_COL);
458 D_obufmax = D_COL;
459 D_obuflenmax = D_obuflen - D_obufmax;
462 /* Some xterm entries set F0 and F10 to the same string. Nuke F0. */
463 if (D_tcs[T_CAPS].str && D_tcs[T_CAPS + 10].str && !strcmp(D_tcs[T_CAPS].str, D_tcs[T_CAPS + 10].str))
464 D_tcs[T_CAPS].str = 0;
465 /* Some xterm entries set kD to ^?. Nuke it. */
466 if (D_tcs[T_NAVIGATE_DELETE].str && !strcmp(D_tcs[T_NAVIGATE_DELETE].str, "\0177"))
467 D_tcs[T_NAVIGATE_DELETE].str = 0;
468 /* wyse52 entries have kcub1 == kb == ^H. Nuke... */
469 if (D_tcs[T_CURSOR + 3].str && !strcmp(D_tcs[T_CURSOR + 3].str, "\008"))
470 D_tcs[T_CURSOR + 3].str = 0;
472 #ifdef MAPKEYS
473 D_nseqs = 0;
474 for (i = 0; i < T_OCAPS - T_CAPS; i++)
475 remap(i, 1);
476 for (i = 0; i < kmap_extn; i++)
477 remap(i + (KMAP_KEYS+KMAP_AKEYS), 1);
478 D_seqp = D_kmaps + 3;
479 D_seql = 0;
480 D_seqh = 0;
481 #endif
483 D_tcinited = 1;
484 MakeTermcap(0);
485 #ifdef MAPKEYS
486 CheckEscape();
487 #endif
488 return 0;
491 #ifdef MAPKEYS
494 remap(n, map)
495 int n;
496 int map;
498 char *s = 0;
499 int fl = 0, domap = 0;
500 struct action *a1, *a2, *tab;
501 int l = 0;
502 struct kmap_ext *kme = 0;
504 a1 = 0;
505 if (n >= KMAP_KEYS+KMAP_AKEYS)
507 kme = kmap_exts + (n - (KMAP_KEYS+KMAP_AKEYS));
508 s = kme->str;
509 l = kme->fl & ~KMAP_NOTIMEOUT;
510 fl = kme->fl & KMAP_NOTIMEOUT;
511 a1 = &kme->um;
513 tab = umtab;
514 for (;;)
516 a2 = 0;
517 if (n < KMAP_KEYS+KMAP_AKEYS)
519 a1 = &tab[n];
520 if (n >= KMAP_KEYS)
521 n -= T_OCAPS-T_CURSOR;
522 s = D_tcs[n + T_CAPS].str;
523 l = s ? strlen(s) : 0;
524 if (n >= T_CURSOR-T_CAPS)
525 a2 = &tab[n + (T_OCAPS-T_CURSOR)];
527 if (s == 0 || l == 0)
528 return 0;
529 if (a1 && a1->nr == RC_ILLEGAL)
530 a1 = 0;
531 if (a2 && a2->nr == RC_ILLEGAL)
532 a2 = 0;
533 if (a1 && a1->nr == RC_STUFF && a1->args[0] && strcmp(a1->args[0], s) == 0)
534 a1 = 0;
535 if (a2 && a2->nr == RC_STUFF && a2->args[0] && strcmp(a2->args[0], s) == 0)
536 a2 = 0;
537 domap |= (a1 || a2);
538 if (tab == umtab)
540 tab = dmtab;
541 a1 = kme ? &kme->dm : 0;
543 else if (tab == dmtab)
545 tab = mmtab;
546 a1 = kme ? &kme->mm : 0;
548 else
549 break;
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);
562 void
563 CheckEscape()
565 struct display *odisplay;
566 int i, nr;
568 if (DefaultEsc >= 0)
569 return;
571 odisplay = display;
572 for (display = displays; display; display = display->d_next)
574 for (i = 0; i < D_nseqs; i += D_kmaps[i + 2] * 2 + 4)
576 nr = (D_kmaps[i] << 8 | D_kmaps[i + 1]) & ~KMAP_NOTIMEOUT;
577 if (nr < KMAP_KEYS+KMAP_AKEYS)
579 if (umtab[nr].nr == RC_COMMAND)
580 break;
581 if (umtab[nr].nr == RC_ILLEGAL && dmtab[nr].nr == RC_COMMAND)
582 break;
584 else
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;
594 if (display == 0)
596 display = odisplay;
597 return;
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;
609 static int
610 findseq_ge(seq, k, sp)
611 char *seq;
612 int k;
613 unsigned char **sp;
615 unsigned char *p;
616 int j, l;
618 p = D_kmaps;
619 while (p - D_kmaps < D_nseqs)
621 l = p[2];
622 p += 3;
623 for (j = 0; ; j++)
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;
633 if (j >= 0)
635 *sp = p - 3;
636 return j;
638 p += 2 * l + 1;
640 *sp = p;
641 return -1;
644 static void
645 setseqoff(p, i, o)
646 unsigned char *p;
647 int i;
648 int o;
650 unsigned char *q;
651 int l, k;
653 k = p[2];
654 if (o < 256)
656 p[k + 4 + i] = o;
657 return;
659 /* go for the biggest offset */
660 for (q = p + k * 2 + 4; ; q += l * 2 + 4)
662 l = q[2];
663 if ((q + l * 2 - p) / 2 >= 256)
665 p[k + 4 + i] = (q - p - 4) / 2;
666 return;
671 static int
672 addmapseq(seq, k, nr)
673 char *seq;
674 int k;
675 int nr;
677 int i, j, l, mo, m;
678 unsigned char *p, *q;
680 if (k >= 254)
681 return -1;
682 j = findseq_ge(seq, k, &p);
683 if (j == 0)
685 p[0] = nr >> 8;
686 p[1] = nr;
687 return 0;
689 i = p - D_kmaps;
690 if (D_nseqs + 2 * k + 4 >= D_aseqs)
692 D_kmaps = (unsigned char *)xrealloc((char *)D_kmaps, D_aseqs + 256);
693 D_aseqs += 256;
694 p = D_kmaps + i;
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)
710 q = p + 2 * k + 4;
711 l = q[2];
712 for (i = 0; i < k; i++)
714 if (p[3 + i] != q[3 + i])
716 p[k + 4 + i] = k;
717 break;
719 setseqoff(p, i, q[l + 4 + i] ? q[l + 4 + i] + k + 2: 0);
722 for (q = D_kmaps; q < p; q += 2 * l + 4)
724 l = q[2];
725 for (m = j = 0; j < l; j++)
727 mo = m;
728 if (!m && q[3 + j] != seq[j])
729 m = 1;
730 if (q[l + 4 + j] == 0)
732 if (!mo && m)
733 setseqoff(q, j, (p - q - 4) / 2);
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);
739 #ifdef DEBUGG
740 dumpmap();
741 #endif
742 return 0;
745 static int
746 remmapseq(seq, k)
747 char *seq;
748 int k;
750 int j, l;
751 unsigned char *p, *q;
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)
757 l = q[2];
758 for (j = 0; j < l; j++)
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;
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;
779 #ifdef DEBUGG
780 static void
781 dumpmap()
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)
791 l = p[2];
792 debug1("%d: ", p - D_kmaps + 3);
793 for (j = 0; j < l; j++)
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)
800 debug3("%c[%d:%d] ", p[j + 3], oo, o);
802 else
803 debug3("\\%03o[%d:%d] ", p[j + 3], oo, o);
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;
810 #endif /* DEBUGG */
812 #endif /* MAPKEYS */
815 * Appends to the static variable Termcap
817 static void
818 AddCap(s)
819 char *s;
821 register int n;
823 if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < TERMCAP_BUFSIZE - 4 - 1)
825 strcpy(Termcap + Termcaplen, "\\\n\t:");
826 Termcaplen += 4;
827 tcLineLen = 0;
829 if (Termcaplen + n < TERMCAP_BUFSIZE - 1)
831 strcpy(Termcap + Termcaplen, s);
832 Termcaplen += n;
833 tcLineLen += n;
835 else
836 Panic(0, "TERMCAP overflow - sorry.");
840 * Reads a displays capabilities and reconstructs a termcap entry in the
841 * global buffer "Termcap". A pointer to this buffer is returned.
843 char *
844 MakeTermcap(aflag)
845 int aflag;
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
854 if (display)
856 wi = D_width;
857 he = D_height;
858 tname = D_termname;
860 else
862 wi = 80;
863 he = 24;
864 tname = "vt100";
866 debug1("MakeTermcap(%d)\n", aflag);
867 if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE)
869 sprintf(Termcap, "TERMCAP=%s", s);
870 strcpy(Term, "TERM=screen");
871 debug("getenvSCREENCAP o.k.\n");
872 return Termcap;
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)
879 debug("MakeTermcap sets screenterm=screen\n");
880 strcpy(screenterm, "screen");
882 #if 0
883 found = 1;
884 #endif
887 strcpy(Term, "TERM=");
888 p = Term + 5;
889 if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR-1)
891 sprintf(p, "%s.%s", screenterm, tname);
892 if (e_tgetent(buf, p) == 1)
893 break;
895 #ifdef COLOR
896 if (nwin_default.bce)
898 sprintf(p, "%s-bce", screenterm);
899 if (e_tgetent(buf, p) == 1)
900 break;
902 #endif
903 #ifdef CHECK_SCREEN_W
904 if (wi >= 132)
906 sprintf(p, "%s-w", screenterm);
907 if (e_tgetent(buf, p) == 1)
908 break;
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
919 while (0); /* Goto free programming... */
921 #if 0
922 #ifndef TERMINFO
923 /* check for compatibility problems, displays == 0 after fork */
924 if (found)
926 char xbuf[TERMCAP_BUFSIZE], *xbp = xbuf;
927 if (tgetstr("im", &xbp) && tgetstr("ic", &xbp) && displays)
929 Msg(0, "Warning: im and ic set in %s termcap entry", p);
932 #endif
933 #endif
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)
943 for (cp = extra_outcap; (p = index(cp, ':')); cp = p)
945 ch = *++p;
946 *p = '\0';
947 AddCap(cp);
948 *p = ch;
950 tcLineLen = 100; /* Force NL */
952 debug1("MakeTermcap after outcap '%s'\n", (char *)TermcapConst);
953 if (Termcaplen + strlen(TermcapConst) < TERMCAP_BUFSIZE)
955 strcpy(Termcap + Termcaplen, (char *)TermcapConst);
956 Termcaplen += strlen(TermcapConst);
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)
963 AddCap("xn:");
964 AddCap("xv:");
965 AddCap("LP:");
967 if (aflag || (D_CS && D_SR) || D_AL || D_CAL)
969 AddCap("sr=\\EM:");
970 AddCap("al=\\E[L:");
971 AddCap("AL=\\E[%dL:");
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)
979 AddCap("dl=\\E[M:");
980 AddCap("DL=\\E[%dM:");
982 if (aflag || D_DC || D_CDC)
984 AddCap("dc=\\E[P:");
985 AddCap("DC=\\E[%dP:");
987 if (aflag || D_CIC || D_IC || D_IM)
989 AddCap("im=\\E[4h:");
990 AddCap("ei=\\E[4l:");
991 AddCap("mi:");
992 AddCap("IC=\\E[%d@:");
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)
1005 if (D_US)
1007 AddCap("us=\\E[4m:");
1008 AddCap("ue=\\E[24m:");
1010 if (D_SO)
1012 AddCap("so=\\E[3m:");
1013 AddCap("se=\\E[23m:");
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)
1032 AddCap("ks=\\E=:");
1033 AddCap("ke=\\E>:");
1035 if (D_CCS)
1037 AddCap("CS=\\E[?1h:");
1038 AddCap("CE=\\E[?1l:");
1040 #endif
1041 if (D_CG0)
1042 AddCap("G0:");
1043 if (D_CC0 || (D_CS0 && *D_CS0))
1045 AddCap("as=\\E(0:");
1046 AddCap("ae=\\E(B:");
1047 /* avoid `` because some shells dump core... */
1048 AddCap("ac=\\140\\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:");
1050 if (D_PO)
1052 AddCap("po=\\E[5i:");
1053 AddCap("pf=\\E[4i:");
1055 if (D_CZ0)
1057 AddCap("Z0=\\E[?3h:");
1058 AddCap("Z1=\\E[?3l:");
1060 if (D_CWS)
1061 AddCap("WS=\\E[8;%d;%dt:");
1063 for (i = T_CAPS; i < T_ECAPS; i++)
1065 #ifdef MAPKEYS
1066 struct action *act;
1067 if (i < T_OCAPS)
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)
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)];
1077 else
1079 act = &umtab[i - T_CAPS];
1080 if (act->nr == RC_ILLEGAL)
1081 act = &dmtab[i - T_CAPS];
1083 if (act->nr == RC_ILLEGAL && (i == T_NAVIGATE + 1 || i == T_NAVIGATE + 3))
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];
1090 if (act->nr != RC_ILLEGAL)
1092 if (act->nr == RC_STUFF)
1094 MakeString(term[i].tcname, buf, sizeof(buf), act->args[0]);
1095 AddCap(buf);
1097 continue;
1100 #endif
1101 if (display == 0)
1102 continue;
1103 switch(term[i].type)
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;
1121 debug("MakeTermcap: end\n");
1122 return Termcap;
1125 static void
1126 MakeString(cap, buf, buflen, s)
1127 char *cap, *buf;
1128 int buflen;
1129 char *s;
1131 register char *p, *pmax;
1132 register unsigned int c;
1134 p = buf;
1135 pmax = p + buflen - (3+4+2);
1136 *p++ = *cap++;
1137 *p++ = *cap;
1138 *p++ = '=';
1139 while ((c = *s++) && (p < pmax))
1141 switch (c)
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)
1159 sprintf(p, "\\%03o", c & 0377);
1160 p += 4;
1162 else if (c < ' ')
1164 *p++ = '^';
1165 *p++ = c + '@';
1167 else
1168 *p++ = c;
1171 *p++ = ':';
1172 *p = '\0';
1176 #undef QUOTES
1177 #define QUOTES(p) \
1178 (*p == '\\' && (p[1] == '\\' || p[1] == ',' || p[1] == '%'))
1180 #ifdef FONT
1182 CreateTransTable(s)
1183 char *s;
1185 int curchar;
1186 char *templ, *arg;
1187 int templlen;
1188 int templnsub;
1189 char *p, *sx;
1190 char **ctable;
1191 int l, c;
1193 if ((D_xtable = (char ***)malloc(256 * sizeof(char **))) == 0)
1195 Msg(0, strnomem);
1196 return -1;
1198 bzero((char *)D_xtable, 256 * sizeof(char **));
1200 while (*s)
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)
1212 if ((D_xtable[curchar] = (char **)malloc(257 * sizeof(char *))) == 0)
1214 Msg(0, strnomem);
1215 FreeTransTable();
1216 return -1;
1218 bzero((char *)D_xtable[curchar], 257 * sizeof(char *));
1220 ctable = D_xtable[curchar];
1221 for(; *s && *s != ','; s++)
1223 if (QUOTES(s))
1224 s++;
1225 else if (*s == '%')
1227 templnsub++;
1228 continue;
1230 templlen++;
1232 if (*s++ == 0)
1233 break;
1234 while (*s && *s != ',')
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)
1249 Msg(0, strnomem);
1250 FreeTransTable();
1251 return -1;
1253 sx = ctable[c];
1254 for (p = ((c == 256) ? "%" : templ); *p && *p != ','; p++)
1256 if (QUOTES(p))
1257 p++;
1258 else if (*p == '%')
1260 s = arg;
1261 sx += copyarg(&s, sx);
1262 continue;
1264 *sx++ = *p;
1266 *sx = 0;
1267 ASSERT(ctable[c] + l * templnsub + templlen == sx);
1268 debug3("XC: %c %c->%s\n", curchar, c, ctable[c]);
1270 if (*s == ',')
1271 s++;
1273 return 0;
1276 void
1277 FreeTransTable()
1279 char ***p, **q;
1280 int i, j;
1282 if ((p = D_xtable) == 0)
1283 return;
1284 for (i = 0; i < 256; i++, p++)
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);
1294 free(D_xtable);
1296 #endif /* FONT */
1298 static int
1299 copyarg(pp, s)
1300 char **pp, *s;
1302 int l;
1303 char *p;
1305 for (l = 0, p = *pp; *p && *p != ','; p++)
1307 if (QUOTES(p))
1308 p++;
1309 if (s)
1310 *s++ = *p;
1311 l++;
1313 if (*p == ',')
1314 p++;
1315 *pp = p;
1316 return l;
1322 ** Termcap routines that use our extra_incap
1326 static int
1327 e_tgetent(bp, name)
1328 char *bp, *name;
1330 int r;
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;
1345 /* findcap:
1346 * cap = capability we are looking for
1347 * tepp = pointer to bufferpointer
1348 * n = size of buffer (0 = infinity)
1351 static char *
1352 findcap(cap, tepp, n)
1353 char *cap;
1354 char **tepp;
1355 int n;
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;
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; )
1370 if (strncmp(p, cap, capl) == 0)
1372 p += capl;
1373 c = *p;
1374 if (c && c != ':' && c != '@')
1375 p++;
1376 if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
1377 cp = tep;
1379 while ((c = *p))
1381 p++;
1382 if (mode == 0)
1384 if (c == ':')
1385 break;
1386 if (c == '^')
1387 mode = 1;
1388 if (c == '\\')
1389 mode = 2;
1391 else if (mode == 1)
1393 mode = 0;
1394 c = c & 0x1f;
1396 else if (mode == 2)
1398 mode = 0;
1399 switch(c)
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;
1434 if (mode > 2)
1436 num = num * 8 + (c - '0');
1437 if (mode++ == 5 || (*p < '0' || *p > '9'))
1439 c = num;
1440 mode = 0;
1443 if (mode)
1444 continue;
1446 if (cp && n != 1)
1448 *cp++ = c;
1449 n--;
1452 if (cp)
1454 *cp++ = 0;
1455 *tepp = cp;
1456 debug2("'%s' found in extra_incap -> %s\n", cap, tep);
1457 return tep;
1460 return 0;
1463 static char *
1464 e_tgetstr(cap, tepp)
1465 char *cap;
1466 char **tepp;
1468 char *tep;
1469 if ((tep = findcap(cap, tepp, 0)))
1470 return (*tep == '@') ? 0 : tep;
1471 return tgetstr(cap, tepp);
1474 static int
1475 e_tgetflag(cap)
1476 char *cap;
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;
1486 static int
1487 e_tgetnum(cap)
1488 char *cap;
1490 char buf[20], *bufp;
1491 char *tep, c;
1492 int res, base = 10;
1494 bufp = buf;
1495 if ((tep = findcap(cap, &bufp, 20)))
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;
1507 return tgetnum(cap);