2 /***************************************************************************
4 ****************************************************************************
5 * ncurses is copyright (C) 1992-1995 *
7 * zmbenhal@netcom.com *
9 * esr@snark.thyrsus.com *
11 * Permission is hereby granted to reproduce and distribute ncurses *
12 * by any means and for any fee, whether alone or as part of a *
13 * larger distribution, in source or in binary form, PROVIDED *
14 * this notice is included with any such distribution, and is not *
15 * removed from any of its header files. Mention of ncurses in any *
16 * applications linked with it is highly appreciated. *
18 * ncurses comes AS IS with no warranty, implied or expressed. *
20 ***************************************************************************/
28 #include <curses.priv.h>
32 MODULE_ID("$Id: lib_tparm.c,v 1.18 1997/04/26 18:37:50 tom Exp $")
38 * Substitute the given parameters into the given string by the following
39 * rules (taken from terminfo(5)):
41 * Cursor addressing and other strings requiring parame-
42 * ters in the terminal are described by a parameterized string
43 * capability, with like escapes %x in it. For example, to
44 * address the cursor, the cup capability is given, using two
45 * parameters: the row and column to address to. (Rows and
46 * columns are numbered from zero and refer to the physical
47 * screen visible to the user, not to any unseen memory.) If
48 * the terminal has memory relative cursor addressing, that can
51 * The parameter mechanism uses a stack and special %
52 * codes to manipulate it. Typically a sequence will push one
53 * of the parameters onto the stack and then print it in some
54 * format. Often more complex operations are necessary.
56 * The % encodings have the following meanings:
59 * %d print pop() like %d in printf()
60 * %2d print pop() like %2d in printf()
61 * %02d print pop() like %02d in printf()
62 * %3d print pop() like %3d in printf()
63 * %03d print pop() like %03d in printf()
64 * %2x print pop() like %2x in printf()
65 * %02x print pop() like %02x in printf()
66 * %3x print pop() like %3x in printf()
67 * %03x print pop() like %03x in printf()
68 * %c print pop() like %c in printf()
69 * %s print pop() like %s in printf()
71 * %p[1-9] push ith parm
72 * %P[a-z] set variable [a-z] to pop()
73 * %g[a-z] get variable [a-z] and push it
74 * %'c' push char constant c
75 * %{nn} push integer constant nn
78 * arithmetic (%m is mod): push(pop() op pop())
79 * %& %| %^ bit operations: push(pop() op pop())
80 * %= %> %< logical operations: push(pop() op pop())
81 * %A %O logical and & or operations for conditionals
82 * %! %~ unary operations push(op pop())
83 * %i add 1 to first two parms (for ANSI terminals)
85 * %? expr %t thenpart %e elsepart %;
86 * if-then-else, %e elsepart is optional.
87 * else-if's are possible ala Algol 68:
88 * %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
90 * For those of the above operators which are binary and not commutative,
91 * the stack works in the usual way, with
93 * resulting in x mod y, not the reverse.
106 static stack_frame stack[STACKSIZE];
107 static int stack_ptr;
109 static const char *tname;
112 static char *out_buff;
113 static size_t out_size;
114 static size_t out_used;
117 void _nc_free_tparm(void)
120 FreeAndNull(out_buff);
127 static void save_text(char *s)
129 size_t want = strlen(s);
130 size_t need = want + out_used + 1;
132 if (need > out_size) {
135 out_buff = malloc(out_size);
137 out_buff = realloc(out_buff, out_size);
139 (void)strcpy(out_buff + out_used, s);
143 static void save_number(const char *fmt, int number)
146 (void)sprintf(temp, fmt, number);
150 static inline void save_char(int c)
157 static inline void npush(int x)
159 if (stack_ptr < STACKSIZE) {
160 stack[stack_ptr].num = x;
165 static inline int npop(void)
167 return (stack_ptr > 0 ? stack[--stack_ptr].num : 0);
170 static inline char *spop(void)
172 return (stack_ptr > 0 ? stack[--stack_ptr].str : 0);
175 static inline char *tparam_internal(const char *string, va_list ap)
185 register const char *cp;
192 * Find the highest parameter-number referred to in the format string.
193 * Use this value to limit the number of arguments copied from the
194 * variable-length argument list.
196 for (cp = string, popcount = number = 0; *cp != '\0'; cp++) {
197 if (cp[0] == '%' && cp[1] != '\0') {
208 if (cp[1] >= '1' && cp[1] <= '9') {
214 case '0': case '1': case '2': case '3': case '4':
215 case '5': case '6': case '7': case '8': case '9':
216 case 'd': case 'c': case 's':
223 if (number > 9) number = 9;
224 for (i = 0; i < max(popcount, number); i++) {
226 * FIXME: potential loss here if sizeof(int) != sizeof(char *).
227 * A few caps (such as plab_norm) have string-valued parms.
229 param[i] = va_arg(ap, int);
233 * This is a termcap compatibility hack. If there are no explicit pop
234 * operations in the string, load the stack in such a way that
235 * successive pops will grab successive parameters. That will make
236 * the expansion of (for example) \E[%d;%dH work correctly in termcap
237 * style, which means tparam() will expand termcap strings OK.
242 for (i = number - 1; i >= 0; i--)
247 if (_nc_tracing & TRACE_CALLS) {
248 for (i = 0; i < popcount; i++)
249 save_number(", %d", param[i]);
250 _tracef(T_CALLED("%s(%s%s)"), tname, _nc_visbuf(string), out_buff);
268 save_number("%d", npop());
272 save_number("%x", npop());
278 if (len == '2' || len == '3')
281 if (*string == 'd') {
283 save_number("%02d", npop());
285 save_number("%03d", npop());
287 else if (*string == 'x') {
289 save_number("%02x", npop());
291 save_number("%03x", npop());
298 if (*string == 'd') {
299 save_number("%2d", npop());
301 else if (*string == 'x') {
302 save_number("%2x", npop());
308 if (*string == 'd') {
309 save_number("%3d", npop());
311 else if (*string == 'x') {
312 save_number("%3x", npop());
326 if (*string >= '1' && *string <= '9')
327 npush(param[*string - '1']);
332 if (*string >= 'a' && *string <= 'z')
333 variable[*string - 'a'] = npop();
338 if (*string >= 'a' && *string <= 'z')
339 npush(variable[*string - 'a']);
351 while (*string >= '0' && *string <= '9') {
352 number = number * 10 + *string - '0';
359 npush(npop() + npop());
369 npush(npop() * npop());
385 npush(npop() && npop());
389 npush(npop() || npop());
393 npush(npop() & npop());
397 npush(npop() | npop());
401 npush(npop() ^ npop());
441 /* scan forward for %e or %; at level zero */
445 if (*string == '%') {
449 else if (*string == ';') {
455 else if (*string == 'e' && level == 0)
466 /* scan forward for a %; at level zero */
470 if (*string == '%') {
474 else if (*string == ';') {
490 } /* endswitch (*string) */
491 } /* endelse (*string == '%') */
497 } /* endwhile (*string) */
499 T((T_RETURN("%s"), _nc_visbuf(out_buff)));
503 char *tparm(const char *string, ...)
508 va_start(ap, string);
512 result = tparam_internal(string, ap);
517 #ifdef __UNUSED__ /* we never documented this, and it confuses Emacs */
518 char *tparam(const char *string, char *buffer, int bufsiz, ...)
523 va_start(ap, bufsiz);
527 if (tparam_internal(string, ap) != 0
528 && (int)out_used < bufsiz)
529 result = strcpy(buffer, out_buff);
533 #endif /* __UNUSED */