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