+static NCURSES_INLINE char *
+tparam_internal(TPARM_STATE *tps, const char *string, TPARM_DATA *data)
+{
+ int number;
+ int len;
+ int level;
+ int x, y;
+ int i;
+ const char *s;
+ const char *cp = string;
+ size_t len2 = strlen(cp);
+ bool incremented_two = FALSE;
+ bool termcap_hack = tparm_tc_compat(tps, data);
+ /*
+ * SVr4 curses stores variables 'A' to 'Z' in the TERMINAL structure (so
+ * they are initialized once to zero), and variables 'a' to 'z' on the
+ * stack in tparm, referring to the former as "static" and the latter as
+ * "dynamic". However, it makes no check to ensure that the "dynamic"
+ * variables are initialized.
+ *
+ * Solaris xpg4 curses makes no distinction between the upper/lower, and
+ * stores the common set of 26 variables on the stack, without initializing
+ * them.
+ *
+ * In ncurses, both sets of variables are initialized on the first use.
+ */
+ bool dynamic_used = FALSE;
+ int dynamic_vars[NUM_VARS];
+
+ tparm_trace_call(tps, string, data);
+
+ while ((cp - string) < (int) len2) {
+ if (*cp != '%') {
+ save_char(tps, UChar(*cp));
+ } else {
+ TPS(tparam_base) = cp++;
+ cp = parse_format(cp, TPS(fmt_buff), &len);
+ switch (*cp) {
+ default:
+ break;
+ case '%':
+ save_char(tps, '%');
+ break;
+
+ case 'd': /* FALLTHRU */
+ case 'o': /* FALLTHRU */
+ case 'x': /* FALLTHRU */
+ case 'X': /* FALLTHRU */
+ x = npop(tps);
+ save_number(tps, TPS(fmt_buff), x, len);
+ break;
+
+ case 'c': /* FALLTHRU */
+ x = npop(tps);
+ save_char(tps, x);
+ break;
+
+#ifdef EXP_XTERM_1005
+ case 'u':
+ {
+ unsigned char target[10];
+ unsigned source = (unsigned) npop(tps);
+ int rc = _nc_conv_to_utf8(target, source, (unsigned)
+ sizeof(target));
+ int n;
+ for (n = 0; n < rc; ++n) {
+ save_char(tps, target[n]);
+ }
+ }
+ break;
+#endif
+ case 'l':
+ s = spop(tps);
+ npush(tps, (int) strlen(s));
+ break;
+
+ case 's':
+ s = spop(tps);
+ save_text(tps, TPS(fmt_buff), s, len);
+ break;
+
+ case 'p':
+ cp++;
+ i = (UChar(*cp) - '1');
+ if (i >= 0 && i < NUM_PARM) {
+ if (data->p_is_s[i]) {
+ spush(tps, data->p_is_s[i]);
+ } else {
+ npush(tps, (int) data->param[i]);
+ }
+ }
+ break;
+
+ case 'P':
+ cp++;
+ if (isUPPER(*cp)) {
+ i = (UChar(*cp) - 'A');
+ TPS(static_vars)[i] = npop(tps);
+ } else if (isLOWER(*cp)) {
+ i = (UChar(*cp) - 'a');
+ init_vars(dynamic);
+ dynamic_vars[i] = npop(tps);
+ }
+ break;
+
+ case 'g':
+ cp++;
+ if (isUPPER(*cp)) {
+ i = (UChar(*cp) - 'A');
+ npush(tps, TPS(static_vars)[i]);
+ } else if (isLOWER(*cp)) {
+ i = (UChar(*cp) - 'a');
+ init_vars(dynamic);
+ npush(tps, dynamic_vars[i]);
+ }
+ break;
+
+ case S_QUOTE:
+ cp++;
+ npush(tps, UChar(*cp));
+ cp++;
+ break;
+
+ case L_BRACE:
+ number = 0;
+ cp++;
+ while (isdigit(UChar(*cp))) {
+ number = (number * 10) + (UChar(*cp) - '0');
+ cp++;
+ }
+ npush(tps, number);
+ break;
+
+ case '+':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x + y);
+ break;
+
+ case '-':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x - y);
+ break;
+
+ case '*':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x * y);
+ break;
+
+ case '/':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y ? (x / y) : 0);
+ break;
+
+ case 'm':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y ? (x % y) : 0);
+ break;
+
+ case 'A':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y && x);
+ break;
+
+ case 'O':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, y || x);
+ break;
+
+ case '&':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x & y);
+ break;
+
+ case '|':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x | y);
+ break;
+
+ case '^':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x ^ y);
+ break;
+
+ case '=':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x == y);
+ break;
+
+ case '<':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x < y);
+ break;
+
+ case '>':
+ y = npop(tps);
+ x = npop(tps);
+ npush(tps, x > y);
+ break;
+
+ case '!':
+ x = npop(tps);
+ npush(tps, !x);
+ break;
+
+ case '~':
+ x = npop(tps);
+ npush(tps, ~x);
+ break;
+
+ case 'i':
+ /*
+ * Increment the first two parameters -- if they are numbers
+ * rather than strings. As a side effect, assign into the
+ * stack; if this is termcap, then the stack was populated
+ * using the termcap hack above rather than via the terminfo
+ * 'p' case.
+ */
+ if (!incremented_two) {
+ incremented_two = TRUE;
+ if (data->p_is_s[0] == 0) {
+ data->param[0]++;
+ if (termcap_hack)
+ TPS(stack)[0].data.num = (int) data->param[0];
+ }
+ if (data->p_is_s[1] == 0) {
+ data->param[1]++;
+ if (termcap_hack)
+ TPS(stack)[1].data.num = (int) data->param[1];
+ }
+ }
+ break;
+
+ case '?':
+ break;
+
+ case 't':
+ x = npop(tps);
+ if (!x) {
+ /* scan forward for %e or %; at level zero */
+ cp++;
+ level = 0;
+ while (*cp) {
+ if (*cp == '%') {
+ cp++;
+ if (*cp == '?')
+ level++;
+ else if (*cp == ';') {
+ if (level > 0)
+ level--;
+ else
+ break;
+ } else if (*cp == 'e' && level == 0)