/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1995-1998 by Sun Microsystems, Inc. * All rights reserved. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * tparm.c * * XCurses Library * * Copyright 1990, 1995 by Mrotice Kern Systems Inc. All rights reserved. * */ #ifdef M_RCSID #ifndef lint static char rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/tparm.c 1.2 1995/08/31 19:44:03 danv Exp $"; #endif #endif /*l * Substitute the given parameters into the given string by the * following rules (taken from terminfo(5)): * * Cursor addressing and other strings requiring parameters * in the terminal are described by a parameterized string * capability, with like escapes %x in it. For example, to * address the cursor, the cup capability is given, using two * parameters: the row and column to address to. (Rows and * columns are numbered from zero and refer to the physical * screen visible to the user, not to any unseen memory.) If * the terminal has memory relative cursor addressing, that can * be indicated by * * The parameter mechanism uses a stack and special % * codes to manipulate it. Typically a sequence will push one * of the parameters onto the stack and then print it in some * format. Often more complex operations are necessary. * * The % encodings have the following meanings: * * %% outputs `%' * %d print pop() like %d in printf() * %2d print pop() like %2d in printf() * %02d print pop() like %02d in printf() * %3d print pop() like %3d in printf() * %03d print pop() like %03d in printf() * %c print pop() like %c in printf() * %s print pop() like %s in printf() * * %p[1-9] push ith parm * %P[a-z] set variable [a-z] to pop() * %g[a-z] get variable [a-z] and push it * %'c' push char constant c * %{nn} push integer constant nn * * %+ %- %* %/ %m * arithmetic (%m is mod): push(pop() op pop()) * %& %| %^ bit operations: push(pop() op pop()) * %= %> %< logical operations: push(pop() op pop()) * %! %~ unary operations push(op pop()) * %i add 1 to first two parms (for ANSI terminals) * * %? expr %t thenpart %e elsepart %; * if-then-else, %e elsepart is optional. * else-if's are possible ala Algol 68: * %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %; * * For those of the above operators which are binary and not commutative, * the stack works in the usual way, with * %gx %gy %m * resulting in x mod y, not the reverse. */ #include #include #include #include #include #define STACKSIZE 20 #define npush(x) if (stack_ptr < STACKSIZE) {\ stack[stack_ptr].num = x; stack_ptr++; } #define npop() (stack_ptr > 0 ? stack[--stack_ptr].num : 0) #define spop() (stack_ptr > 0 ? stack[--stack_ptr].str : (char *) 0) typedef union { unsigned int num; char* str; } stack_frame; static char buffer[256]; /*f * Do parameter substitution. */ const char * #ifdef STDARG_VERSION tparm(const char *string, ...) #else tparm(string, p1, p2, p3, p4, p5, p6, p7, p8, p9) const char *string; long p1, p2, p3, p4, p5, p6, p7, p8, p9; #endif /* STDARG_VERSION */ { char len; long parm[9]; va_list vparm; int varyable[26]; int number, level, x, y; int stack_ptr = 0; stack_frame stack[STACKSIZE]; char *bufptr = buffer; #ifdef STDARG_VERSION /* We've had too many problems porting this particular module * to different compilers and machines, in particular RISC, * that we can't make clever assumptions about how variable * arguments might be handled. The best solution is the * slow and simple one. * * We read the va_args into an array, since the tparm format * string may want to address parameters in arbitrary order. */ va_start(vparm, string); for (x = 0; x < 9; ++x) parm[x] = va_arg(vparm, long); va_end(vparm); #else parm[0] = p1; parm[1] = p2; parm[2] = p3; parm[3] = p4; parm[4] = p5; parm[5] = p6; parm[6] = p7; parm[7] = p8; parm[8] = p9; #endif /* STDARG_VERSION */ #ifdef M_CURSES_TRACE __m_trace( "tparm(\"%s\", %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld)", string, parm[0], parm[1], parm[2], parm[3], parm[4], parm[5], parm[6], parm[7], parm[8] ); #endif while (*string) { if (*string != '%') *(bufptr++) = *string; else { string++; switch (*string) { default: break; case '%': *(bufptr++) = '%'; break; case 'd': bufptr += sprintf(bufptr, "%ld", npop()); break; case '0': len = -(*++string - '0'); if ((len == (char)-2 || len == (char)-3) && *++string == 'd') bufptr += sprintf( bufptr, "%0*ld", len, npop() ); break; case '2': case '3': len = *string++ - '0'; if (*string == 'd') bufptr += sprintf( bufptr, "%*ld", len, npop() ); break; case 'c': *(bufptr++) = (char) npop(); break; case 's': strcpy(bufptr, spop()); bufptr += strlen(bufptr); break; case 'p': string++; if ('1' <= *string && *string <= '9') npush(parm[*string - '1']); break; case 'P': { int i; int c; ++string; c = (int)*string; i = m_ord(c); if (0 < i) varyable[i-1] = npop(); break; } case 'g': { int i; int c; ++string; c = (int)*string; i = m_ord(c); if (0 < i) npush(varyable[i-1]); break; } case '\'': string++; npush(*string); string++; break; case '{': number = 0; string++; while ('0' <= *string && *string <= '9') { number = number * 10 + *string - '0'; string++; } npush(number); break; case '+': y = npop(); x = npop(); npush(x + y); break; case '-': y = npop(); x = npop(); npush(x - y); break; case '*': y = npop(); x = npop(); npush(x * y); break; case '/': y = npop(); x = npop(); npush(x / y); break; case 'm': y = npop(); x = npop(); npush(x % y); break; case '&': y = npop(); x = npop(); npush(x & y); break; case '|': y = npop(); x = npop(); npush(x | y); break; case '^': y = npop(); x = npop(); npush(x ^ y); break; case '=': y = npop(); x = npop(); npush(x == y); break; case '<': y = npop(); x = npop(); npush(x < y); break; case '>': y = npop(); x = npop(); npush(x > y); break; case '!': x = npop(); npush(!x); break; case '~': x = npop(); npush(~x); break; case 'i': parm[0]++; parm[1]++; break; case '?': break; case 't': x = npop(); if (x) { /* do nothing; keep executing */ } else { /* scan forward for %e or %; at * level zero */ string++; level = 0; while (*string) { if (*string == '%') { string++; if (*string == '?') level++; else if (*string == ';') { if (level <= 0) break; level--; } else if (*string == 'e' && level == 0) break; } if (*string) string++; } } break; case 'e': /* scan forward for a %; at level zero */ string++; level = 0; while (*string) { if (*string == '%') { string++; if (*string == '?') level++; else if (*string == ';') { if (level <= 0) break; level--; } } if (*string) string++; } break; case ';': break; } /* endswitch (*string) */ } /* endelse (*string == '%') */ if (*string == '\0') break; string++; } /* endwhile (*string) */ *bufptr = '\0'; return __m_return_pointer("tparm", buffer); }