/****************************************************************************
- * Copyright (c) 1998 Free Software Foundation, Inc. *
+ * Copyright 2018-2019,2020 Thomas E. Dickey *
+ * Copyright 1998-2016,2017 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 *
/****************************************************************************
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
* and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996-on *
****************************************************************************/
-
-
/*
- * 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 *captoinfo(n, s, parametrized)
+ * char *_nc_captoinfo(n, s, parameterized)
*
* Convert value s for termcap string capability named n into terminfo
* format.
#include <ctype.h>
#include <tic.h>
-MODULE_ID("$Id: captoinfo.c,v 1.24 1999/07/24 20:06:13 tom Exp $")
+MODULE_ID("$Id: captoinfo.c,v 1.100 2020/07/08 21:39:54 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 */
-#define MAX_ENTRY 2048 /* maximum chars in a translated capability */
static int stack[MAX_PUSHED]; /* the stack */
static int stackptr; /* the next empty place on the stack */
static int param; /* current parameter */
static char *dp; /* pointer to end of the converted string */
-static char *my_string;
+static char *my_string;
static size_t my_length;
-static char *init_string(void)
+static char *
+init_string(void)
/* initialize 'my_string', 'my_length' */
{
- if (my_string == 0)
- my_string = typeMalloc(char, my_length = 256);
- if (my_string == 0)
- _nc_err_abort("Out of memory");
+ if (my_string == 0)
+ TYPE_MALLOC(char, my_length = 256, my_string);
- *my_string = '\0';
- return my_string;
+ *my_string = '\0';
+ return my_string;
}
-static char *save_string(char *d, const char *const s)
+static char *
+save_string(char *d, const char *const s)
{
- size_t have = (d - my_string);
- size_t need = have + strlen(s) + 2;
- if (need > my_length) {
- my_string = (char *)realloc(my_string, my_length = (need + need));
- if (my_string == 0)
- _nc_err_abort("Out of memory");
- d = my_string + have;
- }
- (void) strcpy(d, s);
- return d + strlen(d);
+ size_t have = (size_t) (d - my_string);
+ size_t need = have + strlen(s) + 2;
+ if (need > my_length) {
+ my_string = (char *) _nc_doalloc(my_string, my_length = (need + need));
+ if (my_string == 0)
+ _nc_err_abort(MSG_NO_MEMORY);
+ d = my_string + have;
+ }
+ _nc_STRCPY(d, s, my_length - have);
+ return d + strlen(d);
}
-static inline char *save_char(char *s, char c)
+static NCURSES_INLINE char *
+save_char(char *s, int c)
{
- static char temp[2];
- temp[0] = c;
- return save_string(s, temp);
+ static char temp[2];
+ temp[0] = (char) c;
+ return save_string(s, temp);
}
-static void push(void)
+static void
+push(void)
/* push onstack on to the stack */
{
- if (stackptr > MAX_PUSHED)
+ if (stackptr >= MAX_PUSHED)
_nc_warning("string too complex to convert");
else
stack[stackptr++] = onstack;
}
-static void pop(void)
+static void
+pop(void)
/* pop the top of the stack into onstack */
{
if (stackptr == 0) {
_nc_warning("I'm confused");
else
onstack = 0;
- }
- else
+ } else
onstack = stack[--stackptr];
param++;
}
-static int cvtchar(register const char *sp)
+static int
+cvtchar(register const char *sp)
/* convert a character to a terminfo push */
{
unsigned char c = 0;
int len;
- switch(*sp) {
+ switch (*sp) {
case '\\':
- switch(*++sp) {
+ switch (*++sp) {
case '\'':
case '$':
case '\\':
case '%':
- c = *sp;
+ c = UChar(*sp);
len = 2;
break;
case '\0':
case '2':
case '3':
len = 1;
- while (isdigit(*sp))
- {
- c = 8 * c + (*sp++ - '0');
+ while (isdigit(UChar(*sp))) {
+ c = UChar(8 * c + (*sp++ - '0'));
len++;
}
break;
default:
- c = *sp;
- len = 2;
+ c = UChar(*sp);
+ len = (c != '\0') ? 2 : 1;
break;
}
break;
case '^':
- c = (*++sp & 0x1f);
len = 2;
+ c = UChar(*++sp);
+ if (c == '?') {
+ c = 127;
+ } else if (c == '\0') {
+ len = 1;
+ } else {
+ c &= 0x1f;
+ }
break;
default:
- c = *sp;
- len = 1;
+ c = UChar(*sp);
+ len = (c != '\0') ? 1 : 0;
}
if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
- *dp++ = '%'; *dp++ = '\''; *dp++ = c; *dp++ = '\'';
- } else {
- *dp++ = '%'; *dp++ = '{';
+ dp = save_string(dp, "%\'");
+ dp = save_char(dp, c);
+ dp = save_char(dp, '\'');
+ } else if (c != '\0') {
+ dp = save_string(dp, "%{");
if (c > 99)
- *dp++ = c / 100 + '0';
+ dp = save_char(dp, c / 100 + '0');
if (c > 9)
- *dp++ = ((int)(c / 10)) % 10 + '0';
- *dp++ = c % 10 + '0';
- *dp++ = '}';
+ dp = save_char(dp, ((int) (c / 10)) % 10 + '0');
+ dp = save_char(dp, c % 10 + '0');
+ dp = save_char(dp, '}');
}
return len;
}
-static void getparm(int parm, int n)
+static void
+getparm(int parm, int n)
/* push n copies of param on the terminfo stack if not already there */
{
- if (seenr) {
- if (parm == 1)
- parm = 2;
- else if (parm == 2)
- parm = 1;
- }
- if (onstack == parm) {
- if (n > 1) {
- _nc_warning("string may not be optimal");
- *dp++ = '%'; *dp++ = 'P'; *dp++ = 'a';
- while(n--) {
- *dp++ = '%'; *dp++ = 'g'; *dp++ = 'a';
- }
- }
- return;
- }
- if (onstack != 0)
- push();
+ int nn;
- onstack = parm;
+ if (seenr) {
+ if (parm == 1)
+ parm = 2;
+ else if (parm == 2)
+ parm = 1;
+ }
- while(n--) { /* %p0 */
- *dp++ = '%'; *dp++ = 'p'; *dp++ = '0' + parm;
- }
+ for (nn = 0; nn < n; ++nn) {
+ dp = save_string(dp, "%p");
+ dp = save_char(dp, '0' + parm);
+ }
- if (seenn && parm < 3) { /* %{96}%^ */
- *dp++ = '%'; *dp++ = '{'; *dp++ = '9'; *dp++ = '6'; *dp++ = '}';
- *dp++ = '%'; *dp++ = '^';
+ if (onstack == parm) {
+ if (n > 1) {
+ _nc_warning("string may not be optimal");
+ dp = save_string(dp, "%Pa");
+ while (n-- > 0) {
+ dp = save_string(dp, "%ga");
+ }
}
+ return;
+ }
+ if (onstack != 0)
+ push();
- if (seenm && parm < 3) { /* %{127}%^ */
- *dp++ = '%'; *dp++ = '{'; *dp++ = '1'; *dp++ = '2'; *dp++ = '7';
- *dp++ = '}'; *dp++ = '%'; *dp++ = '^';
- }
+ onstack = parm;
+
+ if (seenn && parm < 3) {
+ dp = save_string(dp, "%{96}%^");
+ }
+
+ if (seenm && parm < 3) {
+ dp = save_string(dp, "%{127}%^");
+ }
}
-char *_nc_captoinfo(
-/* convert a termcap string to terminfo format */
-register const char *cap, /* relevant terminfo capability index */
-register const char *s, /* string value of the capability */
-int const parametrized) /* do % translations if 1, pad translations if >=0 */
+/*
+ * Convert a termcap string to terminfo format.
+ * 'cap' is the relevant terminfo capability index.
+ * 's' is the string value of the capability.
+ * 'parameterized' tells what type of translations to do:
+ * % translations if 1
+ * pad translations if >=0
+ */
+NCURSES_EXPORT(char *)
+_nc_captoinfo(const char *cap, const char *s, int const parameterized)
{
- static char line[MAX_ENTRY];
const char *capstart;
stackptr = 0;
seenr = 0;
param = 1;
- dp = line;
+ DEBUG_THIS(("_nc_captoinfo params %d, %s", parameterized, s));
+
+ dp = init_string();
/* skip the initial padding (if we haven't been told not to) */
capstart = 0;
if (s == 0)
s = "";
- if (parametrized >= 0 && isdigit(*s))
- for (capstart = s; ; s++)
- if (!(isdigit(*s) || *s == '*' || *s == '.'))
+ if (parameterized >= 0 && isdigit(UChar(*s)))
+ for (capstart = s; *s != '\0'; s++)
+ if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.'))
break;
- while(*s != '\0') {
- switch(*s) {
+ while (*s != '\0') {
+ switch (*s) {
case '%':
s++;
- if (parametrized < 1) {
- *dp++ = '%';
+ if (parameterized < 1) {
+ dp = save_char(dp, '%');
break;
}
- switch(*s++) {
- case '%': *dp++ = '%'; break;
+ switch (*s++) {
+ case '%':
+ dp = save_string(dp, "%%");
+ break;
case 'r':
if (seenr++ == 1) {
_nc_warning("saw %%r twice in %s", cap);
_nc_warning("saw %%n twice in %s", cap);
}
break;
- case 'i': *dp++ = '%'; *dp++ = 'i'; break;
+ case 'i':
+ dp = save_string(dp, "%i");
+ break;
case '6':
case 'B':
- getparm(param, 2);
- /* %{6}%*%+ */
- *dp++ = '%'; *dp++ = '{'; *dp++ = '6';
- *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
- *dp++ = '%'; *dp++ = '+';
+ getparm(param, 1);
+ dp = save_string(dp, "%{10}%/%{16}%*");
+ getparm(param, 1);
+ dp = save_string(dp, "%{10}%m%+");
break;
case '8':
case 'D':
getparm(param, 2);
- /* %{2}%*%- */
- *dp++ = '%'; *dp++ = '{'; *dp++ = '2';
- *dp++ = '}'; *dp++ = '%'; *dp++ = '*';
- *dp++ = '%'; *dp++ = '-';
+ dp = save_string(dp, "%{2}%*%-");
break;
case '>':
- getparm(param, 2);
/* %?%{x}%>%t%{y}%+%; */
- *dp++ = '%'; *dp++ = '?';
- s += cvtchar(s);
- *dp++ = '%'; *dp++ = '>';
- *dp++ = '%'; *dp++ = 't';
- s += cvtchar(s);
- *dp++ = '%'; *dp++ = '+';
- *dp++ = '%'; *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 == '-'
l++;
} else
l += cvtchar(s + 2);
- switch(*s) {
+ switch (*s) {
case '+':
- *dp++ = '%'; *dp++ = '+';
+ dp = save_string(dp, "%+");
break;
case '-':
- *dp++ = '%'; *dp++ = '-';
+ dp = save_string(dp, "%-");
break;
case '*':
- *dp++ = '%'; *dp++ = '*';
+ dp = save_string(dp, "%*");
break;
case '/':
- *dp++ = '%'; *dp++ = '/';
+ dp = save_string(dp, "%/");
break;
case '=':
if (seenr) {
onstack = 1;
else
onstack = param;
- }
- else
+ } else
onstack = param;
break;
}
}
getparm(param, 1);
s += cvtchar(s);
- *dp++ = '%'; *dp++ = '+';
+ dp = save_string(dp, "%+");
break;
case '+':
getparm(param, 1);
s += cvtchar(s);
- *dp++ = '%'; *dp++ = '+';
- *dp++ = '%'; *dp++ = 'c';
+ dp = save_string(dp, "%+%c");
pop();
break;
case 's':
#ifdef WATERLOO
s += cvtchar(s);
getparm(param, 1);
- *dp++ = '%'; *dp++ = '-';
+ dp = save_string(dp, "%-");
#else
getparm(param, 1);
- *dp++ = '%'; *dp++ = 's';
+ dp = save_string(dp, "%s");
pop();
#endif /* WATERLOO */
break;
case '-':
s += cvtchar(s);
getparm(param, 1);
- *dp++ = '%'; *dp++ = '-';
- *dp++ = '%'; *dp++ = 'c';
+ dp = save_string(dp, "%-%c");
pop();
break;
case '.':
getparm(param, 1);
- *dp++ = '%'; *dp++ = 'c';
+ dp = save_string(dp, "%c");
pop();
break;
- case '0': /* not clear any of the historical termcaps did this */
- if (*s == '3')
+ case '0': /* not clear any of the historical termcaps did this */
+ 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++ = '%'; /* *dp++ = '0'; */
- *dp++ = '2'; *dp++ = 'd';
+ dp = save_string(dp, "%2d");
pop();
break;
- case '3': see03:
+ case '3':
+ see03:
getparm(param, 1);
- *dp++ = '%'; /* *dp++ = '0'; */
- *dp++ = '3'; *dp++ = 'd';
+ dp = save_string(dp, "%3d");
pop();
break;
case 'd':
getparm(param, 1);
- *dp++ = '%'; *dp++ = 'd';
+ dp = save_string(dp, "%d");
pop();
break;
case 'f':
param--;
break;
case '\\':
- *dp++ = '%';
- *dp++ = '\\';
+ dp = save_string(dp, "%\\");
break;
- default: invalid:
- *dp++ = '%';
+ default:
+ invalid:
+ dp = save_char(dp, '%');
s--;
- _nc_warning("unknown %% code %s in %s",
- _tracechar(*s), cap);
+ _nc_warning("unknown %% code %s (%#x) in %s",
+ unctrl((chtype) *s), UChar(*s), cap);
break;
}
break;
-#ifdef REVISIBILIZE
- case '\\':
- *dp++ = *s++; *dp++ = *s++; break;
- case '\n':
- *dp++ = '\\'; *dp++ = 'n'; s++; break;
- case '\t':
- *dp++ = '\\'; *dp++ = 't'; s++; break;
- case '\r':
- *dp++ = '\\'; *dp++ = 'r'; s++; break;
- case '\200':
- *dp++ = '\\'; *dp++ = '0'; s++; break;
- case '\f':
- *dp++ = '\\'; *dp++ = 'f'; s++; break;
- case '\b':
- *dp++ = '\\'; *dp++ = 'b'; s++; break;
- case ' ':
- *dp++ = '\\'; *dp++ = 's'; s++; break;
- case '^':
- *dp++ = '\\'; *dp++ = '^'; s++; break;
- case ':':
- *dp++ = '\\'; *dp++ = ':'; s++; break;
- case ',':
- *dp++ = '\\'; *dp++ = ','; s++; break;
- default:
- if (*s == '\033') {
- *dp++ = '\\';
- *dp++ = 'E';
- s++;
- } else if (*s > 0 && *s < 32) {
- *dp++ = '^';
- *dp++ = *s + '@';
- s++;
- } else if (*s <= 0 || *s >= 127) {
- *dp++ = '\\';
- *dp++ = ((*s & 0300) >> 6) + '0';
- *dp++ = ((*s & 0070) >> 3) + '0';
- *dp++ = (*s & 0007) + '0';
- s++;
- } else
- *dp++ = *s++;
- break;
-#else
default:
- *dp++ = *s++;
+ if (*s != '\0')
+ dp = save_char(dp, *s++);
break;
-#endif
}
}
* Now, if we stripped off some leading padding, add it at the end
* of the string as mandatory padding.
*/
- if (capstart)
- {
- *dp++ = '$';
- *dp++ = '<';
- for (s = capstart; ; s++)
- if (isdigit(*s) || *s == '*' || *s == '.')
- *dp++ = *s;
+ if (capstart) {
+ dp = save_string(dp, "$<");
+ for (s = capstart; *s != '\0'; s++)
+ if (isdigit(UChar(*s)) || *s == '*' || *s == '.')
+ dp = save_char(dp, *s);
else
break;
- *dp++ = '/';
- *dp++ = '>';
+ dp = save_string(dp, "/>");
+ }
+
+ (void) save_char(dp, '\0');
+
+ DEBUG_THIS(("... _nc_captoinfo %s", NonNull(my_string)));
+
+ return (my_string);
+}
+
+/*
+ * Check for an expression that corresponds to "%B" (BCD):
+ * (parameter / 10) * 16 + (parameter % 10)
+ */
+static int
+bcd_expression(const char *str)
+{
+ /* leave this non-const for HPUX */
+ static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+";
+ int len = 0;
+ char ch1, ch2;
+
+ if (sscanf(str, fmt, &ch1, &ch2) == 2
+ && isdigit(UChar(ch1))
+ && isdigit(UChar(ch2))
+ && (ch1 == ch2)) {
+ len = 28;
+#ifndef NDEBUG
+ {
+ char buffer[80];
+ int tst;
+ _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) fmt, ch1, ch2);
+ tst = strlen(buffer) - 1;
+ assert(len == tst);
+ }
+#endif
+ }
+ return len;
+}
+
+static char *
+save_tc_char(char *bufptr, int c1)
+{
+ 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));
+ } else {
+ _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
+ "\\%03o", c1);
+ }
+ bufptr = save_string(bufptr, temp);
}
+ return bufptr;
+}
- *dp = '\0';
- return(line);
+static char *
+save_tc_inequality(char *bufptr, int c1, int c2)
+{
+ bufptr = save_string(bufptr, "%>");
+ bufptr = save_tc_char(bufptr, c1);
+ bufptr = save_tc_char(bufptr, c2);
+ return bufptr;
}
/*
+ * info-to-cap --- conversion between terminfo and termcap formats
+ *
* Here are the capabilities infotocap assumes it can translate to:
*
* %% output `%'
* %m exclusive-or all parameters with 0177 (not in 4.4BSD)
*/
-char *_nc_infotocap(
-/* convert a terminfo string to termcap format */
-register const char *cap GCC_UNUSED, /* relevant termcap capability index */
-register const char *str, /* string value of the capability */
-int const parametrized) /* do % translations if 1, pad translations if >=0 */
+#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().
+ */
+NCURSES_EXPORT(char *)
+_nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameterized)
{
- int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
+ int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
const char *padding;
const char *trimmed = 0;
+ int in0, in1, in2;
char ch1 = 0, ch2 = 0;
char *bufptr = init_string();
- char temp[256];
+ 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;
- if (*padding == '>' && *--padding == '/')
- {
- --padding;
- while (isdigit(*padding) || *padding == '.' || *padding == '*')
+ if (padding > str && *padding == '>') {
+ if (padding > (str + 1) && *--padding == '/')
+ --padding;
+ while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
padding--;
- if (*padding == '<' && *--padding == '$')
+ if (padding > str && *padding == '<' && *--padding == '$')
trimmed = padding;
padding += 2;
- while (isdigit(*padding) || *padding == '.' || *padding == '*')
+ while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
bufptr = save_char(bufptr, *padding++);
}
- for (; *str && str != trimmed; str++)
- {
- int c1, c2;
- char *cp = 0;
+ for (; !syntax_error &&
+ *str &&
+ ((trimmed == 0) || (str < trimmed)); str++) {
+ int c1, c2;
+ char *cp = 0;
- if (str[0] == '\\' && (str[1] == '^' || str[1] == ','))
- {
- bufptr = save_char(bufptr, *++str);
- }
- else if (str[0] == '$' && str[1] == '<') /* discard padding */
- {
+ if (str[0] == '^') {
+ 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);
+ }
+ } else if (str[0] == '\\') {
+ if (str[1] == '\0' || (str + 1) == trimmed) {
+ bufptr = save_string(bufptr, "\\134");
+ ++str;
+ } else if (str[1] == '^') {
+ bufptr = save_string(bufptr, "\\136");
+ ++str;
+ } else if (str[1] == ',') {
+ bufptr = save_char(bufptr, *++str);
+ } else {
+ int xx1;
+
+ bufptr = save_char(bufptr, *str++);
+ xx1 = *str;
+ if (_nc_strict_bsd) {
+
+ if (isoctal(UChar(xx1))) {
+ int pad = 0;
+ int xx2;
+ int fix = 0;
+
+ if (!isoctal(UChar(str[1])))
+ pad = 2;
+ else if (str[1] && !isoctal(UChar(str[2])))
+ pad = 1;
+
+ /*
+ * Test for "\0", "\00" or "\000" and transform those
+ * into "\200".
+ */
+ if (xx1 == '0'
+ && ((pad == 2) || (str[1] == '0'))
+ && ((pad >= 1) || (str[2] == '0'))) {
+ xx2 = '2';
+ } else {
+ 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':
+ xx1 = 'E';
+ break;
+ case 'l':
+ xx1 = 'n';
+ break;
+ case 's':
+ bufptr = save_char(bufptr, '0');
+ bufptr = save_char(bufptr, '4');
+ xx1 = '0';
+ break;
+ case ':':
+ /*
+ * Note: termcap documentation claims that ":"
+ * must be escaped as "\072", however the
+ * documentation is incorrect - read the code.
+ * The replacement does not work reliably,
+ * so the advice is not helpful.
+ */
+ bufptr = save_char(bufptr, '0');
+ bufptr = save_char(bufptr, '7');
+ xx1 = '2';
+ break;
+ default:
+ /* should not happen, but handle this anyway */
+ _nc_SPRINTF(octal, _nc_SLIMIT(sizeof(octal))
+ "%03o", UChar(xx1));
+ bufptr = save_char(bufptr, octal[0]);
+ bufptr = save_char(bufptr, octal[1]);
+ xx1 = octal[2];
+ 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);
+ }
+ } else if (str[0] == '$' && str[1] == '<') { /* discard padding */
str += 2;
- while (isdigit(*str) || *str == '.' || *str == '*' || *str == '/' || *str == '>')
+ while (isdigit(UChar(*str))
+ || *str == '.'
+ || *str == '*'
+ || *str == '/'
+ || *str == '>')
str++;
--str;
- }
- else if (*str != '%' || (parametrized < 1))
+ } else if (sscanf(str,
+ "[%%?%%p1%%{8}%%<%%t%d%%p1%%d%%e%%p1%%{16}%%<%%t%d%%p1%%{8}%%-%%d%%e%d;5;%%p1%%d%%;m",
+ &in0, &in1, &in2) == 3
+ && ((in0 == 4 && in1 == 10 && in2 == 48)
+ || (in0 == 3 && in1 == 9 && in2 == 38))) {
+ /* dumb-down an optimized case from xterm-256color for termcap */
+ if ((str = strstr(str, ";m")) == 0)
+ break; /* cannot happen */
+ ++str;
+ if (in2 == 48) {
+ bufptr = save_string(bufptr, "[48;5;%dm");
+ } else {
+ bufptr = save_string(bufptr, "[38;5;%dm");
+ }
+ } else if (str[0] == '%' && str[1] == '%') { /* escaped '%' */
+ bufptr = save_string(bufptr, "%%");
+ ++str;
+ } else if (*str != '%' || (parameterized < 1)) {
bufptr = save_char(bufptr, *str);
- else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1,&c2) == 2)
- {
+ } else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) {
str = strchr(str, ';');
- (void) sprintf(temp, "%%>%s%s", unctrl(c1), unctrl(c2));
- bufptr = save_string(bufptr, temp);
- }
- else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1,&ch2) == 2)
- {
+ bufptr = save_tc_inequality(bufptr, c1, c2);
+ } else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) {
str = strchr(str, ';');
- (void) sprintf(temp, "%%>%s%c", unctrl(c1), ch2);
- bufptr = save_string(bufptr, temp);
- }
- else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1,&c2) == 2)
- {
+ bufptr = save_tc_inequality(bufptr, c1, ch2);
+ } else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) {
str = strchr(str, ';');
- (void) sprintf(temp, "%%>%c%c", ch1, c2);
- bufptr = save_string(bufptr, temp);
- }
- else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2)
- {
+ bufptr = save_tc_inequality(bufptr, ch1, c2);
+ } else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) {
str = strchr(str, ';');
- (void) sprintf(temp, "%%>%c%c", ch1, ch2);
- bufptr = save_string(bufptr, temp);
- }
- else if (strncmp(str, "%{6}%*%+", 8) == 0)
- {
- str += 7;
- (void) sprintf(temp, "%%B");
- bufptr = save_string(bufptr, temp);
- }
- else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
- || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
- && (cp = strchr(str, '+')))
- {
+ bufptr = save_tc_inequality(bufptr, ch1, ch2);
+ } else if ((len = bcd_expression(str)) != 0) {
+ str += len;
+ bufptr = save_string(bufptr, "%B");
+ } 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_char(bufptr, '%');
- bufptr = save_char(bufptr, '+');
+ bufptr = save_string(bufptr, "%+");
if (ch1)
c1 = ch1;
- if (is7bits(c1) && isprint(c1))
- bufptr = save_char(bufptr, (char)c1);
- else
- {
- if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */
- (void) strcpy(temp, unctrl(c1));
- else
- (void) sprintf(temp, "\\%03o", c1);
- bufptr = save_string(bufptr, temp);
- }
+ bufptr = save_tc_char(bufptr, c1);
}
- else if (strncmp(str, "%{2}%*%-", 8) == 0)
- {
+ /* FIXME: this "works" for 'delta' */
+ else if (strncmp(str, "%{2}%*%-", (size_t) 8) == 0) {
str += 7;
- (void) sprintf(temp, "%%D");
- bufptr = save_string(bufptr, temp);
- }
- else if (strncmp(str, "%{96}%^", 7) == 0)
- {
+ bufptr = save_string(bufptr, "%D");
+ } else if (strncmp(str, "%{96}%^", (size_t) 7) == 0) {
str += 6;
- if (saw_m++ == 0)
- {
- (void) sprintf(temp, "%%n");
- bufptr = save_string(bufptr, temp);
+ if (saw_m++ == 0) {
+ bufptr = save_string(bufptr, "%n");
}
- }
- else if (strncmp(str, "%{127}%^", 8) == 0)
- {
+ } else if (strncmp(str, "%{127}%^", (size_t) 8) == 0) {
str += 7;
- if (saw_n++ == 0)
- {
- (void) sprintf(temp, "%%m");
- bufptr = save_string(bufptr, temp);
+ if (saw_n++ == 0) {
+ bufptr = save_string(bufptr, "%m");
}
- }
- else
- {
+ } else { /* cm-style format element */
str++;
switch (*str) {
case '%':
case '8':
case '9':
bufptr = save_char(bufptr, '%');
- while (isdigit(*str))
- bufptr = save_char(bufptr, *str++);
- if (*str == 'd')
- str++;
- else
- _nc_warning("numeric prefix is missing trailing d in %s",
- cap);
- --str;
+ ch1 = 0;
+ ch2 = 0;
+ digits = 0;
+ while (isdigit(UChar(*str))) {
+ if (++digits > 2) {
+ syntax_error = TRUE;
+ break;
+ }
+ ch2 = ch1;
+ ch1 = *str++;
+ 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') {
+ syntax_error = TRUE;
+ } else if (ch1 < '2') {
+ ch1 = 'd';
+ }
+ bufptr = save_char(bufptr, ch1);
+ }
+ if (strchr("oxX.", *str)) {
+ syntax_error = TRUE; /* termcap doesn't have octal, hex */
+ }
break;
case 'd':
- bufptr = save_char(bufptr, '%');
- bufptr = save_char(bufptr, 'd');
+ bufptr = save_string(bufptr, "%d");
break;
case 'c':
- bufptr = save_char(bufptr, '%');
- bufptr = save_char(bufptr, '.');
+ bufptr = save_string(bufptr, "%.");
break;
- /*
- * %s isn't in termcap, but it's convenient to pass it through
- * so we can represent things like terminfo pfkey strings in
- * termcap notation.
- */
+ /*
+ * %s isn't in termcap, but it's convenient to pass it through
+ * so we can represent things like terminfo pfkey strings in
+ * termcap notation.
+ */
case 's':
- bufptr = save_char(bufptr, '%');
- bufptr = save_char(bufptr, 's');
+ if (_nc_strict_bsd) {
+ syntax_error = TRUE;
+ } else {
+ bufptr = save_string(bufptr, "%s");
+ }
break;
case 'p':
str++;
if (*str == '1')
seenone = 1;
- else if (*str == '2')
- {
- if (!seenone && !seentwo)
- {
- bufptr = save_char(bufptr, '%');
- bufptr = save_char(bufptr, 'r');
+ else if (*str == '2') {
+ if (!seenone && !seentwo) {
+ bufptr = save_string(bufptr, "%r");
seentwo++;
}
+ } else if (*str >= '3') {
+ syntax_error = TRUE;
}
- else if (*str >= '3')
- return(0);
break;
case 'i':
- bufptr = save_char(bufptr, '%');
- bufptr = save_char(bufptr, 'i');
+ bufptr = save_string(bufptr, "%i");
break;
default:
- return(0);
-
- } /* endswitch (*str) */
- } /* endelse (*str == '%') */
+ bufptr = save_char(bufptr, *str);
+ syntax_error = TRUE;
+ break;
+ } /* endswitch (*str) */
+ } /* endelse (*str == '%') */
- if (*str == '\0')
+ /*
+ * 'str' always points to the end of what was scanned in this step,
+ * but that may not be the end of the string.
+ */
+ assert(str != 0);
+ if (str == 0 || *str == '\0')
break;
- } /* endwhile (*str) */
+ } /* 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(my_string);
+ return (syntax_error ? NULL : my_string);
}
#ifdef MAIN
int curr_line;
-int main(int argc, char *argv[])
+int
+main(int argc, char *argv[])
{
int c, tc = FALSE;
while ((c = getopt(argc, argv, "c")) != EOF)
- switch (c)
- {
+ switch (c) {
case 'c':
tc = TRUE;
break;
}
curr_line = 0;
- for (;;)
- {
- char buf[BUFSIZ];
+ for (;;) {
+ char buf[BUFSIZ];
++curr_line;
if (fgets(buf, sizeof(buf), stdin) == 0)
buf[strlen(buf) - 1] = '\0';
_nc_set_source(buf);
- if (tc)
- {
- char *cp = _nc_infotocap("to termcap", buf, 1);
+ if (tc) {
+ char *cp = _nc_infotocap("to termcap", buf, 1);
if (cp)
(void) fputs(cp, stdout);
- }
- else
+ } else
(void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
(void) putchar('\n');
}
- return(0);
+ return (0);
}
#endif /* MAIN */
-/* captoinfo.c ends here */
-
+#if NO_LEAKS
+NCURSES_EXPORT(void)
+_nc_captoinfo_leaks(void)
+{
+ if (my_string != 0) {
+ FreeAndNull(my_string);
+ }
+ my_length = 0;
+}
+#endif