Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 1 | /**************************************************************************** |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 2 | * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. * |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 3 | * * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a * |
| 5 | * copy of this software and associated documentation files (the * |
| 6 | * "Software"), to deal in the Software without restriction, including * |
| 7 | * without limitation the rights to use, copy, modify, merge, publish, * |
| 8 | * distribute, distribute with modifications, sublicense, and/or sell * |
| 9 | * copies of the Software, and to permit persons to whom the Software is * |
| 10 | * furnished to do so, subject to the following conditions: * |
| 11 | * * |
| 12 | * The above copyright notice and this permission notice shall be included * |
| 13 | * in all copies or substantial portions of the Software. * |
| 14 | * * |
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
| 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
| 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
| 18 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
| 19 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
| 20 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
| 21 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
| 22 | * * |
| 23 | * Except as contained in this notice, the name(s) of the above copyright * |
| 24 | * holders shall not be used in advertising or otherwise to promote the * |
| 25 | * sale, use or other dealings in this Software without prior written * |
| 26 | * authorization. * |
| 27 | ****************************************************************************/ |
| 28 | |
| 29 | /**************************************************************************** |
| 30 | * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * |
| 31 | * and: Eric S. Raymond <esr@snark.thyrsus.com> * |
| 32 | * and: Thomas E. Dickey, 1996 on * |
| 33 | ****************************************************************************/ |
| 34 | |
| 35 | /* |
| 36 | * tparm.c |
| 37 | * |
| 38 | */ |
| 39 | |
| 40 | #include <curses.priv.h> |
| 41 | |
| 42 | #include <ctype.h> |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 43 | #include <tic.h> |
| 44 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 45 | MODULE_ID("$Id: lib_tparm.c,v 1.94 2015/07/17 01:03:35 tom Exp $") |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 46 | |
| 47 | /* |
| 48 | * char * |
| 49 | * tparm(string, ...) |
| 50 | * |
| 51 | * Substitute the given parameters into the given string by the following |
| 52 | * rules (taken from terminfo(5)): |
| 53 | * |
| 54 | * Cursor addressing and other strings requiring parame- |
| 55 | * ters in the terminal are described by a parameterized string |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 56 | * capability, with escapes like %x in it. For example, to |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 57 | * address the cursor, the cup capability is given, using two |
| 58 | * parameters: the row and column to address to. (Rows and |
| 59 | * columns are numbered from zero and refer to the physical |
| 60 | * screen visible to the user, not to any unseen memory.) If |
| 61 | * the terminal has memory relative cursor addressing, that can |
| 62 | * be indicated by |
| 63 | * |
| 64 | * The parameter mechanism uses a stack and special % |
| 65 | * codes to manipulate it. Typically a sequence will push one |
| 66 | * of the parameters onto the stack and then print it in some |
| 67 | * format. Often more complex operations are necessary. |
| 68 | * |
| 69 | * The % encodings have the following meanings: |
| 70 | * |
| 71 | * %% outputs `%' |
| 72 | * %c print pop() like %c in printf() |
| 73 | * %s print pop() like %s in printf() |
| 74 | * %[[:]flags][width[.precision]][doxXs] |
| 75 | * as in printf, flags are [-+#] and space |
| 76 | * The ':' is used to avoid making %+ or %- |
| 77 | * patterns (see below). |
| 78 | * |
| 79 | * %p[1-9] push ith parm |
| 80 | * %P[a-z] set dynamic variable [a-z] to pop() |
| 81 | * %g[a-z] get dynamic variable [a-z] and push it |
| 82 | * %P[A-Z] set static variable [A-Z] to pop() |
| 83 | * %g[A-Z] get static variable [A-Z] and push it |
| 84 | * %l push strlen(pop) |
| 85 | * %'c' push char constant c |
| 86 | * %{nn} push integer constant nn |
| 87 | * |
| 88 | * %+ %- %* %/ %m |
| 89 | * arithmetic (%m is mod): push(pop() op pop()) |
| 90 | * %& %| %^ bit operations: push(pop() op pop()) |
| 91 | * %= %> %< logical operations: push(pop() op pop()) |
| 92 | * %A %O logical and & or operations for conditionals |
| 93 | * %! %~ unary operations push(op pop()) |
| 94 | * %i add 1 to first two parms (for ANSI terminals) |
| 95 | * |
| 96 | * %? expr %t thenpart %e elsepart %; |
| 97 | * if-then-else, %e elsepart is optional. |
| 98 | * else-if's are possible ala Algol 68: |
| 99 | * %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %; |
| 100 | * |
| 101 | * For those of the above operators which are binary and not commutative, |
| 102 | * the stack works in the usual way, with |
| 103 | * %gx %gy %m |
| 104 | * resulting in x mod y, not the reverse. |
| 105 | */ |
| 106 | |
| 107 | NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0; |
| 108 | |
| 109 | #define TPS(var) _nc_prescreen.tparm_state.var |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 110 | #define popcount _nc_popcount /* workaround for NetBSD 6.0 defect */ |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 111 | |
| 112 | #if NO_LEAKS |
| 113 | NCURSES_EXPORT(void) |
| 114 | _nc_free_tparm(void) |
| 115 | { |
| 116 | if (TPS(out_buff) != 0) { |
| 117 | FreeAndNull(TPS(out_buff)); |
| 118 | TPS(out_size) = 0; |
| 119 | TPS(out_used) = 0; |
| 120 | FreeAndNull(TPS(fmt_buff)); |
| 121 | TPS(fmt_size) = 0; |
| 122 | } |
| 123 | } |
| 124 | #endif |
| 125 | |
| 126 | static NCURSES_INLINE void |
| 127 | get_space(size_t need) |
| 128 | { |
| 129 | need += TPS(out_used); |
| 130 | if (need > TPS(out_size)) { |
| 131 | TPS(out_size) = need * 2; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 132 | TYPE_REALLOC(char, TPS(out_size), TPS(out_buff)); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 133 | } |
| 134 | } |
| 135 | |
| 136 | static NCURSES_INLINE void |
| 137 | save_text(const char *fmt, const char *s, int len) |
| 138 | { |
| 139 | size_t s_len = strlen(s); |
| 140 | if (len > (int) s_len) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 141 | s_len = (size_t) len; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 142 | |
| 143 | get_space(s_len + 1); |
| 144 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 145 | _nc_SPRINTF(TPS(out_buff) + TPS(out_used), |
| 146 | _nc_SLIMIT(TPS(out_size) - TPS(out_used)) |
| 147 | fmt, s); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 148 | TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); |
| 149 | } |
| 150 | |
| 151 | static NCURSES_INLINE void |
| 152 | save_number(const char *fmt, int number, int len) |
| 153 | { |
| 154 | if (len < 30) |
| 155 | len = 30; /* actually log10(MAX_INT)+1 */ |
| 156 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 157 | get_space((size_t) len + 1); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 158 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 159 | _nc_SPRINTF(TPS(out_buff) + TPS(out_used), |
| 160 | _nc_SLIMIT(TPS(out_size) - TPS(out_used)) |
| 161 | fmt, number); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 162 | TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); |
| 163 | } |
| 164 | |
| 165 | static NCURSES_INLINE void |
| 166 | save_char(int c) |
| 167 | { |
| 168 | if (c == 0) |
| 169 | c = 0200; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 170 | get_space((size_t) 1); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 171 | TPS(out_buff)[TPS(out_used)++] = (char) c; |
| 172 | } |
| 173 | |
| 174 | static NCURSES_INLINE void |
| 175 | npush(int x) |
| 176 | { |
| 177 | if (TPS(stack_ptr) < STACKSIZE) { |
| 178 | TPS(stack)[TPS(stack_ptr)].num_type = TRUE; |
| 179 | TPS(stack)[TPS(stack_ptr)].data.num = x; |
| 180 | TPS(stack_ptr)++; |
| 181 | } else { |
| 182 | DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(TPS(tparam_base)))); |
| 183 | _nc_tparm_err++; |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | static NCURSES_INLINE int |
| 188 | npop(void) |
| 189 | { |
| 190 | int result = 0; |
| 191 | if (TPS(stack_ptr) > 0) { |
| 192 | TPS(stack_ptr)--; |
| 193 | if (TPS(stack)[TPS(stack_ptr)].num_type) |
| 194 | result = TPS(stack)[TPS(stack_ptr)].data.num; |
| 195 | } else { |
| 196 | DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(TPS(tparam_base)))); |
| 197 | _nc_tparm_err++; |
| 198 | } |
| 199 | return result; |
| 200 | } |
| 201 | |
| 202 | static NCURSES_INLINE void |
| 203 | spush(char *x) |
| 204 | { |
| 205 | if (TPS(stack_ptr) < STACKSIZE) { |
| 206 | TPS(stack)[TPS(stack_ptr)].num_type = FALSE; |
| 207 | TPS(stack)[TPS(stack_ptr)].data.str = x; |
| 208 | TPS(stack_ptr)++; |
| 209 | } else { |
| 210 | DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(TPS(tparam_base)))); |
| 211 | _nc_tparm_err++; |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | static NCURSES_INLINE char * |
| 216 | spop(void) |
| 217 | { |
| 218 | static char dummy[] = ""; /* avoid const-cast */ |
| 219 | char *result = dummy; |
| 220 | if (TPS(stack_ptr) > 0) { |
| 221 | TPS(stack_ptr)--; |
| 222 | if (!TPS(stack)[TPS(stack_ptr)].num_type |
| 223 | && TPS(stack)[TPS(stack_ptr)].data.str != 0) |
| 224 | result = TPS(stack)[TPS(stack_ptr)].data.str; |
| 225 | } else { |
| 226 | DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(TPS(tparam_base)))); |
| 227 | _nc_tparm_err++; |
| 228 | } |
| 229 | return result; |
| 230 | } |
| 231 | |
| 232 | static NCURSES_INLINE const char * |
| 233 | parse_format(const char *s, char *format, int *len) |
| 234 | { |
| 235 | *len = 0; |
| 236 | if (format != 0) { |
| 237 | bool done = FALSE; |
| 238 | bool allowminus = FALSE; |
| 239 | bool dot = FALSE; |
| 240 | bool err = FALSE; |
| 241 | char *fmt = format; |
| 242 | int my_width = 0; |
| 243 | int my_prec = 0; |
| 244 | int value = 0; |
| 245 | |
| 246 | *len = 0; |
| 247 | *format++ = '%'; |
| 248 | while (*s != '\0' && !done) { |
| 249 | switch (*s) { |
| 250 | case 'c': /* FALLTHRU */ |
| 251 | case 'd': /* FALLTHRU */ |
| 252 | case 'o': /* FALLTHRU */ |
| 253 | case 'x': /* FALLTHRU */ |
| 254 | case 'X': /* FALLTHRU */ |
| 255 | case 's': |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 256 | #ifdef EXP_XTERM_1005 |
| 257 | case 'u': |
| 258 | #endif |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 259 | *format++ = *s; |
| 260 | done = TRUE; |
| 261 | break; |
| 262 | case '.': |
| 263 | *format++ = *s++; |
| 264 | if (dot) { |
| 265 | err = TRUE; |
| 266 | } else { /* value before '.' is the width */ |
| 267 | dot = TRUE; |
| 268 | my_width = value; |
| 269 | } |
| 270 | value = 0; |
| 271 | break; |
| 272 | case '#': |
| 273 | *format++ = *s++; |
| 274 | break; |
| 275 | case ' ': |
| 276 | *format++ = *s++; |
| 277 | break; |
| 278 | case ':': |
| 279 | s++; |
| 280 | allowminus = TRUE; |
| 281 | break; |
| 282 | case '-': |
| 283 | if (allowminus) { |
| 284 | *format++ = *s++; |
| 285 | } else { |
| 286 | done = TRUE; |
| 287 | } |
| 288 | break; |
| 289 | default: |
| 290 | if (isdigit(UChar(*s))) { |
| 291 | value = (value * 10) + (*s - '0'); |
| 292 | if (value > 10000) |
| 293 | err = TRUE; |
| 294 | *format++ = *s++; |
| 295 | } else { |
| 296 | done = TRUE; |
| 297 | } |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | /* |
| 302 | * If we found an error, ignore (and remove) the flags. |
| 303 | */ |
| 304 | if (err) { |
| 305 | my_width = my_prec = value = 0; |
| 306 | format = fmt; |
| 307 | *format++ = '%'; |
| 308 | *format++ = *s; |
| 309 | } |
| 310 | |
| 311 | /* |
| 312 | * Any value after '.' is the precision. If we did not see '.', then |
| 313 | * the value is the width. |
| 314 | */ |
| 315 | if (dot) |
| 316 | my_prec = value; |
| 317 | else |
| 318 | my_width = value; |
| 319 | |
| 320 | *format = '\0'; |
| 321 | /* return maximum string length in print */ |
| 322 | *len = (my_width > my_prec) ? my_width : my_prec; |
| 323 | } |
| 324 | return s; |
| 325 | } |
| 326 | |
| 327 | #define isUPPER(c) ((c) >= 'A' && (c) <= 'Z') |
| 328 | #define isLOWER(c) ((c) >= 'a' && (c) <= 'z') |
| 329 | |
| 330 | /* |
| 331 | * Analyze the string to see how many parameters we need from the varargs list, |
| 332 | * and what their types are. We will only accept string parameters if they |
| 333 | * appear as a %l or %s format following an explicit parameter reference (e.g., |
| 334 | * %p2%s). All other parameters are numbers. |
| 335 | * |
| 336 | * 'number' counts coarsely the number of pop's we see in the string, and |
| 337 | * 'popcount' shows the highest parameter number in the string. We would like |
| 338 | * to simply use the latter count, but if we are reading termcap strings, there |
| 339 | * may be cases that we cannot see the explicit parameter numbers. |
| 340 | */ |
| 341 | NCURSES_EXPORT(int) |
| 342 | _nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount) |
| 343 | { |
| 344 | size_t len2; |
| 345 | int i; |
| 346 | int lastpop = -1; |
| 347 | int len; |
| 348 | int number = 0; |
| 349 | const char *cp = string; |
| 350 | static char dummy[] = ""; |
| 351 | |
| 352 | if (cp == 0) |
| 353 | return 0; |
| 354 | |
| 355 | if ((len2 = strlen(cp)) > TPS(fmt_size)) { |
| 356 | TPS(fmt_size) = len2 + TPS(fmt_size) + 2; |
| 357 | TPS(fmt_buff) = typeRealloc(char, TPS(fmt_size), TPS(fmt_buff)); |
| 358 | if (TPS(fmt_buff) == 0) |
| 359 | return 0; |
| 360 | } |
| 361 | |
| 362 | memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM); |
| 363 | *popcount = 0; |
| 364 | |
| 365 | while ((cp - string) < (int) len2) { |
| 366 | if (*cp == '%') { |
| 367 | cp++; |
| 368 | cp = parse_format(cp, TPS(fmt_buff), &len); |
| 369 | switch (*cp) { |
| 370 | default: |
| 371 | break; |
| 372 | |
| 373 | case 'd': /* FALLTHRU */ |
| 374 | case 'o': /* FALLTHRU */ |
| 375 | case 'x': /* FALLTHRU */ |
| 376 | case 'X': /* FALLTHRU */ |
| 377 | case 'c': /* FALLTHRU */ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 378 | #ifdef EXP_XTERM_1005 |
| 379 | case 'u': |
| 380 | #endif |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 381 | if (lastpop <= 0) |
| 382 | number++; |
| 383 | lastpop = -1; |
| 384 | break; |
| 385 | |
| 386 | case 'l': |
| 387 | case 's': |
| 388 | if (lastpop > 0) |
| 389 | p_is_s[lastpop - 1] = dummy; |
| 390 | ++number; |
| 391 | break; |
| 392 | |
| 393 | case 'p': |
| 394 | cp++; |
| 395 | i = (UChar(*cp) - '0'); |
| 396 | if (i >= 0 && i <= NUM_PARM) { |
| 397 | lastpop = i; |
| 398 | if (lastpop > *popcount) |
| 399 | *popcount = lastpop; |
| 400 | } |
| 401 | break; |
| 402 | |
| 403 | case 'P': |
| 404 | ++number; |
| 405 | ++cp; |
| 406 | break; |
| 407 | |
| 408 | case 'g': |
| 409 | cp++; |
| 410 | break; |
| 411 | |
| 412 | case S_QUOTE: |
| 413 | cp += 2; |
| 414 | lastpop = -1; |
| 415 | break; |
| 416 | |
| 417 | case L_BRACE: |
| 418 | cp++; |
| 419 | while (isdigit(UChar(*cp))) { |
| 420 | cp++; |
| 421 | } |
| 422 | break; |
| 423 | |
| 424 | case '+': |
| 425 | case '-': |
| 426 | case '*': |
| 427 | case '/': |
| 428 | case 'm': |
| 429 | case 'A': |
| 430 | case 'O': |
| 431 | case '&': |
| 432 | case '|': |
| 433 | case '^': |
| 434 | case '=': |
| 435 | case '<': |
| 436 | case '>': |
| 437 | lastpop = -1; |
| 438 | number += 2; |
| 439 | break; |
| 440 | |
| 441 | case '!': |
| 442 | case '~': |
| 443 | lastpop = -1; |
| 444 | ++number; |
| 445 | break; |
| 446 | |
| 447 | case 'i': |
| 448 | /* will add 1 to first (usually two) parameters */ |
| 449 | break; |
| 450 | } |
| 451 | } |
| 452 | if (*cp != '\0') |
| 453 | cp++; |
| 454 | } |
| 455 | |
| 456 | if (number > NUM_PARM) |
| 457 | number = NUM_PARM; |
| 458 | return number; |
| 459 | } |
| 460 | |
| 461 | static NCURSES_INLINE char * |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 462 | tparam_internal(int use_TPARM_ARG, const char *string, va_list ap) |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 463 | { |
| 464 | char *p_is_s[NUM_PARM]; |
| 465 | TPARM_ARG param[NUM_PARM]; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 466 | int popcount = 0; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 467 | int number; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 468 | int num_args; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 469 | int len; |
| 470 | int level; |
| 471 | int x, y; |
| 472 | int i; |
| 473 | const char *cp = string; |
| 474 | size_t len2; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 475 | bool termcap_hack; |
| 476 | bool incremented_two; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 477 | |
| 478 | if (cp == NULL) |
| 479 | return NULL; |
| 480 | |
| 481 | TPS(out_used) = 0; |
| 482 | len2 = strlen(cp); |
| 483 | |
| 484 | /* |
| 485 | * Find the highest parameter-number referred to in the format string. |
| 486 | * Use this value to limit the number of arguments copied from the |
| 487 | * variable-length argument list. |
| 488 | */ |
| 489 | number = _nc_tparm_analyze(cp, p_is_s, &popcount); |
| 490 | if (TPS(fmt_buff) == 0) |
| 491 | return NULL; |
| 492 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 493 | incremented_two = FALSE; |
| 494 | |
| 495 | if (number > NUM_PARM) |
| 496 | number = NUM_PARM; |
| 497 | if (popcount > NUM_PARM) |
| 498 | popcount = NUM_PARM; |
| 499 | num_args = max(popcount, number); |
| 500 | |
| 501 | for (i = 0; i < num_args; i++) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 502 | /* |
| 503 | * A few caps (such as plab_norm) have string-valued parms. |
| 504 | * We'll have to assume that the caller knows the difference, since |
| 505 | * a char* and an int may not be the same size on the stack. The |
| 506 | * normal prototype for this uses 9 long's, which is consistent with |
| 507 | * our va_arg() usage. |
| 508 | */ |
| 509 | if (p_is_s[i] != 0) { |
| 510 | p_is_s[i] = va_arg(ap, char *); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 511 | param[i] = 0; |
| 512 | } else if (use_TPARM_ARG) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 513 | param[i] = va_arg(ap, TPARM_ARG); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 514 | } else { |
| 515 | param[i] = (TPARM_ARG) va_arg(ap, int); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 516 | } |
| 517 | } |
| 518 | |
| 519 | /* |
| 520 | * This is a termcap compatibility hack. If there are no explicit pop |
| 521 | * operations in the string, load the stack in such a way that |
| 522 | * successive pops will grab successive parameters. That will make |
| 523 | * the expansion of (for example) \E[%d;%dH work correctly in termcap |
| 524 | * style, which means tparam() will expand termcap strings OK. |
| 525 | */ |
| 526 | TPS(stack_ptr) = 0; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 527 | termcap_hack = FALSE; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 528 | if (popcount == 0) { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 529 | termcap_hack = TRUE; |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 530 | popcount = number; |
| 531 | for (i = number - 1; i >= 0; i--) { |
| 532 | if (p_is_s[i]) |
| 533 | spush(p_is_s[i]); |
| 534 | else |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 535 | npush((int) param[i]); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 536 | } |
| 537 | } |
| 538 | #ifdef TRACE |
| 539 | if (USE_TRACEF(TRACE_CALLS)) { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 540 | for (i = 0; i < num_args; i++) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 541 | if (p_is_s[i] != 0) |
| 542 | save_text(", %s", _nc_visbuf(p_is_s[i]), 0); |
| 543 | else |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 544 | save_number(", %d", (int) param[i], 0); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 545 | } |
| 546 | _tracef(T_CALLED("%s(%s%s)"), TPS(tname), _nc_visbuf(cp), TPS(out_buff)); |
| 547 | TPS(out_used) = 0; |
| 548 | _nc_unlock_global(tracef); |
| 549 | } |
| 550 | #endif /* TRACE */ |
| 551 | |
| 552 | while ((cp - string) < (int) len2) { |
| 553 | if (*cp != '%') { |
| 554 | save_char(UChar(*cp)); |
| 555 | } else { |
| 556 | TPS(tparam_base) = cp++; |
| 557 | cp = parse_format(cp, TPS(fmt_buff), &len); |
| 558 | switch (*cp) { |
| 559 | default: |
| 560 | break; |
| 561 | case '%': |
| 562 | save_char('%'); |
| 563 | break; |
| 564 | |
| 565 | case 'd': /* FALLTHRU */ |
| 566 | case 'o': /* FALLTHRU */ |
| 567 | case 'x': /* FALLTHRU */ |
| 568 | case 'X': /* FALLTHRU */ |
| 569 | save_number(TPS(fmt_buff), npop(), len); |
| 570 | break; |
| 571 | |
| 572 | case 'c': /* FALLTHRU */ |
| 573 | save_char(npop()); |
| 574 | break; |
| 575 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 576 | #ifdef EXP_XTERM_1005 |
| 577 | case 'u': |
| 578 | { |
| 579 | unsigned char target[10]; |
| 580 | unsigned source = (unsigned) npop(); |
| 581 | int rc = _nc_conv_to_utf8(target, source, (unsigned) |
| 582 | sizeof(target)); |
| 583 | int n; |
| 584 | for (n = 0; n < rc; ++n) { |
| 585 | save_char(target[n]); |
| 586 | } |
| 587 | } |
| 588 | break; |
| 589 | #endif |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 590 | case 'l': |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 591 | npush((int) strlen(spop())); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 592 | break; |
| 593 | |
| 594 | case 's': |
| 595 | save_text(TPS(fmt_buff), spop(), len); |
| 596 | break; |
| 597 | |
| 598 | case 'p': |
| 599 | cp++; |
| 600 | i = (UChar(*cp) - '1'); |
| 601 | if (i >= 0 && i < NUM_PARM) { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 602 | if (p_is_s[i]) { |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 603 | spush(p_is_s[i]); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 604 | } else { |
| 605 | npush((int) param[i]); |
| 606 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 607 | } |
| 608 | break; |
| 609 | |
| 610 | case 'P': |
| 611 | cp++; |
| 612 | if (isUPPER(*cp)) { |
| 613 | i = (UChar(*cp) - 'A'); |
| 614 | TPS(static_vars)[i] = npop(); |
| 615 | } else if (isLOWER(*cp)) { |
| 616 | i = (UChar(*cp) - 'a'); |
| 617 | TPS(dynamic_var)[i] = npop(); |
| 618 | } |
| 619 | break; |
| 620 | |
| 621 | case 'g': |
| 622 | cp++; |
| 623 | if (isUPPER(*cp)) { |
| 624 | i = (UChar(*cp) - 'A'); |
| 625 | npush(TPS(static_vars)[i]); |
| 626 | } else if (isLOWER(*cp)) { |
| 627 | i = (UChar(*cp) - 'a'); |
| 628 | npush(TPS(dynamic_var)[i]); |
| 629 | } |
| 630 | break; |
| 631 | |
| 632 | case S_QUOTE: |
| 633 | cp++; |
| 634 | npush(UChar(*cp)); |
| 635 | cp++; |
| 636 | break; |
| 637 | |
| 638 | case L_BRACE: |
| 639 | number = 0; |
| 640 | cp++; |
| 641 | while (isdigit(UChar(*cp))) { |
| 642 | number = (number * 10) + (UChar(*cp) - '0'); |
| 643 | cp++; |
| 644 | } |
| 645 | npush(number); |
| 646 | break; |
| 647 | |
| 648 | case '+': |
| 649 | npush(npop() + npop()); |
| 650 | break; |
| 651 | |
| 652 | case '-': |
| 653 | y = npop(); |
| 654 | x = npop(); |
| 655 | npush(x - y); |
| 656 | break; |
| 657 | |
| 658 | case '*': |
| 659 | npush(npop() * npop()); |
| 660 | break; |
| 661 | |
| 662 | case '/': |
| 663 | y = npop(); |
| 664 | x = npop(); |
| 665 | npush(y ? (x / y) : 0); |
| 666 | break; |
| 667 | |
| 668 | case 'm': |
| 669 | y = npop(); |
| 670 | x = npop(); |
| 671 | npush(y ? (x % y) : 0); |
| 672 | break; |
| 673 | |
| 674 | case 'A': |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 675 | y = npop(); |
| 676 | x = npop(); |
| 677 | npush(y && x); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 678 | break; |
| 679 | |
| 680 | case 'O': |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 681 | y = npop(); |
| 682 | x = npop(); |
| 683 | npush(y || x); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 684 | break; |
| 685 | |
| 686 | case '&': |
| 687 | npush(npop() & npop()); |
| 688 | break; |
| 689 | |
| 690 | case '|': |
| 691 | npush(npop() | npop()); |
| 692 | break; |
| 693 | |
| 694 | case '^': |
| 695 | npush(npop() ^ npop()); |
| 696 | break; |
| 697 | |
| 698 | case '=': |
| 699 | y = npop(); |
| 700 | x = npop(); |
| 701 | npush(x == y); |
| 702 | break; |
| 703 | |
| 704 | case '<': |
| 705 | y = npop(); |
| 706 | x = npop(); |
| 707 | npush(x < y); |
| 708 | break; |
| 709 | |
| 710 | case '>': |
| 711 | y = npop(); |
| 712 | x = npop(); |
| 713 | npush(x > y); |
| 714 | break; |
| 715 | |
| 716 | case '!': |
| 717 | npush(!npop()); |
| 718 | break; |
| 719 | |
| 720 | case '~': |
| 721 | npush(~npop()); |
| 722 | break; |
| 723 | |
| 724 | case 'i': |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 725 | /* |
| 726 | * Increment the first two parameters -- if they are numbers |
| 727 | * rather than strings. As a side effect, assign into the |
| 728 | * stack; if this is termcap, then the stack was populated |
| 729 | * using the termcap hack above rather than via the terminfo |
| 730 | * 'p' case. |
| 731 | */ |
| 732 | if (!incremented_two) { |
| 733 | incremented_two = TRUE; |
| 734 | if (p_is_s[0] == 0) { |
| 735 | param[0]++; |
| 736 | if (termcap_hack) |
| 737 | TPS(stack)[0].data.num = (int) param[0]; |
| 738 | } |
| 739 | if (p_is_s[1] == 0) { |
| 740 | param[1]++; |
| 741 | if (termcap_hack) |
| 742 | TPS(stack)[1].data.num = (int) param[1]; |
| 743 | } |
| 744 | } |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 745 | break; |
| 746 | |
| 747 | case '?': |
| 748 | break; |
| 749 | |
| 750 | case 't': |
| 751 | x = npop(); |
| 752 | if (!x) { |
| 753 | /* scan forward for %e or %; at level zero */ |
| 754 | cp++; |
| 755 | level = 0; |
| 756 | while (*cp) { |
| 757 | if (*cp == '%') { |
| 758 | cp++; |
| 759 | if (*cp == '?') |
| 760 | level++; |
| 761 | else if (*cp == ';') { |
| 762 | if (level > 0) |
| 763 | level--; |
| 764 | else |
| 765 | break; |
| 766 | } else if (*cp == 'e' && level == 0) |
| 767 | break; |
| 768 | } |
| 769 | |
| 770 | if (*cp) |
| 771 | cp++; |
| 772 | } |
| 773 | } |
| 774 | break; |
| 775 | |
| 776 | case 'e': |
| 777 | /* scan forward for a %; at level zero */ |
| 778 | cp++; |
| 779 | level = 0; |
| 780 | while (*cp) { |
| 781 | if (*cp == '%') { |
| 782 | cp++; |
| 783 | if (*cp == '?') |
| 784 | level++; |
| 785 | else if (*cp == ';') { |
| 786 | if (level > 0) |
| 787 | level--; |
| 788 | else |
| 789 | break; |
| 790 | } |
| 791 | } |
| 792 | |
| 793 | if (*cp) |
| 794 | cp++; |
| 795 | } |
| 796 | break; |
| 797 | |
| 798 | case ';': |
| 799 | break; |
| 800 | |
| 801 | } /* endswitch (*cp) */ |
| 802 | } /* endelse (*cp == '%') */ |
| 803 | |
| 804 | if (*cp == '\0') |
| 805 | break; |
| 806 | |
| 807 | cp++; |
| 808 | } /* endwhile (*cp) */ |
| 809 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 810 | get_space((size_t) 1); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 811 | TPS(out_buff)[TPS(out_used)] = '\0'; |
| 812 | |
| 813 | T((T_RETURN("%s"), _nc_visbuf(TPS(out_buff)))); |
| 814 | return (TPS(out_buff)); |
| 815 | } |
| 816 | |
| 817 | #if NCURSES_TPARM_VARARGS |
| 818 | #define tparm_varargs tparm |
| 819 | #else |
| 820 | #define tparm_proto tparm |
| 821 | #endif |
| 822 | |
| 823 | NCURSES_EXPORT(char *) |
| 824 | tparm_varargs(NCURSES_CONST char *string,...) |
| 825 | { |
| 826 | va_list ap; |
| 827 | char *result; |
| 828 | |
| 829 | _nc_tparm_err = 0; |
| 830 | va_start(ap, string); |
| 831 | #ifdef TRACE |
| 832 | TPS(tname) = "tparm"; |
| 833 | #endif /* TRACE */ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 834 | result = tparam_internal(TRUE, string, ap); |
Amit Daniel Kachhap | e6a01f5 | 2011-07-20 11:45:59 +0530 | [diff] [blame] | 835 | va_end(ap); |
| 836 | return result; |
| 837 | } |
| 838 | |
| 839 | #if !NCURSES_TPARM_VARARGS |
| 840 | NCURSES_EXPORT(char *) |
| 841 | tparm_proto(NCURSES_CONST char *string, |
| 842 | TPARM_ARG a1, |
| 843 | TPARM_ARG a2, |
| 844 | TPARM_ARG a3, |
| 845 | TPARM_ARG a4, |
| 846 | TPARM_ARG a5, |
| 847 | TPARM_ARG a6, |
| 848 | TPARM_ARG a7, |
| 849 | TPARM_ARG a8, |
| 850 | TPARM_ARG a9) |
| 851 | { |
| 852 | return tparm_varargs(string, a1, a2, a3, a4, a5, a6, a7, a8, a9); |
| 853 | } |
| 854 | #endif /* NCURSES_TPARM_VARARGS */ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 855 | |
| 856 | NCURSES_EXPORT(char *) |
| 857 | tiparm(const char *string,...) |
| 858 | { |
| 859 | va_list ap; |
| 860 | char *result; |
| 861 | |
| 862 | _nc_tparm_err = 0; |
| 863 | va_start(ap, string); |
| 864 | #ifdef TRACE |
| 865 | TPS(tname) = "tiparm"; |
| 866 | #endif /* TRACE */ |
| 867 | result = tparam_internal(FALSE, string, ap); |
| 868 | va_end(ap); |
| 869 | return result; |
| 870 | } |