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