X-Git-Url: http://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Fcaptoinfo.c;h=9362105ab795ebd4192e812737ca1e798e0eece9;hp=dd02d902dc5261a67c4849508d8c15c07ec22b68;hb=790a85dbd4a81d5f5d8dd02a44d84f01512ef443;hpb=76a479337308b4b5e749fa8c38b7b7f482998c5b diff --git a/ncurses/tinfo/captoinfo.c b/ncurses/tinfo/captoinfo.c index dd02d902..9362105a 100644 --- a/ncurses/tinfo/captoinfo.c +++ b/ncurses/tinfo/captoinfo.c @@ -1,5 +1,6 @@ /**************************************************************************** - * Copyright (c) 1998-2012,2016 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 * @@ -33,12 +34,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 . * - * There is just one entry point: + * It has just one entry point: * * char *_nc_captoinfo(n, s, parameterized) * @@ -93,7 +98,13 @@ #include #include -MODULE_ID("$Id: captoinfo.c,v 1.78 2016/05/28 23:22:52 tom Exp $") +MODULE_ID("$Id: captoinfo.c,v 1.99 2020/05/25 21:28:29 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 +192,7 @@ cvtchar(register const char *sp) case '$': case '\\': case '%': - c = (unsigned char) (*sp); + c = UChar(*sp); len = 2; break; case '\0': @@ -194,29 +205,36 @@ 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); len = 2; + c = UChar(*++sp); + if (c == '?') { + c = 127; + } else if (c == '\0') { + len = 1; + } else { + c &= 0x1f; + } 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 +250,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 +259,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 +268,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 +308,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 +317,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 +331,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 +364,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 +456,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 +501,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 +513,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 +522,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); } @@ -554,6 +590,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 +609,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 +626,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 +651,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 +661,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); @@ -631,13 +689,14 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz 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; /* @@ -652,10 +711,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': @@ -691,6 +771,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); } @@ -737,8 +835,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, "%+"); @@ -781,26 +880,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; @@ -818,9 +937,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': @@ -832,8 +953,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': @@ -857,6 +979,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 + ? "" + : _nc_visbuf(my_string))); + return (syntax_error ? NULL : my_string); }