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