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