GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcurses/tinfo/lib_tparm.c Lines: 136 285 47.7 %
Date: 2017-11-07 Branches: 75 220 34.1 %

Line Branch Exec Source
1
/* $OpenBSD: lib_tparm.c,v 1.9 2010/01/12 23:22:06 nicm Exp $ */
2
3
/****************************************************************************
4
 * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
5
 *                                                                          *
6
 * Permission is hereby granted, free of charge, to any person obtaining a  *
7
 * copy of this software and associated documentation files (the            *
8
 * "Software"), to deal in the Software without restriction, including      *
9
 * without limitation the rights to use, copy, modify, merge, publish,      *
10
 * distribute, distribute with modifications, sublicense, and/or sell       *
11
 * copies of the Software, and to permit persons to whom the Software is    *
12
 * furnished to do so, subject to the following conditions:                 *
13
 *                                                                          *
14
 * The above copyright notice and this permission notice shall be included  *
15
 * in all copies or substantial portions of the Software.                   *
16
 *                                                                          *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20
 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24
 *                                                                          *
25
 * Except as contained in this notice, the name(s) of the above copyright   *
26
 * holders shall not be used in advertising or otherwise to promote the     *
27
 * sale, use or other dealings in this Software without prior written       *
28
 * authorization.                                                           *
29
 ****************************************************************************/
30
31
/****************************************************************************
32
 *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
33
 *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
34
 *     and: Thomas E. Dickey, 1996 on                                       *
35
 ****************************************************************************/
36
37
/*
38
 *	tparm.c
39
 *
40
 */
41
42
#include <curses.priv.h>
43
44
#include <ctype.h>
45
#include <term.h>
46
#include <tic.h>
47
48
MODULE_ID("$Id: lib_tparm.c,v 1.9 2010/01/12 23:22:06 nicm Exp $")
49
50
/*
51
 *	char *
52
 *	tparm(string, ...)
53
 *
54
 *	Substitute the given parameters into the given string by the following
55
 *	rules (taken from terminfo(5)):
56
 *
57
 *	     Cursor addressing and other strings  requiring  parame-
58
 *	ters in the terminal are described by a parameterized string
59
 *	capability, with like escapes %x in  it.   For  example,  to
60
 *	address  the  cursor, the cup capability is given, using two
61
 *	parameters: the row and column to  address  to.   (Rows  and
62
 *	columns  are  numbered  from  zero and refer to the physical
63
 *	screen visible to the user, not to any  unseen  memory.)  If
64
 *	the terminal has memory relative cursor addressing, that can
65
 *	be indicated by
66
 *
67
 *	     The parameter mechanism uses  a  stack  and  special  %
68
 *	codes  to manipulate it.  Typically a sequence will push one
69
 *	of the parameters onto the stack and then print it  in  some
70
 *	format.  Often more complex operations are necessary.
71
 *
72
 *	     The % encodings have the following meanings:
73
 *
74
 *	     %%        outputs `%'
75
 *	     %c        print pop() like %c in printf()
76
 *	     %s        print pop() like %s in printf()
77
 *           %[[:]flags][width[.precision]][doxXs]
78
 *                     as in printf, flags are [-+#] and space
79
 *                     The ':' is used to avoid making %+ or %-
80
 *                     patterns (see below).
81
 *
82
 *	     %p[1-9]   push ith parm
83
 *	     %P[a-z]   set dynamic variable [a-z] to pop()
84
 *	     %g[a-z]   get dynamic variable [a-z] and push it
85
 *	     %P[A-Z]   set static variable [A-Z] to pop()
86
 *	     %g[A-Z]   get static variable [A-Z] and push it
87
 *	     %l        push strlen(pop)
88
 *	     %'c'      push char constant c
89
 *	     %{nn}     push integer constant nn
90
 *
91
 *	     %+ %- %* %/ %m
92
 *	               arithmetic (%m is mod): push(pop() op pop())
93
 *	     %& %| %^  bit operations: push(pop() op pop())
94
 *	     %= %> %<  logical operations: push(pop() op pop())
95
 *	     %A %O     logical and & or operations for conditionals
96
 *	     %! %~     unary operations push(op pop())
97
 *	     %i        add 1 to first two parms (for ANSI terminals)
98
 *
99
 *	     %? expr %t thenpart %e elsepart %;
100
 *	               if-then-else, %e elsepart is optional.
101
 *	               else-if's are possible ala Algol 68:
102
 *	               %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
103
 *
104
 *	For those of the above operators which are binary and not commutative,
105
 *	the stack works in the usual way, with
106
 *			%gx %gy %m
107
 *	resulting in x mod y, not the reverse.
108
 */
109
110
NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0;
111
112
#define TPS(var) _nc_prescreen.tparm_state.var
113
114
#if NO_LEAKS
115
NCURSES_EXPORT(void)
116
_nc_free_tparm(void)
117
{
118
    if (TPS(out_buff) != 0) {
119
	FreeAndNull(TPS(out_buff));
120
	TPS(out_size) = 0;
121
	TPS(out_used) = 0;
122
	FreeAndNull(TPS(fmt_buff));
123
	TPS(fmt_size) = 0;
124
    }
125
}
126
#endif
127
128
static NCURSES_INLINE void
129
get_space(size_t need)
130
{
131
64650
    need += TPS(out_used);
132
32325
    if (need > TPS(out_size)) {
133
407
	TPS(out_size) = need * 2;
134
407
	TPS(out_buff) = typeRealloc(char, TPS(out_size), TPS(out_buff));
135
407
	if (TPS(out_buff) == 0)
136
	    _nc_err_abort(MSG_NO_MEMORY);
137
    }
138
32325
}
139
140
static NCURSES_INLINE void
141
save_text(const char *fmt, const char *s, int len)
142
{
143
    size_t s_len = strlen(s);
144
    if (len > (int) s_len)
145
	s_len = len;
146
147
    get_space(s_len + 1);
148
149
    (void) snprintf(TPS(out_buff) + TPS(out_used), TPS(out_size) - TPS(out_used), fmt, s);
150
    TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used));
151
}
152
153
static NCURSES_INLINE void
154
save_number(const char *fmt, int number, int len)
155
{
156
16056
    if (len < 30)
157
	len = 30;		/* actually log10(MAX_INT)+1 */
158
159
8028
    get_space((unsigned) len + 1);
160
161
8028
    (void) snprintf(TPS(out_buff) + TPS(out_used), TPS(out_size) - TPS(out_used), fmt, number);
162
8028
    TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used));
163
8028
}
164
165
static NCURSES_INLINE void
166
save_char(int c)
167
{
168
38854
    if (c == 0)
169
	c = 0200;
170
19427
    get_space(1);
171
19427
    TPS(out_buff)[TPS(out_used)++] = (char) c;
172
19427
}
173
174
static NCURSES_INLINE void
175
npush(int x)
176
{
177
20964
    if (TPS(stack_ptr) < STACKSIZE) {
178
10482
	TPS(stack)[TPS(stack_ptr)].num_type = TRUE;
179
10482
	TPS(stack)[TPS(stack_ptr)].data.num = x;
180
10482
	TPS(stack_ptr)++;
181
10482
    } else {
182
	DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(TPS(tparam_base))));
183
	_nc_tparm_err++;
184
    }
185
10482
}
186
187
static NCURSES_INLINE int
188
npop(void)
189
{
190
    int result = 0;
191
20964
    if (TPS(stack_ptr) > 0) {
192
10482
	TPS(stack_ptr)--;
193
10482
	if (TPS(stack)[TPS(stack_ptr)].num_type)
194
10482
	    result = TPS(stack)[TPS(stack_ptr)].data.num;
195
    } else {
196
	DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(TPS(tparam_base))));
197
	_nc_tparm_err++;
198
    }
199
10482
    return result;
200
}
201
202
static NCURSES_INLINE void
203
spush(char *x)
204
{
205
    if (TPS(stack_ptr) < STACKSIZE) {
206
	TPS(stack)[TPS(stack_ptr)].num_type = FALSE;
207
	TPS(stack)[TPS(stack_ptr)].data.str = x;
208
	TPS(stack_ptr)++;
209
    } else {
210
	DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(TPS(tparam_base))));
211
	_nc_tparm_err++;
212
    }
213
}
214
215
static NCURSES_INLINE char *
216
spop(void)
217
{
218
    static char dummy[] = "";	/* avoid const-cast */
219
    char *result = dummy;
220
    if (TPS(stack_ptr) > 0) {
221
	TPS(stack_ptr)--;
222
	if (!TPS(stack)[TPS(stack_ptr)].num_type
223
	    && TPS(stack)[TPS(stack_ptr)].data.str != 0)
224
	    result = TPS(stack)[TPS(stack_ptr)].data.str;
225
    } else {
226
	DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(TPS(tparam_base))));
227
	_nc_tparm_err++;
228
    }
229
    return result;
230
}
231
232
static NCURSES_INLINE const char *
233
parse_format(const char *s, char *format, int *len)
234
{
235
111164
    *len = 0;
236
55582
    if (format != 0) {
237
	bool done = FALSE;
238
	bool allowminus = FALSE;
239
	bool dot = FALSE;
240
	bool err = FALSE;
241
	char *fmt = format;
242
	int my_width = 0;
243
	int my_prec = 0;
244
	int value = 0;
245
246
55582
	*len = 0;
247
55582
	*format++ = '%';
248

277910
	while (*s != '\0' && !done) {
249



55582
	    switch (*s) {
250
	    case 'c':		/* FALLTHRU */
251
	    case 'd':		/* FALLTHRU */
252
	    case 'o':		/* FALLTHRU */
253
	    case 'x':		/* FALLTHRU */
254
	    case 'X':		/* FALLTHRU */
255
	    case 's':
256
16056
		*format++ = *s;
257
		done = TRUE;
258
16056
		break;
259
	    case '.':
260
		*format++ = *s++;
261
		if (dot) {
262
		    err = TRUE;
263
		} else {	/* value before '.' is the width */
264
		    dot = TRUE;
265
		    my_width = value;
266
		}
267
		value = 0;
268
		break;
269
	    case '#':
270
		*format++ = *s++;
271
		break;
272
	    case ' ':
273
		*format++ = *s++;
274
		break;
275
	    case ':':
276
		s++;
277
		allowminus = TRUE;
278
		break;
279
	    case '-':
280
		if (allowminus) {
281
		    *format++ = *s++;
282
		} else {
283
		    done = TRUE;
284
		}
285
		break;
286
	    default:
287
39526
		if (isdigit(UChar(*s))) {
288
		    value = (value * 10) + (*s - '0');
289
		    if (value > 10000)
290
			err = TRUE;
291
		    *format++ = *s++;
292
		} else {
293
		    done = TRUE;
294
		}
295
	    }
296
	}
297
298
	/*
299
	 * If we found an error, ignore (and remove) the flags.
300
	 */
301
55582
	if (err) {
302
	    my_width = my_prec = value = 0;
303
	    format = fmt;
304
	    *format++ = '%';
305
	    *format++ = *s;
306
	}
307
308
	/*
309
	 * Any value after '.' is the precision.  If we did not see '.', then
310
	 * the value is the width.
311
	 */
312
55582
	if (dot)
313
	    my_prec = value;
314
	else
315
	    my_width = value;
316
317
55582
	*format = '\0';
318
	/* return maximum string length in print */
319
55582
	*len = (my_width > my_prec) ? my_width : my_prec;
320
55582
    }
321
55582
    return s;
322
}
323
324
#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
325
#define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
326
327
/*
328
 * Analyze the string to see how many parameters we need from the varargs list,
329
 * and what their types are.  We will only accept string parameters if they
330
 * appear as a %l or %s format following an explicit parameter reference (e.g.,
331
 * %p2%s).  All other parameters are numbers.
332
 *
333
 * 'number' counts coarsely the number of pop's we see in the string, and
334
 * 'popcount' shows the highest parameter number in the string.  We would like
335
 * to simply use the latter count, but if we are reading termcap strings, there
336
 * may be cases that we cannot see the explicit parameter numbers.
337
 */
338
NCURSES_EXPORT(int)
339
_nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount)
340
{
341
    size_t len2;
342
    int i;
343
    int lastpop = -1;
344
9740
    int len;
345
    int number = 0;
346
    const char *cp = string;
347
    static char dummy[] = "";
348
349
4870
    if (cp == 0)
350
	return 0;
351
352
4870
    if ((len2 = strlen(cp)) > TPS(fmt_size)) {
353
160
	TPS(fmt_size) = len2 + TPS(fmt_size) + 2;
354
160
	TPS(fmt_buff) = typeRealloc(char, TPS(fmt_size), TPS(fmt_buff));
355
160
	if (TPS(fmt_buff) == 0)
356
	    return 0;
357
    }
358
359
4870
    memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM);
360
4870
    *popcount = 0;
361
362
62395
    while ((cp - string) < (int) len2) {
363
52655
	if (*cp == '%') {
364
70880
	    cp++;
365
70880
	    cp = parse_format(cp, TPS(fmt_buff), &len);
366







70880
	    switch (*cp) {
367
	    default:
368
		break;
369
370
	    case 'd':		/* FALLTHRU */
371
	    case 'o':		/* FALLTHRU */
372
	    case 'x':		/* FALLTHRU */
373
	    case 'X':		/* FALLTHRU */
374
	    case 'c':		/* FALLTHRU */
375
8028
		if (lastpop <= 0)
376
		    number++;
377
		lastpop = -1;
378
8028
		break;
379
380
	    case 'l':
381
	    case 's':
382
		if (lastpop > 0)
383
		    p_is_s[lastpop - 1] = dummy;
384
		++number;
385
		break;
386
387
	    case 'p':
388
10354
		cp++;
389
10354
		i = (UChar(*cp) - '0');
390
10354
		if (i >= 0 && i <= NUM_PARM) {
391
		    lastpop = i;
392
10354
		    if (lastpop > *popcount)
393
8528
			*popcount = lastpop;
394
		}
395
		break;
396
397
	    case 'P':
398
		++number;
399
		++cp;
400
		break;
401
402
	    case 'g':
403
		cp++;
404
		break;
405
406
	    case S_QUOTE:
407
		cp += 2;
408
		lastpop = -1;
409
		break;
410
411
	    case L_BRACE:
412
		cp++;
413
		while (isdigit(UChar(*cp))) {
414
		    cp++;
415
		}
416
		break;
417
418
	    case '+':
419
	    case '-':
420
	    case '*':
421
	    case '/':
422
	    case 'm':
423
	    case 'A':
424
	    case 'O':
425
	    case '&':
426
	    case '|':
427
	    case '^':
428
	    case '=':
429
	    case '<':
430
	    case '>':
431
		lastpop = -1;
432
128
		number += 2;
433
128
		break;
434
435
	    case '!':
436
	    case '~':
437
		lastpop = -1;
438
		++number;
439
		break;
440
441
	    case 'i':
442
		/* will add 1 to first (usually two) parameters */
443
		break;
444
	    }
445
	}
446
52655
	if (*cp != '\0')
447
52655
	    cp++;
448
    }
449
450
4870
    if (number > NUM_PARM)
451
	number = NUM_PARM;
452
4870
    return number;
453
4870
}
454
455
static NCURSES_INLINE char *
456
tparam_internal(const char *string, va_list ap)
457
{
458
9740
    char *p_is_s[NUM_PARM];
459
4870
    TPARM_ARG param[NUM_PARM];
460
4870
    int popcount;
461
    int number;
462
4870
    int len;
463
    int level;
464
    int x, y;
465
    int i;
466
    const char *cp = string;
467
    size_t len2;
468
469
4870
    if (cp == NULL)
470
	return NULL;
471
472
4870
    TPS(out_used) = 0;
473
4870
    len2 = strlen(cp);
474
475
    /*
476
     * Find the highest parameter-number referred to in the format string.
477
     * Use this value to limit the number of arguments copied from the
478
     * variable-length argument list.
479
     */
480
4870
    number = _nc_tparm_analyze(cp, p_is_s, &popcount);
481
4870
    if (TPS(fmt_buff) == 0)
482
	return NULL;
483
484
31448
    for (i = 0; i < max(popcount, number); i++) {
485
	/*
486
	 * A few caps (such as plab_norm) have string-valued parms.
487
	 * We'll have to assume that the caller knows the difference, since
488
	 * a char* and an int may not be the same size on the stack.  The
489
	 * normal prototype for this uses 9 long's, which is consistent with
490
	 * our va_arg() usage.
491
	 */
492
10854
	if (p_is_s[i] != 0) {
493
	    p_is_s[i] = va_arg(ap, char *);
494
	} else {
495
32562
	    param[i] = va_arg(ap, TPARM_ARG);
496
	}
497
    }
498
499
    /*
500
     * This is a termcap compatibility hack.  If there are no explicit pop
501
     * operations in the string, load the stack in such a way that
502
     * successive pops will grab successive parameters.  That will make
503
     * the expansion of (for example) \E[%d;%dH work correctly in termcap
504
     * style, which means tparam() will expand termcap strings OK.
505
     */
506
4870
    TPS(stack_ptr) = 0;
507
4870
    if (popcount == 0) {
508
	popcount = number;
509
	for (i = number - 1; i >= 0; i--) {
510
	    if (p_is_s[i])
511
		spush(p_is_s[i]);
512
	    else
513
		npush(param[i]);
514
	}
515
    }
516
#ifdef TRACE
517
    if (USE_TRACEF(TRACE_CALLS)) {
518
	for (i = 0; i < popcount; i++) {
519
	    if (p_is_s[i] != 0)
520
		save_text(", %s", _nc_visbuf(p_is_s[i]), 0);
521
	    else
522
		save_number(", %d", param[i], 0);
523
	}
524
	_tracef(T_CALLED("%s(%s%s)"), TPS(tname), _nc_visbuf(cp), TPS(out_buff));
525
	TPS(out_used) = 0;
526
	_nc_unlock_global(tracef);
527
    }
528
#endif /* TRACE */
529
530
97108
    while ((cp - string) < (int) len2) {
531
46119
	if (*cp != '%') {
532
19427
	    save_char(UChar(*cp));
533
19427
	} else {
534
70171
	    TPS(tparam_base) = cp++;
535
70171
	    cp = parse_format(cp, TPS(fmt_buff), &len);
536








70171
	    switch (*cp) {
537
	    default:
538
		break;
539
	    case '%':
540
		save_char('%');
541
		break;
542
543
	    case 'd':		/* FALLTHRU */
544
	    case 'o':		/* FALLTHRU */
545
	    case 'x':		/* FALLTHRU */
546
	    case 'X':		/* FALLTHRU */
547
8028
		save_number(TPS(fmt_buff), npop(), len);
548
8028
		break;
549
550
	    case 'c':		/* FALLTHRU */
551
		save_char(npop());
552
		break;
553
554
	    case 'l':
555
		save_number("%d", (int) strlen(spop()), 0);
556
		break;
557
558
	    case 's':
559
		save_text(TPS(fmt_buff), spop(), len);
560
		break;
561
562
	    case 'p':
563
10354
		cp++;
564
10354
		i = (UChar(*cp) - '1');
565
10354
		if (i >= 0 && i < NUM_PARM) {
566
10354
		    if (p_is_s[i])
567
			spush(p_is_s[i]);
568
		    else
569
10354
			npush(param[i]);
570
		}
571
		break;
572
573
	    case 'P':
574
		cp++;
575
		if (isUPPER(*cp)) {
576
		    i = (UChar(*cp) - 'A');
577
		    TPS(static_vars)[i] = npop();
578
		} else if (isLOWER(*cp)) {
579
		    i = (UChar(*cp) - 'a');
580
		    TPS(dynamic_var)[i] = npop();
581
		}
582
		break;
583
584
	    case 'g':
585
		cp++;
586
		if (isUPPER(*cp)) {
587
		    i = (UChar(*cp) - 'A');
588
		    npush(TPS(static_vars)[i]);
589
		} else if (isLOWER(*cp)) {
590
		    i = (UChar(*cp) - 'a');
591
		    npush(TPS(dynamic_var)[i]);
592
		}
593
		break;
594
595
	    case S_QUOTE:
596
		cp++;
597
		npush(UChar(*cp));
598
		cp++;
599
		break;
600
601
	    case L_BRACE:
602
		number = 0;
603
		cp++;
604
		while (isdigit(UChar(*cp))) {
605
		    number = (number * 10) + (UChar(*cp) - '0');
606
		    cp++;
607
		}
608
		npush(number);
609
		break;
610
611
	    case '+':
612
		npush(npop() + npop());
613
		break;
614
615
	    case '-':
616
		y = npop();
617
		x = npop();
618
		npush(x - y);
619
		break;
620
621
	    case '*':
622
		npush(npop() * npop());
623
		break;
624
625
	    case '/':
626
		y = npop();
627
		x = npop();
628
		npush(y ? (x / y) : 0);
629
		break;
630
631
	    case 'm':
632
		y = npop();
633
		x = npop();
634
		npush(y ? (x % y) : 0);
635
		break;
636
637
	    case 'A':
638
		npush(npop() && npop());
639
		break;
640
641
	    case 'O':
642
		npush(npop() || npop());
643
		break;
644
645
	    case '&':
646
		npush(npop() & npop());
647
		break;
648
649
	    case '|':
650
128
		npush(npop() | npop());
651
128
		break;
652
653
	    case '^':
654
		npush(npop() ^ npop());
655
		break;
656
657
	    case '=':
658
		y = npop();
659
		x = npop();
660
		npush(x == y);
661
		break;
662
663
	    case '<':
664
		y = npop();
665
		x = npop();
666
		npush(x < y);
667
		break;
668
669
	    case '>':
670
		y = npop();
671
		x = npop();
672
		npush(x > y);
673
		break;
674
675
	    case '!':
676
		npush(!npop());
677
		break;
678
679
	    case '~':
680
		npush(~npop());
681
		break;
682
683
	    case 'i':
684
3472
		if (p_is_s[0] == 0)
685
3472
		    param[0]++;
686
3472
		if (p_is_s[1] == 0)
687
3472
		    param[1]++;
688
		break;
689
690
	    case '?':
691
		break;
692
693
	    case 't':
694
2198
		x = npop();
695
2198
		if (!x) {
696
		    /* scan forward for %e or %; at level zero */
697
2041
		    cp++;
698
		    level = 0;
699
8135
		    while (*cp) {
700
6094
			if (*cp == '%') {
701
2041
			    cp++;
702
2041
			    if (*cp == '?')
703
				level++;
704
2041
			    else if (*cp == ';') {
705
1884
				if (level > 0)
706
				    level--;
707
				else
708
				    break;
709
157
			    } else if (*cp == 'e' && level == 0)
710
				break;
711
			}
712
713
4053
			if (*cp)
714
4053
			    cp++;
715
		    }
716
		}
717
		break;
718
719
	    case 'e':
720
		/* scan forward for a %; at level zero */
721
157
		cp++;
722
		level = 0;
723
599
		while (*cp) {
724
442
		    if (*cp == '%') {
725
157
			cp++;
726
157
			if (*cp == '?')
727
			    level++;
728
157
			else if (*cp == ';') {
729
157
			    if (level > 0)
730
				level--;
731
			    else
732
				break;
733
			}
734
		    }
735
736
285
		    if (*cp)
737
285
			cp++;
738
		}
739
		break;
740
741
	    case ';':
742
		break;
743
744
	    }			/* endswitch (*cp) */
745
	}			/* endelse (*cp == '%') */
746
747
46119
	if (*cp == '\0')
748
	    break;
749
750
46119
	cp++;
751
    }				/* endwhile (*cp) */
752
753
4870
    get_space(1);
754
4870
    TPS(out_buff)[TPS(out_used)] = '\0';
755
756
    T((T_RETURN("%s"), _nc_visbuf(TPS(out_buff))));
757
4870
    return (TPS(out_buff));
758
4870
}
759
760
#if NCURSES_TPARM_VARARGS
761
#define tparm_varargs tparm
762
#else
763
#define tparm_proto tparm
764
#endif
765
766
NCURSES_EXPORT(char *)
767
tparm_varargs(NCURSES_CONST char *string,...)
768
{
769
9740
    va_list ap;
770
    char *result;
771
772
4870
    _nc_tparm_err = 0;
773
4870
    va_start(ap, string);
774
#ifdef TRACE
775
    TPS(tname) = "tparm";
776
#endif /* TRACE */
777
4870
    result = tparam_internal(string, ap);
778
4870
    va_end(ap);
779
4870
    return result;
780
4870
}
781
782
#if !NCURSES_TPARM_VARARGS
783
NCURSES_EXPORT(char *)
784
tparm_proto(NCURSES_CONST char *string,
785
	    TPARM_ARG a1,
786
	    TPARM_ARG a2,
787
	    TPARM_ARG a3,
788
	    TPARM_ARG a4,
789
	    TPARM_ARG a5,
790
	    TPARM_ARG a6,
791
	    TPARM_ARG a7,
792
	    TPARM_ARG a8,
793
	    TPARM_ARG a9)
794
{
795
    return tparm_varargs(string, a1, a2, a3, a4, a5, a6, a7, a8, a9);
796
}
797
#endif /* NCURSES_TPARM_VARARGS */