1 /* Substitution of parameters in strings from terminal descriptions.
2 Copyright (C) 2006-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation, either version 3 of the
7 License, or (at your option) any later version.
9 This file 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Originally by Ross Ridge, Public Domain, 92/02/01 07:30:36 */
25 #include "attribute.h"
29 static const char SCCSid
[] = "@(#) mytinfo tparm.c 3.2 92/02/01 public domain, By Ross Ridge";
44 typedef struct stack_str
51 static stack S
[MAX_PUSHED
];
52 static stack vars
['z'-'a'+1];
65 static va_list tparm_args
;
70 if (pos
== MAX_PUSHED
)
73 S
[pos
++].argnum
= arg
;
80 if (pos
== MAX_PUSHED
)
88 getarg (int argnum
, int type
, void *p
)
90 while (argcnt
< argnum
)
92 arg_list
[argcnt
].type
= INTEGER
;
93 arg_list
[argcnt
++].integer
= (int) va_arg (tparm_args
, int);
97 if (arg_list
[argnum
].type
!= type
)
99 else if (type
== STRING
)
100 *(char **)p
= arg_list
[argnum
].string
;
102 *(int *)p
= arg_list
[argnum
].integer
;
106 arg_list
[argcnt
].type
= type
;
108 *(char **)p
= arg_list
[argcnt
++].string
= (char *) va_arg (tparm_args
, char *);
110 *(int *)p
= arg_list
[argcnt
++].integer
= (int) va_arg (tparm_args
, int);
116 popstring (char **str
)
120 if (S
[pos
].type
!= ARG
)
122 return getarg (S
[pos
].argnum
, STRING
, str
);
133 return getarg (S
[pos
].argnum
, INTEGER
, num
);
142 cvtchar (const char *sp
, char *c
)
159 if (sp
[1] == '0' && sp
[2] == '0')
164 *c
= '\200'; /* '\0' ???? */
176 /* sigh... this has got to be the ugliest code I've ever written.
177 Trying to handle everything has its cost, I guess.
179 It actually isn't too hard to figure out if a given % code is supposed
180 to be interpreted with its termcap or terminfo meaning since almost
181 all terminfo codes are invalid unless something has been pushed on
182 the stack and termcap strings will never push things on the stack
183 (%p isn't used by termcap). So where we have a choice we make the
184 decision by whether or not something has been pushed on the stack.
185 The static variable termcap keeps track of this; it starts out set
186 to 1 and is incremented for each argument processed for a termcap % code,
187 however if something is pushed on the stack it's set to 0 and the
188 rest of the % codes are interpreted as terminfo % codes. Another way
189 of putting it is that if termcap equals one we haven't decided either
190 way yet, if it equals zero we're looking for terminfo codes, and if
191 its greater than 1 we're looking for termcap codes.
196 %[[:][-+# ][width][.precision]][doxXs]
197 output pop according to the printf format
198 %c output pop as a char
199 %'c' push character constant c.
200 %{n} push decimal constant n.
201 %p[1-9] push parameter [1-9]
202 %g[a-z] push variable [a-z]
203 %P[a-z] put pop in variable [a-z]
204 %l push the length of pop (a string)
205 %+ add pop to pop and push the result
206 %- subtract pop from pop and push the result
207 %* multiply pop and pop and push the result
208 %& bitwise and pop and pop and push the result
209 %| bitwise or pop and pop and push the result
210 %^ bitwise xor pop and pop and push the result
211 %~ push the bitwise not of pop
212 %= compare if pop and pop are equal and push the result
213 %> compare if pop is less than pop and push the result
214 %< compare if pop is greater than pop and push the result
215 %A logical and pop and pop and push the result
216 %O logical or pop and pop and push the result
217 %! push the logical not of pop
218 %? condition %t if_true [%e if_false] %;
219 if condition evaluates as true then evaluate if_true,
220 else evaluate if_false. elseif's can be done:
221 %? cond %t true [%e cond2 %t true2] ... [%e condN %t trueN] [%e false] %;
222 %i add one to parameters 1 and 2. (ANSI)
227 %. output parameter as a character
228 %d output parameter as a decimal number
229 %2 output parameter in printf format %02d
230 %3 output parameter in printf format %03d
231 %+x add the character x to parameter and output it as a character
232 (UW) %-x subtract parameter FROM the character x and output it as a char
233 (UW) %ax add the character x to parameter
236 (UW) %sx subtract parameter FROM the character x
237 %>xy if parameter > character x then add character y to parameter
238 %B convert to BCD (parameter = (parameter/10)*16 + parameter%16)
239 %D Delta Data encode (parameter = parameter - 2*(parameter%16))
240 %i increment the first two parameters by one
241 %n xor the first two parameters by 0140
242 (GNU) %m xor the first two parameters by 0177
243 %r swap the first two parameters
244 (GNU) %b backup to previous parameter
245 (GNU) %f skip this parameter
247 Note the two definitions of %a, the GNU definition is used if the characters
248 after the 'a' are valid, otherwise the UW definition is used.
250 (GNU) used by GNU Emacs termcap libraries
251 (UW) used by the University of Waterloo (MFCF) termcap libraries
256 tparm (const char *str
, ...)
259 static char OOPS
[] = "OOPS";
260 static char buf
[MAX_LINE
];
267 char fmt_buf
[MAX_LINE
];
270 va_start (tparm_args
, str
);
299 if (*sp
== scan_for
&& if_depth
== scan_depth
)
327 if (popnum (&j
) || popnum (&i
))
340 if (getarg (termcap
- 1, INTEGER
, &i
))
357 if (getarg (termcap
- 1, INTEGER
, &i
))
361 if ((sp
[1] == 'p' || sp
[1] == 'c')
362 && sp
[2] != '\0' && fmt
== NULL
)
364 /* GNU arithmetic parameter, what they really need is
369 && getarg (termcap
- 1 + sp
[2] - '@', INTEGER
, &val
))
374 lc
= cvtchar (sp
+ 2, &c
) + 2;
375 /* Mask out 8th bit so \200 can be used for \0 as per
398 /* Not really GNU's %a after all... */
401 lc
= cvtchar (sp
, &c
);
406 arg_list
[termcap
- 1].integer
= val
;
412 sp
+= cvtchar (sp
, &c
);
413 arg_list
[termcap
- 1].integer
= c
+ i
;
424 if (popnum (&j
) || popnum (&i
))
435 if (termcap
&& (fmt
== NULL
|| *sp
== '-'))
438 if (getarg (termcap
- 1, INTEGER
, &i
))
444 sp
+= cvtchar (sp
, &c
);
445 arg_list
[termcap
- 1].integer
= c
- i
;
455 if (termcap
&& fmt
== NULL
)
459 if (termcap
&& fmt
== NULL
)
463 if (termcap
&& fmt
== NULL
)
467 if (termcap
&& fmt
== NULL
)
470 case ':': case ' ': case '#': case 'u':
471 case 'x': case 'X': case 'o': case 'c':
472 case '0': case '1': case '4': case '5':
473 case '6': case '7': case '8': case '9':
483 while (*sp
!= 's' && *sp
!= 'x' && *sp
!= 'X' && *sp
!= 'd'
484 && *sp
!= 'o' && *sp
!= 'c' && *sp
!= 'u')
495 char conv_char
= fmt
[strlen (fmt
) - 1];
496 if (conv_char
== 's')
501 sprintf (sbuf
, fmt
, s
);
508 if (getarg (termcap
++ - 1, INTEGER
, &i
))
514 if (i
== 0 && conv_char
== 'c')
515 strcpy (sbuf
, "\000");
517 sprintf (sbuf
, fmt
, i
);
532 if (!termcap
|| getarg (1, INTEGER
, &i
))
534 arg_list
[1].integer
= arg_list
[0].integer
;
535 arg_list
[0].integer
= i
;
542 if (getarg (1, INTEGER
, &i
) || arg_list
[0].type
!= INTEGER
)
545 arg_list
[1].integer
++;
546 arg_list
[0].integer
++;
552 if (!termcap
|| getarg (1, INTEGER
, &i
))
555 arg_list
[0].integer
^= 0140;
556 arg_list
[1].integer
^= 0140;
563 if (popnum (&j
) || popnum (&i
))
573 if (getarg (termcap
-1, INTEGER
, &i
))
577 sp
+= cvtchar (sp
, &c
);
580 sp
+= cvtchar (sp
, &c
);
581 arg_list
[termcap
-1].integer
+= c
;
584 sp
+= cvtchar (sp
, &c
);
592 if (!termcap
|| getarg (termcap
-1, INTEGER
, &i
))
594 arg_list
[termcap
-1].integer
= 16 * (i
/ 10) + i
% 10;
601 if (!termcap
|| getarg (termcap
-1, INTEGER
, &i
))
603 arg_list
[termcap
-1].integer
= i
- 2 * (i
% 16);
613 int i
= (*sp
== '0' ? 9 : *sp
- '1');
623 if (termcap
|| *++sp
== '\0')
631 switch (vars
[i
].type
= S
[pos
].type
)
634 vars
[i
].argnum
= S
[pos
].argnum
;
637 vars
[i
].value
= S
[pos
].value
;
643 if (termcap
|| *++sp
== '\0')
649 switch (vars
[i
].type
)
652 if (pusharg (vars
[i
].argnum
))
656 if (pushnum (vars
[i
].value
))
669 sp
+= cvtchar (sp
, &c
);
670 if (pushnum (c
) || *sp
++ != '\'')
682 while (c_isdigit (*sp
))
683 i
= 10 * i
+ *sp
++ - '0';
684 if (*sp
++ != '}' || pushnum (i
))
693 if (termcap
|| popstring (&s
))
704 if (termcap
|| popnum (&j
) || popnum (&i
))
715 if (termcap
|| popnum (&j
) || popnum (&i
))
727 if (getarg (1, INTEGER
, &i
))
729 arg_list
[0].integer
^= 0177;
730 arg_list
[1].integer
^= 0177;
736 if (popnum (&j
) || popnum (&i
))
747 if (popnum (&j
) || popnum (&i
))
758 if (popnum (&j
) || popnum (&i
))
769 if (popnum (&j
) || popnum (&i
))
780 if (popnum (&j
) || popnum (&i
))
791 if (popnum (&j
) || popnum (&i
))
802 if (popnum (&j
) || popnum (&i
))
813 if (popnum (&j
) || popnum (&i
))
853 if (popnum (&i
) || if_depth
== 0)
858 scan_depth
= if_depth
;
867 scan_depth
= if_depth
;