aboutsummaryrefslogtreecommitdiff
path: root/ncurses/tinfo/captoinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'ncurses/tinfo/captoinfo.c')
-rw-r--r--ncurses/tinfo/captoinfo.c240
1 files changed, 189 insertions, 51 deletions
diff --git a/ncurses/tinfo/captoinfo.c b/ncurses/tinfo/captoinfo.c
index e02e622b0de3..a9eb1e53454d 100644
--- a/ncurses/tinfo/captoinfo.c
+++ b/ncurses/tinfo/captoinfo.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2018,2019 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
@@ -33,12 +33,16 @@
****************************************************************************/
/*
- * captoinfo.c --- conversion between termcap and terminfo formats
+ * captoinfo.c
+ *
+ * Provide conversion in both directions between termcap and terminfo.
+ *
+ * cap-to-info --- conversion between termcap and terminfo formats
*
* The captoinfo() code was swiped from Ross Ridge's mytinfo package,
* adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
*
- * There is just one entry point:
+ * It has just one entry point:
*
* char *_nc_captoinfo(n, s, parameterized)
*
@@ -93,7 +97,13 @@
#include <ctype.h>
#include <tic.h>
-MODULE_ID("$Id: captoinfo.c,v 1.77 2012/12/30 00:50:40 tom Exp $")
+MODULE_ID("$Id: captoinfo.c,v 1.97 2019/10/15 23:13:35 tom Exp $")
+
+#if 0
+#define DEBUG_THIS(p) DEBUG(9, p)
+#else
+#define DEBUG_THIS(p) /* nothing */
+#endif
#define MAX_PUSHED 16 /* max # args we can push onto the stack */
@@ -181,7 +191,7 @@ cvtchar(register const char *sp)
case '$':
case '\\':
case '%':
- c = (unsigned char) (*sp);
+ c = UChar(*sp);
len = 2;
break;
case '\0':
@@ -194,29 +204,33 @@ cvtchar(register const char *sp)
case '3':
len = 1;
while (isdigit(UChar(*sp))) {
- c = (unsigned char) (8 * c + (*sp++ - '0'));
+ c = UChar(8 * c + (*sp++ - '0'));
len++;
}
break;
default:
- c = (unsigned char) (*sp);
- len = 2;
+ c = UChar(*sp);
+ len = (c != '\0') ? 2 : 1;
break;
}
break;
case '^':
- c = (unsigned char) (*++sp & 0x1f);
+ c = UChar(*++sp);
+ if (c == '?')
+ c = 127;
+ else
+ c &= 0x1f;
len = 2;
break;
default:
- c = (unsigned char) (*sp);
- len = 1;
+ c = UChar(*sp);
+ len = (c != '\0') ? 1 : 0;
}
if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
dp = save_string(dp, "%\'");
dp = save_char(dp, c);
dp = save_char(dp, '\'');
- } else {
+ } else if (c != '\0') {
dp = save_string(dp, "%{");
if (c > 99)
dp = save_char(dp, c / 100 + '0');
@@ -232,6 +246,8 @@ static void
getparm(int parm, int n)
/* push n copies of param on the terminfo stack if not already there */
{
+ int nn;
+
if (seenr) {
if (parm == 1)
parm = 2;
@@ -239,7 +255,7 @@ getparm(int parm, int n)
parm = 1;
}
- while (n--) {
+ for (nn = 0; nn < n; ++nn) {
dp = save_string(dp, "%p");
dp = save_char(dp, '0' + parm);
}
@@ -248,7 +264,7 @@ getparm(int parm, int n)
if (n > 1) {
_nc_warning("string may not be optimal");
dp = save_string(dp, "%Pa");
- while (n--) {
+ while (n-- > 0) {
dp = save_string(dp, "%ga");
}
}
@@ -288,6 +304,8 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
seenr = 0;
param = 1;
+ DEBUG_THIS(("_nc_captoinfo params %d, %s", parameterized, s));
+
dp = init_string();
/* skip the initial padding (if we haven't been told not to) */
@@ -295,7 +313,7 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
if (s == 0)
s = "";
if (parameterized >= 0 && isdigit(UChar(*s)))
- for (capstart = s;; s++)
+ for (capstart = s; *s != '\0'; s++)
if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.'))
break;
@@ -309,7 +327,7 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
}
switch (*s++) {
case '%':
- dp = save_char(dp, '%');
+ dp = save_string(dp, "%%");
break;
case 'r':
if (seenr++ == 1) {
@@ -342,13 +360,18 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
dp = save_string(dp, "%{2}%*%-");
break;
case '>':
- getparm(param, 2);
/* %?%{x}%>%t%{y}%+%; */
- dp = save_string(dp, "%?");
- s += cvtchar(s);
- dp = save_string(dp, "%>%t");
- s += cvtchar(s);
- dp = save_string(dp, "%+%;");
+ if (s[0] && s[1]) {
+ getparm(param, 2);
+ dp = save_string(dp, "%?");
+ s += cvtchar(s);
+ dp = save_string(dp, "%>%t");
+ s += cvtchar(s);
+ dp = save_string(dp, "%+%;");
+ } else {
+ _nc_warning("expected two characters after %%>");
+ dp = save_string(dp, "%>");
+ }
break;
case 'a':
if ((*s == '=' || *s == '+' || *s == '-'
@@ -429,12 +452,17 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
pop();
break;
case '0': /* not clear any of the historical termcaps did this */
- if (*s == '3')
+ if (*s == '3') {
+ ++s;
goto see03;
- else if (*s != '2')
- goto invalid;
- /* FALLTHRU */
+ }
+ if (*s == '2') {
+ ++s;
+ goto see02;
+ }
+ goto invalid;
case '2':
+ see02:
getparm(param, 1);
dp = save_string(dp, "%2d");
pop();
@@ -469,7 +497,8 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
}
break;
default:
- dp = save_char(dp, *s++);
+ if (*s != '\0')
+ dp = save_char(dp, *s++);
break;
}
}
@@ -480,7 +509,7 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
*/
if (capstart) {
dp = save_string(dp, "$<");
- for (s = capstart;; s++)
+ for (s = capstart; *s != '\0'; s++)
if (isdigit(UChar(*s)) || *s == '*' || *s == '.')
dp = save_char(dp, *s);
else
@@ -489,6 +518,9 @@ _nc_captoinfo(const char *cap, const char *s, int const parameterized)
}
(void) save_char(dp, '\0');
+
+ DEBUG_THIS(("... _nc_captoinfo %s", NonNull(my_string)));
+
return (my_string);
}
@@ -525,13 +557,13 @@ bcd_expression(const char *str)
static char *
save_tc_char(char *bufptr, int c1)
{
- char temp[80];
-
if (is7bits(c1) && isprint(c1)) {
if (c1 == ':' || c1 == '\\')
bufptr = save_char(bufptr, '\\');
bufptr = save_char(bufptr, c1);
} else {
+ char temp[80];
+
if (c1 == (c1 & 0x1f)) { /* iscntrl() returns T on 255 */
_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
"%.20s", unctrl((chtype) c1));
@@ -554,6 +586,8 @@ save_tc_inequality(char *bufptr, int c1, int c2)
}
/*
+ * info-to-cap --- conversion between terminfo and termcap formats
+ *
* Here are the capabilities infotocap assumes it can translate to:
*
* %% output `%'
@@ -571,6 +605,8 @@ save_tc_inequality(char *bufptr, int c1, int c2)
* %m exclusive-or all parameters with 0177 (not in 4.4BSD)
*/
+#define octal_fixup(n, c) fixups[n].ch = ((fixups[n].ch << 3) | ((c) - '0'))
+
/*
* Convert a terminfo string to termcap format. Parameters are as in
* _nc_captoinfo().
@@ -586,7 +622,15 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
char *bufptr = init_string();
char octal[4];
int len;
+ int digits;
bool syntax_error = FALSE;
+ int myfix = 0;
+ struct {
+ int ch;
+ int offset;
+ } fixups[MAX_TC_FIXUPS];
+
+ DEBUG_THIS(("_nc_infotocap params %d, %s", parameterized, str));
/* we may have to move some trailing mandatory padding up front */
padding = str + strlen(str) - 1;
@@ -603,7 +647,9 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
bufptr = save_char(bufptr, *padding++);
}
- for (; *str && ((trimmed == 0) || (str < trimmed)); str++) {
+ for (; !syntax_error &&
+ *str &&
+ ((trimmed == 0) || (str < trimmed)); str++) {
int c1, c2;
char *cp = 0;
@@ -611,6 +657,14 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
if (str[1] == '\0' || (str + 1) == trimmed) {
bufptr = save_string(bufptr, "\\136");
++str;
+ } else if (str[1] == '?') {
+ /*
+ * Although the 4.3BSD termcap file has an instance of "kb=^?",
+ * that appears to be just cut/paste since neither 4.3BSD nor
+ * 4.4BSD termcap interprets "^?" as DEL.
+ */
+ bufptr = save_string(bufptr, "\\177");
+ ++str;
} else {
bufptr = save_char(bufptr, *str++);
bufptr = save_char(bufptr, *str);
@@ -625,17 +679,20 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
} else if (str[1] == ',') {
bufptr = save_char(bufptr, *++str);
} else {
- int xx1, xx2;
+ int xx1;
bufptr = save_char(bufptr, *str++);
xx1 = *str;
if (_nc_strict_bsd) {
- if (isdigit(UChar(xx1))) {
+
+ if (isoctal(UChar(xx1))) {
int pad = 0;
+ int xx2;
+ int fix = 0;
- if (!isdigit(UChar(str[1])))
+ if (!isoctal(UChar(str[1])))
pad = 2;
- else if (str[1] && !isdigit(UChar(str[2])))
+ else if (str[1] && !isoctal(UChar(str[2])))
pad = 1;
/*
@@ -650,10 +707,31 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
xx2 = '0';
pad = 0; /* FIXME - optionally pad to 3 digits */
}
+ if (myfix < MAX_TC_FIXUPS) {
+ fix = 3 - pad;
+ fixups[myfix].ch = 0;
+ fixups[myfix].offset = (int) (bufptr
+ - my_string
+ - 1);
+ }
while (pad-- > 0) {
bufptr = save_char(bufptr, xx2);
+ if (myfix < MAX_TC_FIXUPS) {
+ fixups[myfix].ch <<= 3;
+ fixups[myfix].ch |= (xx2 - '0');
+ }
xx2 = '0';
}
+ if (myfix < MAX_TC_FIXUPS) {
+ int n;
+ for (n = 0; n < fix; ++n) {
+ fixups[myfix].ch <<= 3;
+ fixups[myfix].ch |= (str[n] - '0');
+ }
+ if (fixups[myfix].ch < 32) {
+ ++myfix;
+ }
+ }
} else if (strchr("E\\nrtbf", xx1) == 0) {
switch (xx1) {
case 'e':
@@ -689,6 +767,24 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
break;
}
}
+ } else {
+ if (myfix < MAX_TC_FIXUPS && isoctal(UChar(xx1))) {
+ bool will_fix = TRUE;
+ int n;
+
+ fixups[myfix].ch = 0;
+ fixups[myfix].offset = (int) (bufptr - my_string - 1);
+ for (n = 0; n < 3; ++n) {
+ if (isoctal(str[n])) {
+ octal_fixup(myfix, str[n]);
+ } else {
+ will_fix = FALSE;
+ break;
+ }
+ }
+ if (will_fix && (fixups[myfix].ch < 32))
+ ++myfix;
+ }
}
bufptr = save_char(bufptr, xx1);
}
@@ -735,8 +831,9 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
} else if ((len = bcd_expression(str)) != 0) {
str += len;
bufptr = save_string(bufptr, "%B");
- } else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
- || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
+ } else if ((sscanf(str, "%%{%d}%%+%%%c", &c1, &ch2) == 2
+ || sscanf(str, "%%'%c'%%+%%%c", &ch1, &ch2) == 2)
+ && ch2 == 'c'
&& (cp = strchr(str, '+'))) {
str = cp + 2;
bufptr = save_string(bufptr, "%+");
@@ -779,26 +876,46 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
bufptr = save_char(bufptr, '%');
ch1 = 0;
ch2 = 0;
+ digits = 0;
while (isdigit(UChar(*str))) {
+ if (++digits > 2) {
+ syntax_error = TRUE;
+ break;
+ }
ch2 = ch1;
ch1 = *str++;
- if (_nc_strict_bsd) {
- if (ch1 > '3')
- return 0;
+ if (digits == 2 && ch2 != '0') {
+ syntax_error = TRUE;
+ break;
+ } else if (_nc_strict_bsd) {
+ if (ch1 > '3') {
+ syntax_error = TRUE;
+ break;
+ }
} else {
bufptr = save_char(bufptr, ch1);
}
}
+ if (syntax_error)
+ break;
+ /*
+ * Convert %02 to %2 and %03 to %3
+ */
+ if (ch2 == '0' && !_nc_strict_bsd) {
+ ch2 = 0;
+ bufptr[-2] = bufptr[-1];
+ *--bufptr = 0;
+ }
if (_nc_strict_bsd) {
- if (ch2 != 0 && ch2 != '0')
- return 0;
- if (ch1 < '2')
+ if (ch2 != 0 && ch2 != '0') {
+ syntax_error = TRUE;
+ } else if (ch1 < '2') {
ch1 = 'd';
+ }
bufptr = save_char(bufptr, ch1);
}
- if (strchr("doxX.", *str)) {
- if (*str != 'd') /* termcap doesn't have octal, hex */
- return 0;
+ if (strchr("oxX.", *str)) {
+ syntax_error = TRUE; /* termcap doesn't have octal, hex */
}
break;
@@ -816,9 +933,11 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
* termcap notation.
*/
case 's':
- if (_nc_strict_bsd)
- return 0;
- bufptr = save_string(bufptr, "%s");
+ if (_nc_strict_bsd) {
+ syntax_error = TRUE;
+ } else {
+ bufptr = save_string(bufptr, "%s");
+ }
break;
case 'p':
@@ -830,8 +949,9 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
bufptr = save_string(bufptr, "%r");
seentwo++;
}
- } else if (*str >= '3')
- return (0);
+ } else if (*str >= '3') {
+ syntax_error = TRUE;
+ }
break;
case 'i':
@@ -855,6 +975,24 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz
} /* endwhile (*str) */
+ if (!syntax_error &&
+ myfix > 0 &&
+ ((int) strlen(my_string) - (4 * myfix)) < MIN_TC_FIXUPS) {
+ while (--myfix >= 0) {
+ char *p = fixups[myfix].offset + my_string;
+ *p++ = '^';
+ *p++ = (char) (fixups[myfix].ch | '@');
+ while ((p[0] = p[2]) != '\0') {
+ ++p;
+ }
+ }
+ }
+
+ DEBUG_THIS(("... _nc_infotocap %s",
+ syntax_error
+ ? "<ERR>"
+ : _nc_visbuf(my_string)));
+
return (syntax_error ? NULL : my_string);
}