Release v.5.0.0
[screen.git] / src / termcap.c
blobb49818b1a7ba9ea55362f4109422d5ff6bdf1f77
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 * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include "config.h"
31 #include "termcap.h"
33 #include <sys/types.h>
34 #include <stdint.h>
36 #include "screen.h"
38 #include "encoding.h"
39 #include "kmapdef.h"
40 #include "misc.h"
41 #include "process.h"
42 #include "resize.h"
44 static void AddCap(char *);
45 static void MakeString(char *, char *, int, char *);
46 static char *findcap(char *, char **, int);
47 static int copyarg(char **, char *);
48 static int e_tgetent(char *, char *);
49 static char *e_tgetstr(char *, char **);
50 static int e_tgetflag(char *);
51 static int e_tgetnum(char *);
52 static int findseq_ge(char *, int, unsigned char **);
53 static void setseqoff(unsigned char *, int, int);
54 static int addmapseq(char *, int, int);
55 static int remmapseq(char *, int);
57 char Termcap[TERMCAP_BUFSIZE + 8]; /* new termcap +8:"TERMCAP=" */
58 static int Termcaplen;
59 static int tcLineLen;
60 char Term[MAXSTR + 5]; /* +5: "TERM=" */
61 char screenterm[MAXTERMLEN + 1]; /* new $TERM, usually "screen" */
63 char *extra_incap, *extra_outcap;
65 static const char TermcapConst[] = "DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:\
66 UP=\\E[%dA:bs:bt=\\E[Z:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:\
67 ct=\\E[3g:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\
68 le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:";
70 char *gettermcapstring(char *s)
72 int i;
74 if (display == NULL || s == NULL)
75 return NULL;
76 for (i = 0; i < T_N; i++) {
77 if (term[i].type != T_STR)
78 continue;
79 if (strcmp(term[i].tcname, s) == 0)
80 return D_tcs[i].str;
82 return NULL;
86 * Compile the terminal capabilities for a display.
87 * Input: tgetent(, D_termname) extra_incap, extra_outcap.
88 * Effect: display initialisation.
90 int InitTermcap(int width, int height)
92 char *s;
93 int i;
94 char tbuf[TERMCAP_BUFSIZE], *tp;
95 int t, xue, xse, xme;
97 memset(tbuf, 0, ARRAY_SIZE(tbuf));
98 if (*D_termname == 0 || e_tgetent(tbuf, D_termname) != 1) {
99 Msg(0, "Cannot find terminfo entry for '%s'.", D_termname);
100 return -1;
103 if ((D_tentry = malloc(TERMCAP_BUFSIZE + (extra_incap ? strlen(extra_incap) + 1 : 0))) == NULL) {
104 Msg(0, "%s", strnomem);
105 return -1;
109 * loop through all needed capabilities, record their values in the display
111 tp = D_tentry;
112 for (i = 0; i < T_N; i++) {
113 switch (term[i].type) {
114 case T_FLG:
115 D_tcs[i].flg = e_tgetflag(term[i].tcname);
116 break;
117 case T_NUM:
118 D_tcs[i].num = e_tgetnum(term[i].tcname);
119 break;
120 case T_STR:
121 D_tcs[i].str = e_tgetstr(term[i].tcname, &tp);
122 /* no empty strings, please */
123 if (D_tcs[i].str && *D_tcs[i].str == 0)
124 D_tcs[i].str = NULL;
125 break;
126 default:
127 Panic(0, "Illegal tc type in entry #%d", i);
128 /*NOTREACHED*/}
132 * Now a good deal of sanity checks on the retrieved capabilities.
134 if (D_HC) {
135 Msg(0, "You can't run screen on a hardcopy terminal.");
136 return -1;
138 if (D_OS) {
139 Msg(0, "You can't run screen on a terminal that overstrikes.");
140 return -1;
142 if (!D_CL) {
143 Msg(0, "Clear screen capability required.");
144 return -1;
146 if (!D_CM) {
147 Msg(0, "Addressable cursor capability required.");
148 return -1;
150 if ((s = getenv("COLUMNS")) && (i = atoi(s)) > 0)
151 D_CO = i;
152 if ((s = getenv("LINES")) && (i = atoi(s)) > 0)
153 D_LI = i;
154 if (width)
155 D_CO = width;
156 if (height)
157 D_LI = height;
158 if (D_CO <= 0)
159 D_CO = 80;
160 if (D_LI <= 0)
161 D_LI = 24;
163 if (D_CTF) {
164 /* standard fixes for xterms etc */
165 /* assume color for everything that looks ansi-compatible */
166 if (!D_CAF && D_ME && (strstr(D_ME, "\033[m") || strstr(D_ME, "\033[0m"))) {
167 D_CAF = "\033[3%p1%dm";
168 D_CAB = "\033[4%p1%dm";
170 if (D_OP && strstr(D_OP, "\033[39;49m"))
171 D_CAX = 1;
172 if (D_OP && (strstr(D_OP, "\033[m") || strstr(D_OP, "\033[0m")))
173 D_OP = NULL;
174 /* ISO2022 */
175 if ((D_EA && strstr(D_EA, "\033(B")) || (D_AS && strstr(D_AS, "\033(0")))
176 D_CG0 = 1;
177 if (strstr(D_termname, "xterm") || strstr(D_termname, "rxvt") || (D_CKM &&
178 (strstr(D_CKM, "\033[M") || strstr(D_CKM, "\033[<")))) {
179 D_CXT = 1;
180 kmapdef[0] = D_CKM ? SaveStr(D_CKM) : NULL;
182 /* "be" seems to be standard for xterms... */
183 if (D_CXT)
184 D_BE = 1;
186 if (nwin_options.flowflag == nwin_undef.flowflag)
187 nwin_default.flowflag = D_CNF ? FLOW_OFF : D_NX ? FLOW_ON : FLOW_AUTOFLAG;
188 D_CLP |= (!D_AM || D_XV || D_XN);
189 if (!D_BL)
190 D_BL = "\007";
191 if (!D_BC) {
192 if (D_BS)
193 D_BC = "\b";
194 else
195 D_BC = D_LE;
197 if (!D_CR)
198 D_CR = "\r";
199 if (!D_NL)
200 D_NL = "\n";
203 * Set up attribute handling.
204 * This is rather complicated because termcap has different
205 * attribute groups.
208 if (D_UG > 0)
209 D_US = D_UE = NULL;
210 if (D_SG > 0)
211 D_SO = D_SE = NULL;
212 /* Unfortunately there is no 'mg' capability.
213 * For now we think that mg > 0 if sg and ug > 0.
215 if (D_UG > 0 && D_SG > 0)
216 D_MH = D_MD = D_MR = D_MB = D_ME = NULL;
218 xue = ATYP_U;
219 xse = ATYP_S;
220 xme = ATYP_M;
222 if (D_SO && D_SE == NULL) {
223 Msg(0, "Warning: 'so' but no 'se' capability.");
224 if (D_ME)
225 xse = xme;
226 else
227 D_SO = NULL;
229 if (D_US && D_UE == NULL) {
230 Msg(0, "Warning: 'us' but no 'ue' capability.");
231 if (D_ME)
232 xue = xme;
233 else
234 D_US = NULL;
236 if ((D_MH || D_MD || D_MR || D_MB) && D_ME == NULL) {
237 Msg(0, "Warning: 'm?' but no 'me' capability.");
238 D_MH = D_MD = D_MR = D_MB = NULL;
241 * Does ME also reverse the effect of SO and/or US? This is not
242 * clearly specified by the termcap manual. Anyway, we should at
243 * least look whether ME and SE/UE are equal:
245 if (D_UE && D_SE && strcmp(D_SE, D_UE) == 0)
246 xse = xue;
247 if (D_SE && D_ME && strcmp(D_ME, D_SE) == 0)
248 xse = xme;
249 if (D_UE && D_ME && strcmp(D_ME, D_UE) == 0)
250 xue = xme;
252 for (i = 0; i < NATTR; i++) {
253 D_attrtab[i] = D_tcs[T_ATTR + i].str;
254 D_attrtyp[i] = i == ATTR_SO ? xse : (i == ATTR_US ? xue : xme);
257 /* Set up missing entries (attributes are priority ordered) */
258 s = NULL;
259 t = 0;
260 for (i = 0; i < NATTR; i++)
261 if ((s = D_attrtab[i])) {
262 t = D_attrtyp[i];
263 break;
265 for (i = 0; i < NATTR; i++) {
266 if (D_attrtab[i] == NULL) {
267 D_attrtab[i] = s;
268 D_attrtyp[i] = t;
269 } else {
270 s = D_attrtab[i];
271 t = D_attrtyp[i];
274 if (D_CAF || D_CAB || D_CSF || D_CSB)
275 D_hascolor = 1;
276 if (D_UT)
277 D_BE = 1; /* screen erased with background color */
279 if (!D_DO)
280 D_DO = D_NL;
281 if (!D_SF)
282 D_SF = D_NL;
283 if (D_IN)
284 D_IC = D_IM = NULL;
285 if (D_EI == NULL)
286 D_IM = NULL;
287 /* some strange termcap entries have IC == IM */
288 if (D_IC && D_IM && strcmp(D_IC, D_IM) == 0)
289 D_IC = NULL;
290 if (D_KE == NULL)
291 D_KS = NULL;
292 if (D_CVN == NULL)
293 D_CVR = NULL;
294 if (D_VE == NULL)
295 D_VI = D_VS = NULL;
296 if (D_CCE == NULL)
297 D_CCS = NULL;
299 if (D_CG0) {
300 if (D_CS0 == NULL)
301 D_CS0 = "\033(%p1%c";
302 if (D_CE0 == NULL)
303 D_CE0 = "\033(B";
304 D_AC = NULL;
305 D_EA = NULL;
306 } else if (D_AC || (D_AS && D_AE)) { /* some kind of graphics */
307 D_CS0 = (D_AS && D_AE) ? D_AS : "";
308 D_CE0 = (D_AS && D_AE) ? D_AE : "";
309 D_CC0 = D_AC;
310 } else {
311 D_CS0 = D_CE0 = "";
312 D_CC0 = NULL;
313 D_AC = ""; /* enable default string */
316 for (i = 0; i < 256; i++)
317 D_c0_tab[i] = i;
318 if (D_AC) {
319 /* init with default string first */
320 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>";
321 for (i = (strlen(s) - 2) & ~1; i >= 0; i -= 2)
322 D_c0_tab[(int)(unsigned char)s[i]] = s[i + 1];
324 if (D_CC0)
325 for (i = (strlen(D_CC0) - 2) & ~1; i >= 0; i -= 2)
326 D_c0_tab[(int)(unsigned char)D_CC0[i]] = D_CC0[i + 1];
327 if (D_PF == NULL)
328 D_PO = NULL;
330 if (D_CXC)
331 if (CreateTransTable(D_CXC))
332 return -1;
334 /* Termcap fields Z0 & Z1 contain width-changing sequences. */
335 if (D_CZ1 == NULL)
336 D_CZ0 = NULL;
338 CheckScreenSize(0);
340 if (D_TS == NULL || D_FS == NULL || D_DS == NULL)
341 D_HS = 0;
342 if (D_HS) {
343 if (D_WS < 0)
344 D_WS = 0;
346 D_has_hstatus = hardstatusemu & ~HSTATUS_ALWAYS;
347 if (D_HS && !(hardstatusemu & HSTATUS_ALWAYS))
348 D_has_hstatus = HSTATUS_HS;
350 if (D_CKJ) {
351 int enc = FindEncoding(D_CKJ);
352 if (enc != -1)
353 D_encoding = enc;
355 if (!D_tcs[T_NAVIGATE].str && D_tcs[T_NAVIGATE + 1].str)
356 D_tcs[T_NAVIGATE].str = D_tcs[T_NAVIGATE + 1].str; /* kh = @1 */
357 if (!D_tcs[T_NAVIGATE + 2].str && D_tcs[T_NAVIGATE + 3].str)
358 D_tcs[T_NAVIGATE + 2].str = D_tcs[T_NAVIGATE + 3].str; /* kH = @7 */
360 D_UPcost = CalcCost(D_UP);
361 D_DOcost = CalcCost(D_DO);
362 D_NLcost = CalcCost(D_NL);
363 D_LEcost = CalcCost(D_BC);
364 D_NDcost = CalcCost(D_ND);
365 D_CRcost = CalcCost(D_CR);
366 D_IMcost = CalcCost(D_IM);
367 D_EIcost = CalcCost(D_EI);
369 if (D_CAN) {
370 D_auto_nuke = true;
372 if (D_COL > 0) {
373 D_obufmax = D_COL;
374 D_obuflenmax = D_obuflen - D_obufmax;
377 /* Some xterm entries set F0 and F10 to the same string. Nuke F0. */
378 if (D_tcs[T_CAPS].str && D_tcs[T_CAPS + 10].str && !strcmp(D_tcs[T_CAPS].str, D_tcs[T_CAPS + 10].str))
379 D_tcs[T_CAPS].str = NULL;
380 /* Some xterm entries set kD to ^?. Nuke it. */
381 if (D_tcs[T_NAVIGATE_DELETE].str && !strcmp(D_tcs[T_NAVIGATE_DELETE].str, "\0177"))
382 D_tcs[T_NAVIGATE_DELETE].str = NULL;
383 /* wyse52 entries have kcub1 == kb == ^H. Nuke... */
384 if (D_tcs[T_CURSOR + 3].str && !strcmp(D_tcs[T_CURSOR + 3].str, "\008"))
385 D_tcs[T_CURSOR + 3].str = NULL;
387 D_nseqs = 0;
388 for (i = 0; i < T_OCAPS - T_CAPS; i++)
389 remap(i, 1);
390 for (i = 0; i < kmap_extn; i++)
391 remap(i + (KMAP_KEYS + KMAP_AKEYS), 1);
392 D_seqp = D_kmaps + 3;
393 D_seql = 0;
394 D_seqh = NULL;
396 D_tcinited = 1;
397 MakeTermcap(0);
398 /* Make sure libterm uses external term properties for our tputs() calls. */
399 e_tgetent(tbuf, D_termname);
400 CheckEscape();
401 return 0;
404 int remap(int n, int map)
406 char *s = NULL;
407 int fl = 0, domap = 0;
408 struct action *a1, *a2, *tab;
409 int l = 0;
410 struct kmap_ext *kme = NULL;
412 a1 = NULL;
413 if (n >= KMAP_KEYS + KMAP_AKEYS) {
414 kme = kmap_exts + (n - (KMAP_KEYS + KMAP_AKEYS));
415 s = kme->str;
416 l = kme->fl & ~KMAP_NOTIMEOUT;
417 fl = kme->fl & KMAP_NOTIMEOUT;
418 a1 = &kme->um;
420 tab = umtab;
421 for (;;) {
422 a2 = NULL;
423 if (n < KMAP_KEYS + KMAP_AKEYS) {
424 a1 = &tab[n];
425 if (n >= KMAP_KEYS)
426 n -= T_OCAPS - T_CURSOR;
427 s = D_tcs[n + T_CAPS].str;
428 l = s ? strlen(s) : 0;
429 if (n >= T_CURSOR - T_CAPS)
430 a2 = &tab[n + (T_OCAPS - T_CURSOR)];
432 if (s == NULL || l == 0)
433 return 0;
434 if (a1 && a1->nr == RC_ILLEGAL)
435 a1 = NULL;
436 if (a2 && a2->nr == RC_ILLEGAL)
437 a2 = NULL;
438 if (a1 && a1->nr == RC_STUFF && a1->args[0] && strcmp(a1->args[0], s) == 0)
439 a1 = NULL;
440 if (a2 && a2->nr == RC_STUFF && a2->args[0] && strcmp(a2->args[0], s) == 0)
441 a2 = NULL;
442 domap |= (a1 || a2);
443 if (tab == umtab) {
444 tab = dmtab;
445 a1 = kme ? &kme->dm : NULL;
446 } else if (tab == dmtab) {
447 tab = mmtab;
448 a1 = kme ? &kme->mm : NULL;
449 } else
450 break;
452 if (n < KMAP_KEYS)
453 domap = 1;
454 if (map == 0 && domap)
455 return 0;
456 if (map && !domap)
457 return 0;
458 if (map)
459 return addmapseq(s, l, n | fl);
460 else
461 return remmapseq(s, l);
464 void CheckEscape(void)
466 Display *odisplay;
467 int i, nr;
469 if (DefaultEsc >= 0)
470 return;
472 odisplay = display;
473 for (display = displays; display; display = display->d_next) {
474 for (i = 0; i < D_nseqs; i += D_kmaps[i + 2] * 2 + 4) {
475 nr = (D_kmaps[i] << 8 | D_kmaps[i + 1]) & ~KMAP_NOTIMEOUT;
476 if (nr < KMAP_KEYS + KMAP_AKEYS) {
477 if (umtab[nr].nr == RC_COMMAND)
478 break;
479 if (umtab[nr].nr == RC_ILLEGAL && dmtab[nr].nr == RC_COMMAND)
480 break;
481 } else {
482 struct kmap_ext *kme = kmap_exts + nr - (KMAP_KEYS + KMAP_AKEYS);
483 if (kme->um.nr == RC_COMMAND)
484 break;
485 if (kme->um.nr == RC_ILLEGAL && kme->dm.nr == RC_COMMAND)
486 break;
490 if (display == NULL) {
491 display = odisplay;
492 return;
494 SetEscape(NULL, Ctrl('a'), 'a');
495 if (odisplay->d_user->u_Esc == -1)
496 odisplay->d_user->u_Esc = DefaultEsc;
497 if (odisplay->d_user->u_MetaEsc == -1)
498 odisplay->d_user->u_MetaEsc = DefaultMetaEsc;
499 display = NULL;
500 Msg(0, "Warning: escape char set back to ^A");
501 display = odisplay;
504 static int findseq_ge(char *seq, int k, unsigned char **sp)
506 unsigned char *p;
507 int j, l;
509 p = D_kmaps;
510 while (p - D_kmaps < D_nseqs) {
511 l = p[2];
512 p += 3;
513 for (j = 0;; j++) {
514 if (j == k || j == l)
515 j = l - k;
516 else if (p[j] != ((unsigned char *)seq)[j])
517 j = p[j] - ((unsigned char *)seq)[j];
518 else
519 continue;
520 break;
522 if (j >= 0) {
523 *sp = p - 3;
524 return j;
526 p += 2 * l + 1;
528 *sp = p;
529 return -1;
532 static void setseqoff(unsigned char *p, int i, int o)
534 unsigned char *q;
535 int l, k;
537 k = p[2];
538 if (o < 256) {
539 p[k + 4 + i] = o;
540 return;
542 /* go for the biggest offset */
543 for (q = p + k * 2 + 4;; q += l * 2 + 4) {
544 l = q[2];
545 if ((q + l * 2 - p) / 2 >= 256) {
546 p[k + 4 + i] = (q - p - 4) / 2;
547 return;
552 static int addmapseq(char *seq, int k, int nr)
554 int i, j, l, mo, m;
555 unsigned char *p, *q;
557 if (k >= 254)
558 return -1;
559 j = findseq_ge(seq, k, &p);
560 if (j == 0) {
561 p[0] = nr >> 8;
562 p[1] = nr;
563 return 0;
565 i = p - D_kmaps;
566 if (D_nseqs + 2 * k + 4 >= D_aseqs) {
567 D_kmaps = xrealloc((char *)D_kmaps, D_aseqs + 256);
568 D_aseqs += 256;
569 p = D_kmaps + i;
571 D_seqp = D_kmaps + 3;
572 D_seql = 0;
573 D_seqh = NULL;
574 evdeq(&D_mapev);
575 if (j > 0)
576 memmove((char *)p + 2 * k + 4, (char *)p, D_nseqs - i);
577 p[0] = nr >> 8;
578 p[1] = nr;
579 p[2] = k;
580 memmove((char *)p + 3, seq, k);
581 memset(p + k + 3, 0, k + 1);
582 D_nseqs += 2 * k + 4;
583 if (j > 0) {
584 q = p + 2 * k + 4;
585 l = q[2];
586 for (i = 0; i < k; i++) {
587 if (p[3 + i] != q[3 + i]) {
588 p[k + 4 + i] = k;
589 break;
591 setseqoff(p, i, q[l + 4 + i] ? q[l + 4 + i] + k + 2 : 0);
594 for (q = D_kmaps; q < p; q += 2 * l + 4) {
595 l = q[2];
596 for (m = j = 0; j < l; j++) {
597 mo = m;
598 if (!m && q[3 + j] != seq[j])
599 m = 1;
600 if (q[l + 4 + j] == 0) {
601 if (!mo && m)
602 setseqoff(q, j, (p - q - 4) / 2);
603 } else if (q + q[l + 4 + j] * 2 + 4 > p || (q + q[l + 4 + j] * 2 + 4 == p && !m))
604 setseqoff(q, j, q[l + 4 + j] + k + 2);
607 return 0;
610 static int remmapseq(char *seq, int k)
612 int j, l;
613 unsigned char *p, *q;
615 if (k >= 254 || (j = findseq_ge(seq, k, &p)) != 0)
616 return -1;
617 for (q = D_kmaps; q < p; q += 2 * l + 4) {
618 l = q[2];
619 for (j = 0; j < l; j++) {
620 if (q + q[l + 4 + j] * 2 + 4 == p)
621 setseqoff(q, j, p[k + 4 + j] ? q[l + 4 + j] + p[k + 4 + j] - k : 0);
622 else if (q + q[l + 4 + j] * 2 + 4 > p)
623 q[l + 4 + j] -= k + 2;
626 if (D_kmaps + D_nseqs > p + 2 * k + 4)
627 memmove((char *)p, (char *)p + 2 * k + 4, (D_kmaps + D_nseqs) - (p + 2 * k + 4));
628 D_nseqs -= 2 * k + 4;
629 D_seqp = D_kmaps + 3;
630 D_seql = 0;
631 D_seqh = NULL;
632 evdeq(&D_mapev);
633 return 0;
637 * Appends to the static variable Termcap
639 static void AddCap(char *s)
641 int n;
643 n = strlen(s);
644 if (Termcaplen + n < TERMCAP_BUFSIZE - 1) {
645 strcpy(Termcap + Termcaplen, s);
646 Termcaplen += n;
647 tcLineLen += n;
652 * Reads a displays capabilities and reconstructs a termcap entry in the
653 * global buffer "Termcap". A pointer to this buffer is returned.
655 char *MakeTermcap(bool aflag)
657 char buf[TERMCAP_BUFSIZE];
658 char *p, *cp, *s, ch, *tname;
659 int i, width, height;
661 if (display) {
662 width = D_width;
663 height = D_height;
664 tname = D_termname;
665 } else {
666 width = 80;
667 height = 24;
668 tname = "vt100";
670 if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE) {
671 sprintf(Termcap, "TERMCAP=%s", s);
672 strcpy(Term, "TERM=screen");
673 return Termcap;
675 Termcaplen = 0;
676 if (*screenterm == '\0' || strlen(screenterm) > MAXSTR - 3) {
677 strncpy(screenterm, "screen", MAXTERMLEN);
678 screenterm[MAXTERMLEN] = '\0';
680 do {
681 strcpy(Term, "TERM=");
682 p = Term + 5;
683 if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR - 1) {
684 sprintf(p, "%s.%s", screenterm, tname);
685 if (e_tgetent(buf, p) == 1)
686 break;
688 if (nwin_default.bce) {
689 sprintf(p, "%s-bce", screenterm);
690 if (e_tgetent(buf, p) == 1)
691 break;
693 strcpy(p, screenterm);
694 if (e_tgetent(buf, p) == 1)
695 break;
696 strcpy(p, "vt100");
698 while (0); /* Goto free programming... */
700 tcLineLen = 100; /* Force NL */
701 if (strlen(Term) > TERMCAP_BUFSIZE - 40)
702 strcpy(Term, "too_long");
703 sprintf(Termcap, "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal:", Term + 5);
704 Termcaplen = strlen(Termcap);
705 if (extra_outcap && *extra_outcap) {
706 for (cp = extra_outcap; (p = strchr(cp, ':')); cp = p) {
707 ch = *++p;
708 *p = '\0';
709 AddCap(cp);
710 *p = ch;
712 tcLineLen = 100; /* Force NL */
714 if (Termcaplen + strlen(TermcapConst) < TERMCAP_BUFSIZE) {
715 strcpy(Termcap + Termcaplen, TermcapConst);
716 Termcaplen += strlen(TermcapConst);
718 sprintf(buf, "li#%d:co#%d:", height, width);
719 AddCap(buf);
720 AddCap("am:");
721 if (aflag || (force_vt && !D_COP) || D_CLP || !D_AM) {
722 AddCap("xn:");
723 AddCap("xv:");
724 AddCap("LP:");
726 if (aflag || (D_CS && D_SR) || D_AL || D_CAL) {
727 AddCap("sr=\\EM:");
728 AddCap("al=\\E[L:");
729 AddCap("AL=\\E[%dL:");
730 } else if (D_SR)
731 AddCap("sr=\\EM:");
732 if (aflag || D_CS)
733 AddCap("cs=\\E[%i%d;%dr:");
734 if (aflag || D_CS || D_DL || D_CDL) {
735 AddCap("dl=\\E[M:");
736 AddCap("DL=\\E[%dM:");
738 if (aflag || D_DC || D_CDC) {
739 AddCap("dc=\\E[P:");
740 AddCap("DC=\\E[%dP:");
742 if (aflag || D_CIC || D_IC || D_IM) {
743 AddCap("im=\\E[4h:");
744 AddCap("ei=\\E[4l:");
745 AddCap("mi:");
746 AddCap("IC=\\E[%d@:");
748 AddCap("ks=\\E[?1h\\E=:");
749 AddCap("ke=\\E[?1l\\E>:");
750 AddCap("vi=\\E[?25l:");
751 AddCap("ve=\\E[34h\\E[?25h:");
752 AddCap("vs=\\E[34l:");
753 AddCap("ti=\\E[?1049h:");
754 AddCap("te=\\E[?1049l:");
755 if (display) {
756 if (D_US) {
757 AddCap("us=\\E[4m:");
758 AddCap("ue=\\E[24m:");
760 if (D_CZH) {
761 AddCap("so=\\E[3m:");
762 AddCap("se=\\E[23m:");
764 if (D_SO) {
765 AddCap("so=\\E[7m:");
766 AddCap("se=\\E[27m:");
768 if (D_MB)
769 AddCap("mb=\\E[5m:");
770 if (D_MD)
771 AddCap("md=\\E[1m:");
772 if (D_MH)
773 AddCap("mh=\\E[2m:");
774 if (D_MR)
775 AddCap("mr=\\E[7m:");
776 if (D_MB || D_MD || D_MH || D_MR)
777 AddCap("me=\\E[m:ms:");
778 if (D_hascolor)
779 AddCap("Co#8:pa#64:AF=\\E[3%dm:AB=\\E[4%dm:op=\\E[39;49m:AX:");
780 if (D_VB)
781 AddCap("vb=\\Eg:");
782 if (D_CG0)
783 AddCap("G0:");
784 if (D_CC0 || (D_CS0 && *D_CS0)) {
785 AddCap("as=\\E(0:");
786 AddCap("ae=\\E(B:");
787 /* avoid `` because some shells dump core... */
788 AddCap("ac=\\140\\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:");
790 if (D_PO) {
791 AddCap("po=\\E[5i:");
792 AddCap("pf=\\E[4i:");
794 if (D_CZ0) {
795 AddCap("Z0=\\E[?3h:");
796 AddCap("Z1=\\E[?3l:");
798 if (D_CWS)
799 AddCap("WS=\\E[8;%d;%dt:");
801 for (i = T_CAPS; i < T_ECAPS; i++) {
802 struct action *act;
803 if (i < T_OCAPS) {
804 if (i >= T_KEYPAD) /* don't put keypad codes in TERMCAP */
805 continue; /* - makes it too big */
806 #if (TERMCAP_BUFSIZE < 1024)
807 if (i >= T_FEXTRA && i < T_BACKTAB) /* also skip extra vt220 keys */
808 continue;
809 if (i > T_BACKTAB && i < T_NAVIGATE) /* more vt220 keys */
810 continue;
811 #endif
812 if (i >= T_CURSOR && i < T_OCAPS) {
813 act = &umtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
814 if (act->nr == RC_ILLEGAL)
815 act = &dmtab[i - (T_CURSOR - T_OCAPS + T_CAPS)];
816 } else {
817 act = &umtab[i - T_CAPS];
818 if (act->nr == RC_ILLEGAL)
819 act = &dmtab[i - T_CAPS];
821 if (act->nr == RC_ILLEGAL && (i == T_NAVIGATE + 1 || i == T_NAVIGATE + 3)) {
822 /* kh -> @1, kH -> @7 */
823 act = &umtab[i - T_CAPS - 1];
824 if (act->nr == RC_ILLEGAL)
825 act = &dmtab[i - T_CAPS - 1];
827 if (act->nr != RC_ILLEGAL) {
828 if (act->nr == RC_STUFF) {
829 MakeString(term[i].tcname, buf, ARRAY_SIZE(buf), act->args[0]);
830 AddCap(buf);
832 continue;
835 if (display == NULL)
836 continue;
837 switch (term[i].type) {
838 case T_STR:
839 if (D_tcs[i].str == NULL)
840 break;
841 MakeString(term[i].tcname, buf, ARRAY_SIZE(buf), D_tcs[i].str);
842 AddCap(buf);
843 break;
844 case T_FLG:
845 if (D_tcs[i].flg == 0)
846 break;
847 sprintf(buf, "%s:", term[i].tcname);
848 AddCap(buf);
849 break;
850 default:
851 break;
854 return Termcap;
857 #define TERMCAP_MAX_WIDTH 63
858 void DumpTermcap(int aflag, FILE *f)
860 const char *p, *pe;
861 int n, col = 0;
863 if ((p = index(MakeTermcap(aflag), '=')) == NULL)
864 return;
865 p++;
866 /* write termcap entry with wrapping */
867 while ((pe = index(p, ':')))
869 n = pe - p + 1;
870 if ((col > 8) && ((col + n) > TERMCAP_MAX_WIDTH))
872 fwrite("\\\n\t:", 1, 4, f);
873 col = 8;
875 fwrite(p, 1, n, f);
876 col += n;
877 p = ++pe;
879 if(*p)
880 fwrite(p, 1, strlen(p), f);
881 fputc('\n', f);
884 static void MakeString(char *cap, char *buf, int buflen, char *s)
886 char *p, *pmax;
887 unsigned int c;
889 p = buf;
890 pmax = p + buflen - (3 + 4 + 2);
891 *p++ = *cap++;
892 *p++ = *cap;
893 *p++ = '=';
894 while ((c = *s++) && (p < pmax)) {
895 switch (c) {
896 case '\033':
897 *p++ = '\\';
898 *p++ = 'E';
899 break;
900 case ':':
901 strcpy(p, "\\072");
902 p += 4;
903 break;
904 case '^':
905 case '\\':
906 *p++ = '\\';
907 *p++ = c;
908 break;
909 default:
910 if (c >= 200) {
911 sprintf(p, "\\%03o", c & 0377);
912 p += 4;
913 } else if (c < ' ') {
914 *p++ = '^';
915 *p++ = c + '@';
916 } else
917 *p++ = c;
920 *p++ = ':';
921 *p = '\0';
924 #undef QUOTES
925 #define QUOTES(p) \
926 (*p == '\\' && (p[1] == '\\' || p[1] == ',' || p[1] == '%'))
928 int CreateTransTable(char *s)
930 int curchar;
931 char *templ, *arg;
932 int templlen;
933 int templnsub;
934 char *p, *sx;
935 char **ctable;
936 int l, c;
938 if ((D_xtable = calloc(256, sizeof(char **))) == NULL) {
939 Msg(0, "%s", strnomem);
940 return -1;
943 while (*s) {
944 if (QUOTES(s))
945 s++;
946 curchar = (unsigned char)*s++;
947 if (curchar == 'B')
948 curchar = 0; /* ASCII */
949 templ = s;
950 templlen = 0;
951 templnsub = 0;
952 if (D_xtable[curchar] == NULL) {
953 if ((D_xtable[curchar] = calloc(257, sizeof(char *))) == NULL) {
954 Msg(0, "%s", strnomem);
955 FreeTransTable();
956 return -1;
959 ctable = D_xtable[curchar];
960 for (; *s && *s != ','; s++) {
961 if (QUOTES(s))
962 s++;
963 else if (*s == '%') {
964 templnsub++;
965 continue;
967 templlen++;
969 if (*s++ == 0)
970 break;
971 while (*s && *s != ',') {
972 c = (unsigned char)*s++;
973 if (QUOTES((s - 1)))
974 c = (unsigned char)*s++;
975 else if (c == '%')
976 c = 256;
977 if (ctable[c])
978 free(ctable[c]);
979 arg = s;
980 l = copyarg(&s, NULL);
981 if (c != 256)
982 l = l * templnsub + templlen;
983 if ((ctable[c] = malloc(l + 1)) == NULL) {
984 Msg(0, "%s", strnomem);
985 FreeTransTable();
986 return -1;
988 sx = ctable[c];
989 for (p = ((c == 256) ? "%" : templ); *p && *p != ','; p++) {
990 if (QUOTES(p))
991 p++;
992 else if (*p == '%') {
993 s = arg;
994 sx += copyarg(&s, sx);
995 continue;
997 *sx++ = *p;
999 *sx = 0;
1001 if (*s == ',')
1002 s++;
1004 return 0;
1007 void FreeTransTable(void)
1009 char ***p, **q;
1010 int i, j;
1012 if ((p = D_xtable) == NULL)
1013 return;
1014 for (i = 0; i < 256; i++, p++) {
1015 if (*p == NULL)
1016 continue;
1017 q = *p;
1018 for (j = 0; j < 257; j++, q++)
1019 if (*q)
1020 free(*q);
1021 free(*p);
1023 free(D_xtable);
1024 D_xtable = NULL;
1027 static int copyarg(char **pp, char *s)
1029 int l;
1030 char *p;
1032 for (l = 0, p = *pp; *p && *p != ','; p++) {
1033 if (QUOTES(p))
1034 p++;
1035 if (s)
1036 *s++ = *p;
1037 l++;
1039 if (*p == ',')
1040 p++;
1041 *pp = p;
1042 return l;
1047 ** Termcap routines that use our extra_incap
1051 static int e_tgetent(char *bp, char *name)
1053 int r;
1055 xseteuid(real_uid);
1056 xsetegid(real_gid);
1057 r = tgetent(bp, name);
1058 xseteuid(eff_uid);
1059 xsetegid(eff_gid);
1060 return r;
1063 /* findcap:
1064 * cap = capability we are looking for
1065 * tepp = pointer to bufferpointer
1066 * n = size of buffer (0 = infinity)
1069 static char *findcap(char *cap, char **tepp, int n)
1071 char *tep;
1072 char c, *p, *cp;
1073 int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */
1074 int num = 0, capl;
1076 if (!extra_incap)
1077 return NULL;
1078 tep = *tepp;
1079 capl = strlen(cap);
1080 cp = NULL;
1081 mode = 0;
1082 for (p = extra_incap; *p;) {
1083 if (strncmp(p, cap, capl) == 0) {
1084 p += capl;
1085 c = *p;
1086 if (c && c != ':' && c != '@')
1087 p++;
1088 if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
1089 cp = tep;
1091 while ((c = *p)) {
1092 p++;
1093 if (mode == 0) {
1094 if (c == ':')
1095 break;
1096 if (c == '^')
1097 mode = 1;
1098 if (c == '\\')
1099 mode = 2;
1100 } else if (mode == 1) {
1101 mode = 0;
1102 c = c & 0x1f;
1103 } else if (mode == 2) {
1104 mode = 0;
1105 switch (c) {
1106 case '0':
1107 case '1':
1108 case '2':
1109 case '3':
1110 case '4':
1111 case '5':
1112 case '6':
1113 case '7':
1114 case '8':
1115 case '9':
1116 mode = 3;
1117 num = 0;
1118 break;
1119 case 'E':
1120 c = 27;
1121 break;
1122 case 'n':
1123 c = '\n';
1124 break;
1125 case 'r':
1126 c = '\r';
1127 break;
1128 case 't':
1129 c = '\t';
1130 break;
1131 case 'b':
1132 c = '\b';
1133 break;
1134 case 'f':
1135 c = '\f';
1136 break;
1139 if (mode > 2) {
1140 num = num * 8 + (c - '0');
1141 if (mode++ == 5 || (*p < '0' || *p > '9')) {
1142 c = num;
1143 mode = 0;
1146 if (mode)
1147 continue;
1149 if (cp && n != 1) {
1150 *cp++ = c;
1151 n--;
1154 if (cp) {
1155 *cp++ = 0;
1156 *tepp = cp;
1157 return tep;
1160 return NULL;
1163 static char *e_tgetstr(char *cap, char **tepp)
1165 char *tep;
1166 if ((tep = findcap(cap, tepp, 0)))
1167 return (*tep == '@') ? NULL : tep;
1168 return tgetstr(cap, tepp);
1171 static int e_tgetflag(char *cap)
1173 char buf[2], *bufp;
1174 char *tep;
1175 bufp = buf;
1176 if ((tep = findcap(cap, &bufp, 2)))
1177 return (*tep == '@') ? 0 : 1;
1178 return tgetflag(cap) > 0;
1181 static int e_tgetnum(char *cap)
1183 char buf[20], *bufp;
1184 char *tep, c;
1185 int res, base = 10;
1187 bufp = buf;
1188 if ((tep = findcap(cap, &bufp, 20))) {
1189 c = *tep;
1190 if (c == '@')
1191 return -1;
1192 if (c == '0')
1193 base = 8;
1194 res = 0;
1195 while ((c = *tep++) >= '0' && c <= '9')
1196 res = res * base + (c - '0');
1197 return res;
1199 return tgetnum(cap);