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