28 typedef struct stack_str {
34 static stack S[MAX_PUSHED];
35 static stack vars['z'-'a'+1];
38 static struct arg_str {
46 static va_list tparm_args;
48 static int pusharg(int arg)
50 if (pos == MAX_PUSHED)
53 S[pos++].argnum = arg;
57 static int pushnum(int num)
59 if (pos == MAX_PUSHED)
67 static int getarg(int argnum, int type, anyptr p)
69 while (argcnt < argnum) {
70 arg_list[argcnt].type = INTEGER;
71 arg_list[argcnt++].integer = (int) va_arg(tparm_args, int);
73 if (argcnt > argnum) {
74 if (arg_list[argnum].type != type)
76 else if (type == STRING)
77 *(char **)p = arg_list[argnum].string;
79 *(int *)p = arg_list[argnum].integer;
81 arg_list[argcnt].type = type;
83 *(char **)p = arg_list[argcnt++].string
84 = (char *) va_arg(tparm_args, char *);
86 *(int *)p = arg_list[argcnt++].integer = (int) va_arg(tparm_args, int);
92 static int popstring(char **str)
96 if (S[pos].type != ARG)
98 return(getarg(S[pos].argnum, STRING, (anyptr) str));
101 static int popnum(int *num)
105 switch (S[pos].type) {
107 return (getarg(S[pos].argnum, INTEGER, (anyptr) num));
115 static int cvtchar(const char *sp, char *c)
130 if (sp[1] == '0' && sp[2] == '0') {
134 *c = '\200'; /* '\0' ???? */
148 /* sigh... this has got to be the ugliest code I've ever written.
149 Trying to handle everything has its cost, I guess.
151 It actually isn't to hard to figure out if a given % code is supposed
152 to be interpeted with its termcap or terminfo meaning since almost
153 all terminfo codes are invalid unless something has been pushed on
154 the stack and termcap strings will never push things on the stack
155 (%p isn't used by termcap). So where we have a choice we make the
156 decision by wether or not somthing has been pushed on the stack.
157 The static variable termcap keeps track of this; it starts out set
158 to 1 and is incremented as each argument processed by a termcap % code,
159 however if something is pushed on the stack it's set to 0 and the
160 rest of the % codes are interpeted as terminfo % codes. Another way
161 of putting it is that if termcap equals one we haven't decided either
162 way yet, if it equals zero we're looking for terminfo codes, and if
163 its greater than 1 we're looking for termcap codes.
168 %[[:][-+# ][width][.precision]][doxXs]
169 output pop according to the printf format
170 %c output pop as a char
171 %'c' push character constant c.
172 %{n} push decimal constant n.
173 %p[1-9] push paramter [1-9]
174 %g[a-z] push variable [a-z]
175 %P[a-z] put pop in variable [a-z]
176 %l push the length of pop (a string)
177 %+ add pop to pop and push the result
178 %- subtract pop from pop and push the result
179 %* multiply pop and pop and push the result
180 %& bitwise and pop and pop and push the result
181 %| bitwise or pop and pop and push the result
182 %^ bitwise xor pop and pop and push the result
183 %~ push the bitwise not of pop
184 %= compare if pop and pop are equal and push the result
185 %> compare if pop is less than pop and push the result
186 %< compare if pop is greater than pop and push the result
187 %A logical and pop and pop and push the result
188 %O logical or pop and pop and push the result
189 %! push the logical not of pop
190 %? condition %t if_true [%e if_false] %;
191 if condtion evaulates as true then evaluate if_true,
192 else evaluate if_false. elseif's can be done:
193 %? cond %t true [%e cond2 %t true2] ... [%e condN %t trueN] [%e false] %;
194 %i add one to parameters 1 and 2. (ANSI)
199 %. output parameter as a character
200 %d output parameter as a decimal number
201 %2 output parameter in printf format %02d
202 %3 output parameter in printf format %03d
203 %+x add the character x to parameter and output it as a character
204 (UW) %-x subtract parameter FROM the character x and output it as a char
205 (UW) %ax add the character x to parameter
208 (UW) %sx subtract parameter FROM the character x
209 %>xy if parameter > character x then add character y to parameter
210 %B convert to BCD (parameter = (parameter/10)*16 + parameter%16)
211 %D Delta Data encode (parameter = parameter - 2*(paramter%16))
212 %i increment the first two parameters by one
213 %n xor the first two parameters by 0140
214 (GNU) %m xor the first two parameters by 0177
215 %r swap the first two parameters
216 (GNU) %b backup to previous parameter
217 (GNU) %f skip this parameter
219 Note the two definitions of %a, the GNU defintion is used if the characters
220 after the 'a' are valid, otherwise the UW definition is used.
222 (GNU) used by GNU Emacs termcap libraries
223 (UW) used by the University of Waterloo (MFCF) termcap libraries
227 char *tparm(const char *str, ...) {
228 static char OOPS[] = "OOPS";
229 static char buf[MAX_LINE];
230 register const char *sp;
235 int scan_depth = 0, if_depth;
238 char fmt_buf[MAX_LINE];
241 va_start(tparm_args, str);
250 while (*sp != '\0') {
265 if (*sp == scan_for && if_depth == scan_depth) {
269 } else if (*sp == '?')
271 else if (*sp == ';') {
287 if (popnum(&j) || popnum(&i))
298 if (getarg(termcap - 1, INTEGER, &i))
312 if (getarg(termcap - 1, INTEGER, (anyptr) &i))
316 if ((sp[1] == 'p' || sp[1] == 'c')
317 && sp[2] != '\0' && fmt == NULL) {
318 /* GNU aritmitic parameter, what they
319 realy need is terminfo. */
322 && getarg(termcap - 1 + sp[2] - '@',
323 INTEGER, (anyptr) &val))
326 lc = cvtchar(sp + 2, &c) + 2;
327 /* Mask out 8th bit so \200 can be
328 used for \0 as per GNU doc's */
348 /* Not really GNU's %a after all... */
349 lc = cvtchar(sp, &c);
353 arg_list[termcap - 1].integer = val;
357 sp += cvtchar(sp, &c);
358 arg_list[termcap - 1].integer = c + i;
365 if (popnum(&j) || popnum(&i))
376 if (termcap && (fmt == NULL || *sp == '-')) {
377 if (getarg(termcap - 1, INTEGER, &i))
381 sp += cvtchar(sp, &c);
382 arg_list[termcap - 1].integer = c - i;
391 if (termcap && fmt == NULL)
395 if (termcap && fmt == NULL)
399 if (termcap && fmt == NULL)
403 if (termcap && fmt == NULL)
406 case ':': case ' ': case '#': case 'u':
407 case 'x': case 'X': case 'o': case 'c':
408 case '0': case '1': case '4': case '5':
409 case '6': case '7': case '8': case '9':
417 while(*sp != 's' && *sp != 'x' && *sp != 'X' && *sp != 'd' && *sp != 'o' && *sp != 'c' && *sp != 'u') {
426 conv_char = fmt[strlen(fmt) - 1];
427 if (conv_char == 's') {
430 sprintf(sbuf, fmt, s);
433 if (getarg(termcap++ - 1,
439 if (i == 0 && conv_char == 'c')
442 sprintf(sbuf, fmt, i);
446 while(*fmt != '\0') {
453 if (!termcap || getarg(1, INTEGER, &i))
455 arg_list[1].integer = arg_list[0].integer;
456 arg_list[0].integer = i;
460 if (getarg(1, INTEGER, &i)
461 || arg_list[0].type != INTEGER)
463 arg_list[1].integer++;
464 arg_list[0].integer++;
468 if (!termcap || getarg(1, INTEGER, &i))
470 arg_list[0].integer ^= 0140;
471 arg_list[1].integer ^= 0140;
476 if (popnum(&j) || popnum(&i))
484 if (getarg(termcap-1, INTEGER, &i))
486 sp += cvtchar(sp, &c);
488 sp += cvtchar(sp, &c);
489 arg_list[termcap-1].integer += c;
491 sp += cvtchar(sp, &c);
495 if (!termcap || getarg(termcap-1, INTEGER, &i))
497 arg_list[termcap-1].integer = 16*(i/10)+i%10;
501 if (!termcap || getarg(termcap-1, INTEGER, &i))
503 arg_list[termcap-1].integer = i - 2 * (i % 16);
523 if (termcap || *++sp == '\0')
530 switch(vars[i].type = S[pos].type) {
532 vars[i].argnum = S[pos].argnum;
535 vars[i].value = S[pos].value;
540 if (termcap || *++sp == '\0')
545 switch(vars[i].type) {
547 if (pusharg(vars[i].argnum))
551 if (pushnum(vars[i].value))
561 sp += cvtchar(sp, &c);
562 if (pushnum(c) || *sp++ != '\'')
571 while(isdigit((int) (unsigned char) *sp))
572 i = 10 * i + *sp++ - '0';
573 if (*sp++ != '}' || pushnum(i))
578 if (termcap || popstring(&s))
586 if (termcap || popnum(&j) || popnum(&i))
594 if (termcap || popnum(&j) || popnum(&i))
603 if (getarg(1, INTEGER, &i))
605 arg_list[0].integer ^= 0177;
606 arg_list[1].integer ^= 0177;
610 if (popnum(&j) || popnum(&i))
618 if (popnum(&j) || popnum(&i))
626 if (popnum(&j) || popnum(&i))
634 if (popnum(&j) || popnum(&i))
642 if (popnum(&j) || popnum(&i))
650 if (popnum(&j) || popnum(&i))
658 if (popnum(&j) || popnum(&i))
666 if (popnum(&j) || popnum(&i))
697 if (popnum(&i) || if_depth == 0)
701 scan_depth = if_depth;
709 scan_depth = if_depth;