150276Speter/**************************************************************************** 2262685Sdelphij * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32166124Srafan * and: Thomas E. Dickey, 1996 on * 3350276Speter ****************************************************************************/ 3450276Speter 3550276Speter/* 3650276Speter * tparm.c 3750276Speter * 3850276Speter */ 3950276Speter 4050276Speter#include <curses.priv.h> 4150276Speter 4250276Speter#include <ctype.h> 4350276Speter#include <tic.h> 4450276Speter 45262685SdelphijMODULE_ID("$Id: lib_tparm.c,v 1.90 2013/11/09 14:53:05 tom Exp $") 4650276Speter 4750276Speter/* 4850276Speter * char * 4950276Speter * tparm(string, ...) 5050276Speter * 5150276Speter * Substitute the given parameters into the given string by the following 5250276Speter * rules (taken from terminfo(5)): 5350276Speter * 5450276Speter * Cursor addressing and other strings requiring parame- 5550276Speter * ters in the terminal are described by a parameterized string 56262685Sdelphij * capability, with escapes like %x in it. For example, to 5750276Speter * address the cursor, the cup capability is given, using two 5850276Speter * parameters: the row and column to address to. (Rows and 5950276Speter * columns are numbered from zero and refer to the physical 6050276Speter * screen visible to the user, not to any unseen memory.) If 6150276Speter * the terminal has memory relative cursor addressing, that can 6250276Speter * be indicated by 6350276Speter * 6450276Speter * The parameter mechanism uses a stack and special % 6550276Speter * codes to manipulate it. Typically a sequence will push one 6650276Speter * of the parameters onto the stack and then print it in some 6750276Speter * format. Often more complex operations are necessary. 6850276Speter * 6950276Speter * The % encodings have the following meanings: 7050276Speter * 7150276Speter * %% outputs `%' 7250276Speter * %c print pop() like %c in printf() 7350276Speter * %s print pop() like %s in printf() 7450276Speter * %[[:]flags][width[.precision]][doxXs] 7550276Speter * as in printf, flags are [-+#] and space 7666963Speter * The ':' is used to avoid making %+ or %- 7766963Speter * patterns (see below). 7850276Speter * 7950276Speter * %p[1-9] push ith parm 8050276Speter * %P[a-z] set dynamic variable [a-z] to pop() 8150276Speter * %g[a-z] get dynamic variable [a-z] and push it 8250276Speter * %P[A-Z] set static variable [A-Z] to pop() 8350276Speter * %g[A-Z] get static variable [A-Z] and push it 8450276Speter * %l push strlen(pop) 8550276Speter * %'c' push char constant c 8650276Speter * %{nn} push integer constant nn 8750276Speter * 8850276Speter * %+ %- %* %/ %m 8950276Speter * arithmetic (%m is mod): push(pop() op pop()) 9050276Speter * %& %| %^ bit operations: push(pop() op pop()) 9150276Speter * %= %> %< logical operations: push(pop() op pop()) 9250276Speter * %A %O logical and & or operations for conditionals 9350276Speter * %! %~ unary operations push(op pop()) 9450276Speter * %i add 1 to first two parms (for ANSI terminals) 9550276Speter * 9650276Speter * %? expr %t thenpart %e elsepart %; 9750276Speter * if-then-else, %e elsepart is optional. 9850276Speter * else-if's are possible ala Algol 68: 9950276Speter * %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %; 10050276Speter * 10150276Speter * For those of the above operators which are binary and not commutative, 10250276Speter * the stack works in the usual way, with 10350276Speter * %gx %gy %m 10450276Speter * resulting in x mod y, not the reverse. 10550276Speter */ 10650276Speter 10776726SpeterNCURSES_EXPORT_VAR(int) _nc_tparm_err = 0; 10876726Speter 109174993Srafan#define TPS(var) _nc_prescreen.tparm_state.var 110262685Sdelphij#define popcount _nc_popcount /* workaround for NetBSD 6.0 defect */ 11166963Speter 11250276Speter#if NO_LEAKS 11376726SpeterNCURSES_EXPORT(void) 11466963Speter_nc_free_tparm(void) 11550276Speter{ 116174993Srafan if (TPS(out_buff) != 0) { 117174993Srafan FreeAndNull(TPS(out_buff)); 118174993Srafan TPS(out_size) = 0; 119174993Srafan TPS(out_used) = 0; 120174993Srafan FreeAndNull(TPS(fmt_buff)); 121174993Srafan TPS(fmt_size) = 0; 12266963Speter } 12350276Speter} 12450276Speter#endif 12550276Speter 126166124Srafanstatic NCURSES_INLINE void 12766963Speterget_space(size_t need) 12850276Speter{ 129174993Srafan need += TPS(out_used); 130174993Srafan if (need > TPS(out_size)) { 131174993Srafan TPS(out_size) = need * 2; 132262685Sdelphij TYPE_REALLOC(char, TPS(out_size), TPS(out_buff)); 133166124Srafan } 13450276Speter} 13550276Speter 136166124Srafanstatic NCURSES_INLINE void 13766963Spetersave_text(const char *fmt, const char *s, int len) 13850276Speter{ 13966963Speter size_t s_len = strlen(s); 14066963Speter if (len > (int) s_len) 141262629Sdelphij s_len = (size_t) len; 14250276Speter 14366963Speter get_space(s_len + 1); 14450276Speter 145262685Sdelphij _nc_SPRINTF(TPS(out_buff) + TPS(out_used), 146262685Sdelphij _nc_SLIMIT(TPS(out_size) - TPS(out_used)) 147262685Sdelphij fmt, s); 148174993Srafan TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); 14950276Speter} 15050276Speter 151166124Srafanstatic NCURSES_INLINE void 15266963Spetersave_number(const char *fmt, int number, int len) 15350276Speter{ 15466963Speter if (len < 30) 15566963Speter len = 30; /* actually log10(MAX_INT)+1 */ 15650276Speter 157262685Sdelphij get_space((size_t) len + 1); 15850276Speter 159262685Sdelphij _nc_SPRINTF(TPS(out_buff) + TPS(out_used), 160262685Sdelphij _nc_SLIMIT(TPS(out_size) - TPS(out_used)) 161262685Sdelphij fmt, number); 162174993Srafan TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); 16350276Speter} 16450276Speter 165166124Srafanstatic NCURSES_INLINE void 16666963Spetersave_char(int c) 16750276Speter{ 16866963Speter if (c == 0) 16966963Speter c = 0200; 170262685Sdelphij get_space((size_t) 1); 171184989Srafan TPS(out_buff)[TPS(out_used)++] = (char) c; 17250276Speter} 17350276Speter 174166124Srafanstatic NCURSES_INLINE void 17566963Speternpush(int x) 17650276Speter{ 177174993Srafan if (TPS(stack_ptr) < STACKSIZE) { 178174993Srafan TPS(stack)[TPS(stack_ptr)].num_type = TRUE; 179174993Srafan TPS(stack)[TPS(stack_ptr)].data.num = x; 180174993Srafan TPS(stack_ptr)++; 18176726Speter } else { 182174993Srafan DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(TPS(tparam_base)))); 18376726Speter _nc_tparm_err++; 18466963Speter } 18550276Speter} 18650276Speter 187166124Srafanstatic NCURSES_INLINE int 18866963Speternpop(void) 18950276Speter{ 19066963Speter int result = 0; 191174993Srafan if (TPS(stack_ptr) > 0) { 192174993Srafan TPS(stack_ptr)--; 193174993Srafan if (TPS(stack)[TPS(stack_ptr)].num_type) 194174993Srafan result = TPS(stack)[TPS(stack_ptr)].data.num; 19576726Speter } else { 196174993Srafan DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(TPS(tparam_base)))); 19776726Speter _nc_tparm_err++; 19866963Speter } 19966963Speter return result; 20050276Speter} 20150276Speter 202166124Srafanstatic NCURSES_INLINE void 20366963Speterspush(char *x) 20450276Speter{ 205174993Srafan if (TPS(stack_ptr) < STACKSIZE) { 206174993Srafan TPS(stack)[TPS(stack_ptr)].num_type = FALSE; 207174993Srafan TPS(stack)[TPS(stack_ptr)].data.str = x; 208174993Srafan TPS(stack_ptr)++; 20976726Speter } else { 210174993Srafan DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(TPS(tparam_base)))); 21176726Speter _nc_tparm_err++; 21266963Speter } 21350276Speter} 21450276Speter 215166124Srafanstatic NCURSES_INLINE char * 21666963Speterspop(void) 21750276Speter{ 21866963Speter static char dummy[] = ""; /* avoid const-cast */ 21966963Speter char *result = dummy; 220174993Srafan if (TPS(stack_ptr) > 0) { 221174993Srafan TPS(stack_ptr)--; 222174993Srafan if (!TPS(stack)[TPS(stack_ptr)].num_type 223174993Srafan && TPS(stack)[TPS(stack_ptr)].data.str != 0) 224174993Srafan result = TPS(stack)[TPS(stack_ptr)].data.str; 22576726Speter } else { 226174993Srafan DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(TPS(tparam_base)))); 22776726Speter _nc_tparm_err++; 22866963Speter } 22966963Speter return result; 23066963Speter} 23150276Speter 232166124Srafanstatic NCURSES_INLINE const char * 23366963Speterparse_format(const char *s, char *format, int *len) 23466963Speter{ 235166124Srafan *len = 0; 236166124Srafan if (format != 0) { 237166124Srafan bool done = FALSE; 238166124Srafan bool allowminus = FALSE; 239166124Srafan bool dot = FALSE; 240166124Srafan bool err = FALSE; 241166124Srafan char *fmt = format; 242166124Srafan int my_width = 0; 243166124Srafan int my_prec = 0; 244166124Srafan int value = 0; 24566963Speter 246166124Srafan *len = 0; 247166124Srafan *format++ = '%'; 248166124Srafan while (*s != '\0' && !done) { 249166124Srafan switch (*s) { 250166124Srafan case 'c': /* FALLTHRU */ 251166124Srafan case 'd': /* FALLTHRU */ 252166124Srafan case 'o': /* FALLTHRU */ 253166124Srafan case 'x': /* FALLTHRU */ 254166124Srafan case 'X': /* FALLTHRU */ 255166124Srafan case 's': 256166124Srafan *format++ = *s; 257166124Srafan done = TRUE; 258166124Srafan break; 259166124Srafan case '.': 26066963Speter *format++ = *s++; 261166124Srafan if (dot) { 26266963Speter err = TRUE; 263166124Srafan } else { /* value before '.' is the width */ 264166124Srafan dot = TRUE; 265166124Srafan my_width = value; 266166124Srafan } 267166124Srafan value = 0; 268166124Srafan break; 269166124Srafan case '#': 27066963Speter *format++ = *s++; 271166124Srafan break; 272166124Srafan case ' ': 273166124Srafan *format++ = *s++; 274166124Srafan break; 275166124Srafan case ':': 276166124Srafan s++; 277166124Srafan allowminus = TRUE; 278166124Srafan break; 279166124Srafan case '-': 280166124Srafan if (allowminus) { 281166124Srafan *format++ = *s++; 282166124Srafan } else { 283166124Srafan done = TRUE; 284166124Srafan } 285166124Srafan break; 286166124Srafan default: 287166124Srafan if (isdigit(UChar(*s))) { 288166124Srafan value = (value * 10) + (*s - '0'); 289166124Srafan if (value > 10000) 290166124Srafan err = TRUE; 291166124Srafan *format++ = *s++; 292166124Srafan } else { 293166124Srafan done = TRUE; 294166124Srafan } 29566963Speter } 29666963Speter } 29766963Speter 298166124Srafan /* 299166124Srafan * If we found an error, ignore (and remove) the flags. 300166124Srafan */ 301166124Srafan if (err) { 302166124Srafan my_width = my_prec = value = 0; 303166124Srafan format = fmt; 304166124Srafan *format++ = '%'; 305166124Srafan *format++ = *s; 306166124Srafan } 30766963Speter 308166124Srafan /* 309166124Srafan * Any value after '.' is the precision. If we did not see '.', then 310166124Srafan * the value is the width. 311166124Srafan */ 312166124Srafan if (dot) 313166124Srafan my_prec = value; 314166124Srafan else 315166124Srafan my_width = value; 31666963Speter 317166124Srafan *format = '\0'; 318166124Srafan /* return maximum string length in print */ 319166124Srafan *len = (my_width > my_prec) ? my_width : my_prec; 320166124Srafan } 32166963Speter return s; 32250276Speter} 32350276Speter 32450276Speter#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z') 32550276Speter#define isLOWER(c) ((c) >= 'a' && (c) <= 'z') 32650276Speter 327166124Srafan/* 328166124Srafan * Analyze the string to see how many parameters we need from the varargs list, 329166124Srafan * and what their types are. We will only accept string parameters if they 330166124Srafan * appear as a %l or %s format following an explicit parameter reference (e.g., 331166124Srafan * %p2%s). All other parameters are numbers. 332166124Srafan * 333166124Srafan * 'number' counts coarsely the number of pop's we see in the string, and 334166124Srafan * 'popcount' shows the highest parameter number in the string. We would like 335166124Srafan * to simply use the latter count, but if we are reading termcap strings, there 336166124Srafan * may be cases that we cannot see the explicit parameter numbers. 337166124Srafan */ 338166124SrafanNCURSES_EXPORT(int) 339166124Srafan_nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount) 34050276Speter{ 341166124Srafan size_t len2; 342166124Srafan int i; 343166124Srafan int lastpop = -1; 34466963Speter int len; 345166124Srafan int number = 0; 346166124Srafan const char *cp = string; 34766963Speter static char dummy[] = ""; 34850276Speter 349166124Srafan if (cp == 0) 350166124Srafan return 0; 35150276Speter 352174993Srafan if ((len2 = strlen(cp)) > TPS(fmt_size)) { 353174993Srafan TPS(fmt_size) = len2 + TPS(fmt_size) + 2; 354174993Srafan TPS(fmt_buff) = typeRealloc(char, TPS(fmt_size), TPS(fmt_buff)); 355174993Srafan if (TPS(fmt_buff) == 0) 356174993Srafan return 0; 35766963Speter } 35866963Speter 359166124Srafan memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM); 360166124Srafan *popcount = 0; 36166963Speter 362166124Srafan while ((cp - string) < (int) len2) { 36366963Speter if (*cp == '%') { 36466963Speter cp++; 365174993Srafan cp = parse_format(cp, TPS(fmt_buff), &len); 36666963Speter switch (*cp) { 36766963Speter default: 36866963Speter break; 36966963Speter 37066963Speter case 'd': /* FALLTHRU */ 37166963Speter case 'o': /* FALLTHRU */ 37266963Speter case 'x': /* FALLTHRU */ 37366963Speter case 'X': /* FALLTHRU */ 37466963Speter case 'c': /* FALLTHRU */ 375166124Srafan if (lastpop <= 0) 376166124Srafan number++; 37766963Speter lastpop = -1; 37866963Speter break; 37966963Speter 38066963Speter case 'l': 38166963Speter case 's': 38266963Speter if (lastpop > 0) 38366963Speter p_is_s[lastpop - 1] = dummy; 38466963Speter ++number; 38566963Speter break; 38666963Speter 38766963Speter case 'p': 38866963Speter cp++; 389166124Srafan i = (UChar(*cp) - '0'); 390166124Srafan if (i >= 0 && i <= NUM_PARM) { 39166963Speter lastpop = i; 392166124Srafan if (lastpop > *popcount) 393166124Srafan *popcount = lastpop; 39450276Speter } 39566963Speter break; 39650276Speter 39766963Speter case 'P': 398166124Srafan ++number; 399166124Srafan ++cp; 400166124Srafan break; 401166124Srafan 40266963Speter case 'g': 40366963Speter cp++; 40466963Speter break; 40566963Speter 40666963Speter case S_QUOTE: 40766963Speter cp += 2; 40866963Speter lastpop = -1; 40966963Speter break; 41066963Speter 41166963Speter case L_BRACE: 41266963Speter cp++; 413166124Srafan while (isdigit(UChar(*cp))) { 41466963Speter cp++; 41566963Speter } 41666963Speter break; 41766963Speter 41866963Speter case '+': 41966963Speter case '-': 42066963Speter case '*': 42166963Speter case '/': 42266963Speter case 'm': 42366963Speter case 'A': 42466963Speter case 'O': 42566963Speter case '&': 42666963Speter case '|': 42766963Speter case '^': 42866963Speter case '=': 42966963Speter case '<': 43066963Speter case '>': 431166124Srafan lastpop = -1; 432166124Srafan number += 2; 433166124Srafan break; 434166124Srafan 43566963Speter case '!': 43666963Speter case '~': 43766963Speter lastpop = -1; 438166124Srafan ++number; 43966963Speter break; 44066963Speter 44166963Speter case 'i': 442166124Srafan /* will add 1 to first (usually two) parameters */ 44366963Speter break; 44466963Speter } 44550276Speter } 44666963Speter if (*cp != '\0') 44766963Speter cp++; 44866963Speter } 44950276Speter 450166124Srafan if (number > NUM_PARM) 451166124Srafan number = NUM_PARM; 452166124Srafan return number; 453166124Srafan} 454166124Srafan 455166124Srafanstatic NCURSES_INLINE char * 456262685Sdelphijtparam_internal(int use_TPARM_ARG, const char *string, va_list ap) 457166124Srafan{ 458166124Srafan char *p_is_s[NUM_PARM]; 459166124Srafan TPARM_ARG param[NUM_PARM]; 460262629Sdelphij int popcount = 0; 461166124Srafan int number; 462262629Sdelphij int num_args; 463166124Srafan int len; 464166124Srafan int level; 465166124Srafan int x, y; 466166124Srafan int i; 467166124Srafan const char *cp = string; 468166124Srafan size_t len2; 469166124Srafan 470166124Srafan if (cp == NULL) 471166124Srafan return NULL; 472166124Srafan 473174993Srafan TPS(out_used) = 0; 474166124Srafan len2 = strlen(cp); 475166124Srafan 476166124Srafan /* 477166124Srafan * Find the highest parameter-number referred to in the format string. 478166124Srafan * Use this value to limit the number of arguments copied from the 479166124Srafan * variable-length argument list. 480166124Srafan */ 481166124Srafan number = _nc_tparm_analyze(cp, p_is_s, &popcount); 482174993Srafan if (TPS(fmt_buff) == 0) 483166124Srafan return NULL; 484166124Srafan 485262629Sdelphij if (number > NUM_PARM) 486262629Sdelphij number = NUM_PARM; 487262629Sdelphij if (popcount > NUM_PARM) 488262629Sdelphij popcount = NUM_PARM; 489262629Sdelphij num_args = max(popcount, number); 490262629Sdelphij 491262629Sdelphij for (i = 0; i < num_args; i++) { 49250276Speter /* 49366963Speter * A few caps (such as plab_norm) have string-valued parms. 49466963Speter * We'll have to assume that the caller knows the difference, since 495166124Srafan * a char* and an int may not be the same size on the stack. The 496166124Srafan * normal prototype for this uses 9 long's, which is consistent with 497166124Srafan * our va_arg() usage. 49850276Speter */ 49966963Speter if (p_is_s[i] != 0) { 50066963Speter p_is_s[i] = va_arg(ap, char *); 501262629Sdelphij param[i] = 0; 502262629Sdelphij } else if (use_TPARM_ARG) { 503262629Sdelphij param[i] = va_arg(ap, TPARM_ARG); 50466963Speter } else { 505262629Sdelphij param[i] = (TPARM_ARG) va_arg(ap, int); 50650276Speter } 50766963Speter } 50850276Speter 50966963Speter /* 51066963Speter * This is a termcap compatibility hack. If there are no explicit pop 51166963Speter * operations in the string, load the stack in such a way that 51266963Speter * successive pops will grab successive parameters. That will make 51366963Speter * the expansion of (for example) \E[%d;%dH work correctly in termcap 51466963Speter * style, which means tparam() will expand termcap strings OK. 51566963Speter */ 516174993Srafan TPS(stack_ptr) = 0; 51766963Speter if (popcount == 0) { 51866963Speter popcount = number; 519184989Srafan for (i = number - 1; i >= 0; i--) { 520184989Srafan if (p_is_s[i]) 521184989Srafan spush(p_is_s[i]); 522184989Srafan else 523262629Sdelphij npush((int) param[i]); 524184989Srafan } 52566963Speter } 52650276Speter#ifdef TRACE 527174993Srafan if (USE_TRACEF(TRACE_CALLS)) { 528262685Sdelphij for (i = 0; i < num_args; i++) { 52966963Speter if (p_is_s[i] != 0) 53066963Speter save_text(", %s", _nc_visbuf(p_is_s[i]), 0); 53166963Speter else 532262629Sdelphij save_number(", %d", (int) param[i], 0); 53350276Speter } 534174993Srafan _tracef(T_CALLED("%s(%s%s)"), TPS(tname), _nc_visbuf(cp), TPS(out_buff)); 535174993Srafan TPS(out_used) = 0; 536174993Srafan _nc_unlock_global(tracef); 53766963Speter } 53850276Speter#endif /* TRACE */ 53950276Speter 540166124Srafan while ((cp - string) < (int) len2) { 541166124Srafan if (*cp != '%') { 542166124Srafan save_char(UChar(*cp)); 54366963Speter } else { 544174993Srafan TPS(tparam_base) = cp++; 545174993Srafan cp = parse_format(cp, TPS(fmt_buff), &len); 546166124Srafan switch (*cp) { 54766963Speter default: 54866963Speter break; 54966963Speter case '%': 55066963Speter save_char('%'); 55166963Speter break; 55250276Speter 55366963Speter case 'd': /* FALLTHRU */ 55466963Speter case 'o': /* FALLTHRU */ 55566963Speter case 'x': /* FALLTHRU */ 55666963Speter case 'X': /* FALLTHRU */ 557174993Srafan save_number(TPS(fmt_buff), npop(), len); 558166124Srafan break; 559166124Srafan 56066963Speter case 'c': /* FALLTHRU */ 561166124Srafan save_char(npop()); 56266963Speter break; 56350276Speter 56466963Speter case 'l': 565262685Sdelphij npush((int) strlen(spop())); 56666963Speter break; 56750276Speter 56866963Speter case 's': 569174993Srafan save_text(TPS(fmt_buff), spop(), len); 57066963Speter break; 57150276Speter 57266963Speter case 'p': 573166124Srafan cp++; 574166124Srafan i = (UChar(*cp) - '1'); 575166124Srafan if (i >= 0 && i < NUM_PARM) { 57666963Speter if (p_is_s[i]) 57766963Speter spush(p_is_s[i]); 57866963Speter else 579262629Sdelphij npush((int) param[i]); 58066963Speter } 58166963Speter break; 58250276Speter 58366963Speter case 'P': 584166124Srafan cp++; 585166124Srafan if (isUPPER(*cp)) { 586166124Srafan i = (UChar(*cp) - 'A'); 587174993Srafan TPS(static_vars)[i] = npop(); 588166124Srafan } else if (isLOWER(*cp)) { 589166124Srafan i = (UChar(*cp) - 'a'); 590174993Srafan TPS(dynamic_var)[i] = npop(); 59166963Speter } 59266963Speter break; 59350276Speter 59466963Speter case 'g': 595166124Srafan cp++; 596166124Srafan if (isUPPER(*cp)) { 597166124Srafan i = (UChar(*cp) - 'A'); 598174993Srafan npush(TPS(static_vars)[i]); 599166124Srafan } else if (isLOWER(*cp)) { 600166124Srafan i = (UChar(*cp) - 'a'); 601174993Srafan npush(TPS(dynamic_var)[i]); 60266963Speter } 60366963Speter break; 60450276Speter 60566963Speter case S_QUOTE: 606166124Srafan cp++; 607166124Srafan npush(UChar(*cp)); 608166124Srafan cp++; 60966963Speter break; 61050276Speter 61166963Speter case L_BRACE: 61266963Speter number = 0; 613166124Srafan cp++; 614166124Srafan while (isdigit(UChar(*cp))) { 615166124Srafan number = (number * 10) + (UChar(*cp) - '0'); 616166124Srafan cp++; 61766963Speter } 61866963Speter npush(number); 61966963Speter break; 62050276Speter 62166963Speter case '+': 62266963Speter npush(npop() + npop()); 62366963Speter break; 62450276Speter 62566963Speter case '-': 62666963Speter y = npop(); 62766963Speter x = npop(); 62866963Speter npush(x - y); 62966963Speter break; 63050276Speter 63166963Speter case '*': 63266963Speter npush(npop() * npop()); 63366963Speter break; 63450276Speter 63566963Speter case '/': 63666963Speter y = npop(); 63766963Speter x = npop(); 63866963Speter npush(y ? (x / y) : 0); 63966963Speter break; 64050276Speter 64166963Speter case 'm': 64266963Speter y = npop(); 64366963Speter x = npop(); 64466963Speter npush(y ? (x % y) : 0); 64566963Speter break; 64650276Speter 64766963Speter case 'A': 64866963Speter npush(npop() && npop()); 64966963Speter break; 65050276Speter 65166963Speter case 'O': 65266963Speter npush(npop() || npop()); 65366963Speter break; 65450276Speter 65566963Speter case '&': 65666963Speter npush(npop() & npop()); 65766963Speter break; 65850276Speter 65966963Speter case '|': 66066963Speter npush(npop() | npop()); 66166963Speter break; 66250276Speter 66366963Speter case '^': 66466963Speter npush(npop() ^ npop()); 66566963Speter break; 66650276Speter 66766963Speter case '=': 66866963Speter y = npop(); 66966963Speter x = npop(); 67066963Speter npush(x == y); 67166963Speter break; 67250276Speter 67366963Speter case '<': 67466963Speter y = npop(); 67566963Speter x = npop(); 67666963Speter npush(x < y); 67766963Speter break; 67850276Speter 67966963Speter case '>': 68066963Speter y = npop(); 68166963Speter x = npop(); 68266963Speter npush(x > y); 68366963Speter break; 68450276Speter 68566963Speter case '!': 68666963Speter npush(!npop()); 68766963Speter break; 68850276Speter 68966963Speter case '~': 69066963Speter npush(~npop()); 69166963Speter break; 69250276Speter 69366963Speter case 'i': 69466963Speter if (p_is_s[0] == 0) 69566963Speter param[0]++; 69666963Speter if (p_is_s[1] == 0) 69766963Speter param[1]++; 69866963Speter break; 69950276Speter 70066963Speter case '?': 70166963Speter break; 70266963Speter 70366963Speter case 't': 70466963Speter x = npop(); 70566963Speter if (!x) { 70666963Speter /* scan forward for %e or %; at level zero */ 707166124Srafan cp++; 70866963Speter level = 0; 709166124Srafan while (*cp) { 710166124Srafan if (*cp == '%') { 711166124Srafan cp++; 712166124Srafan if (*cp == '?') 71366963Speter level++; 714166124Srafan else if (*cp == ';') { 71566963Speter if (level > 0) 71666963Speter level--; 71766963Speter else 71866963Speter break; 719166124Srafan } else if (*cp == 'e' && level == 0) 72050276Speter break; 72166963Speter } 72250276Speter 723166124Srafan if (*cp) 724166124Srafan cp++; 72566963Speter } 72666963Speter } 72766963Speter break; 72850276Speter 72966963Speter case 'e': 73066963Speter /* scan forward for a %; at level zero */ 731166124Srafan cp++; 73266963Speter level = 0; 733166124Srafan while (*cp) { 734166124Srafan if (*cp == '%') { 735166124Srafan cp++; 736166124Srafan if (*cp == '?') 73766963Speter level++; 738166124Srafan else if (*cp == ';') { 73966963Speter if (level > 0) 74066963Speter level--; 74166963Speter else 74250276Speter break; 74366963Speter } 74466963Speter } 74550276Speter 746166124Srafan if (*cp) 747166124Srafan cp++; 74866963Speter } 74966963Speter break; 75050276Speter 75166963Speter case ';': 75266963Speter break; 75350276Speter 754166124Srafan } /* endswitch (*cp) */ 755166124Srafan } /* endelse (*cp == '%') */ 75650276Speter 757166124Srafan if (*cp == '\0') 75866963Speter break; 75950276Speter 760166124Srafan cp++; 761166124Srafan } /* endwhile (*cp) */ 76250276Speter 763262685Sdelphij get_space((size_t) 1); 764174993Srafan TPS(out_buff)[TPS(out_used)] = '\0'; 76550276Speter 766174993Srafan T((T_RETURN("%s"), _nc_visbuf(TPS(out_buff)))); 767174993Srafan return (TPS(out_buff)); 76850276Speter} 76950276Speter 770166124Srafan#if NCURSES_TPARM_VARARGS 771166124Srafan#define tparm_varargs tparm 772166124Srafan#else 773166124Srafan#define tparm_proto tparm 774166124Srafan#endif 775166124Srafan 77676726SpeterNCURSES_EXPORT(char *) 777166124Srafantparm_varargs(NCURSES_CONST char *string,...) 77850276Speter{ 77966963Speter va_list ap; 78066963Speter char *result; 78150276Speter 78276726Speter _nc_tparm_err = 0; 78366963Speter va_start(ap, string); 78450276Speter#ifdef TRACE 785174993Srafan TPS(tname) = "tparm"; 78650276Speter#endif /* TRACE */ 787262629Sdelphij result = tparam_internal(TRUE, string, ap); 78866963Speter va_end(ap); 78966963Speter return result; 79050276Speter} 791166124Srafan 792166124Srafan#if !NCURSES_TPARM_VARARGS 793166124SrafanNCURSES_EXPORT(char *) 794166124Srafantparm_proto(NCURSES_CONST char *string, 795166124Srafan TPARM_ARG a1, 796166124Srafan TPARM_ARG a2, 797166124Srafan TPARM_ARG a3, 798166124Srafan TPARM_ARG a4, 799166124Srafan TPARM_ARG a5, 800166124Srafan TPARM_ARG a6, 801166124Srafan TPARM_ARG a7, 802166124Srafan TPARM_ARG a8, 803166124Srafan TPARM_ARG a9) 804166124Srafan{ 805166124Srafan return tparm_varargs(string, a1, a2, a3, a4, a5, a6, a7, a8, a9); 806166124Srafan} 807166124Srafan#endif /* NCURSES_TPARM_VARARGS */ 808262629Sdelphij 809262629SdelphijNCURSES_EXPORT(char *) 810262629Sdelphijtiparm(const char *string,...) 811262629Sdelphij{ 812262629Sdelphij va_list ap; 813262629Sdelphij char *result; 814262629Sdelphij 815262629Sdelphij _nc_tparm_err = 0; 816262629Sdelphij va_start(ap, string); 817262629Sdelphij#ifdef TRACE 818262629Sdelphij TPS(tname) = "tiparm"; 819262629Sdelphij#endif /* TRACE */ 820262629Sdelphij result = tparam_internal(FALSE, string, ap); 821262629Sdelphij va_end(ap); 822262629Sdelphij return result; 823262629Sdelphij} 824