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