Rearrange the python scripting support a bit.
[screen-lua.git] / src / termcap.c
blob2b63a2440863161d22644fce953a26c0bc12f726
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 #undef DEBUGG
36 extern struct display *display, *displays;
37 extern int real_uid, real_gid, eff_uid, eff_gid;
38 extern struct term term[]; /* terminal capabilities */
39 extern struct NewWindow nwin_undef, nwin_default, nwin_options;
40 extern int force_vt;
41 extern int Z0width, Z1width;
42 extern int hardstatusemu;
43 #ifdef MAPKEYS
44 extern struct action umtab[];
45 extern struct action mmtab[];
46 extern struct action dmtab[];
47 extern struct action ktab[];
48 extern struct kmap_ext *kmap_exts;
49 extern int kmap_extn;
50 extern int DefaultEsc;
51 #endif
54 static void AddCap __P((char *));
55 static void MakeString __P((char *, char *, int, char *));
56 static char *findcap __P((char *, char **, int));
57 static int copyarg __P((char **, char *));
58 static int e_tgetent __P((char *, char *));
59 static char *e_tgetstr __P((char *, char **));
60 static int e_tgetflag __P((char *));
61 static int e_tgetnum __P((char *));
62 #ifdef MAPKEYS
63 static int findseq_ge __P((char *, int, unsigned char **));
64 static void setseqoff __P((unsigned char *, int, int));
65 static int addmapseq __P((char *, int, int));
66 static int remmapseq __P((char *, int));
67 #ifdef DEBUGG
68 static void dumpmap __P((void));
69 #endif
70 #endif
73 char Termcap[TERMCAP_BUFSIZE + 8]; /* new termcap +8:"TERMCAP=" */
74 static int Termcaplen;
75 static int tcLineLen;
76 char Term[MAXSTR+5]; /* +5: "TERM=" */
77 char screenterm[20]; /* new $TERM, usually "screen" */
79 char *extra_incap, *extra_outcap;
81 static const char TermcapConst[] = "\\\n\
82 \t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
83 \t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
84 \t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\
85 \t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:";
87 char *
88 gettermcapstring(s)
89 char *s;
91 int i;
93 if (display == 0 || s == 0)
94 return 0;
95 for (i = 0; i < T_N; i++)
97 if (term[i].type != T_STR)
98 continue;
99 if (strcmp(term[i].tcname, s) == 0)
100 return D_tcs[i].str;
102 return 0;
106 * Compile the terminal capabilities for a display.
107 * Input: tgetent(, D_termname) extra_incap, extra_outcap.
108 * Effect: display initialisation.
111 InitTermcap(wi, he)
112 int wi;
113 int he;
115 register char *s;
116 int i;
117 char tbuf[TERMCAP_BUFSIZE], *tp;
118 int t, xue, xse, xme;
120 ASSERT(display);
121 bzero(tbuf, sizeof(tbuf));
122 debug1("InitTermcap: looking for tgetent('%s')\n", D_termname);
123 if (*D_termname == 0 || e_tgetent(tbuf, D_termname) != 1)
125 #ifdef TERMINFO
126 Msg(0, "Cannot find terminfo entry for '%s'.", D_termname);
127 #else
128 Msg(0, "Cannot find termcap entry for '%s'.", D_termname);
129 #endif
130 return -1;
132 debug1("got it:\n%s\n", tbuf);
133 #ifdef DEBUG
134 if (extra_incap)
135 debug1("Extra incap: %s\n", extra_incap);
136 if (extra_outcap)
137 debug1("Extra outcap: %s\n", extra_outcap);
138 #endif
140 if ((D_tentry = (char *)malloc(TERMCAP_BUFSIZE + (extra_incap ? strlen(extra_incap) + 1 : 0))) == 0)
142 Msg(0, strnomem);
143 return -1;
147 * loop through all needed capabilities, record their values in the display
149 tp = D_tentry;
150 for (i = 0; i < T_N; i++)
152 switch(term[i].type)
154 case T_FLG:
155 D_tcs[i].flg = e_tgetflag(term[i].tcname);
156 break;
157 case T_NUM:
158 D_tcs[i].num = e_tgetnum(term[i].tcname);
159 break;
160 case T_STR:
161 D_tcs[i].str = e_tgetstr(term[i].tcname, &tp);
162 /* no empty strings, please */
163 if (D_tcs[i].str && *D_tcs[i].str == 0)
164 D_tcs[i].str = 0;
165 break;
166 default:
167 Panic(0, "Illegal tc type in entry #%d", i);
168 /*NOTREACHED*/
173 * Now a good deal of sanity checks on the retrieved capabilities.
175 if (D_HC)
177 Msg(0, "You can't run screen on a hardcopy terminal.");
178 return -1;
180 if (D_OS)
182 Msg(0, "You can't run screen on a terminal that overstrikes.");
183 return -1;
185 if (!D_CL)
187 Msg(0, "Clear screen capability required.");
188 return -1;
190 if (!D_CM)
192 Msg(0, "Addressable cursor capability required.");
193 return -1;
195 if ((s = getenv("COLUMNS")) && (i = atoi(s)) > 0)
196 D_CO = i;
197 if ((s = getenv("LINES")) && (i = atoi(s)) > 0)
198 D_LI = i;
199 if (wi)
200 D_CO = wi;
201 if (he)
202 D_LI = he;
203 if (D_CO <= 0)
204 D_CO = 80;
205 if (D_LI <= 0)
206 D_LI = 24;
208 if (D_CTF)
210 /* standard fixes for xterms etc */
211 /* assume color for everything that looks ansi-compatible */
212 if (!D_CAF && D_ME && (InStr(D_ME, "\033[m") || InStr(D_ME, "\033[0m")))
214 #ifdef TERMINFO
215 D_CAF = "\033[3%p1%dm";
216 D_CAB = "\033[4%p1%dm";
217 #else
218 D_CAF = "\033[3%dm";
219 D_CAB = "\033[4%dm";
220 #endif
222 if (D_OP && InStr(D_OP, "\033[39;49m"))
223 D_CAX = 1;
224 if (D_OP && (InStr(D_OP, "\033[m") || InStr(D_OP, "\033[0m")))
225 D_OP = 0;
226 /* ISO2022 */
227 if ((D_EA && InStr(D_EA, "\033(B")) || (D_AS && InStr(D_AS, "\033(0")))
228 D_CG0 = 1;
229 if (InStr(D_termname, "xterm") || InStr(D_termname, "rxvt"))
230 D_CXT = 1;
231 /* "be" seems to be standard for xterms... */
232 if (D_CXT)
233 D_BE = 1;
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)
244 if (D_BS)
245 D_BC = "\b";
246 else
247 D_BC = D_LE;
249 if (!D_CR)
250 D_CR = "\r";
251 if (!D_NL)
252 D_NL = "\n";
255 * Set up attribute handling.
256 * This is rather complicated because termcap has different
257 * attribute groups.
260 if (D_UG > 0)
261 D_US = D_UE = 0;
262 if (D_SG > 0)
263 D_SO = D_SE = 0;
264 /* Unfortunatelly there is no 'mg' capability.
265 * For now we think that mg > 0 if sg and ug > 0.
267 if (D_UG > 0 && D_SG > 0)
268 D_MH = D_MD = D_MR = D_MB = D_ME = 0;
270 xue = ATYP_U;
271 xse = ATYP_S;
272 xme = ATYP_M;
274 if (D_SO && D_SE == 0)
276 Msg(0, "Warning: 'so' but no 'se' capability.");
277 if (D_ME)
278 xse = xme;
279 else
280 D_SO = 0;
282 if (D_US && D_UE == 0)
284 Msg(0, "Warning: 'us' but no 'ue' capability.");
285 if (D_ME)
286 xue = xme;
287 else
288 D_US = 0;
290 if ((D_MH || D_MD || D_MR || D_MB) && D_ME == 0)
292 Msg(0, "Warning: 'm?' but no 'me' capability.");
293 D_MH = D_MD = D_MR = D_MB = 0;
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:
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;
307 for (i = 0; i < NATTR; i++)
309 D_attrtab[i] = D_tcs[T_ATTR + i].str;
310 D_attrtyp[i] = i == ATTR_SO ? xse : (i == ATTR_US ? xue : xme);
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]))
319 t = D_attrtyp[i];
320 break;
322 for (i = 0; i < NATTR; i++)
324 if (D_attrtab[i] == 0)
326 D_attrtab[i] = s;
327 D_attrtyp[i] = t;
329 else
331 s = D_attrtab[i];
332 t = D_attrtyp[i];
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 */
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;
360 #ifdef FONT
361 if (D_CG0)
363 if (D_CS0 == 0)
364 #ifdef TERMINFO
365 D_CS0 = "\033(%p1%c";
366 #else
367 D_CS0 = "\033(%.";
368 #endif
369 if (D_CE0 == 0)
370 D_CE0 = "\033(B";
371 D_AC = 0;
372 D_EA = 0;
374 else if (D_AC || (D_AS && D_AE)) /* some kind of graphics */
376 D_CS0 = (D_AS && D_AE) ? D_AS : "";
377 D_CE0 = (D_AS && D_AE) ? D_AE : "";
378 D_CC0 = D_AC;
380 else
382 D_CS0 = D_CE0 = "";
383 D_CC0 = 0;
384 D_AC = ""; /* enable default string */
387 for (i = 0; i < 256; i++)
388 D_c0_tab[i] = i;
389 if (D_AC)
391 /* init with default string first */
392 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>";
393 for (i = strlen(s) & ~1; i >= 0; i -= 2)
394 D_c0_tab[(int)(unsigned char)s[i]] = s[i + 1];
396 if (D_CC0)
397 for (i = strlen(D_CC0) & ~1; i >= 0; i -= 2)
398 D_c0_tab[(int)(unsigned char)D_CC0[i]] = D_CC0[i + 1];
399 debug1("ISO2022 = %d\n", D_CG0);
400 #endif /* FONT */
401 if (D_PF == 0)
402 D_PO = 0;
403 debug2("terminal size is %d, %d (says TERMCAP)\n", D_CO, D_LI);
405 #ifdef FONT
406 if (D_CXC)
407 if (CreateTransTable(D_CXC))
408 return -1;
409 #endif
411 /* Termcap fields Z0 & Z1 contain width-changing sequences. */
412 if (D_CZ1 == 0)
413 D_CZ0 = 0;
414 Z0width = 132;
415 Z1width = 80;
417 CheckScreenSize(0);
419 if (D_TS == 0 || D_FS == 0 || D_DS == 0)
420 D_HS = 0;
421 if (D_HS)
423 debug("oy! we have a hardware status line, says termcap\n");
424 if (D_WS < 0)
425 D_WS = 0;
427 D_has_hstatus = hardstatusemu & ~HSTATUS_ALWAYS;
428 if (D_HS && !(hardstatusemu & HSTATUS_ALWAYS))
429 D_has_hstatus = HSTATUS_HS;
431 #ifdef ENCODINGS
432 if (D_CKJ)
434 int enc = FindEncoding(D_CKJ);
435 if (enc != -1)
436 D_encoding = enc;
438 #endif
439 if (!D_tcs[T_NAVIGATE].str && D_tcs[T_NAVIGATE + 1].str)
440 D_tcs[T_NAVIGATE].str = D_tcs[T_NAVIGATE + 1].str; /* kh = @1 */
441 if (!D_tcs[T_NAVIGATE + 2].str && D_tcs[T_NAVIGATE + 3].str)
442 D_tcs[T_NAVIGATE + 2].str = D_tcs[T_NAVIGATE + 3].str; /* kH = @7 */
444 D_UPcost = CalcCost(D_UP);
445 D_DOcost = CalcCost(D_DO);
446 D_NLcost = CalcCost(D_NL);
447 D_LEcost = CalcCost(D_BC);
448 D_NDcost = CalcCost(D_ND);
449 D_CRcost = CalcCost(D_CR);
450 D_IMcost = CalcCost(D_IM);
451 D_EIcost = CalcCost(D_EI);
453 #ifdef AUTO_NUKE
454 if (D_CAN)
456 debug("termcap has AN, setting autonuke\n");
457 D_auto_nuke = 1;
459 #endif
460 if (D_COL > 0)
462 debug1("termcap has OL (%d), setting limit\n", D_COL);
463 D_obufmax = D_COL;
464 D_obuflenmax = D_obuflen - D_obufmax;
467 /* Some xterm entries set F0 and F10 to the same string. Nuke F0. */
468 if (D_tcs[T_CAPS].str && D_tcs[T_CAPS + 10].str && !strcmp(D_tcs[T_CAPS].str, D_tcs[T_CAPS + 10].str))
469 D_tcs[T_CAPS].str = 0;
470 /* Some xterm entries set kD to ^?. Nuke it. */
471 if (D_tcs[T_NAVIGATE_DELETE].str && !strcmp(D_tcs[T_NAVIGATE_DELETE].str, "\0177"))
472 D_tcs[T_NAVIGATE_DELETE].str = 0;
473 /* wyse52 entries have kcub1 == kb == ^H. Nuke... */
474 if (D_tcs[T_CURSOR + 3].str && !strcmp(D_tcs[T_CURSOR + 3].str, "\008"))
475 D_tcs[T_CURSOR + 3].str = 0;
477 #ifdef MAPKEYS
478 D_nseqs = 0;
479 for (i = 0; i < T_OCAPS - T_CAPS; i++)
480 remap(i, 1);
481 for (i = 0; i < kmap_extn; i++)
482 remap(i + (KMAP_KEYS+KMAP_AKEYS), 1);
483 D_seqp = D_kmaps + 3;
484 D_seql = 0;
485 D_seqh = 0;
486 #endif
488 D_tcinited = 1;
489 MakeTermcap(0);
490 #ifdef MAPKEYS
491 CheckEscape();
492 #endif
493 return 0;
496 #ifdef MAPKEYS
499 remap(n, map)
500 int n;
501 int map;
503 char *s = 0;
504 int fl = 0, domap = 0;
505 struct action *a1, *a2, *tab;
506 int l = 0;
507 struct kmap_ext *kme = 0;
509 a1 = 0;
510 if (n >= KMAP_KEYS+KMAP_AKEYS)
512 kme = kmap_exts + (n - (KMAP_KEYS+KMAP_AKEYS));
513 s = kme->str;
514 l = kme->fl & ~KMAP_NOTIMEOUT;
515 fl = kme->fl & KMAP_NOTIMEOUT;
516 a1 = &kme->um;
518 tab = umtab;
519 for (;;)
521 a2 = 0;
522 if (n < KMAP_KEYS+KMAP_AKEYS)
524 a1 = &tab[n];
525 if (n >= KMAP_KEYS)
526 n -= T_OCAPS-T_CURSOR;
527 s = D_tcs[n + T_CAPS].str;
528 l = s ? strlen(s) : 0;
529 if (n >= T_CURSOR-T_CAPS)
530 a2 = &tab[n + (T_OCAPS-T_CURSOR)];
532 if (s == 0 || l == 0)
533 return 0;
534 if (a1 && a1->nr == RC_ILLEGAL)
535 a1 = 0;
536 if (a2 && a2->nr == RC_ILLEGAL)
537 a2 = 0;
538 if (a1 && a1->nr == RC_STUFF && a1->args[0] && strcmp(a1->args[0], s) == 0)
539 a1 = 0;
540 if (a2 && a2->nr == RC_STUFF && a2->args[0] && strcmp(a2->args[0], s) == 0)
541 a2 = 0;
542 domap |= (a1 || a2);
543 if (tab == umtab)
545 tab = dmtab;
546 a1 = kme ? &kme->dm : 0;
548 else if (tab == dmtab)
550 tab = mmtab;
551 a1 = kme ? &kme->mm : 0;
553 else
554 break;
556 if (n < KMAP_KEYS)
557 domap = 1;
558 if (map == 0 && domap)
559 return 0;
560 if (map && !domap)
561 return 0;
562 debug3("%smapping %s %#x\n", map? "" :"un",s,n);
563 if (map)
564 return addmapseq(s, l, n | fl);
565 else
566 return remmapseq(s, l);
569 void
570 CheckEscape()
572 struct display *odisplay;
573 int i, nr;
575 if (DefaultEsc >= 0)
576 return;
578 odisplay = display;
579 for (display = displays; display; display = display->d_next)
581 for (i = 0; i < D_nseqs; i += D_kmaps[i + 2] * 2 + 4)
583 nr = (D_kmaps[i] << 8 | D_kmaps[i + 1]) & ~KMAP_NOTIMEOUT;
584 if (nr < KMAP_KEYS+KMAP_AKEYS)
586 if (umtab[nr].nr == RC_COMMAND)
587 break;
588 if (umtab[nr].nr == RC_ILLEGAL && dmtab[nr].nr == RC_COMMAND)
589 break;
591 else
593 struct kmap_ext *kme = kmap_exts + nr - (KMAP_KEYS+KMAP_AKEYS);
594 if (kme->um.nr == RC_COMMAND)
595 break;
596 if (kme->um.nr == RC_ILLEGAL && kme->dm.nr == RC_COMMAND)
597 break;
601 if (display == 0)
603 display = odisplay;
604 return;
606 SetEscape((struct acluser *)0, Ctrl('a'), 'a');
607 if (odisplay->d_user->u_Esc == -1)
608 odisplay->d_user->u_Esc = DefaultEsc;
609 if (odisplay->d_user->u_MetaEsc == -1)
610 odisplay->d_user->u_MetaEsc = DefaultMetaEsc;
611 display = 0;
612 Msg(0, "Warning: escape char set back to ^A");
613 display = odisplay;
616 static int
617 findseq_ge(seq, k, sp)
618 char *seq;
619 int k;
620 unsigned char **sp;
622 unsigned char *p;
623 int j, l;
625 p = D_kmaps;
626 while (p - D_kmaps < D_nseqs)
628 l = p[2];
629 p += 3;
630 for (j = 0; ; j++)
632 if (j == k || j == l)
633 j = l - k;
634 else if (p[j] != ((unsigned char *)seq)[j])
635 j = p[j] - ((unsigned char *)seq)[j];
636 else
637 continue;
638 break;
640 if (j >= 0)
642 *sp = p - 3;
643 return j;
645 p += 2 * l + 1;
647 *sp = p;
648 return -1;
651 static void
652 setseqoff(p, i, o)
653 unsigned char *p;
654 int i;
655 int o;
657 unsigned char *q;
658 int l, k;
660 k = p[2];
661 if (o < 256)
663 p[k + 4 + i] = o;
664 return;
666 /* go for the biggest offset */
667 for (q = p + k * 2 + 4; ; q += l * 2 + 4)
669 l = q[2];
670 if ((q + l * 2 - p) / 2 >= 256)
672 p[k + 4 + i] = (q - p - 4) / 2;
673 return;
678 static int
679 addmapseq(seq, k, nr)
680 char *seq;
681 int k;
682 int nr;
684 int i, j, l, mo, m;
685 unsigned char *p, *q;
687 if (k >= 254)
688 return -1;
689 j = findseq_ge(seq, k, &p);
690 if (j == 0)
692 p[0] = nr >> 8;
693 p[1] = nr;
694 return 0;
696 i = p - D_kmaps;
697 if (D_nseqs + 2 * k + 4 >= D_aseqs)
699 D_kmaps = (unsigned char *)xrealloc((char *)D_kmaps, D_aseqs + 256);
700 D_aseqs += 256;
701 p = D_kmaps + i;
703 D_seqp = D_kmaps + 3;
704 D_seql = 0;
705 D_seqh = 0;
706 evdeq(&D_mapev);
707 if (j > 0)
708 bcopy((char *)p, (char *)p + 2 * k + 4, D_nseqs - i);
709 p[0] = nr >> 8;
710 p[1] = nr;
711 p[2] = k;
712 bcopy(seq, (char *)p + 3, k);
713 bzero(p + k + 3, k + 1);
714 D_nseqs += 2 * k + 4;
715 if (j > 0)
717 q = p + 2 * k + 4;
718 l = q[2];
719 for (i = 0; i < k; i++)
721 if (p[3 + i] != q[3 + i])
723 p[k + 4 + i] = k;
724 break;
726 setseqoff(p, i, q[l + 4 + i] ? q[l + 4 + i] + k + 2: 0);
729 for (q = D_kmaps; q < p; q += 2 * l + 4)
731 l = q[2];
732 for (m = j = 0; j < l; j++)
734 mo = m;
735 if (!m && q[3 + j] != seq[j])
736 m = 1;
737 if (q[l + 4 + j] == 0)
739 if (!mo && m)
740 setseqoff(q, j, (p - q - 4) / 2);
742 else if (q + q[l + 4 + j] * 2 + 4 > p || (q + q[l + 4 + j] * 2 + 4 == p && !m))
743 setseqoff(q, j, q[l + 4 + j] + k + 2);
746 #ifdef DEBUGG
747 dumpmap();
748 #endif
749 return 0;
752 static int
753 remmapseq(seq, k)
754 char *seq;
755 int k;
757 int j, l;
758 unsigned char *p, *q;
760 if (k >= 254 || (j = findseq_ge(seq, k, &p)) != 0)
761 return -1;
762 for (q = D_kmaps; q < p; q += 2 * l + 4)
764 l = q[2];
765 for (j = 0; j < l; j++)
767 if (q + q[l + 4 + j] * 2 + 4 == p)
768 setseqoff(q, j, p[k + 4 + j] ? q[l + 4 + j] + p[k + 4 + j] - k : 0);
769 else if (q + q[l + 4 + j] * 2 + 4 > p)
770 q[l + 4 + j] -= k + 2;
773 if (D_kmaps + D_nseqs > p + 2 * k + 4)
774 bcopy((char *)p + 2 * k + 4, (char *)p, (D_kmaps + D_nseqs) - (p + 2 * k + 4));
775 D_nseqs -= 2 * k + 4;
776 D_seqp = D_kmaps + 3;
777 D_seql = 0;
778 D_seqh = 0;
779 evdeq(&D_mapev);
780 #ifdef DEBUGG
781 dumpmap();
782 #endif
783 return 0;
786 #ifdef DEBUGG
787 static void
788 dumpmap()
790 unsigned char *p;
791 int j, n, l, o, oo;
792 debug("Mappings:\n");
793 p = D_kmaps;
794 if (!p)
795 return;
796 while (p < D_kmaps + D_nseqs)
798 l = p[2];
799 debug1("%d: ", p - D_kmaps + 3);
800 for (j = 0; j < l; j++)
802 o = oo = p[l + 4 + j];
803 if (o)
804 o = 2 * o + 4 + (p + 3 + j - D_kmaps);
805 if (p[j + 3] > ' ' && p[j + 3] < 0177)
807 debug3("%c[%d:%d] ", p[j + 3], oo, o);
809 else
810 debug3("\\%03o[%d:%d] ", p[j + 3], oo, o);
812 n = p[0] << 8 | p[1];
813 debug2(" ==> %d%s\n", n & ~KMAP_NOTIMEOUT, (n & KMAP_NOTIMEOUT) ? " (no timeout)" : "");
814 p += 2 * l + 4;
817 #endif /* DEBUGG */
819 #endif /* MAPKEYS */
822 * Appends to the static variable Termcap
824 static void
825 AddCap(s)
826 char *s;
828 register int n;
830 if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < TERMCAP_BUFSIZE - 4 - 1)
832 strcpy(Termcap + Termcaplen, "\\\n\t:");
833 Termcaplen += 4;
834 tcLineLen = 0;
836 if (Termcaplen + n < TERMCAP_BUFSIZE - 1)
838 strcpy(Termcap + Termcaplen, s);
839 Termcaplen += n;
840 tcLineLen += n;
842 else
843 Panic(0, "TERMCAP overflow - sorry.");
847 * Reads a displays capabilities and reconstructs a termcap entry in the
848 * global buffer "Termcap". A pointer to this buffer is returned.
850 char *
851 MakeTermcap(aflag)
852 int aflag;
854 char buf[TERMCAP_BUFSIZE];
855 register char *p, *cp, *s, ch, *tname;
856 int i, wi, he;
857 #if 0
858 int found;
859 #endif
861 if (display)
863 wi = D_width;
864 he = D_height;
865 tname = D_termname;
867 else
869 wi = 80;
870 he = 24;
871 tname = "vt100";
873 debug1("MakeTermcap(%d)\n", aflag);
874 if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE)
876 sprintf(Termcap, "TERMCAP=%s", s);
877 strcpy(Term, "TERM=screen");
878 debug("getenvSCREENCAP o.k.\n");
879 return Termcap;
881 Termcaplen = 0;
882 debug1("MakeTermcap screenterm='%s'\n", screenterm);
883 debug1("MakeTermcap termname='%s'\n", tname);
884 if (*screenterm == '\0' || strlen(screenterm) > MAXSTR - 3)
886 debug("MakeTermcap sets screenterm=screen\n");
887 strcpy(screenterm, "screen");
889 #if 0
890 found = 1;
891 #endif
894 strcpy(Term, "TERM=");
895 p = Term + 5;
896 if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR-1)
898 sprintf(p, "%s.%s", screenterm, tname);
899 if (e_tgetent(buf, p) == 1)
900 break;
902 #ifdef COLOR
903 if (nwin_default.bce)
905 sprintf(p, "%s-bce", screenterm);
906 if (e_tgetent(buf, p) == 1)
907 break;
909 #endif
910 #ifdef CHECK_SCREEN_W
911 if (wi >= 132)
913 sprintf(p, "%s-w", screenterm);
914 if (e_tgetent(buf, p) == 1)
915 break;
917 #endif
918 strcpy(p, screenterm);
919 if (e_tgetent(buf, p) == 1)
920 break;
921 strcpy(p, "vt100");
922 #if 0
923 found = 0;
924 #endif
926 while (0); /* Goto free programming... */
928 #if 0
929 #ifndef TERMINFO
930 /* check for compatibility problems, displays == 0 after fork */
931 if (found)
933 char xbuf[TERMCAP_BUFSIZE], *xbp = xbuf;
934 if (tgetstr("im", &xbp) && tgetstr("ic", &xbp) && displays)
936 Msg(0, "Warning: im and ic set in %s termcap entry", p);
939 #endif
940 #endif
942 tcLineLen = 100; /* Force NL */
943 if (strlen(Term) > TERMCAP_BUFSIZE - 40)
944 strcpy(Term, "too_long");
945 sprintf(Termcap, "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal:", Term + 5);
946 Termcaplen = strlen(Termcap);
947 debug1("MakeTermcap decided '%s'\n", p);
948 if (extra_outcap && *extra_outcap)
950 for (cp = extra_outcap; (p = index(cp, ':')); cp = p)
952 ch = *++p;
953 *p = '\0';
954 AddCap(cp);
955 *p = ch;
957 tcLineLen = 100; /* Force NL */
959 debug1("MakeTermcap after outcap '%s'\n", (char *)TermcapConst);
960 if (Termcaplen + strlen(TermcapConst) < TERMCAP_BUFSIZE)
962 strcpy(Termcap + Termcaplen, (char *)TermcapConst);
963 Termcaplen += strlen(TermcapConst);
965 sprintf(buf, "li#%d:co#%d:", he, wi);
966 AddCap(buf);
967 AddCap("am:");
968 if (aflag || (force_vt && !D_COP) || D_CLP || !D_AM)
970 AddCap("xn:");
971 AddCap("xv:");
972 AddCap("LP:");
974 if (aflag || (D_CS && D_SR) || D_AL || D_CAL)
976 AddCap("sr=\\EM:");
977 AddCap("al=\\E[L:");
978 AddCap("AL=\\E[%dL:");
980 else if (D_SR)
981 AddCap("sr=\\EM:");
982 if (aflag || D_CS)
983 AddCap("cs=\\E[%i%d;%dr:");
984 if (aflag || D_CS || D_DL || D_CDL)
986 AddCap("dl=\\E[M:");
987 AddCap("DL=\\E[%dM:");
989 if (aflag || D_DC || D_CDC)
991 AddCap("dc=\\E[P:");
992 AddCap("DC=\\E[%dP:");
994 if (aflag || D_CIC || D_IC || D_IM)
996 AddCap("im=\\E[4h:");
997 AddCap("ei=\\E[4l:");
998 AddCap("mi:");
999 AddCap("IC=\\E[%d@:");
1001 #ifdef MAPKEYS
1002 AddCap("ks=\\E[?1h\\E=:");
1003 AddCap("ke=\\E[?1l\\E>:");
1004 #endif
1005 AddCap("vi=\\E[?25l:");
1006 AddCap("ve=\\E[34h\\E[?25h:");
1007 AddCap("vs=\\E[34l:");
1008 AddCap("ti=\\E[?1049h:");
1009 AddCap("te=\\E[?1049l:");
1010 if (display)
1012 if (D_US)
1014 AddCap("us=\\E[4m:");
1015 AddCap("ue=\\E[24m:");
1017 if (D_SO)
1019 AddCap("so=\\E[3m:");
1020 AddCap("se=\\E[23m:");
1022 if (D_MB)
1023 AddCap("mb=\\E[5m:");
1024 if (D_MD)
1025 AddCap("md=\\E[1m:");
1026 if (D_MH)
1027 AddCap("mh=\\E[2m:");
1028 if (D_MR)
1029 AddCap("mr=\\E[7m:");
1030 if (D_MB || D_MD || D_MH || D_MR)
1031 AddCap("me=\\E[m:ms:");
1032 if (D_hascolor)
1033 AddCap("Co#8:pa#64:AF=\\E[3%dm:AB=\\E[4%dm:op=\\E[39;49m:AX:");
1034 if (D_VB)
1035 AddCap("vb=\\Eg:");
1036 #ifndef MAPKEYS
1037 if (D_KS)
1039 AddCap("ks=\\E=:");
1040 AddCap("ke=\\E>:");
1042 if (D_CCS)
1044 AddCap("CS=\\E[?1h:");
1045 AddCap("CE=\\E[?1l:");
1047 #endif
1048 if (D_CG0)
1049 AddCap("G0:");
1050 if (D_CC0 || (D_CS0 && *D_CS0))
1052 AddCap("as=\\E(0:");
1053 AddCap("ae=\\E(B:");
1054 /* avoid `` because some shells dump core... */
1055 AddCap("ac=\\140\\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:");
1057 if (D_PO)
1059 AddCap("po=\\E[5i:");
1060 AddCap("pf=\\E[4i:");
1062 if (D_CZ0)
1064 AddCap("Z0=\\E[?3h:");
1065 AddCap("Z1=\\E[?3l:");
1067 if (D_CWS)
1068 AddCap("WS=\\E[8;%d;%dt:");
1070 for (i = T_CAPS; i < T_ECAPS; i++)
1072 #ifdef MAPKEYS
1073 struct action *act;
1074 if (i < T_OCAPS)
1076 if (i >= T_KEYPAD) /* don't put keypad codes in TERMCAP */
1077 continue; /* - makes it too big */
1078 if (i >= T_CURSOR && i < T_OCAPS)
1080 act = &umtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
1081 if (act->nr == RC_ILLEGAL)
1082 act = &dmtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
1084 else
1086 act = &umtab[i - T_CAPS];
1087 if (act->nr == RC_ILLEGAL)
1088 act = &dmtab[i - T_CAPS];
1090 if (act->nr == RC_ILLEGAL && (i == T_NAVIGATE + 1 || i == T_NAVIGATE + 3))
1092 /* kh -> @1, kH -> @7 */
1093 act = &umtab[i - T_CAPS - 1];
1094 if (act->nr == RC_ILLEGAL)
1095 act = &dmtab[i - T_CAPS - 1];
1097 if (act->nr != RC_ILLEGAL)
1099 if (act->nr == RC_STUFF)
1101 MakeString(term[i].tcname, buf, sizeof(buf), act->args[0]);
1102 AddCap(buf);
1104 continue;
1107 #endif
1108 if (display == 0)
1109 continue;
1110 switch(term[i].type)
1112 case T_STR:
1113 if (D_tcs[i].str == 0)
1114 break;
1115 MakeString(term[i].tcname, buf, sizeof(buf), D_tcs[i].str);
1116 AddCap(buf);
1117 break;
1118 case T_FLG:
1119 if (D_tcs[i].flg == 0)
1120 break;
1121 sprintf(buf, "%s:", term[i].tcname);
1122 AddCap(buf);
1123 break;
1124 default:
1125 break;
1128 debug("MakeTermcap: end\n");
1129 return Termcap;
1132 static void
1133 MakeString(cap, buf, buflen, s)
1134 char *cap, *buf;
1135 int buflen;
1136 char *s;
1138 register char *p, *pmax;
1139 register unsigned int c;
1141 p = buf;
1142 pmax = p + buflen - (3+4+2);
1143 *p++ = *cap++;
1144 *p++ = *cap;
1145 *p++ = '=';
1146 while ((c = *s++) && (p < pmax))
1148 switch (c)
1150 case '\033':
1151 *p++ = '\\';
1152 *p++ = 'E';
1153 break;
1154 case ':':
1155 strcpy(p, "\\072");
1156 p += 4;
1157 break;
1158 case '^':
1159 case '\\':
1160 *p++ = '\\';
1161 *p++ = c;
1162 break;
1163 default:
1164 if (c >= 200)
1166 sprintf(p, "\\%03o", c & 0377);
1167 p += 4;
1169 else if (c < ' ')
1171 *p++ = '^';
1172 *p++ = c + '@';
1174 else
1175 *p++ = c;
1178 *p++ = ':';
1179 *p = '\0';
1183 #undef QUOTES
1184 #define QUOTES(p) \
1185 (*p == '\\' && (p[1] == '\\' || p[1] == ',' || p[1] == '%'))
1187 #ifdef FONT
1189 CreateTransTable(s)
1190 char *s;
1192 int curchar;
1193 char *templ, *arg;
1194 int templlen;
1195 int templnsub;
1196 char *p, *sx;
1197 char **ctable;
1198 int l, c;
1200 if ((D_xtable = (char ***)calloc(256, sizeof(char **))) == 0)
1202 Msg(0, strnomem);
1203 return -1;
1206 while (*s)
1208 if (QUOTES(s))
1209 s++;
1210 curchar = (unsigned char)*s++;
1211 if (curchar == 'B')
1212 curchar = 0; /* ASCII */
1213 templ = s;
1214 templlen = 0;
1215 templnsub = 0;
1216 if (D_xtable[curchar] == 0)
1218 if ((D_xtable[curchar] = (char **)calloc(257, sizeof(char *))) == 0)
1220 Msg(0, strnomem);
1221 FreeTransTable();
1222 return -1;
1225 ctable = D_xtable[curchar];
1226 for(; *s && *s != ','; s++)
1228 if (QUOTES(s))
1229 s++;
1230 else if (*s == '%')
1232 templnsub++;
1233 continue;
1235 templlen++;
1237 if (*s++ == 0)
1238 break;
1239 while (*s && *s != ',')
1241 c = (unsigned char)*s++;
1242 if (QUOTES((s - 1)))
1243 c = (unsigned char)*s++;
1244 else if (c == '%')
1245 c = 256;
1246 if (ctable[c])
1247 free(ctable[c]);
1248 arg = s;
1249 l = copyarg(&s, (char *)0);
1250 if (c != 256)
1251 l = l * templnsub + templlen;
1252 if ((ctable[c] = (char *)malloc(l + 1)) == 0)
1254 Msg(0, strnomem);
1255 FreeTransTable();
1256 return -1;
1258 sx = ctable[c];
1259 for (p = ((c == 256) ? "%" : templ); *p && *p != ','; p++)
1261 if (QUOTES(p))
1262 p++;
1263 else if (*p == '%')
1265 s = arg;
1266 sx += copyarg(&s, sx);
1267 continue;
1269 *sx++ = *p;
1271 *sx = 0;
1272 ASSERT(ctable[c] + l * templnsub + templlen == sx);
1273 debug3("XC: %c %c->%s\n", curchar, c, ctable[c]);
1275 if (*s == ',')
1276 s++;
1278 return 0;
1281 void
1282 FreeTransTable()
1284 char ***p, **q;
1285 int i, j;
1287 if ((p = D_xtable) == 0)
1288 return;
1289 for (i = 0; i < 256; i++, p++)
1291 if (*p == 0)
1292 continue;
1293 q = *p;
1294 for (j = 0; j < 257; j++, q++)
1295 if (*q)
1296 free(*q);
1297 free(*p);
1299 free(D_xtable);
1301 #endif /* FONT */
1303 static int
1304 copyarg(pp, s)
1305 char **pp, *s;
1307 int l;
1308 char *p;
1310 for (l = 0, p = *pp; *p && *p != ','; p++)
1312 if (QUOTES(p))
1313 p++;
1314 if (s)
1315 *s++ = *p;
1316 l++;
1318 if (*p == ',')
1319 p++;
1320 *pp = p;
1321 return l;
1327 ** Termcap routines that use our extra_incap
1331 static int
1332 e_tgetent(bp, name)
1333 char *bp, *name;
1335 int r;
1337 #ifdef USE_SETEUID
1338 xseteuid(real_uid);
1339 xsetegid(real_gid);
1340 #endif
1341 r = tgetent(bp, name);
1342 #ifdef USE_SETEUID
1343 xseteuid(eff_uid);
1344 xsetegid(eff_gid);
1345 #endif
1346 return r;
1350 /* findcap:
1351 * cap = capability we are looking for
1352 * tepp = pointer to bufferpointer
1353 * n = size of buffer (0 = infinity)
1356 static char *
1357 findcap(cap, tepp, n)
1358 char *cap;
1359 char **tepp;
1360 int n;
1362 char *tep;
1363 char c, *p, *cp;
1364 int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */
1365 int num = 0, capl;
1367 if (!extra_incap)
1368 return 0;
1369 tep = *tepp;
1370 capl = strlen(cap);
1371 cp = 0;
1372 mode = 0;
1373 for (p = extra_incap; *p; )
1375 if (strncmp(p, cap, capl) == 0)
1377 p += capl;
1378 c = *p;
1379 if (c && c != ':' && c != '@')
1380 p++;
1381 if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
1382 cp = tep;
1384 while ((c = *p))
1386 p++;
1387 if (mode == 0)
1389 if (c == ':')
1390 break;
1391 if (c == '^')
1392 mode = 1;
1393 if (c == '\\')
1394 mode = 2;
1396 else if (mode == 1)
1398 mode = 0;
1399 c = c & 0x1f;
1401 else if (mode == 2)
1403 mode = 0;
1404 switch(c)
1406 case '0':
1407 case '1':
1408 case '2':
1409 case '3':
1410 case '4':
1411 case '5':
1412 case '6':
1413 case '7':
1414 case '8':
1415 case '9':
1416 mode = 3;
1417 num = 0;
1418 break;
1419 case 'E':
1420 c = 27;
1421 break;
1422 case 'n':
1423 c = '\n';
1424 break;
1425 case 'r':
1426 c = '\r';
1427 break;
1428 case 't':
1429 c = '\t';
1430 break;
1431 case 'b':
1432 c = '\b';
1433 break;
1434 case 'f':
1435 c = '\f';
1436 break;
1439 if (mode > 2)
1441 num = num * 8 + (c - '0');
1442 if (mode++ == 5 || (*p < '0' || *p > '9'))
1444 c = num;
1445 mode = 0;
1448 if (mode)
1449 continue;
1451 if (cp && n != 1)
1453 *cp++ = c;
1454 n--;
1457 if (cp)
1459 *cp++ = 0;
1460 *tepp = cp;
1461 debug2("'%s' found in extra_incap -> %s\n", cap, tep);
1462 return tep;
1465 return 0;
1468 static char *
1469 e_tgetstr(cap, tepp)
1470 char *cap;
1471 char **tepp;
1473 char *tep;
1474 if ((tep = findcap(cap, tepp, 0)))
1475 return (*tep == '@') ? 0 : tep;
1476 return tgetstr(cap, tepp);
1479 static int
1480 e_tgetflag(cap)
1481 char *cap;
1483 char buf[2], *bufp;
1484 char *tep;
1485 bufp = buf;
1486 if ((tep = findcap(cap, &bufp, 2)))
1487 return (*tep == '@') ? 0 : 1;
1488 return tgetflag(cap) > 0;
1491 static int
1492 e_tgetnum(cap)
1493 char *cap;
1495 char buf[20], *bufp;
1496 char *tep, c;
1497 int res, base = 10;
1499 bufp = buf;
1500 if ((tep = findcap(cap, &bufp, 20)))
1502 c = *tep;
1503 if (c == '@')
1504 return -1;
1505 if (c == '0')
1506 base = 8;
1507 res = 0;
1508 while ((c = *tep++) >= '0' && c <= '9')
1509 res = res * base + (c - '0');
1510 return res;
1512 return tgetnum(cap);