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