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