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
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.
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]
23 * Copyright 2015 Gary Mills
24 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
25 * All rights reserved.
28 /* Copyright (c) 1988 AT&T */
29 /* All Rights Reserved */
31 /* Copyright (c) 1979 Regents of the University of California */
35 #include "curses_inc.h"
44 #define _CHCTRL(c) ((c) & 037)
47 char *_branchto(char *, char);
50 * Routine to perform parameter substitution.
51 * instring is a string containing printf type escapes.
52 * The whole thing uses a stack, much like an HP 35.
53 * The following escapes are defined for substituting row/column:
55 * %[:[-+ #0]][0-9][.][0-9][dsoxX]
56 * print pop() as in printf(3), as defined in the local
57 * sprintf(3), except that a leading + or - must be preceded
58 * with a colon (:) to distinguish from the plus/minus operators.
60 * %c print pop() like %c in printf(3)
61 * %l pop() a string address and push its length.
62 * %P[a-z] set dynamic variable a-z
63 * %g[a-z] get dynamic variable a-z
64 * %P[A-Z] set static variable A-Z
65 * %g[A-Z] get static variable A-Z
67 * %p[1-0] push ith parm
68 * %'c' char constant c
69 * %{nn} integer constant nn
71 * %+ %- %* %/ %m arithmetic (%m is mod): push(pop() op pop())
72 * %& %| %^ bit operations: push(pop() op pop())
73 * %= %> %< logical operations: push(pop() op pop())
74 * %A %O logical AND, OR push(pop() op pop())
75 * %! %~ unary operations push(op pop())
77 * %? expr %t thenpart %e elsepart %;
78 * if-then-else, %e elsepart is optional.
79 * else-if's are possible ala Algol 68:
80 * %? c1 %t %e c2 %t %e c3 %t %e c4 %t %e %;
81 * % followed by anything else
82 * is not defined, it may output the character,
83 * and it may not. This is done so that further
84 * enhancements to the format capabilities may
85 * be made without worrying about being upwardly
86 * compatible from buggy code.
88 * all other characters are ``self-inserting''. %% gets % output.
90 * The stack structure used here is based on an idea by Joseph Yao.
94 #define MEM_ALLOC_FAIL 1
95 #define STACK_UNDERFLOW 2
111 longjmp(env
, STACK_UNDERFLOW
);
113 return (st
->stack
[st
->top
]);
117 push(STACK
*st
, long i
)
119 if (st
->top
>= (st
->stacksize
- 1)) {
120 st
->stacksize
+= MAX
;
121 if ((st
->stack
= (void *)realloc(st
->stack
,
122 (st
->stacksize
* sizeof (long)))) == NULL
) {
123 longjmp(env
, MEM_ALLOC_FAIL
);
126 st
->stack
[++st
->top
] = (i
);
133 longjmp(env
, STACK_UNDERFLOW
);
135 return (st
->stack
[st
->top
--]);
138 /* The following routine was added to make lint shut up about converting from
139 * a long to a char *. It is identical to the pop routine, except for the
140 * cast on the return statement.
143 pop_char_p(STACK
*st
)
146 longjmp(env
, STACK_UNDERFLOW
);
148 return ((char *)(st
->stack
[st
->top
--]));
152 init_stack(STACK
*st
)
156 if ((st
->stack
= (void *)malloc(MAX
* sizeof (long))) == NULL
) {
157 longjmp(env
, MEM_ALLOC_FAIL
);
162 free_stack(STACK
*st
)
169 tparm_p0(char *instring
)
171 long p
[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
173 return (tparm(instring
, p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6],
178 tparm_p1(char *instring
, long l1
)
180 long p
[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
184 return (tparm(instring
, p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6],
189 tparm_p2(char *instring
, long l1
, long l2
)
191 long p
[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
196 return (tparm(instring
, p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6],
201 tparm_p3(char *instring
, long l1
, long l2
, long l3
)
203 long p
[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
209 return (tparm(instring
, p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6],
214 tparm_p4(char *instring
, long l1
, long l2
, long l3
, long l4
)
216 long p
[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
223 return (tparm(instring
, p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6],
228 tparm_p7(char *instring
, long l1
, long l2
, long l3
, long l4
, long l5
, long l6
,
231 long p
[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
241 return (tparm(instring
, p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6],
247 tparm(char *instring
, long fp1
, long fp2
, long p3
, long p4
,
248 long p5
, long p6
, long p7
, long p8
, long p9
)
250 static char result
[512];
251 static char added
[100];
261 volatile long p1
= fp1
, p2
= fp2
; /* copy in case < 2 actual parms */
263 char formatbuffer
[100];
266 short *regs
= cur_term
->_regs
;
270 if ((val
= setjmp(env
)) != 0) {
274 fprintf(outf
, "TPARM: Memory allocation"
277 case STACK_UNDERFLOW
:
278 fprintf(outf
, "TPARM: Stack underflow.");
283 if (val
== STACK_UNDERFLOW
)
294 fprintf(outf
, "TPARM: null arg\n");
302 while ((c
= *cp
++) != 0) {
329 format
= formatbuffer
;
332 /* leading ':' to allow +/- in format */
336 /* take care of flags, width and precision */
362 /* add in the conversion type */
374 fprintf(outf
, "TPARM: invalid "
375 "conversion type\n");
383 * Pass off the dirty work to sprintf.
384 * It's debatable whether we should just pull in
385 * the appropriate code here. I decided not to for
389 (void) sprintf(outp
, formatbuffer
,
392 (void) sprintf(outp
, formatbuffer
, op
);
394 * Advance outp past what sprintf just did.
395 * sprintf returns an indication of its length on some
396 * systems, others the first char, and there's
397 * no easy way to tell which. The Sys V on
398 * BSD emulations are particularly confusing.
408 * This code is worth scratching your head at for a
409 * while. The idea is that various weird things can
410 * happen to nulls, EOT's, tabs, and newlines by the
411 * tty driver, arpanet, and so on, so we don't send
412 * them if we can help it. So we instead alter the
413 * place being addessed and then move the cursor
414 * locally using UP or RIGHT.
416 * This is a kludge, clearly. It loses if the
417 * parameterized string isn't addressing the cursor
418 * (but hopefully that is all that %c terminals do
419 * with parms). Also, since tab and newline happen
420 * to be next to each other in ASCII, if tab were
421 * included a loop would be needed. Finally, note
422 * that lots of other processing is done here, so
423 * this hack won't always work (e.g. the Ann Arbor
424 * 4080, which uses %B and then %c.)
428 * Null. Problem is that our
429 * output is, by convention, null terminated.
432 op
= 0200; /* Parity should */
436 * Control D. Problem is that certain very
437 * ancient hardware hangs up on this, so the
438 * current(!) UNIX tty driver doesn't xmit
443 * Newline. Problem is that UNIX will expand
447 xp
= (onrow
? cursor_down
:
449 if (onrow
&& xp
&& op
< lines
-1 &&
454 if (xp
&& instring
==
456 (void) strcat(added
, xp
);
461 * Tab used to be in this group too,
462 * because UNIX might expand it to blanks.
463 * We now require that this tab mode be turned
464 * off by any program using this routine,
465 * or using termcap in general, since some
466 * terminals use tab for other stuff, like
467 * nondestructive space. (Filters like ul
468 * or vcrt will lose, since they can't stty.)
469 * Tab was taken out to get the Ann Arbor
480 xp
= pop_char_p(&stk
);
481 push(&stk
, strlen(xp
));
489 * %i: shorthand for increment first two parms.
490 * Useful for terminals that start numbering from
491 * one instead of zero(like ANSI terminals).
498 /* %pi: push the ith parameter */
531 fprintf(outf
, "TPARM:"
541 /* %Pi: pop from stack into variable i (a-z) */
543 if (*cp
>= 'a' && *cp
<= 'z') {
544 vars
[*cp
++ - 'a'] = pop(&stk
);
546 if (*cp
>= 'A' && *cp
<= 'Z') {
553 fprintf(outf
, "TPARM: bad"
560 /* %gi: push variable i (a-z) */
562 if (*cp
>= 'a' && *cp
<= 'z') {
563 push(&stk
, vars
[*cp
++ - 'a']);
565 if (*cp
>= 'A' && *cp
<= 'Z') {
566 push(&stk
, regs
[*cp
++ - 'A']);
570 fprintf(outf
, "TPARM: bad"
578 /* %'c' : character constant */
584 fprintf(outf
, "TPARM: missing"
592 /* %{nn} : integer constant. */
602 while ((c
= *cp
++) >= '0' && c
<= '9') {
603 op
= 10 * op
+ c
- '0';
608 fprintf(outf
, "TPARM: missing "
614 push(&stk
, (sign
* op
));
617 /* binary operators */
621 push(&stk
, (op
+ op2
));
626 push(&stk
, (op
- op2
));
631 push(&stk
, (op
* op2
));
636 push(&stk
, (op
/ op2
));
641 push(&stk
, (op
% op2
));
646 push(&stk
, (op
& op2
));
651 push(&stk
, (op
| op2
));
656 push(&stk
, (op
^ op2
));
661 push(&stk
, (op
== op2
));
666 push(&stk
, (op
> op2
));
671 push(&stk
, (op
< op2
));
676 push(&stk
, (op
&& op2
));
681 push(&stk
, (op
|| op2
));
684 /* Unary operators. */
686 push(&stk
, !pop(&stk
));
689 push(&stk
, ~pop(&stk
));
692 /* Sorry, no unary minus, because minus is binary. */
695 * If-then-else. Implemented by a low level hack of
696 * skipping forward until the match is found, counting
697 * nested if-then-elses.
699 case '?': /* IF - just a marker */
702 case 't': /* THEN - branch if false */
704 cp
= _branchto(cp
, 'e');
707 case 'e': /* ELSE - branch to ENDIF */
708 cp
= _branchto(cp
, ';');
711 case ';': /* ENDIF - just a marker */
717 fprintf(outf
, "TPARM: bad % "
724 (void) strcpy(outp
, added
);
730 _branchto(register char *cp
, char to
)
732 register int level
= 0;
737 if ((c
= *cp
++) == to
|| c
== ';') {
750 fprintf(outf
, "TPARM: no matching ENDIF");