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