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