X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Fcaptoinfo.c;h=f5bad75a97cfebe552a3072d641a2976fef4cca0;hp=cc57db31290ebb998a66705fb992c3b6df698abe;hb=af3d0ee323cbb22d2a7596d564bf68f7307f5076;hpb=03f728e5bb3630a54fffc4a2ff2f8dbfcce9088e diff --git a/ncurses/tinfo/captoinfo.c b/ncurses/tinfo/captoinfo.c index cc57db31..f5bad75a 100644 --- a/ncurses/tinfo/captoinfo.c +++ b/ncurses/tinfo/captoinfo.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2010,2011 Free Software Foundation, Inc. * + * Copyright (c) 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 +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 . * - * There is just one entry point: + * It has just one entry point: * * char *_nc_captoinfo(n, s, parameterized) * @@ -93,7 +97,13 @@ #include #include -MODULE_ID("$Id: captoinfo.c,v 1.70 2011/10/22 14:59:34 tom Exp $") +MODULE_ID("$Id: captoinfo.c,v 1.94 2017/04/21 23:26:38 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 */ @@ -114,9 +124,7 @@ 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(MSG_NO_MEMORY); + TYPE_MALLOC(char, my_length = 256, my_string); *my_string = '\0'; return my_string; @@ -133,7 +141,7 @@ save_string(char *d, const char *const s) _nc_err_abort(MSG_NO_MEMORY); d = my_string + have; } - (void) strcpy(d, s); + _nc_STRCPY(d, s, my_length - have); return d + strlen(d); } @@ -183,7 +191,7 @@ cvtchar(register const char *sp) case '$': case '\\': case '%': - c = (unsigned char) (*sp); + c = UChar(*sp); len = 2; break; case '\0': @@ -196,22 +204,26 @@ 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); + c = UChar(*sp); len = 2; 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); + c = UChar(*sp); len = 1; } if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') { @@ -241,7 +253,7 @@ getparm(int parm, int n) parm = 1; } - while (n--) { + while (n-- > 0) { dp = save_string(dp, "%p"); dp = save_char(dp, '0' + parm); } @@ -250,7 +262,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"); } } @@ -290,6 +302,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) */ @@ -311,7 +325,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) { @@ -431,12 +445,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(); @@ -491,6 +510,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); } @@ -515,7 +537,7 @@ bcd_expression(const char *str) { char buffer[80]; int tst; - sprintf(buffer, fmt, ch1, ch2); + _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) fmt, ch1, ch2); tst = strlen(buffer) - 1; assert(len == tst); } @@ -527,17 +549,20 @@ 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 { - if (c1 == (c1 & 0x1f)) /* iscntrl() returns T on 255 */ - (void) strcpy(temp, unctrl((chtype) c1)); - else - (void) sprintf(temp, "\\%03o", c1); + 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; @@ -553,6 +578,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 `%' @@ -570,6 +597,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(). @@ -585,7 +614,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; @@ -602,7 +639,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; @@ -610,6 +649,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); @@ -624,17 +671,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; - 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; /* @@ -649,10 +699,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': @@ -680,13 +751,32 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz break; default: /* should not happen, but handle this anyway */ - sprintf(octal, "%03o", UChar(xx1)); + _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); } @@ -705,7 +795,8 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz && ((in0 == 4 && in1 == 10 && in2 == 48) || (in0 == 3 && in1 == 9 && in2 == 38))) { /* dumb-down an optimized case from xterm-256color for termcap */ - str = strstr(str, ";m"); + if ((str = strstr(str, ";m")) == 0) + break; /* cannot happen */ ++str; if (in2 == 48) { bufptr = save_string(bufptr, "[48;5;%dm"); @@ -732,8 +823,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, "%+"); @@ -776,26 +868,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; @@ -813,9 +925,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': @@ -827,8 +941,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': @@ -847,11 +962,29 @@ _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameteriz * but that may not be the end of the string. */ assert(str != 0); - if (*str == '\0') + if (str == 0 || *str == '\0') break; } /* 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); }