+++ /dev/null
-/****************************************************************************
- * Copyright (c) 1998 Free Software Foundation, Inc. *
- * *
- * Permission is hereby granted, free of charge, to any person obtaining a *
- * copy of this software and associated documentation files (the *
- * "Software"), to deal in the Software without restriction, including *
- * without limitation the rights to use, copy, modify, merge, publish, *
- * distribute, distribute with modifications, sublicense, and/or sell *
- * copies of the Software, and to permit persons to whom the Software is *
- * furnished to do so, subject to the following conditions: *
- * *
- * The above copyright notice and this permission notice shall be included *
- * in all copies or substantial portions of the Software. *
- * *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
- * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
- * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
- * *
- * Except as contained in this notice, the name(s) of the above copyright *
- * holders shall not be used in advertising or otherwise to promote the *
- * sale, use or other dealings in this Software without prior written *
- * authorization. *
- ****************************************************************************/
-
-/****************************************************************************
- * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
- * and: Eric S. Raymond <esr@snark.thyrsus.com> *
- ****************************************************************************/
-
-
-/*
- * tparm.c
- *
- */
-
-#include <curses.priv.h>
-
-#include <term.h>
-
-MODULE_ID("$Id: lib_tparm.c,v 1.22 1998/02/11 12:13:54 tom Exp $")
-
-/*
- * char *
- * tparm(string, ...)
- *
- * Substitute the given parameters into the given string by the following
- * rules (taken from terminfo(5)):
- *
- * Cursor addressing and other strings requiring parame-
- * ters 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()
- * %2x print pop() like %2x in printf()
- * %02x print pop() like %02x in printf()
- * %3x print pop() like %3x in printf()
- * %03x print pop() like %03x 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())
- * %A %O logical and & or operations for conditionals
- * %! %~ 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.
- */
-
-#define L_BRACE '{'
-#define R_BRACE '}'
-
-#define STACKSIZE 20
-
-typedef union {
- unsigned int num;
- char *str;
-} stack_frame;
-
-static stack_frame stack[STACKSIZE];
-static int stack_ptr;
-#ifdef TRACE
-static const char *tname;
-#endif /* TRACE */
-
-static char *out_buff;
-static size_t out_size;
-static size_t out_used;
-
-#if NO_LEAKS
-void _nc_free_tparm(void)
-{
- if (out_buff != 0) {
- FreeAndNull(out_buff);
- out_size = 0;
- out_used = 0;
- }
-}
-#endif
-
-static void save_text(char *s)
-{
- size_t want = strlen(s);
- size_t need = want + out_used + 1;
-
- if (need > out_size) {
- out_size = need * 2;
- if (out_buff == 0)
- out_buff = malloc(out_size);
- else
- out_buff = realloc(out_buff, out_size);
- }
- (void)strcpy(out_buff + out_used, s);
- out_used += want;
-}
-
-static void save_number(const char *fmt, int number)
-{
- char temp[80];
- (void)sprintf(temp, fmt, number);
- save_text(temp);
-}
-
-static inline void save_char(int c)
-{
- static char text[2];
- if (c == 0)
- c = 0200;
- text[0] = c;
- save_text(text);
-}
-
-static inline void npush(int x)
-{
- if (stack_ptr < STACKSIZE) {
- stack[stack_ptr].num = x;
- stack_ptr++;
- }
-}
-
-static inline int npop(void)
-{
- return (stack_ptr > 0 ? stack[--stack_ptr].num : 0);
-}
-
-static inline char *spop(void)
-{
- return (stack_ptr > 0 ? stack[--stack_ptr].str : 0);
-}
-
-static inline char *tparam_internal(const char *string, va_list ap)
-{
-#define NUM_VARS 26
-int param[9];
-int popcount;
-int variable[NUM_VARS];
-char len;
-int number;
-int level;
-int x, y;
-int i;
-int varused = -1;
-register const char *cp;
-
- out_used = 0;
- if (string == NULL)
- return NULL;
-
- /*
- * Find the highest parameter-number referred to in the format string.
- * Use this value to limit the number of arguments copied from the
- * variable-length argument list.
- */
- for (cp = string, popcount = number = 0; *cp != '\0'; cp++) {
- if (cp[0] == '%' && cp[1] != '\0') {
- switch (cp[1]) {
- case '%':
- cp++;
- break;
- case 'i':
- if (popcount < 2)
- popcount = 2;
- break;
- case 'p':
- cp++;
- if (cp[1] >= '1' && cp[1] <= '9') {
- int c = cp[1] - '0';
- if (c > popcount)
- popcount = c;
- }
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'd': case 'c': case 's':
- ++number;
- break;
- }
- }
- }
-
- if (number > 9) number = 9;
- for (i = 0; i < max(popcount, number); i++) {
- /*
- * FIXME: potential loss here if sizeof(int) != sizeof(char *).
- * A few caps (such as plab_norm) have string-valued parms.
- */
- param[i] = va_arg(ap, int);
- }
-
- /*
- * This is a termcap compatibility hack. If there are no explicit pop
- * operations in the string, load the stack in such a way that
- * successive pops will grab successive parameters. That will make
- * the expansion of (for example) \E[%d;%dH work correctly in termcap
- * style, which means tparam() will expand termcap strings OK.
- */
- stack_ptr = 0;
- if (popcount == 0) {
- popcount = number;
- for (i = number - 1; i >= 0; i--)
- npush(param[i]);
- }
-
-#ifdef TRACE
- if (_nc_tracing & TRACE_CALLS) {
- for (i = 0; i < popcount; i++)
- save_number(", %d", param[i]);
- _tracef(T_CALLED("%s(%s%s)"), tname, _nc_visbuf(string), out_buff);
- out_used = 0;
- }
-#endif /* TRACE */
-
- while (*string) {
- if (*string != '%')
- save_char(*string);
- else {
- string++;
- switch (*string) {
- default:
- break;
- case '%':
- save_char('%');
- break;
-
- case 'd':
- save_number("%d", npop());
- break;
-
- case 'x':
- save_number("%x", npop());
- break;
-
- case '0':
- string++;
- len = *string;
- if (len == '2' || len == '3')
- {
- ++string;
- if (*string == 'd') {
- if (len == '2')
- save_number("%02d", npop());
- else
- save_number("%03d", npop());
- }
- else if (*string == 'x') {
- if (len == '2')
- save_number("%02x", npop());
- else
- save_number("%03x", npop());
- }
- }
- break;
-
- case '2':
- string++;
- if (*string == 'd') {
- save_number("%2d", npop());
- }
- else if (*string == 'x') {
- save_number("%2x", npop());
- }
- break;
-
- case '3':
- string++;
- if (*string == 'd') {
- save_number("%3d", npop());
- }
- else if (*string == 'x') {
- save_number("%3x", npop());
- }
- break;
-
- case 'c':
- save_char(npop());
- break;
-
- case 's':
- save_text(spop());
- break;
-
- case 'p':
- string++;
- if (*string >= '1' && *string <= '9')
- npush(param[*string - '1']);
- break;
-
- case 'P':
- string++;
- i = (*string - 'a');
- if (i >= 0 && i < NUM_VARS) {
- while (varused < i)
- variable[++varused] = 0;
- variable[i] = npop();
- }
- break;
-
- case 'g':
- string++;
- i = (*string - 'a');
- if (i >= 0 && i < NUM_VARS) {
- while (varused < i)
- variable[++varused] = 0;
- npush(variable[i]);
- }
- break;
-
- case '\'':
- string++;
- npush(*string);
- string++;
- break;
-
- case L_BRACE:
- number = 0;
- string++;
- while (*string >= '0' && *string <= '9') {
- number = number * 10 + *string - '0';
- string++;
- }
- npush(number);
- break;
-
- case '+':
- npush(npop() + npop());
- break;
-
- case '-':
- y = npop();
- x = npop();
- npush(x - y);
- break;
-
- case '*':
- npush(npop() * npop());
- break;
-
- case '/':
- y = npop();
- x = npop();
- npush(x / y);
- break;
-
- case 'm':
- y = npop();
- x = npop();
- npush(x % y);
- break;
-
- case 'A':
- npush(npop() && npop());
- break;
-
- case 'O':
- npush(npop() || npop());
- break;
-
- case '&':
- npush(npop() & npop());
- break;
-
- case '|':
- npush(npop() | npop());
- break;
-
- case '^':
- npush(npop() ^ npop());
- 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 '!':
- npush(! npop());
- break;
-
- case '~':
- npush(~ npop());
- break;
-
- case 'i':
- param[0]++;
- param[1]++;
- break;
-
- case '?':
- break;
-
- case 't':
- x = npop();
- if (!x) {
- /* 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)
- level--;
- else
- break;
- }
- 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)
- level--;
- else
- break;
- }
- }
-
- if (*string)
- string++;
- }
- break;
-
- case ';':
- break;
-
- } /* endswitch (*string) */
- } /* endelse (*string == '%') */
-
- if (*string == '\0')
- break;
-
- string++;
- } /* endwhile (*string) */
-
- if (out_buff == 0)
- out_buff = calloc(1,1);
- if (out_used == 0)
- *out_buff = '\0';
-
- T((T_RETURN("%s"), _nc_visbuf(out_buff)));
- return(out_buff);
-}
-
-char *tparm(const char *string, ...)
-{
-va_list ap;
-char *result;
-
- va_start(ap, string);
-#ifdef TRACE
- tname = "tparm";
-#endif /* TRACE */
- result = tparam_internal(string, ap);
- va_end(ap);
- return result;
-}
-
-#ifdef __UNUSED__ /* we never documented this, and it confuses Emacs */
-char *tparam(const char *string, char *buffer, int bufsiz, ...)
-{
-va_list ap;
-char *result = 0;
-
- va_start(ap, bufsiz);
-#ifdef TRACE
- tname = "tparam";
-#endif /* TRACE */
- if (tparam_internal(string, ap) != 0
- && (int)out_used < bufsiz)
- result = strcpy(buffer, out_buff);
- va_end(ap);
- return result;
-}
-#endif /* __UNUSED__ */