#include "curses_inc.h"
#include "curshdr.h"
#include "term.h"
#include <string.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef _CHCTRL
#define _CHCTRL(c) ((c) & 037)
#endif
char *_branchto(char *, char);
#define MAX 10
#define MEM_ALLOC_FAIL 1
#define STACK_UNDERFLOW 2
typedef struct {
long top;
int stacksize;
long *stack;
}STACK;
static jmp_buf env;
static long
tops(STACK *st)
{
if (st->top < 0) {
longjmp(env, STACK_UNDERFLOW);
}
return (st->stack[st->top]);
}
static void
push(STACK *st, long i)
{
if (st->top >= (st->stacksize - 1)) {
st->stacksize += MAX;
if ((st->stack = (void *)realloc(st->stack,
(st->stacksize * sizeof (long)))) == NULL) {
longjmp(env, MEM_ALLOC_FAIL);
}
}
st->stack[++st->top] = (i);
}
static long
pop(STACK *st)
{
if (st->top < 0) {
longjmp(env, STACK_UNDERFLOW);
}
return (st->stack[st->top--]);
}
static char *
pop_char_p(STACK *st)
{
if (st->top < 0) {
longjmp(env, STACK_UNDERFLOW);
}
return ((char *)(st->stack[st->top--]));
}
static void
init_stack(STACK *st)
{
st->top = -1;
st->stacksize = MAX;
if ((st->stack = (void *)malloc(MAX * sizeof (long))) == NULL) {
longjmp(env, MEM_ALLOC_FAIL);
}
}
static void
free_stack(STACK *st)
{
free(st->stack);
}
char *
tparm_p0(char *instring)
{
long p[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
return (tparm(instring, p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8]));
}
char *
tparm_p1(char *instring, long l1)
{
long p[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
p[0] = l1;
return (tparm(instring, p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8]));
}
char *
tparm_p2(char *instring, long l1, long l2)
{
long p[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
p[0] = l1;
p[1] = l2;
return (tparm(instring, p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8]));
}
char *
tparm_p3(char *instring, long l1, long l2, long l3)
{
long p[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
p[0] = l1;
p[1] = l2;
p[2] = l3;
return (tparm(instring, p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8]));
}
char *
tparm_p4(char *instring, long l1, long l2, long l3, long l4)
{
long p[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
p[0] = l1;
p[1] = l2;
p[2] = l3;
p[3] = l4;
return (tparm(instring, p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8]));
}
char *
tparm_p7(char *instring, long l1, long l2, long l3, long l4, long l5, long l6,
long l7)
{
long p[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
p[0] = l1;
p[1] = l2;
p[2] = l3;
p[3] = l4;
p[4] = l5;
p[5] = l6;
p[6] = l7;
return (tparm(instring, p[0], p[1], p[2], p[3], p[4], p[5], p[6],
p[7], p[8]));
}
char *
tparm(char *instring, long fp1, long fp2, long p3, long p4,
long p5, long p6, long p7, long p8, long p9)
{
static char result[512];
static char added[100];
long vars[26];
STACK stk;
char *cp = instring;
char *outp = result;
char c;
long op;
long op2;
int sign;
volatile int onrow = 0;
volatile long p1 = fp1, p2 = fp2;
char *xp;
char formatbuffer[100];
char *format;
int looping;
short *regs = cur_term->_regs;
int val;
if ((val = setjmp(env)) != 0) {
#ifdef DEBUG
switch (val) {
case MEM_ALLOC_FAIL:
fprintf(outf, "TPARM: Memory allocation"
" failure.");
break;
case STACK_UNDERFLOW:
fprintf(outf, "TPARM: Stack underflow.");
break;
}
#endif
if (val == STACK_UNDERFLOW)
free_stack(&stk);
return (NULL);
}
init_stack(&stk);
push(&stk, 0);
if (instring == 0) {
#ifdef DEBUG
if (outf)
fprintf(outf, "TPARM: null arg\n");
#endif
free_stack(&stk);
return (NULL);
}
added[0] = 0;
while ((c = *cp++) != 0) {
if (c != '%') {
*outp++ = c;
continue;
}
op = tops(&stk);
switch (c = *cp++) {
case ':':
case ' ':
case '#':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case 'd':
case 's':
case 'o':
case 'x':
case 'X':
format = formatbuffer;
*format++ = '%';
if (c == ':')
c = *cp++;
looping = 1;
while (c && looping)
switch (c) {
case '-':
case '+':
case ' ':
case '#':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
*format++ = c;
c = *cp++;
break;
default:
looping = 0;
}
switch (c) {
case 'd':
case 's':
case 'o':
case 'x':
case 'X':
*format++ = c;
break;
default:
#ifdef DEBUG
if (outf)
fprintf(outf, "TPARM: invalid "
"conversion type\n");
#endif
free_stack(&stk);
return (NULL);
}
*format = '\0';
if (c == 's')
(void) sprintf(outp, formatbuffer, (char *)op);
else
(void) sprintf(outp, formatbuffer, op);
while (*outp)
outp++;
(void) pop(&stk);
continue;
case 'c':
switch (op) {
case 0:
op = 0200;
break;
case _CHCTRL('d'):
case '\n':
xp = (onrow ? cursor_down :
cursor_right);
if (onrow && xp && op < lines-1 &&
cursor_up) {
op += 2;
xp = cursor_up;
}
if (xp && instring ==
cursor_address) {
(void) strcat(added, xp);
op--;
}
break;
}
*outp++ = (char)op;
(void) pop(&stk);
break;
case 'l':
xp = pop_char_p(&stk);
push(&stk, strlen(xp));
break;
case '%':
*outp++ = c;
break;
case 'i':
p1++;
p2++;
break;
case 'p':
switch (c = *cp++) {
case '1':
push(&stk, p1);
break;
case '2':
push(&stk, p2);
break;
case '3':
push(&stk, p3);
break;
case '4':
push(&stk, p4);
break;
case '5':
push(&stk, p5);
break;
case '6':
push(&stk, p6);
break;
case '7':
push(&stk, p7);
break;
case '8':
push(&stk, p8);
break;
case '9':
push(&stk, p9);
break;
default:
#ifdef DEBUG
if (outf)
fprintf(outf, "TPARM:"
" bad parm"
" number\n");
#endif
free_stack(&stk);
return (NULL);
}
onrow = (c == '1');
break;
case 'P':
if (*cp >= 'a' && *cp <= 'z') {
vars[*cp++ - 'a'] = pop(&stk);
} else {
if (*cp >= 'A' && *cp <= 'Z') {
regs[*cp++ - 'A'] =
(short)pop(&stk);
}
#ifdef DEBUG
else if (outf) {
fprintf(outf, "TPARM: bad"
" register name\n");
}
#endif
}
break;
case 'g':
if (*cp >= 'a' && *cp <= 'z') {
push(&stk, vars[*cp++ - 'a']);
} else {
if (*cp >= 'A' && *cp <= 'Z') {
push(&stk, regs[*cp++ - 'A']);
}
#ifdef DEBUG
else if (outf) {
fprintf(outf, "TPARM: bad"
" register name\n");
}
#endif
}
break;
case '\'':
push(&stk, *cp++);
if (*cp++ != '\'') {
#ifdef DEBUG
if (outf)
fprintf(outf, "TPARM: missing"
" closing quote\n");
#endif
free_stack(&stk);
return (NULL);
}
break;
case '{':
op = 0;
sign = 1;
if (*cp == '-') {
sign = -1;
cp++;
} else
if (*cp == '+')
cp++;
while ((c = *cp++) >= '0' && c <= '9') {
op = 10 * op + c - '0';
}
if (c != '}') {
#ifdef DEBUG
if (outf)
fprintf(outf, "TPARM: missing "
"closing brace\n");
#endif
free_stack(&stk);
return (NULL);
}
push(&stk, (sign * op));
break;
case '+':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op + op2));
break;
case '-':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op - op2));
break;
case '*':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op * op2));
break;
case '/':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op / op2));
break;
case 'm':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op % op2));
break;
case '&':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op & op2));
break;
case '|':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op | op2));
break;
case '^':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op ^ op2));
break;
case '=':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op == op2));
break;
case '>':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op > op2));
break;
case '<':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op < op2));
break;
case 'A':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op && op2));
break;
case 'O':
op2 = pop(&stk);
op = pop(&stk);
push(&stk, (op || op2));
break;
case '!':
push(&stk, !pop(&stk));
break;
case '~':
push(&stk, ~pop(&stk));
break;
case '?':
break;
case 't':
if (!pop(&stk))
cp = _branchto(cp, 'e');
break;
case 'e':
cp = _branchto(cp, ';');
break;
case ';':
break;
default:
#ifdef DEBUG
if (outf)
fprintf(outf, "TPARM: bad % "
"sequence\n");
#endif
free_stack(&stk);
return (NULL);
}
}
(void) strcpy(outp, added);
free_stack(&stk);
return (result);
}
char *
_branchto(register char *cp, char to)
{
register int level = 0;
register char c;
while (c = *cp++) {
if (c == '%') {
if ((c = *cp++) == to || c == ';') {
if (level == 0) {
return (cp);
}
}
if (c == '?')
level++;
if (c == ';')
level--;
}
}
#ifdef DEBUG
if (outf)
fprintf(outf, "TPARM: no matching ENDIF");
#endif
return (NULL);
}