1 /* Substitution of parameters in strings from terminal descriptions.
2 Copyright (C) 2006, 2012, 2015 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Originally by Ross Ridge, Public Domain, 92/02/01 07:30:36 */
28 static const char SCCSid[] = "@(#) mytinfo tparm.c 3.2 92/02/01 public domain, By Ross Ridge";
43 typedef struct stack_str
50 static stack S[MAX_PUSHED];
51 static stack vars['z'-'a'+1];
64 static va_list tparm_args;
69 if (pos == MAX_PUSHED)
72 S[pos++].argnum = arg;
79 if (pos == MAX_PUSHED)
87 getarg (int argnum, int type, void *p)
89 while (argcnt < argnum)
91 arg_list[argcnt].type = INTEGER;
92 arg_list[argcnt++].integer = (int) va_arg (tparm_args, int);
96 if (arg_list[argnum].type != type)
98 else if (type == STRING)
99 *(char **)p = arg_list[argnum].string;
101 *(int *)p = arg_list[argnum].integer;
105 arg_list[argcnt].type = type;
107 *(char **)p = arg_list[argcnt++].string = (char *) va_arg (tparm_args, char *);
109 *(int *)p = arg_list[argcnt++].integer = (int) va_arg (tparm_args, int);
115 popstring (char **str)
119 if (S[pos].type != ARG)
121 return getarg (S[pos].argnum, STRING, str);
132 return getarg (S[pos].argnum, INTEGER, num);
141 cvtchar (const char *sp, char *c)
158 if (sp[1] == '0' && sp[2] == '0')
163 *c = '\200'; /* '\0' ???? */
175 /* sigh... this has got to be the ugliest code I've ever written.
176 Trying to handle everything has its cost, I guess.
178 It actually isn't to hard to figure out if a given % code is supposed
179 to be interpeted with its termcap or terminfo meaning since almost
180 all terminfo codes are invalid unless something has been pushed on
181 the stack and termcap strings will never push things on the stack
182 (%p isn't used by termcap). So where we have a choice we make the
183 decision by wether or not somthing has been pushed on the stack.
184 The static variable termcap keeps track of this; it starts out set
185 to 1 and is incremented as each argument processed by a termcap % code,
186 however if something is pushed on the stack it's set to 0 and the
187 rest of the % codes are interpeted as terminfo % codes. Another way
188 of putting it is that if termcap equals one we haven't decided either
189 way yet, if it equals zero we're looking for terminfo codes, and if
190 its greater than 1 we're looking for termcap codes.
195 %[[:][-+# ][width][.precision]][doxXs]
196 output pop according to the printf format
197 %c output pop as a char
198 %'c' push character constant c.
199 %{n} push decimal constant n.
200 %p[1-9] push paramter [1-9]
201 %g[a-z] push variable [a-z]
202 %P[a-z] put pop in variable [a-z]
203 %l push the length of pop (a string)
204 %+ add pop to pop and push the result
205 %- subtract pop from pop and push the result
206 %* multiply pop and pop and push the result
207 %& bitwise and pop and pop and push the result
208 %| bitwise or pop and pop and push the result
209 %^ bitwise xor pop and pop and push the result
210 %~ push the bitwise not of pop
211 %= compare if pop and pop are equal and push the result
212 %> compare if pop is less than pop and push the result
213 %< compare if pop is greater than pop and push the result
214 %A logical and pop and pop and push the result
215 %O logical or pop and pop and push the result
216 %! push the logical not of pop
217 %? condition %t if_true [%e if_false] %;
218 if condtion evaulates as true then evaluate if_true,
219 else evaluate if_false. elseif's can be done:
220 %? cond %t true [%e cond2 %t true2] ... [%e condN %t trueN] [%e false] %;
221 %i add one to parameters 1 and 2. (ANSI)
226 %. output parameter as a character
227 %d output parameter as a decimal number
228 %2 output parameter in printf format %02d
229 %3 output parameter in printf format %03d
230 %+x add the character x to parameter and output it as a character
231 (UW) %-x subtract parameter FROM the character x and output it as a char
232 (UW) %ax add the character x to parameter
235 (UW) %sx subtract parameter FROM the character x
236 %>xy if parameter > character x then add character y to parameter
237 %B convert to BCD (parameter = (parameter/10)*16 + parameter%16)
238 %D Delta Data encode (parameter = parameter - 2*(paramter%16))
239 %i increment the first two parameters by one
240 %n xor the first two parameters by 0140
241 (GNU) %m xor the first two parameters by 0177
242 %r swap the first two parameters
243 (GNU) %b backup to previous parameter
244 (GNU) %f skip this parameter
246 Note the two definitions of %a, the GNU definition is used if the characters
247 after the 'a' are valid, otherwise the UW definition is used.
249 (GNU) used by GNU Emacs termcap libraries
250 (UW) used by the University of Waterloo (MFCF) termcap libraries
255 tparm (const char *str, ...)
258 static char OOPS[] = "OOPS";
259 static char buf[MAX_LINE];
266 char fmt_buf[MAX_LINE];
269 va_start (tparm_args, str);
298 if (*sp == scan_for && if_depth == scan_depth)
326 if (popnum (&j) || popnum (&i))
339 if (getarg (termcap - 1, INTEGER, &i))
356 if (getarg (termcap - 1, INTEGER, &i))
360 if ((sp[1] == 'p' || sp[1] == 'c')
361 && sp[2] != '\0' && fmt == NULL)
363 /* GNU arithmetic parameter, what they really need is
368 && getarg (termcap - 1 + sp[2] - '@', INTEGER, &val))
373 lc = cvtchar (sp + 2, &c) + 2;
374 /* Mask out 8th bit so \200 can be used for \0 as per
397 /* Not really GNU's %a after all... */
400 lc = cvtchar (sp, &c);
405 arg_list[termcap - 1].integer = val;
411 sp += cvtchar (sp, &c);
412 arg_list[termcap - 1].integer = c + i;
423 if (popnum (&j) || popnum (&i))
434 if (termcap && (fmt == NULL || *sp == '-'))
437 if (getarg (termcap - 1, INTEGER, &i))
443 sp += cvtchar (sp, &c);
444 arg_list[termcap - 1].integer = c - i;
454 if (termcap && fmt == NULL)
458 if (termcap && fmt == NULL)
462 if (termcap && fmt == NULL)
466 if (termcap && fmt == NULL)
469 case ':': case ' ': case '#': case 'u':
470 case 'x': case 'X': case 'o': case 'c':
471 case '0': case '1': case '4': case '5':
472 case '6': case '7': case '8': case '9':
481 while (*sp != 's' && *sp != 'x' && *sp != 'X' && *sp != 'd'
482 && *sp != 'o' && *sp != 'c' && *sp != 'u')
493 char conv_char = fmt[strlen (fmt) - 1];
494 if (conv_char == 's')
499 sprintf (sbuf, fmt, s);
506 if (getarg (termcap++ - 1, INTEGER, &i))
512 if (i == 0 && conv_char == 'c')
513 strcpy (sbuf, "\000");
515 sprintf (sbuf, fmt, i);
530 if (!termcap || getarg (1, INTEGER, &i))
532 arg_list[1].integer = arg_list[0].integer;
533 arg_list[0].integer = i;
540 if (getarg (1, INTEGER, &i) || arg_list[0].type != INTEGER)
543 arg_list[1].integer++;
544 arg_list[0].integer++;
550 if (!termcap || getarg (1, INTEGER, &i))
553 arg_list[0].integer ^= 0140;
554 arg_list[1].integer ^= 0140;
561 if (popnum (&j) || popnum (&i))
571 if (getarg (termcap-1, INTEGER, &i))
575 sp += cvtchar (sp, &c);
578 sp += cvtchar (sp, &c);
579 arg_list[termcap-1].integer += c;
582 sp += cvtchar (sp, &c);
590 if (!termcap || getarg (termcap-1, INTEGER, &i))
592 arg_list[termcap-1].integer = 16 * (i / 10) + i % 10;
599 if (!termcap || getarg (termcap-1, INTEGER, &i))
601 arg_list[termcap-1].integer = i - 2 * (i % 16);
611 int i = (*sp == '0' ? 9 : *sp - '1');
621 if (termcap || *++sp == '\0')
629 switch (vars[i].type = S[pos].type)
632 vars[i].argnum = S[pos].argnum;
635 vars[i].value = S[pos].value;
641 if (termcap || *++sp == '\0')
647 switch (vars[i].type)
650 if (pusharg (vars[i].argnum))
654 if (pushnum (vars[i].value))
667 sp += cvtchar (sp, &c);
668 if (pushnum (c) || *sp++ != '\'')
680 while (c_isdigit (*sp))
681 i = 10 * i + *sp++ - '0';
682 if (*sp++ != '}' || pushnum (i))
691 if (termcap || popstring (&s))
702 if (termcap || popnum (&j) || popnum (&i))
713 if (termcap || popnum (&j) || popnum (&i))
725 if (getarg (1, INTEGER, &i))
727 arg_list[0].integer ^= 0177;
728 arg_list[1].integer ^= 0177;
734 if (popnum (&j) || popnum (&i))
745 if (popnum (&j) || popnum (&i))
756 if (popnum (&j) || popnum (&i))
767 if (popnum (&j) || popnum (&i))
778 if (popnum (&j) || popnum (&i))
789 if (popnum (&j) || popnum (&i))
800 if (popnum (&j) || popnum (&i))
811 if (popnum (&j) || popnum (&i))
851 if (popnum (&i) || if_depth == 0)
856 scan_depth = if_depth;
865 scan_depth = if_depth;