Home | History | Annotate | Line # | Download | only in libterminfo
tparm.c revision 1.8.2.2
      1  1.8.2.2  tls /* $NetBSD: tparm.c,v 1.8.2.2 2013/06/23 06:21:08 tls Exp $ */
      2      1.1  roy 
      3      1.1  roy /*
      4  1.8.2.1  tls  * Copyright (c) 2009, 2011, 2013 The NetBSD Foundation, Inc.
      5      1.1  roy  *
      6      1.1  roy  * This code is derived from software contributed to The NetBSD Foundation
      7      1.1  roy  * by Roy Marples.
      8      1.1  roy  *
      9      1.1  roy  * Redistribution and use in source and binary forms, with or without
     10      1.1  roy  * modification, are permitted provided that the following conditions
     11      1.1  roy  * are met:
     12      1.1  roy  * 1. Redistributions of source code must retain the above copyright
     13      1.1  roy  *    notice, this list of conditions and the following disclaimer.
     14      1.1  roy  * 2. Redistributions in binary form must reproduce the above copyright
     15      1.1  roy  *    notice, this list of conditions and the following disclaimer in the
     16      1.1  roy  *    documentation and/or other materials provided with the distribution.
     17      1.1  roy  *
     18      1.1  roy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19      1.1  roy  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20      1.1  roy  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21      1.1  roy  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22      1.1  roy  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23      1.1  roy  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24      1.1  roy  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25      1.1  roy  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26      1.1  roy  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27      1.1  roy  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28      1.1  roy  */
     29      1.1  roy 
     30      1.1  roy #include <sys/cdefs.h>
     31  1.8.2.2  tls __RCSID("$NetBSD: tparm.c,v 1.8.2.2 2013/06/23 06:21:08 tls Exp $");
     32      1.8  roy #include <sys/param.h>
     33      1.1  roy 
     34      1.1  roy #include <assert.h>
     35      1.1  roy #include <ctype.h>
     36      1.1  roy #include <errno.h>
     37      1.1  roy #include <stdarg.h>
     38      1.1  roy #include <stdio.h>
     39      1.1  roy #include <stdlib.h>
     40      1.1  roy #include <string.h>
     41      1.1  roy #include <term_private.h>
     42      1.1  roy #include <term.h>
     43      1.1  roy 
     44  1.8.2.1  tls #define LONG_STR_MAX ((CHAR_BIT * sizeof(long)) / 3)
     45  1.8.2.1  tls #define BUFINC 128	/* Size to increament the terminal buffer by */
     46  1.8.2.1  tls 
     47  1.8.2.2  tls #define VA_LONG_LONG	1
     48  1.8.2.1  tls #define VA_CHAR_INT	2
     49  1.8.2.2  tls //#define VA_CHAR_LONG	3	/* No need for this yet */
     50  1.8.2.1  tls 
     51      1.1  roy static TERMINAL *dumbterm; /* For non thread safe functions */
     52      1.1  roy 
     53      1.2  roy typedef struct {
     54  1.8.2.1  tls 	long nums[20];
     55      1.1  roy 	char *strings[20];
     56      1.1  roy 	size_t offset;
     57      1.1  roy } TPSTACK;
     58      1.1  roy 
     59      1.2  roy typedef struct {
     60  1.8.2.1  tls 	long num;
     61      1.1  roy 	char *string;
     62      1.1  roy } TPVAR;
     63      1.1  roy 
     64      1.1  roy static int
     65  1.8.2.1  tls push(long num, char *string, TPSTACK *stack)
     66      1.1  roy {
     67  1.8.2.1  tls 	if (stack->offset >= sizeof(stack->nums)) {
     68      1.1  roy 		errno = E2BIG;
     69      1.1  roy 		return -1;
     70      1.1  roy 	}
     71      1.1  roy 	stack->nums[stack->offset] = num;
     72      1.1  roy 	stack->strings[stack->offset] = string;
     73      1.1  roy 	stack->offset++;
     74      1.1  roy 	return 0;
     75      1.1  roy }
     76      1.1  roy 
     77      1.1  roy static int
     78  1.8.2.1  tls pop(long *num, char **string, TPSTACK *stack)
     79      1.1  roy {
     80      1.1  roy 	if (stack->offset == 0) {
     81      1.5  roy 		if (num)
     82      1.5  roy 			*num = 0;
     83      1.5  roy 		if (string)
     84      1.5  roy 			*string = NULL;
     85      1.1  roy 		errno = E2BIG;
     86      1.1  roy 		return -1;
     87      1.1  roy 	}
     88      1.1  roy 	stack->offset--;
     89      1.1  roy 	if (num)
     90      1.1  roy 		*num = stack->nums[stack->offset];
     91      1.1  roy 	if (string)
     92      1.1  roy 		*string = stack->strings[stack->offset];
     93      1.1  roy 	return 0;
     94      1.1  roy }
     95      1.1  roy 
     96      1.1  roy static char *
     97      1.1  roy checkbuf(TERMINAL *term, size_t len)
     98      1.1  roy {
     99      1.1  roy 	char *buf;
    100  1.8.2.2  tls 
    101      1.1  roy 	if (term->_bufpos + len >= term->_buflen) {
    102  1.8.2.1  tls 		len = term->_buflen + MAX(len, BUFINC);
    103      1.1  roy 		buf = realloc(term->_buf, len);
    104      1.1  roy 		if (buf == NULL)
    105      1.8  roy 			return NULL;
    106      1.1  roy 		term->_buf = buf;
    107      1.1  roy 		term->_buflen = len;
    108      1.1  roy 	}
    109      1.1  roy 	return term->_buf;
    110      1.1  roy }
    111      1.1  roy 
    112      1.1  roy static size_t
    113      1.1  roy ochar(TERMINAL *term, int c)
    114      1.1  roy {
    115      1.1  roy 	if (c == 0)
    116      1.1  roy 		c = 0200;
    117      1.1  roy 	/* Check we have space and a terminator */
    118      1.1  roy 	if (checkbuf(term, 2) == NULL)
    119      1.1  roy 		return 0;
    120      1.1  roy 	term->_buf[term->_bufpos++] = (char)c;
    121      1.1  roy 	return 1;
    122      1.1  roy }
    123      1.1  roy 
    124      1.1  roy static size_t
    125  1.8.2.1  tls onum(TERMINAL *term, const char *fmt, int num, unsigned int len)
    126      1.1  roy {
    127      1.1  roy 	size_t l;
    128      1.1  roy 
    129  1.8.2.1  tls 	if (len < LONG_STR_MAX)
    130  1.8.2.1  tls 		len = LONG_STR_MAX;
    131  1.8.2.1  tls 	if (checkbuf(term, len + 2) == NULL)
    132      1.1  roy 		return 0;
    133      1.1  roy 	l = sprintf(term->_buf + term->_bufpos, fmt, num);
    134      1.1  roy 	term->_bufpos += l;
    135      1.1  roy 	return l;
    136      1.1  roy }
    137      1.1  roy 
    138  1.8.2.1  tls /*
    139  1.8.2.1  tls   Make a pass through the string so we can work out
    140  1.8.2.1  tls   which parameters are ints and which are char *.
    141  1.8.2.1  tls   Basically we only use char * if %p[1-9] is followed by %l or %s.
    142  1.8.2.1  tls */
    143  1.8.2.1  tls int
    144  1.8.2.1  tls _ti_parm_analyse(const char *str, int *piss, int piss_len)
    145  1.8.2.1  tls {
    146  1.8.2.1  tls 	int nparm, lpop;
    147  1.8.2.1  tls 	char c;
    148  1.8.2.1  tls 
    149  1.8.2.1  tls 	nparm = 0;
    150  1.8.2.1  tls 	lpop = -1;
    151  1.8.2.1  tls 	while ((c = *str++) != '\0') {
    152  1.8.2.1  tls 		if (c != '%')
    153  1.8.2.1  tls 			continue;
    154  1.8.2.1  tls 		c = *str++;
    155  1.8.2.1  tls 		switch (c) {
    156  1.8.2.1  tls 			case 'l': /* FALLTHROUGH */
    157  1.8.2.1  tls 			case 's':
    158  1.8.2.1  tls 				if (lpop > 0) {
    159  1.8.2.1  tls 					if (lpop <= piss_len)
    160  1.8.2.1  tls 						piss[lpop - 1] = 1;
    161  1.8.2.1  tls 					else if (piss)
    162  1.8.2.1  tls 						errno = E2BIG;
    163  1.8.2.1  tls 				}
    164  1.8.2.1  tls 				break;
    165  1.8.2.1  tls 			case 'p':
    166  1.8.2.1  tls 				c = *str++;
    167  1.8.2.1  tls 				if (c < '1' || c > '9') {
    168  1.8.2.1  tls 					errno = EINVAL;
    169  1.8.2.1  tls 					continue;
    170  1.8.2.1  tls 				} else {
    171  1.8.2.1  tls 					lpop = c - '0';
    172  1.8.2.1  tls 					if (lpop > nparm)
    173  1.8.2.1  tls 						nparm = lpop;
    174  1.8.2.1  tls 				}
    175  1.8.2.1  tls 				break;
    176  1.8.2.1  tls 			default:
    177  1.8.2.1  tls 				lpop = -1;
    178  1.8.2.1  tls 		}
    179  1.8.2.1  tls 	}
    180  1.8.2.1  tls 
    181  1.8.2.1  tls 	return nparm;
    182  1.8.2.1  tls }
    183  1.8.2.1  tls 
    184      1.1  roy static char *
    185  1.8.2.1  tls _ti_tiparm(TERMINAL *term, const char *str, int va_type, va_list parms)
    186      1.1  roy {
    187      1.1  roy 	char c, fmt[64], *fp, *ostr;
    188  1.8.2.1  tls 	long val, val2;
    189  1.8.2.1  tls 	long dnums[26]; /* dynamic variables a-z, not preserved */
    190      1.1  roy 	size_t l, max;
    191      1.1  roy 	TPSTACK stack;
    192  1.8.2.1  tls 	TPVAR params[TPARM_MAX];
    193  1.8.2.1  tls 	unsigned int done, dot, minus, width, precision, olen;
    194  1.8.2.1  tls 	int piss[TPARM_MAX]; /* Parameter IS String - piss ;) */
    195      1.1  roy 
    196      1.1  roy 	if (str == NULL)
    197      1.1  roy 		return NULL;
    198      1.1  roy 
    199      1.1  roy 	/*
    200      1.1  roy 	  If not passed a terminal, malloc a dummy one.
    201      1.1  roy 	  This means we can preserve buffers and variables per terminal and
    202      1.1  roy 	  still work with non thread safe functions (which sadly are still the
    203      1.1  roy 	  norm and standard).
    204      1.1  roy 	*/
    205      1.1  roy 	if (term == NULL) {
    206      1.1  roy 		if (dumbterm == NULL) {
    207      1.1  roy 			dumbterm = malloc(sizeof(*dumbterm));
    208      1.1  roy 			if (dumbterm == NULL)
    209      1.1  roy 				return NULL;
    210      1.1  roy 			dumbterm->_buflen = 0;
    211      1.1  roy 		}
    212      1.1  roy 		term = dumbterm;
    213      1.1  roy 	}
    214      1.1  roy 
    215      1.1  roy 	term->_bufpos = 0;
    216      1.1  roy 	/* Ensure we have an initial buffer */
    217      1.1  roy 	if (term->_buflen == 0) {
    218  1.8.2.1  tls 		term->_buf = malloc(BUFINC);
    219      1.1  roy 		if (term->_buf == NULL)
    220      1.1  roy 			return NULL;
    221  1.8.2.1  tls 		term->_buflen = BUFINC;
    222      1.1  roy 	}
    223      1.1  roy 
    224      1.1  roy 	memset(&piss, 0, sizeof(piss));
    225  1.8.2.1  tls 	max = _ti_parm_analyse(str, piss, TPARM_MAX);
    226      1.1  roy 
    227      1.1  roy 	/* Put our parameters into variables */
    228      1.1  roy 	memset(&params, 0, sizeof(params));
    229      1.1  roy 	for (l = 0; l < max; l++) {
    230  1.8.2.1  tls 		if (piss[l]) {
    231  1.8.2.1  tls 			if (va_type == VA_LONG_LONG) {
    232  1.8.2.1  tls 				/* This only works if char * fits into a long
    233  1.8.2.1  tls 				 * on this platform. */
    234  1.8.2.1  tls 				if (sizeof(char *) <= sizeof(long)/*CONSTCOND*/)
    235  1.8.2.1  tls 					params[l].string =
    236  1.8.2.1  tls 					    (char *)va_arg(parms, long);
    237  1.8.2.1  tls 				else {
    238  1.8.2.1  tls 					errno = ENOTSUP;
    239  1.8.2.1  tls 					return NULL;
    240  1.8.2.1  tls 				}
    241  1.8.2.1  tls 			} else
    242  1.8.2.1  tls 				params[l].string = va_arg(parms, char *);
    243  1.8.2.1  tls 		} else {
    244  1.8.2.1  tls 			if (va_type == VA_CHAR_INT)
    245  1.8.2.1  tls 				params[l].num = (long)va_arg(parms, int);
    246  1.8.2.1  tls 			else
    247  1.8.2.1  tls 				params[l].num = va_arg(parms, long);
    248  1.8.2.1  tls 		}
    249      1.1  roy 	}
    250      1.1  roy 
    251      1.1  roy 	memset(&stack, 0, sizeof(stack));
    252      1.1  roy 	while ((c = *str++) != '\0') {
    253      1.1  roy 		if (c != '%' || (c = *str++) == '%') {
    254      1.1  roy 			if (c == '\0')
    255      1.1  roy 				break;
    256      1.1  roy 			if (ochar(term, c) == 0)
    257      1.1  roy 				return NULL;
    258      1.1  roy 			continue;
    259      1.1  roy 		}
    260      1.1  roy 
    261      1.1  roy 		/* Handle formatting. */
    262      1.1  roy 		fp = fmt;
    263      1.1  roy 		*fp++ = '%';
    264      1.1  roy 		done = dot = minus = width = precision = 0;
    265      1.1  roy 		val = 0;
    266      1.1  roy 		while (done == 0 && (size_t)(fp - fmt) < sizeof(fmt)) {
    267      1.1  roy 			switch (c) {
    268      1.1  roy 			case 'c': /* FALLTHROUGH */
    269  1.8.2.1  tls 			case 's':
    270  1.8.2.1  tls 				*fp++ = c;
    271  1.8.2.1  tls 				done = 1;
    272  1.8.2.1  tls 				break;
    273      1.1  roy 			case 'd': /* FALLTHROUGH */
    274      1.1  roy 			case 'o': /* FALLTHROUGH */
    275      1.1  roy 			case 'x': /* FALLTHROUGH */
    276      1.1  roy 			case 'X': /* FALLTHROUGH */
    277  1.8.2.1  tls 				*fp++ = 'l';
    278      1.1  roy 				*fp++ = c;
    279      1.1  roy 				done = 1;
    280      1.1  roy 				break;
    281      1.1  roy 			case '#': /* FALLTHROUGH */
    282      1.1  roy 			case ' ':
    283      1.1  roy 				*fp++ = c;
    284      1.1  roy 				break;
    285      1.1  roy 			case '.':
    286      1.1  roy 				*fp++ = c;
    287      1.1  roy 				if (dot == 0) {
    288      1.1  roy 					dot = 1;
    289      1.1  roy 					width = val;
    290      1.1  roy 				} else
    291      1.1  roy 					done = 2;
    292      1.1  roy 				val = 0;
    293      1.1  roy 				break;
    294      1.1  roy 			case ':':
    295      1.1  roy 				minus = 1;
    296      1.1  roy 				break;
    297      1.1  roy 			case '-':
    298      1.1  roy 				if (minus)
    299      1.1  roy 					*fp++ = c;
    300      1.1  roy 				else
    301      1.1  roy 					done = 1;
    302      1.1  roy 				break;
    303      1.1  roy 			default:
    304      1.1  roy 				if (isdigit((unsigned char)c)) {
    305      1.1  roy 					val = (val * 10) + (c - '0');
    306      1.1  roy 					if (val > 10000)
    307      1.1  roy 						done = 2;
    308      1.1  roy 					else
    309      1.1  roy 						*fp++ = c;
    310      1.1  roy 				} else
    311      1.1  roy 					done = 1;
    312      1.1  roy 			}
    313      1.1  roy 			if (done == 0)
    314      1.1  roy 				c = *str++;
    315      1.1  roy 		}
    316      1.1  roy 		if (done == 2) {
    317      1.1  roy 			/* Found an error in the format */
    318      1.1  roy 			fp = fmt + 1;
    319      1.1  roy 			*fp = *str;
    320      1.1  roy 			olen = 0;
    321      1.1  roy 		} else {
    322      1.1  roy 			if (dot == 0)
    323      1.1  roy 				width = val;
    324      1.1  roy 			else
    325      1.1  roy 				precision = val;
    326  1.8.2.1  tls 			olen = MAX(width, precision);
    327      1.1  roy 		}
    328      1.1  roy 		*fp++ = '\0';
    329      1.1  roy 
    330      1.1  roy 		/* Handle commands */
    331      1.1  roy 		switch (c) {
    332      1.1  roy 		case 'c':
    333      1.5  roy 			pop(&val, NULL, &stack);
    334      1.1  roy 			if (ochar(term, (unsigned char)val) == 0)
    335      1.1  roy 				return NULL;
    336      1.1  roy 			break;
    337      1.1  roy 		case 's':
    338      1.5  roy 			pop(NULL, &ostr, &stack);
    339      1.1  roy 			if (ostr != NULL) {
    340      1.1  roy 				l = strlen(ostr);
    341      1.1  roy 				if (l < (size_t)olen)
    342      1.1  roy 					l = olen;
    343      1.1  roy 				if (checkbuf(term, (size_t)(l + 1)) == NULL)
    344      1.1  roy 					return NULL;
    345      1.1  roy 				l = sprintf(term->_buf + term->_bufpos,
    346      1.1  roy 				    fmt, ostr);
    347      1.1  roy 				term->_bufpos += l;
    348      1.1  roy 			}
    349      1.1  roy 			break;
    350      1.1  roy 		case 'l':
    351      1.5  roy 			pop(NULL, &ostr, &stack);
    352      1.1  roy 			if (ostr == NULL)
    353      1.1  roy 				l = 0;
    354      1.1  roy 			else
    355      1.1  roy 				l = strlen(ostr);
    356  1.8.2.1  tls #ifdef NCURSES_COMPAT_57
    357  1.8.2.1  tls 			if (onum(term, "%ld", (long)l, 0) == 0)
    358      1.1  roy 				return NULL;
    359  1.8.2.1  tls #else
    360  1.8.2.1  tls 			push((long)l, NULL, &stack);
    361  1.8.2.1  tls #endif
    362      1.1  roy 			break;
    363      1.1  roy 		case 'd': /* FALLTHROUGH */
    364      1.1  roy 		case 'o': /* FALLTHROUGH */
    365      1.1  roy 		case 'x': /* FALLTHROUGH */
    366      1.1  roy 		case 'X':
    367      1.5  roy 			pop(&val, NULL, &stack);
    368  1.8.2.1  tls 			if (onum(term, fmt, (int)val, olen) == 0)
    369      1.1  roy 				return NULL;
    370      1.1  roy 			break;
    371      1.1  roy 		case 'p':
    372      1.5  roy 			if (*str < '1' || *str > '9')
    373      1.5  roy 				break;
    374      1.1  roy 			l = *str++ - '1';
    375      1.1  roy 			if (push(params[l].num, params[l].string, &stack))
    376      1.1  roy 				return NULL;
    377      1.1  roy 			break;
    378      1.1  roy 		case 'P':
    379      1.5  roy 			pop(&val, NULL, &stack);
    380      1.1  roy 			if (*str >= 'a' && *str <= 'z')
    381      1.1  roy 				dnums[*str - 'a'] = val;
    382      1.1  roy 			else if (*str >= 'A' && *str <= 'Z')
    383      1.1  roy 				term->_snums[*str - 'A'] = val;
    384      1.1  roy 			break;
    385      1.1  roy 		case 'g':
    386      1.1  roy 			if (*str >= 'a' && *str <= 'z') {
    387      1.1  roy 				if (push(dnums[*str - 'a'], NULL, &stack))
    388      1.1  roy 					return NULL;
    389      1.1  roy 			} else if (*str >= 'A' && *str <= 'Z') {
    390      1.1  roy 				if (push(term->_snums[*str - 'A'],
    391      1.1  roy 					NULL, &stack))
    392      1.1  roy 					return NULL;
    393      1.1  roy 			}
    394      1.1  roy 			break;
    395      1.1  roy 		case 'i':
    396      1.1  roy 			if (piss[0] == 0)
    397      1.1  roy 				params[0].num++;
    398      1.1  roy 			if (piss[1] == 0)
    399      1.1  roy 				params[1].num++;
    400      1.1  roy 			break;
    401      1.1  roy 		case '\'':
    402  1.8.2.1  tls 			if (push((long)(unsigned char)*str++, NULL, &stack))
    403      1.1  roy 				return NULL;
    404      1.1  roy 			while (*str != '\0' && *str != '\'')
    405      1.1  roy 				str++;
    406      1.1  roy 			if (*str == '\'')
    407      1.1  roy 				str++;
    408      1.1  roy 			break;
    409      1.1  roy 		case '{':
    410      1.1  roy 			val = 0;
    411      1.3  roy 			for (; isdigit((unsigned char)*str);  str++)
    412      1.1  roy 				val = (val * 10) + (*str - '0');
    413      1.1  roy 			if (push(val, NULL, &stack))
    414      1.1  roy 				return NULL;
    415      1.1  roy 			while (*str != '\0' && *str != '}')
    416      1.1  roy 				str++;
    417      1.1  roy 			if (*str == '}')
    418      1.1  roy 				str++;
    419      1.1  roy 			break;
    420      1.1  roy 		case '+': /* FALLTHROUGH */
    421      1.1  roy 		case '-': /* FALLTHROUGH */
    422      1.1  roy 		case '*': /* FALLTHROUGH */
    423      1.1  roy 		case '/': /* FALLTHROUGH */
    424      1.1  roy 		case 'm': /* FALLTHROUGH */
    425      1.1  roy 		case 'A': /* FALLTHROUGH */
    426      1.1  roy 		case 'O': /* FALLTHROUGH */
    427      1.1  roy 		case '&': /* FALLTHROUGH */
    428      1.1  roy 		case '|': /* FALLTHROUGH */
    429      1.1  roy 		case '^': /* FALLTHROUGH */
    430      1.1  roy 		case '=': /* FALLTHROUGH */
    431      1.1  roy 		case '<': /* FALLTHROUGH */
    432      1.1  roy 		case '>':
    433      1.5  roy 			pop(&val, NULL, &stack);
    434      1.5  roy 			pop(&val2, NULL, &stack);
    435      1.1  roy 			switch (c) {
    436      1.1  roy 			case '+':
    437      1.1  roy 				val = val + val2;
    438      1.1  roy 				break;
    439      1.1  roy 			case '-':
    440      1.1  roy 				val = val2 - val;
    441      1.1  roy 				break;
    442      1.1  roy 			case '*':
    443      1.1  roy 				val = val * val2;
    444      1.1  roy 				break;
    445      1.1  roy 			case '/':
    446      1.1  roy 				val = val ? val2 / val : 0;
    447      1.1  roy 				break;
    448      1.1  roy 			case 'm':
    449      1.1  roy 				val = val ? val2 % val : 0;
    450      1.1  roy 				break;
    451      1.1  roy 			case 'A':
    452      1.1  roy 				val = val && val2;
    453      1.1  roy 				break;
    454      1.1  roy 			case 'O':
    455      1.1  roy 				val = val || val2;
    456      1.1  roy 				break;
    457      1.1  roy 			case '&':
    458      1.1  roy 				val = val & val2;
    459      1.1  roy 				break;
    460      1.1  roy 			case '|':
    461      1.1  roy 				val = val | val2;
    462      1.1  roy 				break;
    463      1.1  roy 			case '^':
    464      1.1  roy 				val = val ^ val2;
    465      1.1  roy 				break;
    466      1.1  roy 			case '=':
    467      1.1  roy 				val = val == val2;
    468      1.1  roy 				break;
    469      1.1  roy 			case '<':
    470      1.1  roy 				val = val2 < val;
    471      1.1  roy 				break;
    472      1.1  roy 			case '>':
    473      1.1  roy 				val = val2 > val;
    474      1.1  roy 				break;
    475      1.1  roy 			}
    476      1.1  roy 			if (push(val, NULL, &stack))
    477      1.1  roy 				return NULL;
    478      1.1  roy 			break;
    479      1.1  roy 		case '!':
    480      1.1  roy 		case '~':
    481      1.5  roy 			pop(&val, NULL, &stack);
    482  1.8.2.1  tls 			switch (c) {
    483      1.1  roy 			case '!':
    484      1.1  roy 				val = !val;
    485      1.1  roy 				break;
    486      1.1  roy 			case '~':
    487      1.1  roy 				val = ~val;
    488      1.1  roy 				break;
    489      1.1  roy 			}
    490      1.1  roy 			if (push(val, NULL, &stack))
    491      1.1  roy 				return NULL;
    492      1.1  roy 			break;
    493      1.1  roy 		case '?': /* if */
    494      1.1  roy 			break;
    495      1.1  roy 		case 't': /* then */
    496      1.5  roy 			pop(&val, NULL, &stack);
    497  1.8.2.1  tls 			if (val == 0) {
    498      1.1  roy 				l = 0;
    499      1.1  roy 				for (; *str != '\0'; str++) {
    500      1.1  roy 					if (*str != '%')
    501      1.1  roy 						continue;
    502      1.1  roy 					str++;
    503      1.1  roy 					if (*str == '?')
    504      1.1  roy 						l++;
    505      1.1  roy 					else if (*str == ';') {
    506      1.1  roy 						if (l > 0)
    507      1.1  roy 							l--;
    508  1.8.2.1  tls 						else {
    509  1.8.2.1  tls 							str++;
    510      1.1  roy 							break;
    511  1.8.2.1  tls 						}
    512  1.8.2.1  tls 					} else if (*str == 'e' && l == 0) {
    513  1.8.2.1  tls 						str++;
    514      1.1  roy 						break;
    515  1.8.2.1  tls 					}
    516      1.1  roy 				}
    517      1.1  roy 			}
    518      1.1  roy 			break;
    519      1.1  roy 		case 'e': /* else */
    520      1.1  roy 			l = 0;
    521      1.1  roy 			for (; *str != '\0'; str++) {
    522      1.1  roy 				if (*str != '%')
    523      1.1  roy 					continue;
    524      1.1  roy 				str++;
    525      1.1  roy 				if (*str == '?')
    526      1.1  roy 					l++;
    527      1.1  roy 				else if (*str == ';') {
    528      1.1  roy 					if (l > 0)
    529      1.1  roy 						l--;
    530  1.8.2.1  tls 					else {
    531  1.8.2.1  tls 						str++;
    532      1.1  roy 						break;
    533  1.8.2.1  tls 					}
    534      1.1  roy 				}
    535      1.1  roy 			}
    536      1.1  roy 			break;
    537      1.1  roy 		case ';': /* fi */
    538      1.1  roy 			break;
    539      1.1  roy 		}
    540      1.1  roy 	}
    541      1.1  roy 	term->_buf[term->_bufpos] = '\0';
    542      1.1  roy 	return term->_buf;
    543      1.1  roy }
    544      1.1  roy 
    545      1.1  roy char *
    546      1.6  roy ti_tiparm(TERMINAL *term, const char *str, ...)
    547      1.1  roy {
    548      1.1  roy 	va_list va;
    549      1.1  roy 	char *ret;
    550      1.1  roy 
    551      1.1  roy 	_DIAGASSERT(term != NULL);
    552      1.1  roy 	_DIAGASSERT(str != NULL);
    553      1.1  roy 
    554      1.1  roy 	va_start(va, str);
    555  1.8.2.1  tls 	ret = _ti_tiparm(term, str, VA_CHAR_INT, va);
    556      1.1  roy 	va_end(va);
    557      1.1  roy 	return ret;
    558      1.1  roy }
    559      1.1  roy 
    560      1.1  roy char *
    561      1.6  roy tiparm(const char *str, ...)
    562      1.1  roy {
    563      1.1  roy 	va_list va;
    564      1.1  roy 	char *ret;
    565  1.8.2.2  tls 
    566      1.1  roy 	_DIAGASSERT(str != NULL);
    567      1.1  roy 
    568      1.1  roy 	va_start(va, str);
    569  1.8.2.1  tls 	ret = _ti_tiparm(NULL, str, VA_CHAR_INT, va);
    570  1.8.2.1  tls 	va_end(va);
    571  1.8.2.1  tls 	return ret;
    572  1.8.2.1  tls }
    573  1.8.2.1  tls 
    574  1.8.2.1  tls #ifdef VA_CHAR_LONG
    575  1.8.2.1  tls char *
    576  1.8.2.1  tls ti_tlparm(TERMINAL *term, const char *str, ...)
    577  1.8.2.1  tls {
    578  1.8.2.1  tls 	va_list va;
    579  1.8.2.1  tls 	char *ret;
    580  1.8.2.1  tls 
    581  1.8.2.1  tls 	_DIAGASSERT(term != NULL);
    582  1.8.2.1  tls 	_DIAGASSERT(str != NULL);
    583  1.8.2.1  tls 
    584  1.8.2.1  tls 	va_start(va, str);
    585  1.8.2.1  tls 	ret = _ti_tiparm(term, str, VA_CHAR_LONG, va);
    586  1.8.2.1  tls 	va_end(va);
    587  1.8.2.1  tls 	return ret;
    588  1.8.2.1  tls }
    589  1.8.2.1  tls 
    590  1.8.2.1  tls char *
    591  1.8.2.1  tls tlparm(const char *str, ...)
    592  1.8.2.1  tls {
    593  1.8.2.1  tls 	va_list va;
    594  1.8.2.1  tls 	char *ret;
    595  1.8.2.2  tls 
    596  1.8.2.1  tls 	_DIAGASSERT(str != NULL);
    597  1.8.2.1  tls 
    598  1.8.2.1  tls 	va_start(va, str);
    599  1.8.2.1  tls 	ret = _ti_tiparm(NULL, str, VA_CHAR_LONG, va);
    600  1.8.2.1  tls 	va_end(va);
    601  1.8.2.1  tls 	return ret;
    602  1.8.2.1  tls }
    603  1.8.2.1  tls #endif
    604  1.8.2.1  tls 
    605  1.8.2.1  tls static char *
    606  1.8.2.1  tls _tparm(const char *str, ...)
    607  1.8.2.1  tls {
    608  1.8.2.1  tls 	va_list va;
    609  1.8.2.1  tls 	char *ret;
    610  1.8.2.2  tls 
    611  1.8.2.1  tls 	_DIAGASSERT(str != NULL);
    612  1.8.2.1  tls 
    613  1.8.2.1  tls 	va_start(va, str);
    614  1.8.2.1  tls 	ret = _ti_tiparm(NULL, str, VA_LONG_LONG, va);
    615      1.1  roy 	va_end(va);
    616      1.1  roy 	return ret;
    617      1.1  roy }
    618      1.1  roy 
    619      1.1  roy char *
    620      1.1  roy tparm(const char *str,
    621  1.8.2.1  tls     long p1, long p2, long p3, long p4, long p5,
    622  1.8.2.1  tls     long p6, long p7, long p8, long p9)
    623      1.1  roy {
    624      1.7  roy 
    625  1.8.2.1  tls 	return _tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9);
    626      1.1  roy }
    627