libncurses: Import https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.5.tar.gz changes

Change-Id: I3433d30ca01359fd2e3623ede96b531f0b39cbfa
Signed-off-by: micky387 <mickaelsaibi@free.fr>
diff --git a/ncurses/tinfo/captoinfo.c b/ncurses/tinfo/captoinfo.c
index e02e622..7e14731 100644
--- a/ncurses/tinfo/captoinfo.c
+++ b/ncurses/tinfo/captoinfo.c
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc.              *
+ * Copyright 2018-2020,2021 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 <esr@snark.thyrsus.com>.
  *
- *	There is just one entry point:
+ *	It has just one entry point:
  *
  *	char *_nc_captoinfo(n, s, parameterized)
  *
@@ -93,7 +98,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.102 2021/09/04 10:29:15 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 @@
 	case '$':
 	case '\\':
 	case '%':
-	    c = (unsigned char) (*sp);
+	    c = UChar(*sp);
 	    len = 2;
 	    break;
 	case '\0':
@@ -194,29 +205,36 @@
 	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 @@
 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 @@
 	    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 @@
 	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 @@
     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 @@
     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 @@
 	    }
 	    switch (*s++) {
 	    case '%':
-		dp = save_char(dp, '%');
+		dp = save_string(dp, "%%");
 		break;
 	    case 'r':
 		if (seenr++ == 1) {
@@ -342,13 +364,18 @@
 		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 @@
 		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 @@
 	    }
 	    break;
 	default:
-	    dp = save_char(dp, *s++);
+	    if (*s != '\0')
+		dp = save_char(dp, *s++);
 	    break;
 	}
     }
@@ -480,7 +513,7 @@
      */
     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 @@
     }
 
     (void) save_char(dp, '\0');
+
+    DEBUG_THIS(("... _nc_captoinfo %s", NonNull(my_string)));
+
     return (my_string);
 }
 
@@ -525,13 +561,13 @@
 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 +590,8 @@
 }
 
 /*
+ * info-to-cap --- conversion between terminfo and termcap formats
+ *
  * Here are the capabilities infotocap assumes it can translate to:
  *
  *     %%       output `%'
@@ -571,6 +609,8 @@
  *     %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,12 +626,23 @@
     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 %s params %d, %s",
+		_nc_strict_bsd ? "strict" : "loose",
+		parameterized,
+		_nc_visbuf(str)));
 
     /* we may have to move some trailing mandatory padding up front */
     padding = str + strlen(str) - 1;
     if (padding > str && *padding == '>') {
-	if (*--padding == '/')
+	if (padding > (str + 1) && *--padding == '/')
 	    --padding;
 	while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
 	    padding--;
@@ -603,7 +654,9 @@
 	    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,10 +664,23 @@
 	    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] == ':') {
+	    bufptr = save_char(bufptr, '\\');
+	    bufptr = save_char(bufptr, '0');
+	    bufptr = save_char(bufptr, '7');
+	    bufptr = save_char(bufptr, '2');
 	} else if (str[0] == '\\') {
 	    if (str[1] == '\0' || (str + 1) == trimmed) {
 		bufptr = save_string(bufptr, "\\134");
@@ -625,17 +691,20 @@
 	    } 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))) {
-			int pad = 0;
 
-			if (!isdigit(UChar(str[1])))
+		    if (isoctal(UChar(xx1))) {
+			int pad = 0;
+			int xx2;
+			int fix = 0;
+
+			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 +719,31 @@
 			    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 +779,24 @@
 			    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 +843,9 @@
 	} 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 +888,46 @@
 		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;
 
@@ -811,14 +940,16 @@
 		break;
 
 		/*
-		 * %s isn't in termcap, but it's convenient to pass it through
+		 * %s isn't in termcap, but it is convenient to pass it through
 		 * so we can represent things like terminfo pfkey strings in
 		 * 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 +961,9 @@
 			bufptr = save_string(bufptr, "%r");
 			seentwo++;
 		    }
-		} else if (*str >= '3')
-		    return (0);
+		} else if (*str >= '3') {
+		    syntax_error = TRUE;
+		}
 		break;
 
 	    case 'i':
@@ -855,6 +987,24 @@
 
     }				/* 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);
 }