diff options
Diffstat (limited to '')
-rw-r--r-- | termcap.c | 1514 |
1 files changed, 1514 insertions, 0 deletions
diff --git a/termcap.c b/termcap.c new file mode 100644 index 0000000..1190960 --- /dev/null +++ b/termcap.c @@ -0,0 +1,1514 @@ +/* Copyright (c) 2008, 2009 + * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) + * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) + * Micah Cowan (micah@cowan.name) + * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net) + * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007 + * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) + * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) + * Copyright (c) 1987 Oliver Laumann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING); if not, see + * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + * + **************************************************************** + */ + +#include <sys/types.h> +#include "config.h" +#include "screen.h" +#include "extern.h" + +extern struct display *display, *displays; +extern int real_uid, real_gid, eff_uid, eff_gid; +extern struct term term[]; /* terminal capabilities */ +extern struct NewWindow nwin_undef, nwin_default, nwin_options; +extern int force_vt; +extern int hardstatusemu; +#ifdef MAPKEYS +extern struct action umtab[]; +extern struct action mmtab[]; +extern struct action dmtab[]; +extern struct action ktab[]; +extern struct kmap_ext *kmap_exts; +extern int kmap_extn; +extern int DefaultEsc; +#endif + + +static void AddCap __P((char *)); +static void MakeString __P((char *, char *, int, char *)); +static char *findcap __P((char *, char **, int)); +static int copyarg __P((char **, char *)); +static int e_tgetent __P((char *, char *)); +static char *e_tgetstr __P((char *, char **)); +static int e_tgetflag __P((char *)); +static int e_tgetnum __P((char *)); +#ifdef MAPKEYS +static int findseq_ge __P((char *, int, unsigned char **)); +static void setseqoff __P((unsigned char *, int, int)); +static int addmapseq __P((char *, int, int)); +static int remmapseq __P((char *, int)); +#ifdef DEBUGG +static void dumpmap __P((void)); +#endif +#endif + + +char Termcap[TERMCAP_BUFSIZE + 8]; /* new termcap +8:"TERMCAP=" */ +static int Termcaplen; +static int tcLineLen; +char Term[MAXSTR+5]; /* +5: "TERM=" */ +char screenterm[MAXTERMLEN + 1]; /* new $TERM, usually "screen" */ + +char *extra_incap, *extra_outcap; + +static const char TermcapConst[] = "\\\n\ +\t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\ +\t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\ +\t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\ +\t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:"; + +char * +gettermcapstring(s) +char *s; +{ + int i; + + if (display == 0 || s == 0) + return 0; + for (i = 0; i < T_N; i++) + { + if (term[i].type != T_STR) + continue; + if (strcmp(term[i].tcname, s) == 0) + return D_tcs[i].str; + } + return 0; +} + +/* + * Compile the terminal capabilities for a display. + * Input: tgetent(, D_termname) extra_incap, extra_outcap. + * Effect: display initialisation. + */ +int +InitTermcap(wi, he) +int wi; +int he; +{ + register char *s; + int i; + char tbuf[TERMCAP_BUFSIZE], *tp; + int t, xue, xse, xme; + + ASSERT(display); + bzero(tbuf, sizeof(tbuf)); + debug1("InitTermcap: looking for tgetent('%s')\n", D_termname); + if (*D_termname == 0 || e_tgetent(tbuf, D_termname) != 1) + { +#ifdef TERMINFO + Msg(0, "Cannot find terminfo entry for '%s'.", D_termname); +#else + Msg(0, "Cannot find termcap entry for '%s'.", D_termname); +#endif + return -1; + } + debug1("got it:\n%s\n", tbuf); +#ifdef DEBUG + if (extra_incap) + debug1("Extra incap: %s\n", extra_incap); + if (extra_outcap) + debug1("Extra outcap: %s\n", extra_outcap); +#endif + + if ((D_tentry = (char *)malloc(TERMCAP_BUFSIZE + (extra_incap ? strlen(extra_incap) + 1 : 0))) == 0) + { + Msg(0, "%s", strnomem); + return -1; + } + + /* + * loop through all needed capabilities, record their values in the display + */ + tp = D_tentry; + for (i = 0; i < T_N; i++) + { + switch(term[i].type) + { + case T_FLG: + D_tcs[i].flg = e_tgetflag(term[i].tcname); + break; + case T_NUM: + D_tcs[i].num = e_tgetnum(term[i].tcname); + break; + case T_STR: + D_tcs[i].str = e_tgetstr(term[i].tcname, &tp); + /* no empty strings, please */ + if (D_tcs[i].str && *D_tcs[i].str == 0) + D_tcs[i].str = 0; + break; + default: + Panic(0, "Illegal tc type in entry #%d", i); + /*NOTREACHED*/ + } + } + + /* + * Now a good deal of sanity checks on the retrieved capabilities. + */ + if (D_HC) + { + Msg(0, "You can't run screen on a hardcopy terminal."); + return -1; + } + if (D_OS) + { + Msg(0, "You can't run screen on a terminal that overstrikes."); + return -1; + } + if (!D_CL) + { + Msg(0, "Clear screen capability required."); + return -1; + } + if (!D_CM) + { + Msg(0, "Addressable cursor capability required."); + return -1; + } + if ((s = getenv("COLUMNS")) && (i = atoi(s)) > 0) + D_CO = i; + if ((s = getenv("LINES")) && (i = atoi(s)) > 0) + D_LI = i; + if (wi) + D_CO = wi; + if (he) + D_LI = he; + if (D_CO <= 0) + D_CO = 80; + if (D_LI <= 0) + D_LI = 24; + + if (D_CTF) + { + /* standard fixes for xterms etc */ + /* assume color for everything that looks ansi-compatible */ + if (!D_CAF && D_ME && (InStr(D_ME, "\033[m") || InStr(D_ME, "\033[0m"))) + { +#ifdef TERMINFO + D_CAF = "\033[3%p1%dm"; + D_CAB = "\033[4%p1%dm"; +#else + D_CAF = "\033[3%dm"; + D_CAB = "\033[4%dm"; +#endif + } + if (D_OP && InStr(D_OP, "\033[39;49m")) + D_CAX = 1; + if (D_OP && (InStr(D_OP, "\033[m") || InStr(D_OP, "\033[0m"))) + D_OP = 0; + /* ISO2022 */ + if ((D_EA && InStr(D_EA, "\033(B")) || (D_AS && InStr(D_AS, "\033(0"))) + D_CG0 = 1; + if (InStr(D_termname, "xterm") || InStr(D_termname, "rxvt") || + (D_CKM && InStr(D_CKM, "\033[M"))) + D_CXT = 1; + /* "be" seems to be standard for xterms... */ + if (D_CXT) + D_BE = 1; + } + if (nwin_options.flowflag == nwin_undef.flowflag) + nwin_default.flowflag = D_CNF ? FLOW_NOW * 0 : + D_NX ? FLOW_NOW * 1 : + FLOW_AUTOFLAG; + D_CLP |= (!D_AM || D_XV || D_XN); + if (!D_BL) + D_BL = "\007"; + if (!D_BC) + { + if (D_BS) + D_BC = "\b"; + else + D_BC = D_LE; + } + if (!D_CR) + D_CR = "\r"; + if (!D_NL) + D_NL = "\n"; + + /* + * Set up attribute handling. + * This is rather complicated because termcap has different + * attribute groups. + */ + + if (D_UG > 0) + D_US = D_UE = 0; + if (D_SG > 0) + D_SO = D_SE = 0; + /* Unfortunately there is no 'mg' capability. + * For now we think that mg > 0 if sg and ug > 0. + */ + if (D_UG > 0 && D_SG > 0) + D_MH = D_MD = D_MR = D_MB = D_ME = 0; + + xue = ATYP_U; + xse = ATYP_S; + xme = ATYP_M; + + if (D_SO && D_SE == 0) + { + Msg(0, "Warning: 'so' but no 'se' capability."); + if (D_ME) + xse = xme; + else + D_SO = 0; + } + if (D_US && D_UE == 0) + { + Msg(0, "Warning: 'us' but no 'ue' capability."); + if (D_ME) + xue = xme; + else + D_US = 0; + } + if ((D_MH || D_MD || D_MR || D_MB) && D_ME == 0) + { + Msg(0, "Warning: 'm?' but no 'me' capability."); + D_MH = D_MD = D_MR = D_MB = 0; + } + /* + * Does ME also reverse the effect of SO and/or US? This is not + * clearly specified by the termcap manual. Anyway, we should at + * least look whether ME and SE/UE are equal: + */ + if (D_UE && D_SE && strcmp(D_SE, D_UE) == 0) + xse = xue; + if (D_SE && D_ME && strcmp(D_ME, D_SE) == 0) + xse = xme; + if (D_UE && D_ME && strcmp(D_ME, D_UE) == 0) + xue = xme; + + for (i = 0; i < NATTR; i++) + { + D_attrtab[i] = D_tcs[T_ATTR + i].str; + D_attrtyp[i] = i == ATTR_SO ? xse : (i == ATTR_US ? xue : xme); + } + + /* Set up missing entries (attributes are priority ordered) */ + s = 0; + t = 0; + for (i = 0; i < NATTR; i++) + if ((s = D_attrtab[i])) + { + t = D_attrtyp[i]; + break; + } + for (i = 0; i < NATTR; i++) + { + if (D_attrtab[i] == 0) + { + D_attrtab[i] = s; + D_attrtyp[i] = t; + } + else + { + s = D_attrtab[i]; + t = D_attrtyp[i]; + } + } + if (D_CAF || D_CAB || D_CSF || D_CSB) + D_hascolor = 1; + if (D_UT) + D_BE = 1; /* screen erased with background color */ + + if (!D_DO) + D_DO = D_NL; + if (!D_SF) + D_SF = D_NL; + if (D_IN) + D_IC = D_IM = 0; + if (D_EI == 0) + D_IM = 0; + /* some strange termcap entries have IC == IM */ + if (D_IC && D_IM && strcmp(D_IC, D_IM) == 0) + D_IC = 0; + if (D_KE == 0) + D_KS = 0; + if (D_CVN == 0) + D_CVR = 0; + if (D_VE == 0) + D_VI = D_VS = 0; + if (D_CCE == 0) + D_CCS = 0; + +#ifdef FONT + if (D_CG0) + { + if (D_CS0 == 0) +#ifdef TERMINFO + D_CS0 = "\033(%p1%c"; +#else + D_CS0 = "\033(%."; +#endif + if (D_CE0 == 0) + D_CE0 = "\033(B"; + D_AC = 0; + D_EA = 0; + } + else if (D_AC || (D_AS && D_AE)) /* some kind of graphics */ + { + D_CS0 = (D_AS && D_AE) ? D_AS : ""; + D_CE0 = (D_AS && D_AE) ? D_AE : ""; + D_CC0 = D_AC; + } + else + { + D_CS0 = D_CE0 = ""; + D_CC0 = 0; + D_AC = ""; /* enable default string */ + } + + for (i = 0; i < 256; i++) + D_c0_tab[i] = i; + if (D_AC) + { + /* init with default string first */ + 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>"; + for (i = (strlen(s) - 2) & ~1; i >= 0; i -= 2) + D_c0_tab[(int)(unsigned char)s[i]] = s[i + 1]; + } + if (D_CC0) + for (i = (strlen(D_CC0) - 2) & ~1; i >= 0; i -= 2) + D_c0_tab[(int)(unsigned char)D_CC0[i]] = D_CC0[i + 1]; + debug1("ISO2022 = %d\n", D_CG0); +#endif /* FONT */ + if (D_PF == 0) + D_PO = 0; + debug2("terminal size is %d, %d (says TERMCAP)\n", D_CO, D_LI); + +#ifdef FONT + if (D_CXC) + if (CreateTransTable(D_CXC)) + return -1; +#endif + + /* Termcap fields Z0 & Z1 contain width-changing sequences. */ + if (D_CZ1 == 0) + D_CZ0 = 0; + + CheckScreenSize(0); + + if (D_TS == 0 || D_FS == 0 || D_DS == 0) + D_HS = 0; + if (D_HS) + { + debug("oy! we have a hardware status line, says termcap\n"); + if (D_WS < 0) + D_WS = 0; + } + D_has_hstatus = hardstatusemu & ~HSTATUS_ALWAYS; + if (D_HS && !(hardstatusemu & HSTATUS_ALWAYS)) + D_has_hstatus = HSTATUS_HS; + +#ifdef ENCODINGS + if (D_CKJ) + { + int enc = FindEncoding(D_CKJ); + if (enc != -1) + D_encoding = enc; + } +#endif + if (!D_tcs[T_NAVIGATE].str && D_tcs[T_NAVIGATE + 1].str) + D_tcs[T_NAVIGATE].str = D_tcs[T_NAVIGATE + 1].str; /* kh = @1 */ + if (!D_tcs[T_NAVIGATE + 2].str && D_tcs[T_NAVIGATE + 3].str) + D_tcs[T_NAVIGATE + 2].str = D_tcs[T_NAVIGATE + 3].str; /* kH = @7 */ + + D_UPcost = CalcCost(D_UP); + D_DOcost = CalcCost(D_DO); + D_NLcost = CalcCost(D_NL); + D_LEcost = CalcCost(D_BC); + D_NDcost = CalcCost(D_ND); + D_CRcost = CalcCost(D_CR); + D_IMcost = CalcCost(D_IM); + D_EIcost = CalcCost(D_EI); + +#ifdef AUTO_NUKE + if (D_CAN) + { + debug("termcap has AN, setting autonuke\n"); + D_auto_nuke = 1; + } +#endif + if (D_COL > 0) + { + debug1("termcap has OL (%d), setting limit\n", D_COL); + D_obufmax = D_COL; + D_obuflenmax = D_obuflen - D_obufmax; + } + + /* Some xterm entries set F0 and F10 to the same string. Nuke F0. */ + if (D_tcs[T_CAPS].str && D_tcs[T_CAPS + 10].str && !strcmp(D_tcs[T_CAPS].str, D_tcs[T_CAPS + 10].str)) + D_tcs[T_CAPS].str = 0; + /* Some xterm entries set kD to ^?. Nuke it. */ + if (D_tcs[T_NAVIGATE_DELETE].str && !strcmp(D_tcs[T_NAVIGATE_DELETE].str, "\0177")) + D_tcs[T_NAVIGATE_DELETE].str = 0; + /* wyse52 entries have kcub1 == kb == ^H. Nuke... */ + if (D_tcs[T_CURSOR + 3].str && !strcmp(D_tcs[T_CURSOR + 3].str, "\008")) + D_tcs[T_CURSOR + 3].str = 0; + +#ifdef MAPKEYS + D_nseqs = 0; + for (i = 0; i < T_OCAPS - T_CAPS; i++) + remap(i, 1); + for (i = 0; i < kmap_extn; i++) + remap(i + (KMAP_KEYS+KMAP_AKEYS), 1); + D_seqp = D_kmaps + 3; + D_seql = 0; + D_seqh = 0; +#endif + + D_tcinited = 1; + MakeTermcap(0); + /* Make sure libterm uses external term properties for our tputs() calls. */ + e_tgetent(tbuf, D_termname); +#ifdef MAPKEYS + CheckEscape(); +#endif + return 0; +} + +#ifdef MAPKEYS + +int +remap(n, map) +int n; +int map; +{ + char *s = 0; + int fl = 0, domap = 0; + struct action *a1, *a2, *tab; + int l = 0; + struct kmap_ext *kme = 0; + + a1 = 0; + if (n >= KMAP_KEYS+KMAP_AKEYS) + { + kme = kmap_exts + (n - (KMAP_KEYS+KMAP_AKEYS)); + s = kme->str; + l = kme->fl & ~KMAP_NOTIMEOUT; + fl = kme->fl & KMAP_NOTIMEOUT; + a1 = &kme->um; + } + tab = umtab; + for (;;) + { + a2 = 0; + if (n < KMAP_KEYS+KMAP_AKEYS) + { + a1 = &tab[n]; + if (n >= KMAP_KEYS) + n -= T_OCAPS-T_CURSOR; + s = D_tcs[n + T_CAPS].str; + l = s ? strlen(s) : 0; + if (n >= T_CURSOR-T_CAPS) + a2 = &tab[n + (T_OCAPS-T_CURSOR)]; + } + if (s == 0 || l == 0) + return 0; + if (a1 && a1->nr == RC_ILLEGAL) + a1 = 0; + if (a2 && a2->nr == RC_ILLEGAL) + a2 = 0; + if (a1 && a1->nr == RC_STUFF && a1->args[0] && strcmp(a1->args[0], s) == 0) + a1 = 0; + if (a2 && a2->nr == RC_STUFF && a2->args[0] && strcmp(a2->args[0], s) == 0) + a2 = 0; + domap |= (a1 || a2); + if (tab == umtab) + { + tab = dmtab; + a1 = kme ? &kme->dm : 0; + } + else if (tab == dmtab) + { + tab = mmtab; + a1 = kme ? &kme->mm : 0; + } + else + break; + } + if (n < KMAP_KEYS) + domap = 1; + if (map == 0 && domap) + return 0; + if (map && !domap) + return 0; + debug3("%smapping %s %#x\n", map? "" :"un",s,n); + if (map) + return addmapseq(s, l, n | fl); + else + return remmapseq(s, l); +} + +void +CheckEscape() +{ + struct display *odisplay; + int i, nr; + + if (DefaultEsc >= 0) + return; + + odisplay = display; + for (display = displays; display; display = display->d_next) + { + for (i = 0; i < D_nseqs; i += D_kmaps[i + 2] * 2 + 4) + { + nr = (D_kmaps[i] << 8 | D_kmaps[i + 1]) & ~KMAP_NOTIMEOUT; + if (nr < KMAP_KEYS+KMAP_AKEYS) + { + if (umtab[nr].nr == RC_COMMAND) + break; + if (umtab[nr].nr == RC_ILLEGAL && dmtab[nr].nr == RC_COMMAND) + break; + } + else + { + struct kmap_ext *kme = kmap_exts + nr - (KMAP_KEYS+KMAP_AKEYS); + if (kme->um.nr == RC_COMMAND) + break; + if (kme->um.nr == RC_ILLEGAL && kme->dm.nr == RC_COMMAND) + break; + } + } + } + if (display == 0) + { + display = odisplay; + return; + } + SetEscape((struct acluser *)0, Ctrl('a'), 'a'); + if (odisplay->d_user->u_Esc == -1) + odisplay->d_user->u_Esc = DefaultEsc; + if (odisplay->d_user->u_MetaEsc == -1) + odisplay->d_user->u_MetaEsc = DefaultMetaEsc; + display = 0; + Msg(0, "Warning: escape char set back to ^A"); + display = odisplay; +} + +static int +findseq_ge(seq, k, sp) +char *seq; +int k; +unsigned char **sp; +{ + unsigned char *p; + int j, l; + + p = D_kmaps; + while (p - D_kmaps < D_nseqs) + { + l = p[2]; + p += 3; + for (j = 0; ; j++) + { + if (j == k || j == l) + j = l - k; + else if (p[j] != ((unsigned char *)seq)[j]) + j = p[j] - ((unsigned char *)seq)[j]; + else + continue; + break; + } + if (j >= 0) + { + *sp = p - 3; + return j; + } + p += 2 * l + 1; + } + *sp = p; + return -1; +} + +static void +setseqoff(p, i, o) +unsigned char *p; +int i; +int o; +{ + unsigned char *q; + int l, k; + + k = p[2]; + if (o < 256) + { + p[k + 4 + i] = o; + return; + } + /* go for the biggest offset */ + for (q = p + k * 2 + 4; ; q += l * 2 + 4) + { + l = q[2]; + if ((q + l * 2 - p) / 2 >= 256) + { + p[k + 4 + i] = (q - p - 4) / 2; + return; + } + } +} + +static int +addmapseq(seq, k, nr) +char *seq; +int k; +int nr; +{ + int i, j, l, mo, m; + unsigned char *p, *q; + + if (k >= 254) + return -1; + j = findseq_ge(seq, k, &p); + if (j == 0) + { + p[0] = nr >> 8; + p[1] = nr; + return 0; + } + i = p - D_kmaps; + if (D_nseqs + 2 * k + 4 >= D_aseqs) + { + D_kmaps = (unsigned char *)xrealloc((char *)D_kmaps, D_aseqs + 256); + D_aseqs += 256; + p = D_kmaps + i; + } + D_seqp = D_kmaps + 3; + D_seql = 0; + D_seqh = 0; + evdeq(&D_mapev); + if (j > 0) + bcopy((char *)p, (char *)p + 2 * k + 4, D_nseqs - i); + p[0] = nr >> 8; + p[1] = nr; + p[2] = k; + bcopy(seq, (char *)p + 3, k); + bzero(p + k + 3, k + 1); + D_nseqs += 2 * k + 4; + if (j > 0) + { + q = p + 2 * k + 4; + l = q[2]; + for (i = 0; i < k; i++) + { + if (p[3 + i] != q[3 + i]) + { + p[k + 4 + i] = k; + break; + } + setseqoff(p, i, q[l + 4 + i] ? q[l + 4 + i] + k + 2: 0); + } + } + for (q = D_kmaps; q < p; q += 2 * l + 4) + { + l = q[2]; + for (m = j = 0; j < l; j++) + { + mo = m; + if (!m && q[3 + j] != seq[j]) + m = 1; + if (q[l + 4 + j] == 0) + { + if (!mo && m) + setseqoff(q, j, (p - q - 4) / 2); + } + else if (q + q[l + 4 + j] * 2 + 4 > p || (q + q[l + 4 + j] * 2 + 4 == p && !m)) + setseqoff(q, j, q[l + 4 + j] + k + 2); + } + } +#ifdef DEBUGG + dumpmap(); +#endif + return 0; +} + +static int +remmapseq(seq, k) +char *seq; +int k; +{ + int j, l; + unsigned char *p, *q; + + if (k >= 254 || (j = findseq_ge(seq, k, &p)) != 0) + return -1; + for (q = D_kmaps; q < p; q += 2 * l + 4) + { + l = q[2]; + for (j = 0; j < l; j++) + { + if (q + q[l + 4 + j] * 2 + 4 == p) + setseqoff(q, j, p[k + 4 + j] ? q[l + 4 + j] + p[k + 4 + j] - k : 0); + else if (q + q[l + 4 + j] * 2 + 4 > p) + q[l + 4 + j] -= k + 2; + } + } + if (D_kmaps + D_nseqs > p + 2 * k + 4) + bcopy((char *)p + 2 * k + 4, (char *)p, (D_kmaps + D_nseqs) - (p + 2 * k + 4)); + D_nseqs -= 2 * k + 4; + D_seqp = D_kmaps + 3; + D_seql = 0; + D_seqh = 0; + evdeq(&D_mapev); +#ifdef DEBUGG + dumpmap(); +#endif + return 0; +} + +#ifdef DEBUGG +static void +dumpmap() +{ + unsigned char *p; + int j, n, l, o, oo; + debug("Mappings:\n"); + p = D_kmaps; + if (!p) + return; + while (p < D_kmaps + D_nseqs) + { + l = p[2]; + debug1("%d: ", p - D_kmaps + 3); + for (j = 0; j < l; j++) + { + o = oo = p[l + 4 + j]; + if (o) + o = 2 * o + 4 + (p + 3 + j - D_kmaps); + if (p[j + 3] > ' ' && p[j + 3] < 0177) + { + debug3("%c[%d:%d] ", p[j + 3], oo, o); + } + else + debug3("\\%03o[%d:%d] ", p[j + 3], oo, o); + } + n = p[0] << 8 | p[1]; + debug2(" ==> %d%s\n", n & ~KMAP_NOTIMEOUT, (n & KMAP_NOTIMEOUT) ? " (no timeout)" : ""); + p += 2 * l + 4; + } +} +#endif /* DEBUGG */ + +#endif /* MAPKEYS */ + +/* + * Appends to the static variable Termcap + */ +static void +AddCap(s) +char *s; +{ + register int n; + + if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < TERMCAP_BUFSIZE - 4 - 1) + { + strcpy(Termcap + Termcaplen, "\\\n\t:"); + Termcaplen += 4; + tcLineLen = 0; + } + if (Termcaplen + n < TERMCAP_BUFSIZE - 1) + { + strcpy(Termcap + Termcaplen, s); + Termcaplen += n; + tcLineLen += n; + } + else + Panic(0, "TERMCAP overflow - sorry."); +} + +/* + * Reads a displays capabilities and reconstructs a termcap entry in the + * global buffer "Termcap". A pointer to this buffer is returned. + */ +char * +MakeTermcap(aflag) +int aflag; +{ + char buf[TERMCAP_BUFSIZE]; + register char *p, *cp, *s, ch, *tname; + int i, wi, he; +#if 0 + int found; +#endif + + if (display) + { + wi = D_width; + he = D_height; + tname = D_termname; + } + else + { + wi = 80; + he = 24; + tname = "vt100"; + } + debug1("MakeTermcap(%d)\n", aflag); + if ((s = getenv("SCREENCAP")) && strlen(s) < TERMCAP_BUFSIZE) + { + sprintf(Termcap, "TERMCAP=%s", s); + strcpy(Term, "TERM=screen"); + debug("getenvSCREENCAP o.k.\n"); + return Termcap; + } + Termcaplen = 0; + debug1("MakeTermcap screenterm='%s'\n", screenterm); + debug1("MakeTermcap termname='%s'\n", tname); + if (*screenterm == '\0' || strlen(screenterm) > MAXSTR - 3) + { + debug("MakeTermcap sets screenterm=screen\n"); + strncpy(screenterm, "screen", MAXTERMLEN); + screenterm[MAXTERMLEN] = '\0'; + } +#if 0 + found = 1; +#endif + do + { + strcpy(Term, "TERM="); + p = Term + 5; + if (!aflag && strlen(screenterm) + strlen(tname) < MAXSTR-1) + { + sprintf(p, "%s.%s", screenterm, tname); + if (e_tgetent(buf, p) == 1) + break; + } +#ifdef COLOR + if (nwin_default.bce) + { + sprintf(p, "%s-bce", screenterm); + if (e_tgetent(buf, p) == 1) + break; + } +#endif +#ifdef CHECK_SCREEN_W + if (wi >= 132) + { + sprintf(p, "%s-w", screenterm); + if (e_tgetent(buf, p) == 1) + break; + } +#endif + strcpy(p, screenterm); + if (e_tgetent(buf, p) == 1) + break; + strcpy(p, "vt100"); +#if 0 + found = 0; +#endif + } + while (0); /* Goto free programming... */ + +#if 0 +#ifndef TERMINFO + /* check for compatibility problems, displays == 0 after fork */ + if (found) + { + char xbuf[TERMCAP_BUFSIZE], *xbp = xbuf; + if (tgetstr("im", &xbp) && tgetstr("ic", &xbp) && displays) + { + Msg(0, "Warning: im and ic set in %s termcap entry", p); + } + } +#endif +#endif + + tcLineLen = 100; /* Force NL */ + if (strlen(Term) > TERMCAP_BUFSIZE - 40) + strcpy(Term, "too_long"); + sprintf(Termcap, "TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal:", Term + 5); + Termcaplen = strlen(Termcap); + debug1("MakeTermcap decided '%s'\n", p); + if (extra_outcap && *extra_outcap) + { + for (cp = extra_outcap; (p = index(cp, ':')); cp = p) + { + ch = *++p; + *p = '\0'; + AddCap(cp); + *p = ch; + } + tcLineLen = 100; /* Force NL */ + } + debug1("MakeTermcap after outcap '%s'\n", (char *)TermcapConst); + if (Termcaplen + strlen(TermcapConst) < TERMCAP_BUFSIZE) + { + strcpy(Termcap + Termcaplen, (char *)TermcapConst); + Termcaplen += strlen(TermcapConst); + } + sprintf(buf, "li#%d:co#%d:", he, wi); + AddCap(buf); + AddCap("am:"); + if (aflag || (force_vt && !D_COP) || D_CLP || !D_AM) + { + AddCap("xn:"); + AddCap("xv:"); + AddCap("LP:"); + } + if (aflag || (D_CS && D_SR) || D_AL || D_CAL) + { + AddCap("sr=\\EM:"); + AddCap("al=\\E[L:"); + AddCap("AL=\\E[%dL:"); + } + else if (D_SR) + AddCap("sr=\\EM:"); + if (aflag || D_CS) + AddCap("cs=\\E[%i%d;%dr:"); + if (aflag || D_CS || D_DL || D_CDL) + { + AddCap("dl=\\E[M:"); + AddCap("DL=\\E[%dM:"); + } + if (aflag || D_DC || D_CDC) + { + AddCap("dc=\\E[P:"); + AddCap("DC=\\E[%dP:"); + } + if (aflag || D_CIC || D_IC || D_IM) + { + AddCap("im=\\E[4h:"); + AddCap("ei=\\E[4l:"); + AddCap("mi:"); + AddCap("IC=\\E[%d@:"); + } +#ifdef MAPKEYS + AddCap("ks=\\E[?1h\\E=:"); + AddCap("ke=\\E[?1l\\E>:"); +#endif + AddCap("vi=\\E[?25l:"); + AddCap("ve=\\E[34h\\E[?25h:"); + AddCap("vs=\\E[34l:"); + AddCap("ti=\\E[?1049h:"); + AddCap("te=\\E[?1049l:"); + if (display) + { + if (D_US) + { + AddCap("us=\\E[4m:"); + AddCap("ue=\\E[24m:"); + } + if (D_SO) + { + AddCap("so=\\E[3m:"); + AddCap("se=\\E[23m:"); + } + if (D_MB) + AddCap("mb=\\E[5m:"); + if (D_MD) + AddCap("md=\\E[1m:"); + if (D_MH) + AddCap("mh=\\E[2m:"); + if (D_MR) + AddCap("mr=\\E[7m:"); + if (D_MB || D_MD || D_MH || D_MR) + AddCap("me=\\E[m:ms:"); + if (D_hascolor) + AddCap("Co#8:pa#64:AF=\\E[3%dm:AB=\\E[4%dm:op=\\E[39;49m:AX:"); + if (D_VB) + AddCap("vb=\\Eg:"); +#ifndef MAPKEYS + if (D_KS) + { + AddCap("ks=\\E=:"); + AddCap("ke=\\E>:"); + } + if (D_CCS) + { + AddCap("CS=\\E[?1h:"); + AddCap("CE=\\E[?1l:"); + } +#endif + if (D_CG0) + AddCap("G0:"); + if (D_CC0 || (D_CS0 && *D_CS0)) + { + AddCap("as=\\E(0:"); + AddCap("ae=\\E(B:"); + /* avoid `` because some shells dump core... */ + AddCap("ac=\\140\\140aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~..--++,,hhII00:"); + } + if (D_PO) + { + AddCap("po=\\E[5i:"); + AddCap("pf=\\E[4i:"); + } + if (D_CZ0) + { + AddCap("Z0=\\E[?3h:"); + AddCap("Z1=\\E[?3l:"); + } + if (D_CWS) + AddCap("WS=\\E[8;%d;%dt:"); + } + for (i = T_CAPS; i < T_ECAPS; i++) + { +#ifdef MAPKEYS + struct action *act; + if (i < T_OCAPS) + { + if (i >= T_KEYPAD) /* don't put keypad codes in TERMCAP */ + continue; /* - makes it too big */ + if (i >= T_CURSOR && i < T_OCAPS) + { + act = &umtab[i - (T_CURSOR - T_OCAPS + T_CAPS)]; + if (act->nr == RC_ILLEGAL) + act = &dmtab[i - (T_CURSOR - T_OCAPS + T_CAPS)]; + } + else + { + act = &umtab[i - T_CAPS]; + if (act->nr == RC_ILLEGAL) + act = &dmtab[i - T_CAPS]; + } + if (act->nr == RC_ILLEGAL && (i == T_NAVIGATE + 1 || i == T_NAVIGATE + 3)) + { + /* kh -> @1, kH -> @7 */ + act = &umtab[i - T_CAPS - 1]; + if (act->nr == RC_ILLEGAL) + act = &dmtab[i - T_CAPS - 1]; + } + if (act->nr != RC_ILLEGAL) + { + if (act->nr == RC_STUFF) + { + MakeString(term[i].tcname, buf, sizeof(buf), act->args[0]); + AddCap(buf); + } + continue; + } + } +#endif + if (display == 0) + continue; + switch(term[i].type) + { + case T_STR: + if (D_tcs[i].str == 0) + break; + MakeString(term[i].tcname, buf, sizeof(buf), D_tcs[i].str); + AddCap(buf); + break; + case T_FLG: + if (D_tcs[i].flg == 0) + break; + sprintf(buf, "%s:", term[i].tcname); + AddCap(buf); + break; + default: + break; + } + } + debug("MakeTermcap: end\n"); + return Termcap; +} + +static void +MakeString(cap, buf, buflen, s) +char *cap, *buf; +int buflen; +char *s; +{ + register char *p, *pmax; + register unsigned int c; + + p = buf; + pmax = p + buflen - (3+4+2); + *p++ = *cap++; + *p++ = *cap; + *p++ = '='; + while ((c = *s++) && (p < pmax)) + { + switch (c) + { + case '\033': + *p++ = '\\'; + *p++ = 'E'; + break; + case ':': + strcpy(p, "\\072"); + p += 4; + break; + case '^': + case '\\': + *p++ = '\\'; + *p++ = c; + break; + default: + if (c >= 200) + { + sprintf(p, "\\%03o", c & 0377); + p += 4; + } + else if (c < ' ') + { + *p++ = '^'; + *p++ = c + '@'; + } + else + *p++ = c; + } + } + *p++ = ':'; + *p = '\0'; +} + + +#undef QUOTES +#define QUOTES(p) \ + (*p == '\\' && (p[1] == '\\' || p[1] == ',' || p[1] == '%')) + +#ifdef FONT +int +CreateTransTable(s) +char *s; +{ + int curchar; + char *templ, *arg; + int templlen; + int templnsub; + char *p, *sx; + char **ctable; + int l, c; + + if ((D_xtable = (char ***)calloc(256, sizeof(char **))) == 0) + { + Msg(0, "%s", strnomem); + return -1; + } + + while (*s) + { + if (QUOTES(s)) + s++; + curchar = (unsigned char)*s++; + if (curchar == 'B') + curchar = 0; /* ASCII */ + templ = s; + templlen = 0; + templnsub = 0; + if (D_xtable[curchar] == 0) + { + if ((D_xtable[curchar] = (char **)calloc(257, sizeof(char *))) == 0) + { + Msg(0, "%s", strnomem); + FreeTransTable(); + return -1; + } + } + ctable = D_xtable[curchar]; + for(; *s && *s != ','; s++) + { + if (QUOTES(s)) + s++; + else if (*s == '%') + { + templnsub++; + continue; + } + templlen++; + } + if (*s++ == 0) + break; + while (*s && *s != ',') + { + c = (unsigned char)*s++; + if (QUOTES((s - 1))) + c = (unsigned char)*s++; + else if (c == '%') + c = 256; + if (ctable[c]) + free(ctable[c]); + arg = s; + l = copyarg(&s, (char *)0); + if (c != 256) + l = l * templnsub + templlen; + if ((ctable[c] = (char *)malloc(l + 1)) == 0) + { + Msg(0, "%s", strnomem); + FreeTransTable(); + return -1; + } + sx = ctable[c]; + for (p = ((c == 256) ? "%" : templ); *p && *p != ','; p++) + { + if (QUOTES(p)) + p++; + else if (*p == '%') + { + s = arg; + sx += copyarg(&s, sx); + continue; + } + *sx++ = *p; + } + *sx = 0; + ASSERT(ctable[c] + l * templnsub + templlen == sx); + debug3("XC: %c %c->%s\n", curchar, c, ctable[c]); + } + if (*s == ',') + s++; + } + return 0; +} + +void +FreeTransTable() +{ + char ***p, **q; + int i, j; + + if ((p = D_xtable) == 0) + return; + for (i = 0; i < 256; i++, p++) + { + if (*p == 0) + continue; + q = *p; + for (j = 0; j < 257; j++, q++) + if (*q) + free(*q); + free(*p); + } + free(D_xtable); + D_xtable = NULL; +} +#endif /* FONT */ + +static int +copyarg(pp, s) +char **pp, *s; +{ + int l; + char *p; + + for (l = 0, p = *pp; *p && *p != ','; p++) + { + if (QUOTES(p)) + p++; + if (s) + *s++ = *p; + l++; + } + if (*p == ',') + p++; + *pp = p; + return l; +} + + +/* +** +** Termcap routines that use our extra_incap +** +*/ + +static int +e_tgetent(bp, name) +char *bp, *name; +{ + int r; + +#ifdef USE_SETEUID + xseteuid(real_uid); + xsetegid(real_gid); +#endif + r = tgetent(bp, name); +#ifdef USE_SETEUID + xseteuid(eff_uid); + xsetegid(eff_gid); +#endif + return r; +} + + +/* findcap: + * cap = capability we are looking for + * tepp = pointer to bufferpointer + * n = size of buffer (0 = infinity) + */ + +static char * +findcap(cap, tepp, n) +char *cap; +char **tepp; +int n; +{ + char *tep; + char c, *p, *cp; + int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */ + int num = 0, capl; + + if (!extra_incap) + return 0; + tep = *tepp; + capl = strlen(cap); + cp = 0; + mode = 0; + for (p = extra_incap; *p; ) + { + if (strncmp(p, cap, capl) == 0) + { + p += capl; + c = *p; + if (c && c != ':' && c != '@') + p++; + if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#') + cp = tep; + } + while ((c = *p)) + { + p++; + if (mode == 0) + { + if (c == ':') + break; + if (c == '^') + mode = 1; + if (c == '\\') + mode = 2; + } + else if (mode == 1) + { + mode = 0; + c = c & 0x1f; + } + else if (mode == 2) + { + mode = 0; + switch(c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + mode = 3; + num = 0; + break; + case 'E': + c = 27; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + } + } + if (mode > 2) + { + num = num * 8 + (c - '0'); + if (mode++ == 5 || (*p < '0' || *p > '9')) + { + c = num; + mode = 0; + } + } + if (mode) + continue; + + if (cp && n != 1) + { + *cp++ = c; + n--; + } + } + if (cp) + { + *cp++ = 0; + *tepp = cp; + debug2("'%s' found in extra_incap -> %s\n", cap, tep); + return tep; + } + } + return 0; +} + +static char * +e_tgetstr(cap, tepp) +char *cap; +char **tepp; +{ + char *tep; + if ((tep = findcap(cap, tepp, 0))) + return (*tep == '@') ? 0 : tep; + return tgetstr(cap, tepp); +} + +static int +e_tgetflag(cap) +char *cap; +{ + char buf[2], *bufp; + char *tep; + bufp = buf; + if ((tep = findcap(cap, &bufp, 2))) + return (*tep == '@') ? 0 : 1; + return tgetflag(cap) > 0; +} + +static int +e_tgetnum(cap) +char *cap; +{ + char buf[20], *bufp; + char *tep, c; + int res, base = 10; + + bufp = buf; + if ((tep = findcap(cap, &bufp, 20))) + { + c = *tep; + if (c == '@') + return -1; + if (c == '0') + base = 8; + res = 0; + while ((c = *tep++) >= '0' && c <= '9') + res = res * base + (c - '0'); + return res; + } + return tgetnum(cap); +} + |