xref: /dflybsd-src/contrib/ncurses/ncurses/tinfo/lib_tparm.c (revision fdd4e1e09e069e93fafdd13458a9c511bca7e833)
1*fdd4e1e0SJan Lentfer /****************************************************************************
2*fdd4e1e0SJan Lentfer  * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc.              *
3*fdd4e1e0SJan Lentfer  *                                                                          *
4*fdd4e1e0SJan Lentfer  * Permission is hereby granted, free of charge, to any person obtaining a  *
5*fdd4e1e0SJan Lentfer  * copy of this software and associated documentation files (the            *
6*fdd4e1e0SJan Lentfer  * "Software"), to deal in the Software without restriction, including      *
7*fdd4e1e0SJan Lentfer  * without limitation the rights to use, copy, modify, merge, publish,      *
8*fdd4e1e0SJan Lentfer  * distribute, distribute with modifications, sublicense, and/or sell       *
9*fdd4e1e0SJan Lentfer  * copies of the Software, and to permit persons to whom the Software is    *
10*fdd4e1e0SJan Lentfer  * furnished to do so, subject to the following conditions:                 *
11*fdd4e1e0SJan Lentfer  *                                                                          *
12*fdd4e1e0SJan Lentfer  * The above copyright notice and this permission notice shall be included  *
13*fdd4e1e0SJan Lentfer  * in all copies or substantial portions of the Software.                   *
14*fdd4e1e0SJan Lentfer  *                                                                          *
15*fdd4e1e0SJan Lentfer  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16*fdd4e1e0SJan Lentfer  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17*fdd4e1e0SJan Lentfer  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18*fdd4e1e0SJan Lentfer  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19*fdd4e1e0SJan Lentfer  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20*fdd4e1e0SJan Lentfer  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21*fdd4e1e0SJan Lentfer  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22*fdd4e1e0SJan Lentfer  *                                                                          *
23*fdd4e1e0SJan Lentfer  * Except as contained in this notice, the name(s) of the above copyright   *
24*fdd4e1e0SJan Lentfer  * holders shall not be used in advertising or otherwise to promote the     *
25*fdd4e1e0SJan Lentfer  * sale, use or other dealings in this Software without prior written       *
26*fdd4e1e0SJan Lentfer  * authorization.                                                           *
27*fdd4e1e0SJan Lentfer  ****************************************************************************/
28*fdd4e1e0SJan Lentfer 
29*fdd4e1e0SJan Lentfer /****************************************************************************
30*fdd4e1e0SJan Lentfer  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31*fdd4e1e0SJan Lentfer  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32*fdd4e1e0SJan Lentfer  *     and: Thomas E. Dickey, 1996 on                                       *
33*fdd4e1e0SJan Lentfer  ****************************************************************************/
34*fdd4e1e0SJan Lentfer 
35*fdd4e1e0SJan Lentfer /*
36*fdd4e1e0SJan Lentfer  *	tparm.c
37*fdd4e1e0SJan Lentfer  *
38*fdd4e1e0SJan Lentfer  */
39*fdd4e1e0SJan Lentfer 
40*fdd4e1e0SJan Lentfer #include <curses.priv.h>
41*fdd4e1e0SJan Lentfer 
42*fdd4e1e0SJan Lentfer #include <ctype.h>
43*fdd4e1e0SJan Lentfer #include <term.h>
44*fdd4e1e0SJan Lentfer #include <tic.h>
45*fdd4e1e0SJan Lentfer 
46*fdd4e1e0SJan Lentfer MODULE_ID("$Id: lib_tparm.c,v 1.68 2004/02/07 20:52:51 tom Exp $")
47*fdd4e1e0SJan Lentfer 
48*fdd4e1e0SJan Lentfer /*
49*fdd4e1e0SJan Lentfer  *	char *
50*fdd4e1e0SJan Lentfer  *	tparm(string, ...)
51*fdd4e1e0SJan Lentfer  *
52*fdd4e1e0SJan Lentfer  *	Substitute the given parameters into the given string by the following
53*fdd4e1e0SJan Lentfer  *	rules (taken from terminfo(5)):
54*fdd4e1e0SJan Lentfer  *
55*fdd4e1e0SJan Lentfer  *	     Cursor addressing and other strings  requiring  parame-
56*fdd4e1e0SJan Lentfer  *	ters in the terminal are described by a parameterized string
57*fdd4e1e0SJan Lentfer  *	capability, with like escapes %x in  it.   For  example,  to
58*fdd4e1e0SJan Lentfer  *	address  the  cursor, the cup capability is given, using two
59*fdd4e1e0SJan Lentfer  *	parameters: the row and column to  address  to.   (Rows  and
60*fdd4e1e0SJan Lentfer  *	columns  are  numbered  from  zero and refer to the physical
61*fdd4e1e0SJan Lentfer  *	screen visible to the user, not to any  unseen  memory.)  If
62*fdd4e1e0SJan Lentfer  *	the terminal has memory relative cursor addressing, that can
63*fdd4e1e0SJan Lentfer  *	be indicated by
64*fdd4e1e0SJan Lentfer  *
65*fdd4e1e0SJan Lentfer  *	     The parameter mechanism uses  a  stack  and  special  %
66*fdd4e1e0SJan Lentfer  *	codes  to manipulate it.  Typically a sequence will push one
67*fdd4e1e0SJan Lentfer  *	of the parameters onto the stack and then print it  in  some
68*fdd4e1e0SJan Lentfer  *	format.  Often more complex operations are necessary.
69*fdd4e1e0SJan Lentfer  *
70*fdd4e1e0SJan Lentfer  *	     The % encodings have the following meanings:
71*fdd4e1e0SJan Lentfer  *
72*fdd4e1e0SJan Lentfer  *	     %%        outputs `%'
73*fdd4e1e0SJan Lentfer  *	     %c        print pop() like %c in printf()
74*fdd4e1e0SJan Lentfer  *	     %s        print pop() like %s in printf()
75*fdd4e1e0SJan Lentfer  *           %[[:]flags][width[.precision]][doxXs]
76*fdd4e1e0SJan Lentfer  *                     as in printf, flags are [-+#] and space
77*fdd4e1e0SJan Lentfer  *                     The ':' is used to avoid making %+ or %-
78*fdd4e1e0SJan Lentfer  *                     patterns (see below).
79*fdd4e1e0SJan Lentfer  *
80*fdd4e1e0SJan Lentfer  *	     %p[1-9]   push ith parm
81*fdd4e1e0SJan Lentfer  *	     %P[a-z]   set dynamic variable [a-z] to pop()
82*fdd4e1e0SJan Lentfer  *	     %g[a-z]   get dynamic variable [a-z] and push it
83*fdd4e1e0SJan Lentfer  *	     %P[A-Z]   set static variable [A-Z] to pop()
84*fdd4e1e0SJan Lentfer  *	     %g[A-Z]   get static variable [A-Z] and push it
85*fdd4e1e0SJan Lentfer  *	     %l        push strlen(pop)
86*fdd4e1e0SJan Lentfer  *	     %'c'      push char constant c
87*fdd4e1e0SJan Lentfer  *	     %{nn}     push integer constant nn
88*fdd4e1e0SJan Lentfer  *
89*fdd4e1e0SJan Lentfer  *	     %+ %- %* %/ %m
90*fdd4e1e0SJan Lentfer  *	               arithmetic (%m is mod): push(pop() op pop())
91*fdd4e1e0SJan Lentfer  *	     %& %| %^  bit operations: push(pop() op pop())
92*fdd4e1e0SJan Lentfer  *	     %= %> %<  logical operations: push(pop() op pop())
93*fdd4e1e0SJan Lentfer  *	     %A %O     logical and & or operations for conditionals
94*fdd4e1e0SJan Lentfer  *	     %! %~     unary operations push(op pop())
95*fdd4e1e0SJan Lentfer  *	     %i        add 1 to first two parms (for ANSI terminals)
96*fdd4e1e0SJan Lentfer  *
97*fdd4e1e0SJan Lentfer  *	     %? expr %t thenpart %e elsepart %;
98*fdd4e1e0SJan Lentfer  *	               if-then-else, %e elsepart is optional.
99*fdd4e1e0SJan Lentfer  *	               else-if's are possible ala Algol 68:
100*fdd4e1e0SJan Lentfer  *	               %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
101*fdd4e1e0SJan Lentfer  *
102*fdd4e1e0SJan Lentfer  *	For those of the above operators which are binary and not commutative,
103*fdd4e1e0SJan Lentfer  *	the stack works in the usual way, with
104*fdd4e1e0SJan Lentfer  *			%gx %gy %m
105*fdd4e1e0SJan Lentfer  *	resulting in x mod y, not the reverse.
106*fdd4e1e0SJan Lentfer  */
107*fdd4e1e0SJan Lentfer 
108*fdd4e1e0SJan Lentfer #define STACKSIZE	20
109*fdd4e1e0SJan Lentfer 
110*fdd4e1e0SJan Lentfer typedef struct {
111*fdd4e1e0SJan Lentfer     union {
112*fdd4e1e0SJan Lentfer 	int num;
113*fdd4e1e0SJan Lentfer 	char *str;
114*fdd4e1e0SJan Lentfer     } data;
115*fdd4e1e0SJan Lentfer     bool num_type;
116*fdd4e1e0SJan Lentfer } stack_frame;
117*fdd4e1e0SJan Lentfer 
118*fdd4e1e0SJan Lentfer NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0;
119*fdd4e1e0SJan Lentfer 
120*fdd4e1e0SJan Lentfer static stack_frame stack[STACKSIZE];
121*fdd4e1e0SJan Lentfer static int stack_ptr;
122*fdd4e1e0SJan Lentfer static const char *tparam_base = "";
123*fdd4e1e0SJan Lentfer 
124*fdd4e1e0SJan Lentfer #ifdef TRACE
125*fdd4e1e0SJan Lentfer static const char *tname;
126*fdd4e1e0SJan Lentfer #endif /* TRACE */
127*fdd4e1e0SJan Lentfer 
128*fdd4e1e0SJan Lentfer static char *out_buff;
129*fdd4e1e0SJan Lentfer static size_t out_size;
130*fdd4e1e0SJan Lentfer static size_t out_used;
131*fdd4e1e0SJan Lentfer 
132*fdd4e1e0SJan Lentfer static char *fmt_buff;
133*fdd4e1e0SJan Lentfer static size_t fmt_size;
134*fdd4e1e0SJan Lentfer 
135*fdd4e1e0SJan Lentfer #if NO_LEAKS
136*fdd4e1e0SJan Lentfer NCURSES_EXPORT(void)
137*fdd4e1e0SJan Lentfer _nc_free_tparm(void)
138*fdd4e1e0SJan Lentfer {
139*fdd4e1e0SJan Lentfer     if (out_buff != 0) {
140*fdd4e1e0SJan Lentfer 	FreeAndNull(out_buff);
141*fdd4e1e0SJan Lentfer 	out_size = 0;
142*fdd4e1e0SJan Lentfer 	out_used = 0;
143*fdd4e1e0SJan Lentfer 	FreeAndNull(fmt_buff);
144*fdd4e1e0SJan Lentfer 	fmt_size = 0;
145*fdd4e1e0SJan Lentfer     }
146*fdd4e1e0SJan Lentfer }
147*fdd4e1e0SJan Lentfer #endif
148*fdd4e1e0SJan Lentfer 
149*fdd4e1e0SJan Lentfer static inline void
150*fdd4e1e0SJan Lentfer get_space(size_t need)
151*fdd4e1e0SJan Lentfer {
152*fdd4e1e0SJan Lentfer     need += out_used;
153*fdd4e1e0SJan Lentfer     if (need > out_size) {
154*fdd4e1e0SJan Lentfer 	out_size = need * 2;
155*fdd4e1e0SJan Lentfer 	out_buff = typeRealloc(char, out_size, out_buff);
156*fdd4e1e0SJan Lentfer 	if (out_buff == 0)
157*fdd4e1e0SJan Lentfer 	    _nc_err_abort(MSG_NO_MEMORY);
158*fdd4e1e0SJan Lentfer     }
159*fdd4e1e0SJan Lentfer }
160*fdd4e1e0SJan Lentfer 
161*fdd4e1e0SJan Lentfer static inline void
162*fdd4e1e0SJan Lentfer save_text(const char *fmt, const char *s, int len)
163*fdd4e1e0SJan Lentfer {
164*fdd4e1e0SJan Lentfer     size_t s_len = strlen(s);
165*fdd4e1e0SJan Lentfer     if (len > (int) s_len)
166*fdd4e1e0SJan Lentfer 	s_len = len;
167*fdd4e1e0SJan Lentfer 
168*fdd4e1e0SJan Lentfer     get_space(s_len + 1);
169*fdd4e1e0SJan Lentfer 
170*fdd4e1e0SJan Lentfer     (void) sprintf(out_buff + out_used, fmt, s);
171*fdd4e1e0SJan Lentfer     out_used += strlen(out_buff + out_used);
172*fdd4e1e0SJan Lentfer }
173*fdd4e1e0SJan Lentfer 
174*fdd4e1e0SJan Lentfer static inline void
175*fdd4e1e0SJan Lentfer save_number(const char *fmt, int number, int len)
176*fdd4e1e0SJan Lentfer {
177*fdd4e1e0SJan Lentfer     if (len < 30)
178*fdd4e1e0SJan Lentfer 	len = 30;		/* actually log10(MAX_INT)+1 */
179*fdd4e1e0SJan Lentfer 
180*fdd4e1e0SJan Lentfer     get_space((unsigned) len + 1);
181*fdd4e1e0SJan Lentfer 
182*fdd4e1e0SJan Lentfer     (void) sprintf(out_buff + out_used, fmt, number);
183*fdd4e1e0SJan Lentfer     out_used += strlen(out_buff + out_used);
184*fdd4e1e0SJan Lentfer }
185*fdd4e1e0SJan Lentfer 
186*fdd4e1e0SJan Lentfer static inline void
187*fdd4e1e0SJan Lentfer save_char(int c)
188*fdd4e1e0SJan Lentfer {
189*fdd4e1e0SJan Lentfer     if (c == 0)
190*fdd4e1e0SJan Lentfer 	c = 0200;
191*fdd4e1e0SJan Lentfer     get_space(1);
192*fdd4e1e0SJan Lentfer     out_buff[out_used++] = c;
193*fdd4e1e0SJan Lentfer }
194*fdd4e1e0SJan Lentfer 
195*fdd4e1e0SJan Lentfer static inline void
196*fdd4e1e0SJan Lentfer npush(int x)
197*fdd4e1e0SJan Lentfer {
198*fdd4e1e0SJan Lentfer     if (stack_ptr < STACKSIZE) {
199*fdd4e1e0SJan Lentfer 	stack[stack_ptr].num_type = TRUE;
200*fdd4e1e0SJan Lentfer 	stack[stack_ptr].data.num = x;
201*fdd4e1e0SJan Lentfer 	stack_ptr++;
202*fdd4e1e0SJan Lentfer     } else {
203*fdd4e1e0SJan Lentfer 	DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(tparam_base)));
204*fdd4e1e0SJan Lentfer 	_nc_tparm_err++;
205*fdd4e1e0SJan Lentfer     }
206*fdd4e1e0SJan Lentfer }
207*fdd4e1e0SJan Lentfer 
208*fdd4e1e0SJan Lentfer static inline int
209*fdd4e1e0SJan Lentfer npop(void)
210*fdd4e1e0SJan Lentfer {
211*fdd4e1e0SJan Lentfer     int result = 0;
212*fdd4e1e0SJan Lentfer     if (stack_ptr > 0) {
213*fdd4e1e0SJan Lentfer 	stack_ptr--;
214*fdd4e1e0SJan Lentfer 	if (stack[stack_ptr].num_type)
215*fdd4e1e0SJan Lentfer 	    result = stack[stack_ptr].data.num;
216*fdd4e1e0SJan Lentfer     } else {
217*fdd4e1e0SJan Lentfer 	DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(tparam_base)));
218*fdd4e1e0SJan Lentfer 	_nc_tparm_err++;
219*fdd4e1e0SJan Lentfer     }
220*fdd4e1e0SJan Lentfer     return result;
221*fdd4e1e0SJan Lentfer }
222*fdd4e1e0SJan Lentfer 
223*fdd4e1e0SJan Lentfer static inline void
224*fdd4e1e0SJan Lentfer spush(char *x)
225*fdd4e1e0SJan Lentfer {
226*fdd4e1e0SJan Lentfer     if (stack_ptr < STACKSIZE) {
227*fdd4e1e0SJan Lentfer 	stack[stack_ptr].num_type = FALSE;
228*fdd4e1e0SJan Lentfer 	stack[stack_ptr].data.str = x;
229*fdd4e1e0SJan Lentfer 	stack_ptr++;
230*fdd4e1e0SJan Lentfer     } else {
231*fdd4e1e0SJan Lentfer 	DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(tparam_base)));
232*fdd4e1e0SJan Lentfer 	_nc_tparm_err++;
233*fdd4e1e0SJan Lentfer     }
234*fdd4e1e0SJan Lentfer }
235*fdd4e1e0SJan Lentfer 
236*fdd4e1e0SJan Lentfer static inline char *
237*fdd4e1e0SJan Lentfer spop(void)
238*fdd4e1e0SJan Lentfer {
239*fdd4e1e0SJan Lentfer     static char dummy[] = "";	/* avoid const-cast */
240*fdd4e1e0SJan Lentfer     char *result = dummy;
241*fdd4e1e0SJan Lentfer     if (stack_ptr > 0) {
242*fdd4e1e0SJan Lentfer 	stack_ptr--;
243*fdd4e1e0SJan Lentfer 	if (!stack[stack_ptr].num_type && stack[stack_ptr].data.str != 0)
244*fdd4e1e0SJan Lentfer 	    result = stack[stack_ptr].data.str;
245*fdd4e1e0SJan Lentfer     } else {
246*fdd4e1e0SJan Lentfer 	DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(tparam_base)));
247*fdd4e1e0SJan Lentfer 	_nc_tparm_err++;
248*fdd4e1e0SJan Lentfer     }
249*fdd4e1e0SJan Lentfer     return result;
250*fdd4e1e0SJan Lentfer }
251*fdd4e1e0SJan Lentfer 
252*fdd4e1e0SJan Lentfer static inline const char *
253*fdd4e1e0SJan Lentfer parse_format(const char *s, char *format, int *len)
254*fdd4e1e0SJan Lentfer {
255*fdd4e1e0SJan Lentfer     *len = 0;
256*fdd4e1e0SJan Lentfer     if (format != 0) {
257*fdd4e1e0SJan Lentfer 	bool done = FALSE;
258*fdd4e1e0SJan Lentfer 	bool allowminus = FALSE;
259*fdd4e1e0SJan Lentfer 	bool dot = FALSE;
260*fdd4e1e0SJan Lentfer 	bool err = FALSE;
261*fdd4e1e0SJan Lentfer 	char *fmt = format;
262*fdd4e1e0SJan Lentfer 	int my_width = 0;
263*fdd4e1e0SJan Lentfer 	int my_prec = 0;
264*fdd4e1e0SJan Lentfer 	int value = 0;
265*fdd4e1e0SJan Lentfer 
266*fdd4e1e0SJan Lentfer 	*len = 0;
267*fdd4e1e0SJan Lentfer 	*format++ = '%';
268*fdd4e1e0SJan Lentfer 	while (*s != '\0' && !done) {
269*fdd4e1e0SJan Lentfer 	    switch (*s) {
270*fdd4e1e0SJan Lentfer 	    case 'c':		/* FALLTHRU */
271*fdd4e1e0SJan Lentfer 	    case 'd':		/* FALLTHRU */
272*fdd4e1e0SJan Lentfer 	    case 'o':		/* FALLTHRU */
273*fdd4e1e0SJan Lentfer 	    case 'x':		/* FALLTHRU */
274*fdd4e1e0SJan Lentfer 	    case 'X':		/* FALLTHRU */
275*fdd4e1e0SJan Lentfer 	    case 's':
276*fdd4e1e0SJan Lentfer 		*format++ = *s;
277*fdd4e1e0SJan Lentfer 		done = TRUE;
278*fdd4e1e0SJan Lentfer 		break;
279*fdd4e1e0SJan Lentfer 	    case '.':
280*fdd4e1e0SJan Lentfer 		*format++ = *s++;
281*fdd4e1e0SJan Lentfer 		if (dot) {
282*fdd4e1e0SJan Lentfer 		    err = TRUE;
283*fdd4e1e0SJan Lentfer 		} else {	/* value before '.' is the width */
284*fdd4e1e0SJan Lentfer 		    dot = TRUE;
285*fdd4e1e0SJan Lentfer 		    my_width = value;
286*fdd4e1e0SJan Lentfer 		}
287*fdd4e1e0SJan Lentfer 		value = 0;
288*fdd4e1e0SJan Lentfer 		break;
289*fdd4e1e0SJan Lentfer 	    case '#':
290*fdd4e1e0SJan Lentfer 		*format++ = *s++;
291*fdd4e1e0SJan Lentfer 		break;
292*fdd4e1e0SJan Lentfer 	    case ' ':
293*fdd4e1e0SJan Lentfer 		*format++ = *s++;
294*fdd4e1e0SJan Lentfer 		break;
295*fdd4e1e0SJan Lentfer 	    case ':':
296*fdd4e1e0SJan Lentfer 		s++;
297*fdd4e1e0SJan Lentfer 		allowminus = TRUE;
298*fdd4e1e0SJan Lentfer 		break;
299*fdd4e1e0SJan Lentfer 	    case '-':
300*fdd4e1e0SJan Lentfer 		if (allowminus) {
301*fdd4e1e0SJan Lentfer 		    *format++ = *s++;
302*fdd4e1e0SJan Lentfer 		} else {
303*fdd4e1e0SJan Lentfer 		    done = TRUE;
304*fdd4e1e0SJan Lentfer 		}
305*fdd4e1e0SJan Lentfer 		break;
306*fdd4e1e0SJan Lentfer 	    default:
307*fdd4e1e0SJan Lentfer 		if (isdigit(UChar(*s))) {
308*fdd4e1e0SJan Lentfer 		    value = (value * 10) + (*s - '0');
309*fdd4e1e0SJan Lentfer 		    if (value > 10000)
310*fdd4e1e0SJan Lentfer 			err = TRUE;
311*fdd4e1e0SJan Lentfer 		    *format++ = *s++;
312*fdd4e1e0SJan Lentfer 		} else {
313*fdd4e1e0SJan Lentfer 		    done = TRUE;
314*fdd4e1e0SJan Lentfer 		}
315*fdd4e1e0SJan Lentfer 	    }
316*fdd4e1e0SJan Lentfer 	}
317*fdd4e1e0SJan Lentfer 
318*fdd4e1e0SJan Lentfer 	/*
319*fdd4e1e0SJan Lentfer 	 * If we found an error, ignore (and remove) the flags.
320*fdd4e1e0SJan Lentfer 	 */
321*fdd4e1e0SJan Lentfer 	if (err) {
322*fdd4e1e0SJan Lentfer 	    my_width = my_prec = value = 0;
323*fdd4e1e0SJan Lentfer 	    format = fmt;
324*fdd4e1e0SJan Lentfer 	    *format++ = '%';
325*fdd4e1e0SJan Lentfer 	    *format++ = *s;
326*fdd4e1e0SJan Lentfer 	}
327*fdd4e1e0SJan Lentfer 
328*fdd4e1e0SJan Lentfer 	/*
329*fdd4e1e0SJan Lentfer 	 * Any value after '.' is the precision.  If we did not see '.', then
330*fdd4e1e0SJan Lentfer 	 * the value is the width.
331*fdd4e1e0SJan Lentfer 	 */
332*fdd4e1e0SJan Lentfer 	if (dot)
333*fdd4e1e0SJan Lentfer 	    my_prec = value;
334*fdd4e1e0SJan Lentfer 	else
335*fdd4e1e0SJan Lentfer 	    my_width = value;
336*fdd4e1e0SJan Lentfer 
337*fdd4e1e0SJan Lentfer 	*format = '\0';
338*fdd4e1e0SJan Lentfer 	/* return maximum string length in print */
339*fdd4e1e0SJan Lentfer 	*len = (my_width > my_prec) ? my_width : my_prec;
340*fdd4e1e0SJan Lentfer     }
341*fdd4e1e0SJan Lentfer     return s;
342*fdd4e1e0SJan Lentfer }
343*fdd4e1e0SJan Lentfer 
344*fdd4e1e0SJan Lentfer #define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
345*fdd4e1e0SJan Lentfer #define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
346*fdd4e1e0SJan Lentfer 
347*fdd4e1e0SJan Lentfer /*
348*fdd4e1e0SJan Lentfer  * Analyze the string to see how many parameters we need from the varargs list,
349*fdd4e1e0SJan Lentfer  * and what their types are.  We will only accept string parameters if they
350*fdd4e1e0SJan Lentfer  * appear as a %l or %s format following an explicit parameter reference (e.g.,
351*fdd4e1e0SJan Lentfer  * %p2%s).  All other parameters are numbers.
352*fdd4e1e0SJan Lentfer  *
353*fdd4e1e0SJan Lentfer  * 'number' counts coarsely the number of pop's we see in the string, and
354*fdd4e1e0SJan Lentfer  * 'popcount' shows the highest parameter number in the string.  We would like
355*fdd4e1e0SJan Lentfer  * to simply use the latter count, but if we are reading termcap strings, there
356*fdd4e1e0SJan Lentfer  * may be cases that we cannot see the explicit parameter numbers.
357*fdd4e1e0SJan Lentfer  */
358*fdd4e1e0SJan Lentfer NCURSES_EXPORT(int)
359*fdd4e1e0SJan Lentfer _nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount)
360*fdd4e1e0SJan Lentfer {
361*fdd4e1e0SJan Lentfer     size_t len2;
362*fdd4e1e0SJan Lentfer     int i;
363*fdd4e1e0SJan Lentfer     int lastpop = -1;
364*fdd4e1e0SJan Lentfer     int len;
365*fdd4e1e0SJan Lentfer     int number = 0;
366*fdd4e1e0SJan Lentfer     const char *cp = string;
367*fdd4e1e0SJan Lentfer     static char dummy[] = "";
368*fdd4e1e0SJan Lentfer 
369*fdd4e1e0SJan Lentfer     if (cp == 0)
370*fdd4e1e0SJan Lentfer 	return 0;
371*fdd4e1e0SJan Lentfer 
372*fdd4e1e0SJan Lentfer     if ((len2 = strlen(cp)) > fmt_size) {
373*fdd4e1e0SJan Lentfer 	fmt_size = len2 + fmt_size + 2;
374*fdd4e1e0SJan Lentfer 	if ((fmt_buff = typeRealloc(char, fmt_size, fmt_buff)) == 0)
375*fdd4e1e0SJan Lentfer 	      return 0;
376*fdd4e1e0SJan Lentfer     }
377*fdd4e1e0SJan Lentfer 
378*fdd4e1e0SJan Lentfer     memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM);
379*fdd4e1e0SJan Lentfer     *popcount = 0;
380*fdd4e1e0SJan Lentfer 
381*fdd4e1e0SJan Lentfer     while ((cp - string) < (int) len2) {
382*fdd4e1e0SJan Lentfer 	if (*cp == '%') {
383*fdd4e1e0SJan Lentfer 	    cp++;
384*fdd4e1e0SJan Lentfer 	    cp = parse_format(cp, fmt_buff, &len);
385*fdd4e1e0SJan Lentfer 	    switch (*cp) {
386*fdd4e1e0SJan Lentfer 	    default:
387*fdd4e1e0SJan Lentfer 		break;
388*fdd4e1e0SJan Lentfer 
389*fdd4e1e0SJan Lentfer 	    case 'd':		/* FALLTHRU */
390*fdd4e1e0SJan Lentfer 	    case 'o':		/* FALLTHRU */
391*fdd4e1e0SJan Lentfer 	    case 'x':		/* FALLTHRU */
392*fdd4e1e0SJan Lentfer 	    case 'X':		/* FALLTHRU */
393*fdd4e1e0SJan Lentfer 	    case 'c':		/* FALLTHRU */
394*fdd4e1e0SJan Lentfer 		if (lastpop <= 0)
395*fdd4e1e0SJan Lentfer 		    number++;
396*fdd4e1e0SJan Lentfer 		lastpop = -1;
397*fdd4e1e0SJan Lentfer 		break;
398*fdd4e1e0SJan Lentfer 
399*fdd4e1e0SJan Lentfer 	    case 'l':
400*fdd4e1e0SJan Lentfer 	    case 's':
401*fdd4e1e0SJan Lentfer 		if (lastpop > 0)
402*fdd4e1e0SJan Lentfer 		    p_is_s[lastpop - 1] = dummy;
403*fdd4e1e0SJan Lentfer 		++number;
404*fdd4e1e0SJan Lentfer 		break;
405*fdd4e1e0SJan Lentfer 
406*fdd4e1e0SJan Lentfer 	    case 'p':
407*fdd4e1e0SJan Lentfer 		cp++;
408*fdd4e1e0SJan Lentfer 		i = (UChar(*cp) - '0');
409*fdd4e1e0SJan Lentfer 		if (i >= 0 && i <= NUM_PARM) {
410*fdd4e1e0SJan Lentfer 		    lastpop = i;
411*fdd4e1e0SJan Lentfer 		    if (lastpop > *popcount)
412*fdd4e1e0SJan Lentfer 			*popcount = lastpop;
413*fdd4e1e0SJan Lentfer 		}
414*fdd4e1e0SJan Lentfer 		break;
415*fdd4e1e0SJan Lentfer 
416*fdd4e1e0SJan Lentfer 	    case 'P':
417*fdd4e1e0SJan Lentfer 		++number;
418*fdd4e1e0SJan Lentfer 		++cp;
419*fdd4e1e0SJan Lentfer 		break;
420*fdd4e1e0SJan Lentfer 
421*fdd4e1e0SJan Lentfer 	    case 'g':
422*fdd4e1e0SJan Lentfer 		cp++;
423*fdd4e1e0SJan Lentfer 		break;
424*fdd4e1e0SJan Lentfer 
425*fdd4e1e0SJan Lentfer 	    case S_QUOTE:
426*fdd4e1e0SJan Lentfer 		cp += 2;
427*fdd4e1e0SJan Lentfer 		lastpop = -1;
428*fdd4e1e0SJan Lentfer 		break;
429*fdd4e1e0SJan Lentfer 
430*fdd4e1e0SJan Lentfer 	    case L_BRACE:
431*fdd4e1e0SJan Lentfer 		cp++;
432*fdd4e1e0SJan Lentfer 		while (isdigit(UChar(*cp))) {
433*fdd4e1e0SJan Lentfer 		    cp++;
434*fdd4e1e0SJan Lentfer 		}
435*fdd4e1e0SJan Lentfer 		break;
436*fdd4e1e0SJan Lentfer 
437*fdd4e1e0SJan Lentfer 	    case '+':
438*fdd4e1e0SJan Lentfer 	    case '-':
439*fdd4e1e0SJan Lentfer 	    case '*':
440*fdd4e1e0SJan Lentfer 	    case '/':
441*fdd4e1e0SJan Lentfer 	    case 'm':
442*fdd4e1e0SJan Lentfer 	    case 'A':
443*fdd4e1e0SJan Lentfer 	    case 'O':
444*fdd4e1e0SJan Lentfer 	    case '&':
445*fdd4e1e0SJan Lentfer 	    case '|':
446*fdd4e1e0SJan Lentfer 	    case '^':
447*fdd4e1e0SJan Lentfer 	    case '=':
448*fdd4e1e0SJan Lentfer 	    case '<':
449*fdd4e1e0SJan Lentfer 	    case '>':
450*fdd4e1e0SJan Lentfer 		lastpop = -1;
451*fdd4e1e0SJan Lentfer 		number += 2;
452*fdd4e1e0SJan Lentfer 		break;
453*fdd4e1e0SJan Lentfer 
454*fdd4e1e0SJan Lentfer 	    case '!':
455*fdd4e1e0SJan Lentfer 	    case '~':
456*fdd4e1e0SJan Lentfer 		lastpop = -1;
457*fdd4e1e0SJan Lentfer 		++number;
458*fdd4e1e0SJan Lentfer 		break;
459*fdd4e1e0SJan Lentfer 
460*fdd4e1e0SJan Lentfer 	    case 'i':
461*fdd4e1e0SJan Lentfer 		/* will add 1 to first (usually two) parameters */
462*fdd4e1e0SJan Lentfer 		break;
463*fdd4e1e0SJan Lentfer 	    }
464*fdd4e1e0SJan Lentfer 	}
465*fdd4e1e0SJan Lentfer 	if (*cp != '\0')
466*fdd4e1e0SJan Lentfer 	    cp++;
467*fdd4e1e0SJan Lentfer     }
468*fdd4e1e0SJan Lentfer 
469*fdd4e1e0SJan Lentfer     if (number > NUM_PARM)
470*fdd4e1e0SJan Lentfer 	number = NUM_PARM;
471*fdd4e1e0SJan Lentfer     return number;
472*fdd4e1e0SJan Lentfer }
473*fdd4e1e0SJan Lentfer 
474*fdd4e1e0SJan Lentfer static inline char *
475*fdd4e1e0SJan Lentfer tparam_internal(const char *string, va_list ap)
476*fdd4e1e0SJan Lentfer {
477*fdd4e1e0SJan Lentfer #define NUM_VARS 26
478*fdd4e1e0SJan Lentfer     char *p_is_s[NUM_PARM];
479*fdd4e1e0SJan Lentfer     long param[NUM_PARM];
480*fdd4e1e0SJan Lentfer     int popcount;
481*fdd4e1e0SJan Lentfer     int number;
482*fdd4e1e0SJan Lentfer     int len;
483*fdd4e1e0SJan Lentfer     int level;
484*fdd4e1e0SJan Lentfer     int x, y;
485*fdd4e1e0SJan Lentfer     int i;
486*fdd4e1e0SJan Lentfer     const char *cp = string;
487*fdd4e1e0SJan Lentfer     size_t len2;
488*fdd4e1e0SJan Lentfer     static int dynamic_var[NUM_VARS];
489*fdd4e1e0SJan Lentfer     static int static_vars[NUM_VARS];
490*fdd4e1e0SJan Lentfer 
491*fdd4e1e0SJan Lentfer     if (cp == NULL)
492*fdd4e1e0SJan Lentfer 	return NULL;
493*fdd4e1e0SJan Lentfer 
494*fdd4e1e0SJan Lentfer     out_used = 0;
495*fdd4e1e0SJan Lentfer     len2 = strlen(cp);
496*fdd4e1e0SJan Lentfer 
497*fdd4e1e0SJan Lentfer     /*
498*fdd4e1e0SJan Lentfer      * Find the highest parameter-number referred to in the format string.
499*fdd4e1e0SJan Lentfer      * Use this value to limit the number of arguments copied from the
500*fdd4e1e0SJan Lentfer      * variable-length argument list.
501*fdd4e1e0SJan Lentfer      */
502*fdd4e1e0SJan Lentfer     number = _nc_tparm_analyze(cp, p_is_s, &popcount);
503*fdd4e1e0SJan Lentfer     if (fmt_buff == 0)
504*fdd4e1e0SJan Lentfer 	return NULL;
505*fdd4e1e0SJan Lentfer 
506*fdd4e1e0SJan Lentfer     for (i = 0; i < max(popcount, number); i++) {
507*fdd4e1e0SJan Lentfer 	/*
508*fdd4e1e0SJan Lentfer 	 * A few caps (such as plab_norm) have string-valued parms.
509*fdd4e1e0SJan Lentfer 	 * We'll have to assume that the caller knows the difference, since
510*fdd4e1e0SJan Lentfer 	 * a char* and an int may not be the same size on the stack.  The
511*fdd4e1e0SJan Lentfer 	 * normal prototype for this uses 9 long's, which is consistent with
512*fdd4e1e0SJan Lentfer 	 * our va_arg() usage.
513*fdd4e1e0SJan Lentfer 	 */
514*fdd4e1e0SJan Lentfer 	if (p_is_s[i] != 0) {
515*fdd4e1e0SJan Lentfer 	    p_is_s[i] = va_arg(ap, char *);
516*fdd4e1e0SJan Lentfer 	} else {
517*fdd4e1e0SJan Lentfer 	    param[i] = va_arg(ap, long int);
518*fdd4e1e0SJan Lentfer 	}
519*fdd4e1e0SJan Lentfer     }
520*fdd4e1e0SJan Lentfer 
521*fdd4e1e0SJan Lentfer     /*
522*fdd4e1e0SJan Lentfer      * This is a termcap compatibility hack.  If there are no explicit pop
523*fdd4e1e0SJan Lentfer      * operations in the string, load the stack in such a way that
524*fdd4e1e0SJan Lentfer      * successive pops will grab successive parameters.  That will make
525*fdd4e1e0SJan Lentfer      * the expansion of (for example) \E[%d;%dH work correctly in termcap
526*fdd4e1e0SJan Lentfer      * style, which means tparam() will expand termcap strings OK.
527*fdd4e1e0SJan Lentfer      */
528*fdd4e1e0SJan Lentfer     stack_ptr = 0;
529*fdd4e1e0SJan Lentfer     if (popcount == 0) {
530*fdd4e1e0SJan Lentfer 	popcount = number;
531*fdd4e1e0SJan Lentfer 	for (i = number - 1; i >= 0; i--)
532*fdd4e1e0SJan Lentfer 	    npush(param[i]);
533*fdd4e1e0SJan Lentfer     }
534*fdd4e1e0SJan Lentfer #ifdef TRACE
535*fdd4e1e0SJan Lentfer     if (_nc_tracing & TRACE_CALLS) {
536*fdd4e1e0SJan Lentfer 	for (i = 0; i < popcount; i++) {
537*fdd4e1e0SJan Lentfer 	    if (p_is_s[i] != 0)
538*fdd4e1e0SJan Lentfer 		save_text(", %s", _nc_visbuf(p_is_s[i]), 0);
539*fdd4e1e0SJan Lentfer 	    else
540*fdd4e1e0SJan Lentfer 		save_number(", %d", param[i], 0);
541*fdd4e1e0SJan Lentfer 	}
542*fdd4e1e0SJan Lentfer 	_tracef(T_CALLED("%s(%s%s)"), tname, _nc_visbuf(cp), out_buff);
543*fdd4e1e0SJan Lentfer 	out_used = 0;
544*fdd4e1e0SJan Lentfer     }
545*fdd4e1e0SJan Lentfer #endif /* TRACE */
546*fdd4e1e0SJan Lentfer 
547*fdd4e1e0SJan Lentfer     while ((cp - string) < (int) len2) {
548*fdd4e1e0SJan Lentfer 	if (*cp != '%') {
549*fdd4e1e0SJan Lentfer 	    save_char(UChar(*cp));
550*fdd4e1e0SJan Lentfer 	} else {
551*fdd4e1e0SJan Lentfer 	    tparam_base = cp++;
552*fdd4e1e0SJan Lentfer 	    cp = parse_format(cp, fmt_buff, &len);
553*fdd4e1e0SJan Lentfer 	    switch (*cp) {
554*fdd4e1e0SJan Lentfer 	    default:
555*fdd4e1e0SJan Lentfer 		break;
556*fdd4e1e0SJan Lentfer 	    case '%':
557*fdd4e1e0SJan Lentfer 		save_char('%');
558*fdd4e1e0SJan Lentfer 		break;
559*fdd4e1e0SJan Lentfer 
560*fdd4e1e0SJan Lentfer 	    case 'd':		/* FALLTHRU */
561*fdd4e1e0SJan Lentfer 	    case 'o':		/* FALLTHRU */
562*fdd4e1e0SJan Lentfer 	    case 'x':		/* FALLTHRU */
563*fdd4e1e0SJan Lentfer 	    case 'X':		/* FALLTHRU */
564*fdd4e1e0SJan Lentfer 		save_number(fmt_buff, npop(), len);
565*fdd4e1e0SJan Lentfer 		break;
566*fdd4e1e0SJan Lentfer 
567*fdd4e1e0SJan Lentfer 	    case 'c':		/* FALLTHRU */
568*fdd4e1e0SJan Lentfer 		save_char(npop());
569*fdd4e1e0SJan Lentfer 		break;
570*fdd4e1e0SJan Lentfer 
571*fdd4e1e0SJan Lentfer 	    case 'l':
572*fdd4e1e0SJan Lentfer 		save_number("%d", (int) strlen(spop()), 0);
573*fdd4e1e0SJan Lentfer 		break;
574*fdd4e1e0SJan Lentfer 
575*fdd4e1e0SJan Lentfer 	    case 's':
576*fdd4e1e0SJan Lentfer 		save_text(fmt_buff, spop(), len);
577*fdd4e1e0SJan Lentfer 		break;
578*fdd4e1e0SJan Lentfer 
579*fdd4e1e0SJan Lentfer 	    case 'p':
580*fdd4e1e0SJan Lentfer 		cp++;
581*fdd4e1e0SJan Lentfer 		i = (UChar(*cp) - '1');
582*fdd4e1e0SJan Lentfer 		if (i >= 0 && i < NUM_PARM) {
583*fdd4e1e0SJan Lentfer 		    if (p_is_s[i])
584*fdd4e1e0SJan Lentfer 			spush(p_is_s[i]);
585*fdd4e1e0SJan Lentfer 		    else
586*fdd4e1e0SJan Lentfer 			npush(param[i]);
587*fdd4e1e0SJan Lentfer 		}
588*fdd4e1e0SJan Lentfer 		break;
589*fdd4e1e0SJan Lentfer 
590*fdd4e1e0SJan Lentfer 	    case 'P':
591*fdd4e1e0SJan Lentfer 		cp++;
592*fdd4e1e0SJan Lentfer 		if (isUPPER(*cp)) {
593*fdd4e1e0SJan Lentfer 		    i = (UChar(*cp) - 'A');
594*fdd4e1e0SJan Lentfer 		    static_vars[i] = npop();
595*fdd4e1e0SJan Lentfer 		} else if (isLOWER(*cp)) {
596*fdd4e1e0SJan Lentfer 		    i = (UChar(*cp) - 'a');
597*fdd4e1e0SJan Lentfer 		    dynamic_var[i] = npop();
598*fdd4e1e0SJan Lentfer 		}
599*fdd4e1e0SJan Lentfer 		break;
600*fdd4e1e0SJan Lentfer 
601*fdd4e1e0SJan Lentfer 	    case 'g':
602*fdd4e1e0SJan Lentfer 		cp++;
603*fdd4e1e0SJan Lentfer 		if (isUPPER(*cp)) {
604*fdd4e1e0SJan Lentfer 		    i = (UChar(*cp) - 'A');
605*fdd4e1e0SJan Lentfer 		    npush(static_vars[i]);
606*fdd4e1e0SJan Lentfer 		} else if (isLOWER(*cp)) {
607*fdd4e1e0SJan Lentfer 		    i = (UChar(*cp) - 'a');
608*fdd4e1e0SJan Lentfer 		    npush(dynamic_var[i]);
609*fdd4e1e0SJan Lentfer 		}
610*fdd4e1e0SJan Lentfer 		break;
611*fdd4e1e0SJan Lentfer 
612*fdd4e1e0SJan Lentfer 	    case S_QUOTE:
613*fdd4e1e0SJan Lentfer 		cp++;
614*fdd4e1e0SJan Lentfer 		npush(UChar(*cp));
615*fdd4e1e0SJan Lentfer 		cp++;
616*fdd4e1e0SJan Lentfer 		break;
617*fdd4e1e0SJan Lentfer 
618*fdd4e1e0SJan Lentfer 	    case L_BRACE:
619*fdd4e1e0SJan Lentfer 		number = 0;
620*fdd4e1e0SJan Lentfer 		cp++;
621*fdd4e1e0SJan Lentfer 		while (isdigit(UChar(*cp))) {
622*fdd4e1e0SJan Lentfer 		    number = (number * 10) + (UChar(*cp) - '0');
623*fdd4e1e0SJan Lentfer 		    cp++;
624*fdd4e1e0SJan Lentfer 		}
625*fdd4e1e0SJan Lentfer 		npush(number);
626*fdd4e1e0SJan Lentfer 		break;
627*fdd4e1e0SJan Lentfer 
628*fdd4e1e0SJan Lentfer 	    case '+':
629*fdd4e1e0SJan Lentfer 		npush(npop() + npop());
630*fdd4e1e0SJan Lentfer 		break;
631*fdd4e1e0SJan Lentfer 
632*fdd4e1e0SJan Lentfer 	    case '-':
633*fdd4e1e0SJan Lentfer 		y = npop();
634*fdd4e1e0SJan Lentfer 		x = npop();
635*fdd4e1e0SJan Lentfer 		npush(x - y);
636*fdd4e1e0SJan Lentfer 		break;
637*fdd4e1e0SJan Lentfer 
638*fdd4e1e0SJan Lentfer 	    case '*':
639*fdd4e1e0SJan Lentfer 		npush(npop() * npop());
640*fdd4e1e0SJan Lentfer 		break;
641*fdd4e1e0SJan Lentfer 
642*fdd4e1e0SJan Lentfer 	    case '/':
643*fdd4e1e0SJan Lentfer 		y = npop();
644*fdd4e1e0SJan Lentfer 		x = npop();
645*fdd4e1e0SJan Lentfer 		npush(y ? (x / y) : 0);
646*fdd4e1e0SJan Lentfer 		break;
647*fdd4e1e0SJan Lentfer 
648*fdd4e1e0SJan Lentfer 	    case 'm':
649*fdd4e1e0SJan Lentfer 		y = npop();
650*fdd4e1e0SJan Lentfer 		x = npop();
651*fdd4e1e0SJan Lentfer 		npush(y ? (x % y) : 0);
652*fdd4e1e0SJan Lentfer 		break;
653*fdd4e1e0SJan Lentfer 
654*fdd4e1e0SJan Lentfer 	    case 'A':
655*fdd4e1e0SJan Lentfer 		npush(npop() && npop());
656*fdd4e1e0SJan Lentfer 		break;
657*fdd4e1e0SJan Lentfer 
658*fdd4e1e0SJan Lentfer 	    case 'O':
659*fdd4e1e0SJan Lentfer 		npush(npop() || npop());
660*fdd4e1e0SJan Lentfer 		break;
661*fdd4e1e0SJan Lentfer 
662*fdd4e1e0SJan Lentfer 	    case '&':
663*fdd4e1e0SJan Lentfer 		npush(npop() & npop());
664*fdd4e1e0SJan Lentfer 		break;
665*fdd4e1e0SJan Lentfer 
666*fdd4e1e0SJan Lentfer 	    case '|':
667*fdd4e1e0SJan Lentfer 		npush(npop() | npop());
668*fdd4e1e0SJan Lentfer 		break;
669*fdd4e1e0SJan Lentfer 
670*fdd4e1e0SJan Lentfer 	    case '^':
671*fdd4e1e0SJan Lentfer 		npush(npop() ^ npop());
672*fdd4e1e0SJan Lentfer 		break;
673*fdd4e1e0SJan Lentfer 
674*fdd4e1e0SJan Lentfer 	    case '=':
675*fdd4e1e0SJan Lentfer 		y = npop();
676*fdd4e1e0SJan Lentfer 		x = npop();
677*fdd4e1e0SJan Lentfer 		npush(x == y);
678*fdd4e1e0SJan Lentfer 		break;
679*fdd4e1e0SJan Lentfer 
680*fdd4e1e0SJan Lentfer 	    case '<':
681*fdd4e1e0SJan Lentfer 		y = npop();
682*fdd4e1e0SJan Lentfer 		x = npop();
683*fdd4e1e0SJan Lentfer 		npush(x < y);
684*fdd4e1e0SJan Lentfer 		break;
685*fdd4e1e0SJan Lentfer 
686*fdd4e1e0SJan Lentfer 	    case '>':
687*fdd4e1e0SJan Lentfer 		y = npop();
688*fdd4e1e0SJan Lentfer 		x = npop();
689*fdd4e1e0SJan Lentfer 		npush(x > y);
690*fdd4e1e0SJan Lentfer 		break;
691*fdd4e1e0SJan Lentfer 
692*fdd4e1e0SJan Lentfer 	    case '!':
693*fdd4e1e0SJan Lentfer 		npush(!npop());
694*fdd4e1e0SJan Lentfer 		break;
695*fdd4e1e0SJan Lentfer 
696*fdd4e1e0SJan Lentfer 	    case '~':
697*fdd4e1e0SJan Lentfer 		npush(~npop());
698*fdd4e1e0SJan Lentfer 		break;
699*fdd4e1e0SJan Lentfer 
700*fdd4e1e0SJan Lentfer 	    case 'i':
701*fdd4e1e0SJan Lentfer 		if (p_is_s[0] == 0)
702*fdd4e1e0SJan Lentfer 		    param[0]++;
703*fdd4e1e0SJan Lentfer 		if (p_is_s[1] == 0)
704*fdd4e1e0SJan Lentfer 		    param[1]++;
705*fdd4e1e0SJan Lentfer 		break;
706*fdd4e1e0SJan Lentfer 
707*fdd4e1e0SJan Lentfer 	    case '?':
708*fdd4e1e0SJan Lentfer 		break;
709*fdd4e1e0SJan Lentfer 
710*fdd4e1e0SJan Lentfer 	    case 't':
711*fdd4e1e0SJan Lentfer 		x = npop();
712*fdd4e1e0SJan Lentfer 		if (!x) {
713*fdd4e1e0SJan Lentfer 		    /* scan forward for %e or %; at level zero */
714*fdd4e1e0SJan Lentfer 		    cp++;
715*fdd4e1e0SJan Lentfer 		    level = 0;
716*fdd4e1e0SJan Lentfer 		    while (*cp) {
717*fdd4e1e0SJan Lentfer 			if (*cp == '%') {
718*fdd4e1e0SJan Lentfer 			    cp++;
719*fdd4e1e0SJan Lentfer 			    if (*cp == '?')
720*fdd4e1e0SJan Lentfer 				level++;
721*fdd4e1e0SJan Lentfer 			    else if (*cp == ';') {
722*fdd4e1e0SJan Lentfer 				if (level > 0)
723*fdd4e1e0SJan Lentfer 				    level--;
724*fdd4e1e0SJan Lentfer 				else
725*fdd4e1e0SJan Lentfer 				    break;
726*fdd4e1e0SJan Lentfer 			    } else if (*cp == 'e' && level == 0)
727*fdd4e1e0SJan Lentfer 				break;
728*fdd4e1e0SJan Lentfer 			}
729*fdd4e1e0SJan Lentfer 
730*fdd4e1e0SJan Lentfer 			if (*cp)
731*fdd4e1e0SJan Lentfer 			    cp++;
732*fdd4e1e0SJan Lentfer 		    }
733*fdd4e1e0SJan Lentfer 		}
734*fdd4e1e0SJan Lentfer 		break;
735*fdd4e1e0SJan Lentfer 
736*fdd4e1e0SJan Lentfer 	    case 'e':
737*fdd4e1e0SJan Lentfer 		/* scan forward for a %; at level zero */
738*fdd4e1e0SJan Lentfer 		cp++;
739*fdd4e1e0SJan Lentfer 		level = 0;
740*fdd4e1e0SJan Lentfer 		while (*cp) {
741*fdd4e1e0SJan Lentfer 		    if (*cp == '%') {
742*fdd4e1e0SJan Lentfer 			cp++;
743*fdd4e1e0SJan Lentfer 			if (*cp == '?')
744*fdd4e1e0SJan Lentfer 			    level++;
745*fdd4e1e0SJan Lentfer 			else if (*cp == ';') {
746*fdd4e1e0SJan Lentfer 			    if (level > 0)
747*fdd4e1e0SJan Lentfer 				level--;
748*fdd4e1e0SJan Lentfer 			    else
749*fdd4e1e0SJan Lentfer 				break;
750*fdd4e1e0SJan Lentfer 			}
751*fdd4e1e0SJan Lentfer 		    }
752*fdd4e1e0SJan Lentfer 
753*fdd4e1e0SJan Lentfer 		    if (*cp)
754*fdd4e1e0SJan Lentfer 			cp++;
755*fdd4e1e0SJan Lentfer 		}
756*fdd4e1e0SJan Lentfer 		break;
757*fdd4e1e0SJan Lentfer 
758*fdd4e1e0SJan Lentfer 	    case ';':
759*fdd4e1e0SJan Lentfer 		break;
760*fdd4e1e0SJan Lentfer 
761*fdd4e1e0SJan Lentfer 	    }			/* endswitch (*cp) */
762*fdd4e1e0SJan Lentfer 	}			/* endelse (*cp == '%') */
763*fdd4e1e0SJan Lentfer 
764*fdd4e1e0SJan Lentfer 	if (*cp == '\0')
765*fdd4e1e0SJan Lentfer 	    break;
766*fdd4e1e0SJan Lentfer 
767*fdd4e1e0SJan Lentfer 	cp++;
768*fdd4e1e0SJan Lentfer     }				/* endwhile (*cp) */
769*fdd4e1e0SJan Lentfer 
770*fdd4e1e0SJan Lentfer     get_space(1);
771*fdd4e1e0SJan Lentfer     out_buff[out_used] = '\0';
772*fdd4e1e0SJan Lentfer 
773*fdd4e1e0SJan Lentfer     T((T_RETURN("%s"), _nc_visbuf(out_buff)));
774*fdd4e1e0SJan Lentfer     return (out_buff);
775*fdd4e1e0SJan Lentfer }
776*fdd4e1e0SJan Lentfer 
777*fdd4e1e0SJan Lentfer NCURSES_EXPORT(char *)
778*fdd4e1e0SJan Lentfer tparm(NCURSES_CONST char *string,...)
779*fdd4e1e0SJan Lentfer {
780*fdd4e1e0SJan Lentfer     va_list ap;
781*fdd4e1e0SJan Lentfer     char *result;
782*fdd4e1e0SJan Lentfer 
783*fdd4e1e0SJan Lentfer     _nc_tparm_err = 0;
784*fdd4e1e0SJan Lentfer     va_start(ap, string);
785*fdd4e1e0SJan Lentfer #ifdef TRACE
786*fdd4e1e0SJan Lentfer     tname = "tparm";
787*fdd4e1e0SJan Lentfer #endif /* TRACE */
788*fdd4e1e0SJan Lentfer     result = tparam_internal(string, ap);
789*fdd4e1e0SJan Lentfer     va_end(ap);
790*fdd4e1e0SJan Lentfer     return result;
791*fdd4e1e0SJan Lentfer }
792