1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1995-1998 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * tparm.c
31 *
32 * XCurses Library
33 *
34 * Copyright 1990, 1995 by Mrotice Kern Systems Inc. All rights reserved.
35 *
36 */
37
38 #ifdef M_RCSID
39 #ifndef lint
40 static char rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/tparm.c 1.2 1995/08/31 19:44:03 danv Exp $";
41 #endif
42 #endif
43
44 /*l
45 * Substitute the given parameters into the given string by the
46 * following rules (taken from terminfo(5)):
47 *
48 * Cursor addressing and other strings requiring parameters
49 * in the terminal are described by a parameterized string
50 * capability, with like escapes %x in it. For example, to
51 * address the cursor, the cup capability is given, using two
52 * parameters: the row and column to address to. (Rows and
53 * columns are numbered from zero and refer to the physical
54 * screen visible to the user, not to any unseen memory.) If
55 * the terminal has memory relative cursor addressing, that can
56 * be indicated by
57 *
58 * The parameter mechanism uses a stack and special %
59 * codes to manipulate it. Typically a sequence will push one
60 * of the parameters onto the stack and then print it in some
61 * format. Often more complex operations are necessary.
62 *
63 * The % encodings have the following meanings:
64 *
65 * %% outputs `%'
66 * %d print pop() like %d in printf()
67 * %2d print pop() like %2d in printf()
68 * %02d print pop() like %02d in printf()
69 * %3d print pop() like %3d in printf()
70 * %03d print pop() like %03d in printf()
71 * %c print pop() like %c in printf()
72 * %s print pop() like %s in printf()
73 *
74 * %p[1-9] push ith parm
75 * %P[a-z] set variable [a-z] to pop()
76 * %g[a-z] get variable [a-z] and push it
77 * %'c' push char constant c
78 * %{nn} push integer constant nn
79 *
80 * %+ %- %* %/ %m
81 * arithmetic (%m is mod): push(pop() op pop())
82 * %& %| %^ bit operations: push(pop() op pop())
83 * %= %> %< logical operations: push(pop() op pop())
84 * %! %~ unary operations push(op pop())
85 * %i add 1 to first two parms (for ANSI terminals)
86 *
87 * %? expr %t thenpart %e elsepart %;
88 * if-then-else, %e elsepart is optional.
89 * else-if's are possible ala Algol 68:
90 * %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
91 *
92 * For those of the above operators which are binary and not commutative,
93 * the stack works in the usual way, with
94 * %gx %gy %m
95 * resulting in x mod y, not the reverse.
96 */
97
98 #include <private.h>
99 #include <ctype.h>
100 #include <stdarg.h>
101 #include <string.h>
102 #include <m_ord.h>
103
104 #define STACKSIZE 20
105 #define npush(x) if (stack_ptr < STACKSIZE) {\
106 stack[stack_ptr].num = x; stack_ptr++; }
107 #define npop() (stack_ptr > 0 ? stack[--stack_ptr].num : 0)
108 #define spop() (stack_ptr > 0 ? stack[--stack_ptr].str : (char *) 0)
109
110 typedef union {
111 unsigned int num;
112 char* str;
113 } stack_frame;
114
115 static char buffer[256];
116
117 /*f
118 * Do parameter substitution.
119 */
120 const char *
121 #ifdef STDARG_VERSION
tparm(const char * string,...)122 tparm(const char *string, ...)
123 #else
124 tparm(string, p1, p2, p3, p4, p5, p6, p7, p8, p9)
125 const char *string;
126 long p1, p2, p3, p4, p5, p6, p7, p8, p9;
127 #endif /* STDARG_VERSION */
128 {
129 char len;
130 long parm[9];
131 va_list vparm;
132 int varyable[26];
133 int number, level, x, y;
134 int stack_ptr = 0;
135 stack_frame stack[STACKSIZE];
136 char *bufptr = buffer;
137
138 #ifdef STDARG_VERSION
139 /* We've had too many problems porting this particular module
140 * to different compilers and machines, in particular RISC,
141 * that we can't make clever assumptions about how variable
142 * arguments might be handled. The best solution is the
143 * slow and simple one.
144 *
145 * We read the va_args into an array, since the tparm format
146 * string may want to address parameters in arbitrary order.
147 */
148 va_start(vparm, string);
149 for (x = 0; x < 9; ++x)
150 parm[x] = va_arg(vparm, long);
151 va_end(vparm);
152 #else
153 parm[0] = p1;
154 parm[1] = p2;
155 parm[2] = p3;
156 parm[3] = p4;
157 parm[4] = p5;
158 parm[5] = p6;
159 parm[6] = p7;
160 parm[7] = p8;
161 parm[8] = p9;
162 #endif /* STDARG_VERSION */
163
164 #ifdef M_CURSES_TRACE
165 __m_trace(
166 "tparm(\"%s\", %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld)",
167 string, parm[0],
168 parm[1], parm[2], parm[3], parm[4],
169 parm[5], parm[6], parm[7], parm[8]
170 );
171 #endif
172
173 while (*string) {
174 if (*string != '%')
175 *(bufptr++) = *string;
176 else {
177 string++;
178 switch (*string) {
179 default:
180 break;
181 case '%':
182 *(bufptr++) = '%';
183 break;
184 case 'd':
185 bufptr += sprintf(bufptr, "%ld", npop());
186 break;
187 case '0':
188 len = -(*++string - '0');
189 if ((len == (char)-2 || len == (char)-3)
190 && *++string == 'd')
191 bufptr += sprintf(
192 bufptr, "%0*ld", len, npop()
193 );
194 break;
195 case '2':
196 case '3':
197 len = *string++ - '0';
198 if (*string == 'd')
199 bufptr += sprintf(
200 bufptr, "%*ld", len, npop()
201 );
202 break;
203 case 'c':
204 *(bufptr++) = (char) npop();
205 break;
206 case 's':
207 strcpy(bufptr, spop());
208 bufptr += strlen(bufptr);
209 break;
210 case 'p':
211 string++;
212 if ('1' <= *string && *string <= '9')
213 npush(parm[*string - '1']);
214 break;
215 case 'P': {
216 int i;
217 int c;
218 ++string;
219 c = (int)*string;
220 i = m_ord(c);
221 if (0 < i)
222 varyable[i-1] = npop();
223 break;
224 }
225 case 'g': {
226 int i;
227 int c;
228 ++string;
229 c = (int)*string;
230 i = m_ord(c);
231 if (0 < i)
232 npush(varyable[i-1]);
233 break;
234 }
235 case '\'':
236 string++;
237 npush(*string);
238 string++;
239 break;
240 case '{':
241 number = 0;
242 string++;
243 while ('0' <= *string && *string <= '9') {
244 number = number * 10 + *string - '0';
245 string++;
246 }
247 npush(number);
248 break;
249 case '+':
250 y = npop();
251 x = npop();
252 npush(x + y);
253 break;
254 case '-':
255 y = npop();
256 x = npop();
257 npush(x - y);
258 break;
259 case '*':
260 y = npop();
261 x = npop();
262 npush(x * y);
263 break;
264 case '/':
265 y = npop();
266 x = npop();
267 npush(x / y);
268 break;
269 case 'm':
270 y = npop();
271 x = npop();
272 npush(x % y);
273 break;
274 case '&':
275 y = npop();
276 x = npop();
277 npush(x & y);
278 break;
279 case '|':
280 y = npop();
281 x = npop();
282 npush(x | y);
283 break;
284 case '^':
285 y = npop();
286 x = npop();
287 npush(x ^ y);
288 break;
289 case '=':
290 y = npop();
291 x = npop();
292 npush(x == y);
293 break;
294 case '<':
295 y = npop();
296 x = npop();
297 npush(x < y);
298 break;
299 case '>':
300 y = npop();
301 x = npop();
302 npush(x > y);
303 break;
304 case '!':
305 x = npop();
306 npush(!x);
307 break;
308
309 case '~':
310 x = npop();
311 npush(~x);
312 break;
313 case 'i':
314 parm[0]++;
315 parm[1]++;
316 break;
317 case '?':
318 break;
319 case 't':
320 x = npop();
321 if (x) {
322 /* do nothing; keep executing */
323 } else {
324 /* scan forward for %e or %; at
325 * level zero */
326 string++;
327 level = 0;
328 while (*string) {
329 if (*string == '%') {
330 string++;
331 if (*string == '?')
332 level++;
333 else if (*string == ';') {
334 if (level <= 0)
335 break;
336 level--;
337 } else if (*string == 'e' && level == 0)
338 break;
339 }
340 if (*string)
341 string++;
342 }
343 }
344 break;
345 case 'e':
346 /* scan forward for a %; at level zero */
347 string++;
348 level = 0;
349 while (*string) {
350 if (*string == '%') {
351 string++;
352 if (*string == '?')
353 level++;
354 else if (*string == ';') {
355 if (level <= 0)
356 break;
357 level--;
358 }
359 }
360 if (*string)
361 string++;
362 }
363 break;
364 case ';':
365 break;
366
367 } /* endswitch (*string) */
368 } /* endelse (*string == '%') */
369 if (*string == '\0')
370 break;
371 string++;
372 } /* endwhile (*string) */
373 *bufptr = '\0';
374
375 return __m_return_pointer("tparm", buffer);
376 }
377