Some more window-management from the window-list.
[screen-lua.git] / src / termcap.c
blob8f6b8b987ec647cc1686dea069d25908d4e5cd20
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
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.
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.
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 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include "config.h"
31 #include "screen.h"
32 #include "extern.h"
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 Z0width, Z1width;
40 extern int hardstatusemu;
41 #ifdef MAPKEYS
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
52 static void AddCap __P((char *));
53 static void MakeString __P((char *, char *, int, char *));
54 static char *findcap __P((char *, char **, int));
55 static int copyarg __P((char **, char *));
56 static int e_tgetent __P((char *, char *));
57 static char *e_tgetstr __P((char *, char **));
58 static int e_tgetflag __P((char *));
59 static int e_tgetnum __P((char *));
60 #ifdef MAPKEYS
61 static int findseq_ge __P((char *, int, unsigned char **));
62 static void setseqoff __P((unsigned char *, int, int));
63 static int addmapseq __P((char *, int, int));
64 static int remmapseq __P((char *, int));
65 #ifdef DEBUGG
66 static void dumpmap __P((void));
67 #endif
68 #endif
71 char Termcap[TERMCAP_BUFSIZE + 8]; /* new termcap +8:"TERMCAP=" */
72 static int Termcaplen;
73 static int tcLineLen;
74 char Term[MAXSTR+5]; /* +5: "TERM=" */
75 char screenterm[20]; /* new $TERM, usually "screen" */
77 char *extra_incap, *extra_outcap;
79 static const char TermcapConst[] = "\\\n\
80 \t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
81 \t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
82 \t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\
83 \t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:";
85 char *
86 gettermcapstring(s)
87 char *s;
89 int i;
91 if (display == 0 || s == 0)
92 return 0;
93 for (i = 0; i < T_N; i++)
95 if (term[i].type != T_STR)
96 continue;
97 if (strcmp(term[i].tcname, s) == 0)
98 return D_tcs[i].str;
100 return 0;
104 * Compile the terminal capabilities for a display.
105 * Input: tgetent(, D_termname) extra_incap, extra_outcap.
106 * Effect: display initialisation.
109 InitTermcap(wi, he)
110 int wi;
111 int he;
113 register char *s;
114 int i;
115 char tbuf[TERMCAP_BUFSIZE], *tp;
116 int t, xue, xse, xme;
118 ASSERT(display);
119 bzero(tbuf, sizeof(tbuf));
120 debug1("InitTermcap: looking for tgetent('%s')\n", D_termname);
121 if (*D_termname == 0 || e_tgetent(tbuf, D_termname) != 1)
123 #ifdef TERMINFO
124 Msg(0, "Cannot find terminfo entry for '%s'.", D_termname);
125 #else
126 Msg(0, "Cannot find termcap entry for '%s'.", D_termname);
127 #endif
128 return -1;
130 debug1("got it:\n%s\n", tbuf);
131 #ifdef DEBUG
132 if (extra_incap)
133 debug1("Extra incap: %s\n", extra_incap);
134 if (extra_outcap)
135 debug1("Extra outcap: %s\n", extra_outcap);
136 #endif
138 if ((D_tentry = (char *)malloc(TERMCAP_BUFSIZE + (extra_incap ? strlen(extra_incap) + 1 : 0))) == 0)
140 Msg(0, strnomem);
141 return -1;
145 * loop through all needed capabilities, record their values in the display
147 tp = D_tentry;
148 for (i = 0; i < T_N; i++)
150 switch(term[i].type)
152 case T_FLG:
153 D_tcs[i].flg = e_tgetflag(term[i].tcname);
154 break;
155 case T_NUM:
156 D_tcs[i].num = e_tgetnum(term[i].tcname);
157 break;
158 case T_STR:
159 D_tcs[i].str = e_tgetstr(term[i].tcname, &tp);
160 /* no empty strings, please */
161 if (D_tcs[i].str && *D_tcs[i].str == 0)
162 D_tcs[i].str = 0;
163 break;
164 default:
165 Panic(0, "Illegal tc type in entry #%d", i);
166 /*NOTREACHED*/
171 * Now a good deal of sanity checks on the retrieved capabilities.
173 if (D_HC)
175 Msg(0, "You can't run screen on a hardcopy terminal.");
176 return -1;
178 if (D_OS)
180 Msg(0, "You can't run screen on a terminal that overstrikes.");
181 return -1;
183 if (!D_CL)
185 Msg(0, "Clear screen capability required.");
186 return -1;
188 if (!D_CM)
190 Msg(0, "Addressable cursor capability required.");
191 return -1;
193 if ((s = getenv("COLUMNS")) && (i = atoi(s)) > 0)
194 D_CO = i;
195 if ((s = getenv("LINES")) && (i = atoi(s)) > 0)
196 D_LI = i;
197 if (wi)
198 D_CO = wi;
199 if (he)
200 D_LI = he;
201 if (D_CO <= 0)
202 D_CO = 80;
203 if (D_LI <= 0)
204 D_LI = 24;
206 if (D_CTF)
208 /* standard fixes for xterms etc */
209 /* assume color for everything that looks ansi-compatible */
210 if (!D_CAF && D_ME && (InStr(D_ME, "\033[m") || InStr(D_ME, "\033[0m")))
212 #ifdef TERMINFO
213 D_CAF = "\033[3%p1%dm";
214 D_CAB = "\033[4%p1%dm";
215 #else
216 D_CAF = "\033[3%dm";
217 D_CAB = "\033[4%dm";
218 #endif
220 if (D_OP && InStr(D_OP, "\033[39;49m"))
221 D_CAX = 1;
222 if (D_OP && (InStr(D_OP, "\033[m") || InStr(D_OP, "\033[0m")))
223 D_OP = 0;
224 /* ISO2022 */
225 if ((D_EA && InStr(D_EA, "\033(B")) || (D_AS && InStr(D_AS, "\033(0")))
226 D_CG0 = 1;
227 if (InStr(D_termname, "xterm") || InStr(D_termname, "rxvt") ||
228 (D_CKM && InStr(D_CKM, "\033[M")))
229 D_CXT = 1;
230 /* "be" seems to be standard for xterms... */
231 if (D_CXT)
232 D_BE = 1;
234 if (nwin_options.flowflag == nwin_undef.flowflag)
235 nwin_default.flowflag = D_CNF ? FLOW_NOW * 0 :
236 D_NX ? FLOW_NOW * 1 :
237 FLOW_AUTOFLAG;
238 D_CLP |= (!D_AM || D_XV || D_XN);
239 if (!D_BL)
240 D_BL = "\007";
241 if (!D_BC)
243 if (D_BS)
244 D_BC = "\b";
245 else
246 D_BC = D_LE;
248 if (!D_CR)
249 D_CR = "\r";
250 if (!D_NL)
251 D_NL = "\n";
254 * Set up attribute handling.
255 * This is rather complicated because termcap has different
256 * attribute groups.
259 if (D_UG > 0)
260 D_US = D_UE = 0;
261 if (D_SG > 0)
262 D_SO = D_SE = 0;
263 /* Unfortunately there is no 'mg' capability.
264 * For now we think that mg > 0 if sg and ug > 0.
266 if (D_UG > 0 && D_SG > 0)
267 D_MH = D_MD = D_MR = D_MB = D_ME = 0;
269 xue = ATYP_U;
270 xse = ATYP_S;
271 xme = ATYP_M;
273 if (D_SO && D_SE == 0)
275 Msg(0, "Warning: 'so' but no 'se' capability.");
276 if (D_ME)
277 xse = xme;
278 else
279 D_SO = 0;
281 if (D_US && D_UE == 0)
283 Msg(0, "Warning: 'us' but no 'ue' capability.");
284 if (D_ME)
285 xue = xme;
286 else
287 D_US = 0;
289 if ((D_MH || D_MD || D_MR || D_MB) && D_ME == 0)
291 Msg(0, "Warning: 'm?' but no 'me' capability.");
292 D_MH = D_MD = D_MR = D_MB = 0;
295 * Does ME also reverse the effect of SO and/or US? This is not
296 * clearly specified by the termcap manual. Anyway, we should at
297 * least look whether ME and SE/UE are equal:
299 if (D_UE && D_SE && strcmp(D_SE, D_UE) == 0)
300 xse = xue;
301 if (D_SE && D_ME && strcmp(D_ME, D_SE) == 0)
302 xse = xme;
303 if (D_UE && D_ME && strcmp(D_ME, D_UE) == 0)
304 xue = xme;
306 for (i = 0; i < NATTR; i++)
308 D_attrtab[i] = D_tcs[T_ATTR + i].str;
309 D_attrtyp[i] = i == ATTR_SO ? xse : (i == ATTR_US ? xue : xme);
312 /* Set up missing entries (attributes are priority ordered) */
313 s = 0;
314 t = 0;
315 for (i = 0; i < NATTR; i++)
316 if ((s = D_attrtab[i]))
318 t = D_attrtyp[i];
319 break;
321 for (i = 0; i < NATTR; i++)
323 if (D_attrtab[i] == 0)
325 D_attrtab[i] = s;
326 D_attrtyp[i] = t;
328 else
330 s = D_attrtab[i];
331 t = D_attrtyp[i];
334 if (D_CAF || D_CAB || D_CSF || D_CSB)
335 D_hascolor = 1;
336 if (D_UT)
337 D_BE = 1; /* screen erased with background color */
339 if (!D_DO)
340 D_DO = D_NL;
341 if (!D_SF)
342 D_SF = D_NL;
343 if (D_IN)
344 D_IC = D_IM = 0;
345 if (D_EI == 0)
346 D_IM = 0;
347 /* some strange termcap entries have IC == IM */
348 if (D_IC && D_IM && strcmp(D_IC, D_IM) == 0)
349 D_IC = 0;
350 if (D_KE == 0)
351 D_KS = 0;
352 if (D_CVN == 0)
353 D_CVR = 0;
354 if (D_VE == 0)
355 D_VI = D_VS = 0;
356 if (D_CCE == 0)
357 D_CCS = 0;
359 #ifdef FONT
360 if (D_CG0)
362 if (D_CS0 == 0)
363 #ifdef TERMINFO
364 D_CS0 = "\033(%p1%c";
365 #else
366 D_CS0 = "\033(%.";
367 #endif
368 if (D_CE0 == 0)
369 D_CE0 = "\033(B";
370 D_AC = 0;
371 D_EA = 0;
373 else if (D_AC || (D_AS && D_AE)) /* some kind of graphics */
375 D_CS0 = (D_AS && D_AE) ? D_AS : "";
376 D_CE0 = (D_AS && D_AE) ? D_AE : "";
377 D_CC0 = D_AC;
379 else
381 D_CS0 = D_CE0 = "";
382 D_CC0 = 0;
383 D_AC = ""; /* enable default string */
386 for (i = 0; i < 256; i++)
387 D_c0_tab[i] = i;
388 if (D_AC)
390 /* init with default string first */
391 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>";
392 for (i = strlen(s) & ~1; i >= 0; i -= 2)
393 D_c0_tab[(int)(unsigned char)s[i]] = s[i + 1];
395 if (D_CC0)
396 for (i = strlen(D_CC0) & ~1; i >= 0; i -= 2)
397 D_c0_tab[(int)(unsigned char)D_CC0[i]] = D_CC0[i + 1];
398 debug1("ISO2022 = %d\n", D_CG0);
399 #endif /* FONT */
400 if (D_PF == 0)
401 D_PO = 0;
402 debug2("terminal size is %d, %d (says TERMCAP)\n", D_CO, D_LI);
404 #ifdef FONT
405 if (D_CXC)
406 if (CreateTransTable(D_CXC))
407 return -1;
408 #endif
410 /* Termcap fields Z0 & Z1 contain width-changing sequences. */
411 if (D_CZ1 == 0)
412 D_CZ0 = 0;
413 Z0width = 132;
414 Z1width = 80;
416 CheckScreenSize(0);
418 if (D_TS == 0 || D_FS == 0 || D_DS == 0)
419 D_HS = 0;
420 if (D_HS)
422 debug("oy! we have a hardware status line, says termcap\n");
423 if (D_WS < 0)
424 D_WS = 0;
426 D_has_hstatus = hardstatusemu & ~HSTATUS_ALWAYS;
427 if (D_HS && !(hardstatusemu & HSTATUS_ALWAYS))
428 D_has_hstatus = HSTATUS_HS;
430 #ifdef ENCODINGS
431 if (D_CKJ)
433 int enc = FindEncoding(D_CKJ);
434 if (enc != -1)
435 D_encoding = enc;
437 #endif
438 if (!D_tcs[T_NAVIGATE].str && D_tcs[T_NAVIGATE + 1].str)
439 D_tcs[T_NAVIGATE].str = D_tcs[T_NAVIGATE + 1].str; /* kh = @1 */
440 if (!D_tcs[T_NAVIGATE + 2].str && D_tcs[T_NAVIGATE + 3].str)
441 D_tcs[T_NAVIGATE + 2].str = D_tcs[T_NAVIGATE + 3].str; /* kH = @7 */
443 D_UPcost = CalcCost(D_UP);
444 D_DOcost = CalcCost(D_DO);
445 D_NLcost = CalcCost(D_NL);
446 D_LEcost = CalcCost(D_BC);
447 D_NDcost = CalcCost(D_ND);
448 D_CRcost = CalcCost(D_CR);
449 D_IMcost = CalcCost(D_IM);
450 D_EIcost = CalcCost(D_EI);
452 #ifdef AUTO_NUKE
453 if (D_CAN)
455 debug("termcap has AN, setting autonuke\n");
456 D_auto_nuke = 1;
458 #endif
459 if (D_COL > 0)
461 debug1("termcap has OL (%d), setting limit\n", D_COL);
462 D_obufmax = D_COL;
463 D_obuflenmax = D_obuflen - D_obufmax;
466 /* Some xterm entries set F0 and F10 to the same string. Nuke F0. */
467 if (D_tcs[T_CAPS].str && D_tcs[T_CAPS + 10].str && !strcmp(D_tcs[T_CAPS].str, D_tcs[T_CAPS + 10].str))
468 D_tcs[T_CAPS].str = 0;
469 /* Some xterm entries set kD to ^?. Nuke it. */
470 if (D_tcs[T_NAVIGATE_DELETE].str && !strcmp(D_tcs[T_NAVIGATE_DELETE].str, "\0177"))
471 D_tcs[T_NAVIGATE_DELETE].str = 0;
472 /* wyse52 entries have kcub1 == kb == ^H. Nuke... */
473 if (D_tcs[T_CURSOR + 3].str && !strcmp(D_tcs[T_CURSOR + 3].str, "\008"))
474 D_tcs[T_CURSOR + 3].str = 0;
476 #ifdef MAPKEYS
477 D_nseqs = 0;
478 for (i = 0; i < T_OCAPS - T_CAPS; i++)
479 remap(i, 1);
480 for (i = 0; i < kmap_extn; i++)
481 remap(i + (KMAP_KEYS+KMAP_AKEYS), 1);
482 D_seqp = D_kmaps + 3;
483 D_seql = 0;
484 D_seqh = 0;
485 #endif
487 D_tcinited = 1;
488 MakeTermcap(0);
489 #ifdef MAPKEYS
490 CheckEscape();
491 #endif
492 return 0;
495 #ifdef MAPKEYS
498 remap(n, map)
499 int n;
500 int map;
502 char *s = 0;
503 int fl = 0, domap = 0;
504 struct action *a1, *a2, *tab;
505 int l = 0;
506 struct kmap_ext *kme = 0;
508 a1 = 0;
509 if (n >= KMAP_KEYS+KMAP_AKEYS)
511 kme = kmap_exts + (n - (KMAP_KEYS+KMAP_AKEYS));
512 s = kme->str;
513 l = kme->fl & ~KMAP_NOTIMEOUT;
514 fl = kme->fl & KMAP_NOTIMEOUT;
515 a1 = &kme->um;
517 tab = umtab;
518 for (;;)
520 a2 = 0;
521 if (n < KMAP_KEYS+KMAP_AKEYS)
523 a1 = &tab[n];
524 if (n >= KMAP_KEYS)
525 n -= T_OCAPS-T_CURSOR;
526 s = D_tcs[n + T_CAPS].str;
527 l = s ? strlen(s) : 0;
528 if (n >= T_CURSOR-T_CAPS)
529 a2 = &tab[n + (T_OCAPS-T_CURSOR)];
531 if (s == 0 || l == 0)
532 return 0;
533 if (a1 && a1->nr == RC_ILLEGAL)
534 a1 = 0;
535 if (a2 && a2->nr == RC_ILLEGAL)
536 a2 = 0;
537 if (a1 && a1->nr == RC_STUFF && a1->args[0] && strcmp(a1->args[0], s) == 0)
538 a1 = 0;
539 if (a2 && a2->nr == RC_STUFF && a2->args[0] && strcmp(a2->args[0], s) == 0)
540 a2 = 0;
541 domap |= (a1 || a2);
542 if (tab == umtab)
544 tab = dmtab;
545 a1 = kme ? &kme->dm : 0;
547 else if (tab == dmtab)
549 tab = mmtab;
550 a1 = kme ? &kme->mm : 0;
552 else
553 break;
555 if (n < KMAP_KEYS)
556 domap = 1;
557 if (map == 0 && domap)
558 return 0;
559 if (map && !domap)
560 return 0;
561 debug3("%smapping %s %#x\n", map? "" :"un",s,n);
562 if (map)
563 return addmapseq(s, l, n | fl);
564 else
565 return remmapseq(s, l);
568 void
569 CheckEscape()
571 struct display *odisplay;
572 int i, nr;
574 if (DefaultEsc >= 0)
575 return;
577 odisplay = display;
578 for (display = displays; display; display = display->d_next)
580 for (i = 0; i < D_nseqs; i += D_kmaps[i + 2] * 2 + 4)
582 nr = (D_kmaps[i] << 8 | D_kmaps[i + 1]) & ~KMAP_NOTIMEOUT;
583 if (nr < KMAP_KEYS+KMAP_AKEYS)
585 if (umtab[nr].nr == RC_COMMAND)
586 break;
587 if (umtab[nr].nr == RC_ILLEGAL && dmtab[nr].nr == RC_COMMAND)
588 break;
590 else
592 struct kmap_ext *kme = kmap_exts + nr - (KMAP_KEYS+KMAP_AKEYS);
593 if (kme->um.nr == RC_COMMAND)
594 break;
595 if (kme->um.nr == RC_ILLEGAL && kme->dm.nr == RC_COMMAND)
596 break;
600 if (display == 0)
602 display = odisplay;
603 return;
605 SetEscape((struct acluser *)0, Ctrl('a'), 'a');
606 if (odisplay->d_user->u_Esc == -1)
607 odisplay->d_user->u_Esc = DefaultEsc;
608 if (odisplay->d_user->u_MetaEsc == -1)
609 odisplay->d_user->u_MetaEsc = DefaultMetaEsc;
610 display = 0;
611 Msg(0, "Warning: escape char set back to ^A");
612 display = odisplay;
615 static int
616 findseq_ge(seq, k, sp)
617 char *seq;
618 int k;
619 unsigned char **sp;
621 unsigned char *p;
622 int j, l;
624 p = D_kmaps;
625 while (p - D_kmaps < D_nseqs)
627 l = p[2];
628 p += 3;
629 for (j = 0; ; j++)
631 if (j == k || j == l)
632 j = l - k;
633 else if (p[j] != ((unsigned char *)seq)[j])
634 j = p[j] - ((unsigned char *)seq)[j];
635 else
636 continue;
637 break;
639 if (j >= 0)
641 *sp = p - 3;
642 return j;
644 p += 2 * l + 1;
646 *sp = p;
647 return -1;
650 static void
651 setseqoff(p, i, o)
652 unsigned char *p;
653 int i;
654 int o;
656 unsigned char *q;
657 int l, k;
659 k = p[2];
660 if (o < 256)
662 p[k + 4 + i] = o;
663 return;
665 /* go for the biggest offset */
666 for (q = p + k * 2 + 4; ; q += l * 2 + 4)
668 l = q[2];
669 if ((q + l * 2 - p) / 2 >= 256)
671 p[k + 4 + i] = (q - p - 4) / 2;
672 return;
677 static int
678 addmapseq(seq, k, nr)
679 char *seq;
680 int k;
681 int nr;
683 int i, j, l, mo, m;
684 unsigned char *p, *q;
686 if (k >= 254)
687 return -1;
688 j = findseq_ge(seq, k, &p);
689 if (j == 0)
691 p[0] = nr >> 8;
692 p[1] = nr;
693 return 0;
695 i = p - D_kmaps;
696 if (D_nseqs + 2 * k + 4 >= D_aseqs)
698 D_kmaps = (unsigned char *)xrealloc((char *)D_kmaps, D_aseqs + 256);
699 D_aseqs += 256;
700 p = D_kmaps + i;
702 D_seqp = D_kmaps + 3;
703 D_seql = 0;
704 D_seqh = 0;
705 evdeq(&D_mapev);
706 if (j > 0)
707 bcopy((char *)p, (char *)p + 2 * k + 4, D_nseqs - i);
708 p[0] = nr >> 8;
709 p[1] = nr;
710 p[2] = k;
711 bcopy(seq, (char *)p + 3, k);
712 bzero(p + k + 3, k + 1);
713 D_nseqs += 2 * k + 4;
714 if (j > 0)
716 q = p + 2 * k + 4;
717 l = q[2];
718 for (i = 0; i < k; i++)
720 if (p[3 + i] != q[3 + i])
722 p[k + 4 + i] = k;
723 break;
725 setseqoff(p, i, q[l + 4 + i] ? q[l + 4 + i] + k + 2: 0);
728 for (q = D_kmaps; q < p; q += 2 * l + 4)
730 l = q[2];
731 for (m = j = 0; j < l; j++)
733 mo = m;
734 if (!m && q[3 + j] != seq[j])
735 m = 1;
736 if (q[l + 4 + j] == 0)
738 if (!mo && m)
739 setseqoff(q, j, (p - q - 4) / 2);
741 else if (q + q[l + 4 + j] * 2 + 4 > p || (q + q[l + 4 + j] * 2 + 4 == p && !m))
742 setseqoff(q, j, q[l + 4 + j] + k + 2);
745 #ifdef DEBUGG
746 dumpmap();
747 #endif
748 return 0;
751 static int
752 remmapseq(seq, k)
753 char *seq;
754 int k;
756 int j, l;
757 unsigned char *p, *q;
759 if (k >= 254 || (j = findseq_ge(seq, k, &p)) != 0)
760 return -1;
761 for (q = D_kmaps; q < p; q += 2 * l + 4)
763 l = q[2];
764 for (j = 0; j < l; j++)
766 if (q + q[l + 4 + j] * 2 + 4 == p)
767 setseqoff(q, j, p[k + 4 + j] ? q[l + 4 + j] + p[k + 4 + j] - k : 0);
768 else if (q + q[l + 4 + j] * 2 + 4 > p)
769 q[l + 4 + j] -= k + 2;
772 if (D_kmaps + D_nseqs > p + 2 * k + 4)
773 bcopy((char *)p + 2 * k + 4, (char *)p, (D_kmaps + D_nseqs) - (p + 2 * k + 4));
774 D_nseqs -= 2 * k + 4;
775 D_seqp = D_kmaps + 3;
776 D_seql = 0;
777 D_seqh = 0;
778 evdeq(&D_mapev);
779 #ifdef DEBUGG
780 dumpmap();
781 #endif
782 return 0;
785 #ifdef DEBUGG
786 static void
787 dumpmap()
789 unsigned char *p;
790 int j, n, l, o, oo;
791 debug("Mappings:\n");
792 p = D_kmaps;
793 if (!p)
794 return;
795 while (p < D_kmaps + D_nseqs)
797 l = p[2];
798 debug1("%d: ", p - D_kmaps + 3);
799 for (j = 0; j < l; j++)
801 o = oo = p[l + 4 + j];
802 if (o)
803 o = 2 * o + 4 + (p + 3 + j - D_kmaps);
804 if (p[j + 3] > ' ' && p[j + 3] < 0177)
806 debug3("%c[%d:%d] ", p[j + 3], oo, o);
808 else
809 debug3("\\%03o[%d:%d] ", p[j + 3], oo, o);
811 n = p[0] << 8 | p[1];
812 debug2(" ==> %d%s\n", n & ~KMAP_NOTIMEOUT, (n & KMAP_NOTIMEOUT) ? " (no timeout)" : "");
813 p += 2 * l + 4;
816 #endif /* DEBUGG */
818 #endif /* MAPKEYS */
821 * Appends to the static variable Termcap
823 static void
824 AddCap(s)
825 char *s;
827 register int n;
829 if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < TERMCAP_BUFSIZE - 4 - 1)
831 strcpy(Termcap + Termcaplen, "\\\n\t:");
832 Termcaplen += 4;
833 tcLineLen = 0;
835 if (Termcaplen + n < TERMCAP_BUFSIZE - 1)
837 strcpy(Termcap + Termcaplen, s);
838 Termcaplen += n;
839 tcLineLen += n;
841 else
842 Panic(0, "TERMCAP overflow - sorry.");
846 * Reads a displays capabilities and reconstructs a termcap entry in the
847 * global buffer "Termcap". A pointer to this buffer is returned.
849 char *
850 MakeTermcap(aflag)
851 int aflag;
853 char buf[TERMCAP_BUFSIZE];
854 register char *p, *cp, *s, ch, *tname;
855 int i, wi, he;
856 #if 0
857 int found;
858 #endif
860 if (display)
862 wi = D_width;
863 he = D_height;
864 tname = D_termname;
866 else
868 wi = 80;
869 he = 24;
870 tname = "vt100";
872 debug1("MakeTermcap(%d)\n", aflag);
873 if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE)
875 sprintf(Termcap, "TERMCAP=%s", s);
876 strcpy(Term, "TERM=screen");
877 debug("getenvSCREENCAP o.k.\n");
878 return Termcap;
880 Termcaplen = 0;
881 debug1("MakeTermcap screenterm='%s'\n", screenterm);
882 debug1("MakeTermcap termname='%s'\n", tname);
883 if (*screenterm == '\0' || strlen(screenterm) > MAXSTR - 3)
885 debug("MakeTermcap sets screenterm=screen\n");
886 strcpy(screenterm, "screen");
888 #if 0
889 found = 1;
890 #endif
893 strcpy(Term, "TERM=");
894 p = Term + 5;
895 if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR-1)
897 sprintf(p, "%s.%s", screenterm, tname);
898 if (e_tgetent(buf, p) == 1)
899 break;
901 #ifdef COLOR
902 if (nwin_default.bce)
904 sprintf(p, "%s-bce", screenterm);
905 if (e_tgetent(buf, p) == 1)
906 break;
908 #endif
909 #ifdef CHECK_SCREEN_W
910 if (wi >= 132)
912 sprintf(p, "%s-w", screenterm);
913 if (e_tgetent(buf, p) == 1)
914 break;
916 #endif
917 strcpy(p, screenterm);
918 if (e_tgetent(buf, p) == 1)
919 break;
920 strcpy(p, "vt100");
921 #if 0
922 found = 0;
923 #endif
925 while (0); /* Goto free programming... */
927 #if 0
928 #ifndef TERMINFO
929 /* check for compatibility problems, displays == 0 after fork */
930 if (found)
932 char xbuf[TERMCAP_BUFSIZE], *xbp = xbuf;
933 if (tgetstr("im", &xbp) && tgetstr("ic", &xbp) && displays)
935 Msg(0, "Warning: im and ic set in %s termcap entry", p);
938 #endif
939 #endif
941 tcLineLen = 100; /* Force NL */
942 if (strlen(Term) > TERMCAP_BUFSIZE - 40)
943 strcpy(Term, "too_long");
944 sprintf(Termcap, "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal:", Term + 5);
945 Termcaplen = strlen(Termcap);
946 debug1("MakeTermcap decided '%s'\n", p);
947 if (extra_outcap && *extra_outcap)
949 for (cp = extra_outcap; (p = index(cp, ':')); cp = p)
951 ch = *++p;
952 *p = '\0';
953 AddCap(cp);
954 *p = ch;
956 tcLineLen = 100; /* Force NL */
958 debug1("MakeTermcap after outcap '%s'\n", (char *)TermcapConst);
959 if (Termcaplen + strlen(TermcapConst) < TERMCAP_BUFSIZE)
961 strcpy(Termcap + Termcaplen, (char *)TermcapConst);
962 Termcaplen += strlen(TermcapConst);
964 sprintf(buf, "li#%d:co#%d:", he, wi);
965 AddCap(buf);
966 AddCap("am:");
967 if (aflag || (force_vt && !D_COP) || D_CLP || !D_AM)
969 AddCap("xn:");
970 AddCap("xv:");
971 AddCap("LP:");
973 if (aflag || (D_CS && D_SR) || D_AL || D_CAL)
975 AddCap("sr=\\EM:");
976 AddCap("al=\\E[L:");
977 AddCap("AL=\\E[%dL:");
979 else if (D_SR)
980 AddCap("sr=\\EM:");
981 if (aflag || D_CS)
982 AddCap("cs=\\E[%i%d;%dr:");
983 if (aflag || D_CS || D_DL || D_CDL)
985 AddCap("dl=\\E[M:");
986 AddCap("DL=\\E[%dM:");
988 if (aflag || D_DC || D_CDC)
990 AddCap("dc=\\E[P:");
991 AddCap("DC=\\E[%dP:");
993 if (aflag || D_CIC || D_IC || D_IM)
995 AddCap("im=\\E[4h:");
996 AddCap("ei=\\E[4l:");
997 AddCap("mi:");
998 AddCap("IC=\\E[%d@:");
1000 #ifdef MAPKEYS
1001 AddCap("ks=\\E[?1h\\E=:");
1002 AddCap("ke=\\E[?1l\\E>:");
1003 #endif
1004 AddCap("vi=\\E[?25l:");
1005 AddCap("ve=\\E[34h\\E[?25h:");
1006 AddCap("vs=\\E[34l:");
1007 AddCap("ti=\\E[?1049h:");
1008 AddCap("te=\\E[?1049l:");
1009 if (display)
1011 if (D_US)
1013 AddCap("us=\\E[4m:");
1014 AddCap("ue=\\E[24m:");
1016 if (D_SO)
1018 AddCap("so=\\E[3m:");
1019 AddCap("se=\\E[23m:");
1021 if (D_MB)
1022 AddCap("mb=\\E[5m:");
1023 if (D_MD)
1024 AddCap("md=\\E[1m:");
1025 if (D_MH)
1026 AddCap("mh=\\E[2m:");
1027 if (D_MR)
1028 AddCap("mr=\\E[7m:");
1029 if (D_MB || D_MD || D_MH || D_MR)
1030 AddCap("me=\\E[m:ms:");
1031 if (D_hascolor)
1032 AddCap("Co#8:pa#64:AF=\\E[3%dm:AB=\\E[4%dm:op=\\E[39;49m:AX:");
1033 if (D_VB)
1034 AddCap("vb=\\Eg:");
1035 #ifndef MAPKEYS
1036 if (D_KS)
1038 AddCap("ks=\\E=:");
1039 AddCap("ke=\\E>:");
1041 if (D_CCS)
1043 AddCap("CS=\\E[?1h:");
1044 AddCap("CE=\\E[?1l:");
1046 #endif
1047 if (D_CG0)
1048 AddCap("G0:");
1049 if (D_CC0 || (D_CS0 && *D_CS0))
1051 AddCap("as=\\E(0:");
1052 AddCap("ae=\\E(B:");
1053 /* avoid `` because some shells dump core... */
1054 AddCap("ac=\\140\\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:");
1056 if (D_PO)
1058 AddCap("po=\\E[5i:");
1059 AddCap("pf=\\E[4i:");
1061 if (D_CZ0)
1063 AddCap("Z0=\\E[?3h:");
1064 AddCap("Z1=\\E[?3l:");
1066 if (D_CWS)
1067 AddCap("WS=\\E[8;%d;%dt:");
1069 for (i = T_CAPS; i < T_ECAPS; i++)
1071 #ifdef MAPKEYS
1072 struct action *act;
1073 if (i < T_OCAPS)
1075 if (i >= T_KEYPAD) /* don't put keypad codes in TERMCAP */
1076 continue; /* - makes it too big */
1077 if (i >= T_CURSOR && i < T_OCAPS)
1079 act = &umtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
1080 if (act->nr == RC_ILLEGAL)
1081 act = &dmtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
1083 else
1085 act = &umtab[i - T_CAPS];
1086 if (act->nr == RC_ILLEGAL)
1087 act = &dmtab[i - T_CAPS];
1089 if (act->nr == RC_ILLEGAL && (i == T_NAVIGATE + 1 || i == T_NAVIGATE + 3))
1091 /* kh -> @1, kH -> @7 */
1092 act = &umtab[i - T_CAPS - 1];
1093 if (act->nr == RC_ILLEGAL)
1094 act = &dmtab[i - T_CAPS - 1];
1096 if (act->nr != RC_ILLEGAL)
1098 if (act->nr == RC_STUFF)
1100 MakeString(term[i].tcname, buf, sizeof(buf), act->args[0]);
1101 AddCap(buf);
1103 continue;
1106 #endif
1107 if (display == 0)
1108 continue;
1109 switch(term[i].type)
1111 case T_STR:
1112 if (D_tcs[i].str == 0)
1113 break;
1114 MakeString(term[i].tcname, buf, sizeof(buf), D_tcs[i].str);
1115 AddCap(buf);
1116 break;
1117 case T_FLG:
1118 if (D_tcs[i].flg == 0)
1119 break;
1120 sprintf(buf, "%s:", term[i].tcname);
1121 AddCap(buf);
1122 break;
1123 default:
1124 break;
1127 debug("MakeTermcap: end\n");
1128 return Termcap;
1131 static void
1132 MakeString(cap, buf, buflen, s)
1133 char *cap, *buf;
1134 int buflen;
1135 char *s;
1137 register char *p, *pmax;
1138 register unsigned int c;
1140 p = buf;
1141 pmax = p + buflen - (3+4+2);
1142 *p++ = *cap++;
1143 *p++ = *cap;
1144 *p++ = '=';
1145 while ((c = *s++) && (p < pmax))
1147 switch (c)
1149 case '\033':
1150 *p++ = '\\';
1151 *p++ = 'E';
1152 break;
1153 case ':':
1154 strcpy(p, "\\072");
1155 p += 4;
1156 break;
1157 case '^':
1158 case '\\':
1159 *p++ = '\\';
1160 *p++ = c;
1161 break;
1162 default:
1163 if (c >= 200)
1165 sprintf(p, "\\%03o", c & 0377);
1166 p += 4;
1168 else if (c < ' ')
1170 *p++ = '^';
1171 *p++ = c + '@';
1173 else
1174 *p++ = c;
1177 *p++ = ':';
1178 *p = '\0';
1182 #undef QUOTES
1183 #define QUOTES(p) \
1184 (*p == '\\' && (p[1] == '\\' || p[1] == ',' || p[1] == '%'))
1186 #ifdef FONT
1188 CreateTransTable(s)
1189 char *s;
1191 int curchar;
1192 char *templ, *arg;
1193 int templlen;
1194 int templnsub;
1195 char *p, *sx;
1196 char **ctable;
1197 int l, c;
1199 if ((D_xtable = (char ***)calloc(256, sizeof(char **))) == 0)
1201 Msg(0, strnomem);
1202 return -1;
1205 while (*s)
1207 if (QUOTES(s))
1208 s++;
1209 curchar = (unsigned char)*s++;
1210 if (curchar == 'B')
1211 curchar = 0; /* ASCII */
1212 templ = s;
1213 templlen = 0;
1214 templnsub = 0;
1215 if (D_xtable[curchar] == 0)
1217 if ((D_xtable[curchar] = (char **)calloc(257, sizeof(char *))) == 0)
1219 Msg(0, strnomem);
1220 FreeTransTable();
1221 return -1;
1224 ctable = D_xtable[curchar];
1225 for(; *s && *s != ','; s++)
1227 if (QUOTES(s))
1228 s++;
1229 else if (*s == '%')
1231 templnsub++;
1232 continue;
1234 templlen++;
1236 if (*s++ == 0)
1237 break;
1238 while (*s && *s != ',')
1240 c = (unsigned char)*s++;
1241 if (QUOTES((s - 1)))
1242 c = (unsigned char)*s++;
1243 else if (c == '%')
1244 c = 256;
1245 if (ctable[c])
1246 free(ctable[c]);
1247 arg = s;
1248 l = copyarg(&s, (char *)0);
1249 if (c != 256)
1250 l = l * templnsub + templlen;
1251 if ((ctable[c] = (char *)malloc(l + 1)) == 0)
1253 Msg(0, strnomem);
1254 FreeTransTable();
1255 return -1;
1257 sx = ctable[c];
1258 for (p = ((c == 256) ? "%" : templ); *p && *p != ','; p++)
1260 if (QUOTES(p))
1261 p++;
1262 else if (*p == '%')
1264 s = arg;
1265 sx += copyarg(&s, sx);
1266 continue;
1268 *sx++ = *p;
1270 *sx = 0;
1271 ASSERT(ctable[c] + l * templnsub + templlen == sx);
1272 debug3("XC: %c %c->%s\n", curchar, c, ctable[c]);
1274 if (*s == ',')
1275 s++;
1277 return 0;
1280 void
1281 FreeTransTable()
1283 char ***p, **q;
1284 int i, j;
1286 if ((p = D_xtable) == 0)
1287 return;
1288 for (i = 0; i < 256; i++, p++)
1290 if (*p == 0)
1291 continue;
1292 q = *p;
1293 for (j = 0; j < 257; j++, q++)
1294 if (*q)
1295 free(*q);
1296 free(*p);
1298 free(D_xtable);
1300 #endif /* FONT */
1302 static int
1303 copyarg(pp, s)
1304 char **pp, *s;
1306 int l;
1307 char *p;
1309 for (l = 0, p = *pp; *p && *p != ','; p++)
1311 if (QUOTES(p))
1312 p++;
1313 if (s)
1314 *s++ = *p;
1315 l++;
1317 if (*p == ',')
1318 p++;
1319 *pp = p;
1320 return l;
1326 ** Termcap routines that use our extra_incap
1330 static int
1331 e_tgetent(bp, name)
1332 char *bp, *name;
1334 int r;
1336 #ifdef USE_SETEUID
1337 xseteuid(real_uid);
1338 xsetegid(real_gid);
1339 #endif
1340 r = tgetent(bp, name);
1341 #ifdef USE_SETEUID
1342 xseteuid(eff_uid);
1343 xsetegid(eff_gid);
1344 #endif
1345 return r;
1349 /* findcap:
1350 * cap = capability we are looking for
1351 * tepp = pointer to bufferpointer
1352 * n = size of buffer (0 = infinity)
1355 static char *
1356 findcap(cap, tepp, n)
1357 char *cap;
1358 char **tepp;
1359 int n;
1361 char *tep;
1362 char c, *p, *cp;
1363 int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */
1364 int num = 0, capl;
1366 if (!extra_incap)
1367 return 0;
1368 tep = *tepp;
1369 capl = strlen(cap);
1370 cp = 0;
1371 mode = 0;
1372 for (p = extra_incap; *p; )
1374 if (strncmp(p, cap, capl) == 0)
1376 p += capl;
1377 c = *p;
1378 if (c && c != ':' && c != '@')
1379 p++;
1380 if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
1381 cp = tep;
1383 while ((c = *p))
1385 p++;
1386 if (mode == 0)
1388 if (c == ':')
1389 break;
1390 if (c == '^')
1391 mode = 1;
1392 if (c == '\\')
1393 mode = 2;
1395 else if (mode == 1)
1397 mode = 0;
1398 c = c & 0x1f;
1400 else if (mode == 2)
1402 mode = 0;
1403 switch(c)
1405 case '0':
1406 case '1':
1407 case '2':
1408 case '3':
1409 case '4':
1410 case '5':
1411 case '6':
1412 case '7':
1413 case '8':
1414 case '9':
1415 mode = 3;
1416 num = 0;
1417 break;
1418 case 'E':
1419 c = 27;
1420 break;
1421 case 'n':
1422 c = '\n';
1423 break;
1424 case 'r':
1425 c = '\r';
1426 break;
1427 case 't':
1428 c = '\t';
1429 break;
1430 case 'b':
1431 c = '\b';
1432 break;
1433 case 'f':
1434 c = '\f';
1435 break;
1438 if (mode > 2)
1440 num = num * 8 + (c - '0');
1441 if (mode++ == 5 || (*p < '0' || *p > '9'))
1443 c = num;
1444 mode = 0;
1447 if (mode)
1448 continue;
1450 if (cp && n != 1)
1452 *cp++ = c;
1453 n--;
1456 if (cp)
1458 *cp++ = 0;
1459 *tepp = cp;
1460 debug2("'%s' found in extra_incap -> %s\n", cap, tep);
1461 return tep;
1464 return 0;
1467 static char *
1468 e_tgetstr(cap, tepp)
1469 char *cap;
1470 char **tepp;
1472 char *tep;
1473 if ((tep = findcap(cap, tepp, 0)))
1474 return (*tep == '@') ? 0 : tep;
1475 return tgetstr(cap, tepp);
1478 static int
1479 e_tgetflag(cap)
1480 char *cap;
1482 char buf[2], *bufp;
1483 char *tep;
1484 bufp = buf;
1485 if ((tep = findcap(cap, &bufp, 2)))
1486 return (*tep == '@') ? 0 : 1;
1487 return tgetflag(cap) > 0;
1490 static int
1491 e_tgetnum(cap)
1492 char *cap;
1494 char buf[20], *bufp;
1495 char *tep, c;
1496 int res, base = 10;
1498 bufp = buf;
1499 if ((tep = findcap(cap, &bufp, 20)))
1501 c = *tep;
1502 if (c == '@')
1503 return -1;
1504 if (c == '0')
1505 base = 8;
1506 res = 0;
1507 while ((c = *tep++) >= '0' && c <= '9')
1508 res = res * base + (c - '0');
1509 return res;
1511 return tgetnum(cap);