1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1995-1998 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * tparm.c 31 * 32 * XCurses Library 33 * 34 * Copyright 1990, 1995 by Mrotice Kern Systems Inc. All rights reserved. 35 * 36 */ 37 38 #ifdef M_RCSID 39 #ifndef lint 40 static char rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/tparm.c 1.2 1995/08/31 19:44:03 danv Exp $"; 41 #endif 42 #endif 43 44 /*l 45 * Substitute the given parameters into the given string by the 46 * following rules (taken from terminfo(5)): 47 * 48 * Cursor addressing and other strings requiring parameters 49 * in the terminal are described by a parameterized string 50 * capability, with like escapes %x in it. For example, to 51 * address the cursor, the cup capability is given, using two 52 * parameters: the row and column to address to. (Rows and 53 * columns are numbered from zero and refer to the physical 54 * screen visible to the user, not to any unseen memory.) If 55 * the terminal has memory relative cursor addressing, that can 56 * be indicated by 57 * 58 * The parameter mechanism uses a stack and special % 59 * codes to manipulate it. Typically a sequence will push one 60 * of the parameters onto the stack and then print it in some 61 * format. Often more complex operations are necessary. 62 * 63 * The % encodings have the following meanings: 64 * 65 * %% outputs `%' 66 * %d print pop() like %d in printf() 67 * %2d print pop() like %2d in printf() 68 * %02d print pop() like %02d in printf() 69 * %3d print pop() like %3d in printf() 70 * %03d print pop() like %03d in printf() 71 * %c print pop() like %c in printf() 72 * %s print pop() like %s in printf() 73 * 74 * %p[1-9] push ith parm 75 * %P[a-z] set variable [a-z] to pop() 76 * %g[a-z] get variable [a-z] and push it 77 * %'c' push char constant c 78 * %{nn} push integer constant nn 79 * 80 * %+ %- %* %/ %m 81 * arithmetic (%m is mod): push(pop() op pop()) 82 * %& %| %^ bit operations: push(pop() op pop()) 83 * %= %> %< logical operations: push(pop() op pop()) 84 * %! %~ unary operations push(op pop()) 85 * %i add 1 to first two parms (for ANSI terminals) 86 * 87 * %? expr %t thenpart %e elsepart %; 88 * if-then-else, %e elsepart is optional. 89 * else-if's are possible ala Algol 68: 90 * %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %; 91 * 92 * For those of the above operators which are binary and not commutative, 93 * the stack works in the usual way, with 94 * %gx %gy %m 95 * resulting in x mod y, not the reverse. 96 */ 97 98 #include <private.h> 99 #include <ctype.h> 100 #include <stdarg.h> 101 #include <string.h> 102 #include <m_ord.h> 103 104 #define STACKSIZE 20 105 #define npush(x) if (stack_ptr < STACKSIZE) {\ 106 stack[stack_ptr].num = x; stack_ptr++; } 107 #define npop() (stack_ptr > 0 ? stack[--stack_ptr].num : 0) 108 #define spop() (stack_ptr > 0 ? stack[--stack_ptr].str : (char *) 0) 109 110 typedef union { 111 unsigned int num; 112 char* str; 113 } stack_frame; 114 115 static char buffer[256]; 116 117 /*f 118 * Do parameter substitution. 119 */ 120 const char * 121 #ifdef STDARG_VERSION 122 tparm(const char *string, ...) 123 #else 124 tparm(string, p1, p2, p3, p4, p5, p6, p7, p8, p9) 125 const char *string; 126 long p1, p2, p3, p4, p5, p6, p7, p8, p9; 127 #endif /* STDARG_VERSION */ 128 { 129 char len; 130 long parm[9]; 131 va_list vparm; 132 int varyable[26]; 133 int number, level, x, y; 134 int stack_ptr = 0; 135 stack_frame stack[STACKSIZE]; 136 char *bufptr = buffer; 137 138 #ifdef STDARG_VERSION 139 /* We've had too many problems porting this particular module 140 * to different compilers and machines, in particular RISC, 141 * that we can't make clever assumptions about how variable 142 * arguments might be handled. The best solution is the 143 * slow and simple one. 144 * 145 * We read the va_args into an array, since the tparm format 146 * string may want to address parameters in arbitrary order. 147 */ 148 va_start(vparm, string); 149 for (x = 0; x < 9; ++x) 150 parm[x] = va_arg(vparm, long); 151 va_end(vparm); 152 #else 153 parm[0] = p1; 154 parm[1] = p2; 155 parm[2] = p3; 156 parm[3] = p4; 157 parm[4] = p5; 158 parm[5] = p6; 159 parm[6] = p7; 160 parm[7] = p8; 161 parm[8] = p9; 162 #endif /* STDARG_VERSION */ 163 164 #ifdef M_CURSES_TRACE 165 __m_trace( 166 "tparm(\"%s\", %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld)", 167 string, parm[0], 168 parm[1], parm[2], parm[3], parm[4], 169 parm[5], parm[6], parm[7], parm[8] 170 ); 171 #endif 172 173 while (*string) { 174 if (*string != '%') 175 *(bufptr++) = *string; 176 else { 177 string++; 178 switch (*string) { 179 default: 180 break; 181 case '%': 182 *(bufptr++) = '%'; 183 break; 184 case 'd': 185 bufptr += sprintf(bufptr, "%ld", npop()); 186 break; 187 case '0': 188 len = -(*++string - '0'); 189 if ((len == (char)-2 || len == (char)-3) 190 && *++string == 'd') 191 bufptr += sprintf( 192 bufptr, "%0*ld", len, npop() 193 ); 194 break; 195 case '2': 196 case '3': 197 len = *string++ - '0'; 198 if (*string == 'd') 199 bufptr += sprintf( 200 bufptr, "%*ld", len, npop() 201 ); 202 break; 203 case 'c': 204 *(bufptr++) = (char) npop(); 205 break; 206 case 's': 207 strcpy(bufptr, spop()); 208 bufptr += strlen(bufptr); 209 break; 210 case 'p': 211 string++; 212 if ('1' <= *string && *string <= '9') 213 npush(parm[*string - '1']); 214 break; 215 case 'P': { 216 int i; 217 int c; 218 ++string; 219 c = (int)*string; 220 i = m_ord(c); 221 if (0 < i) 222 varyable[i-1] = npop(); 223 break; 224 } 225 case 'g': { 226 int i; 227 int c; 228 ++string; 229 c = (int)*string; 230 i = m_ord(c); 231 if (0 < i) 232 npush(varyable[i-1]); 233 break; 234 } 235 case '\'': 236 string++; 237 npush(*string); 238 string++; 239 break; 240 case '{': 241 number = 0; 242 string++; 243 while ('0' <= *string && *string <= '9') { 244 number = number * 10 + *string - '0'; 245 string++; 246 } 247 npush(number); 248 break; 249 case '+': 250 y = npop(); 251 x = npop(); 252 npush(x + y); 253 break; 254 case '-': 255 y = npop(); 256 x = npop(); 257 npush(x - y); 258 break; 259 case '*': 260 y = npop(); 261 x = npop(); 262 npush(x * y); 263 break; 264 case '/': 265 y = npop(); 266 x = npop(); 267 npush(x / y); 268 break; 269 case 'm': 270 y = npop(); 271 x = npop(); 272 npush(x % y); 273 break; 274 case '&': 275 y = npop(); 276 x = npop(); 277 npush(x & y); 278 break; 279 case '|': 280 y = npop(); 281 x = npop(); 282 npush(x | y); 283 break; 284 case '^': 285 y = npop(); 286 x = npop(); 287 npush(x ^ y); 288 break; 289 case '=': 290 y = npop(); 291 x = npop(); 292 npush(x == y); 293 break; 294 case '<': 295 y = npop(); 296 x = npop(); 297 npush(x < y); 298 break; 299 case '>': 300 y = npop(); 301 x = npop(); 302 npush(x > y); 303 break; 304 case '!': 305 x = npop(); 306 npush(!x); 307 break; 308 309 case '~': 310 x = npop(); 311 npush(~x); 312 break; 313 case 'i': 314 parm[0]++; 315 parm[1]++; 316 break; 317 case '?': 318 break; 319 case 't': 320 x = npop(); 321 if (x) { 322 /* do nothing; keep executing */ 323 } else { 324 /* scan forward for %e or %; at 325 * level zero */ 326 string++; 327 level = 0; 328 while (*string) { 329 if (*string == '%') { 330 string++; 331 if (*string == '?') 332 level++; 333 else if (*string == ';') { 334 if (level <= 0) 335 break; 336 level--; 337 } else if (*string == 'e' && level == 0) 338 break; 339 } 340 if (*string) 341 string++; 342 } 343 } 344 break; 345 case 'e': 346 /* scan forward for a %; at level zero */ 347 string++; 348 level = 0; 349 while (*string) { 350 if (*string == '%') { 351 string++; 352 if (*string == '?') 353 level++; 354 else if (*string == ';') { 355 if (level <= 0) 356 break; 357 level--; 358 } 359 } 360 if (*string) 361 string++; 362 } 363 break; 364 case ';': 365 break; 366 367 } /* endswitch (*string) */ 368 } /* endelse (*string == '%') */ 369 if (*string == '\0') 370 break; 371 string++; 372 } /* endwhile (*string) */ 373 *bufptr = '\0'; 374 375 return __m_return_pointer("tparm", buffer); 376 } 377