Files
epics-base/src/libCom/sCalcPerform.c
1998-03-19 20:45:50 +00:00

1459 lines
30 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* $Id$ */
/*
* Author: Julie Sander and Bob Dalesio
* Date: 07-27-87
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
* 03-18-98 tmm Essentially rewritten to support string operators
*/
/* This module contains the code for processing the arithmetic
* expressions defined in calculation records. postfix must be called
* to convert a valid infix expression to postfix. sCalcPerform
* calculates the postfix expression.
*
* Subroutines
*
* Public
*
* sCalcPerform perform the calculation
* args
* double *parg address of arguments
* int numArgs number of arguments in pargs array
* double *psarg address of string arguments
* int numSArgs number of string arguments in psargs array
* double *presult address of double result
* char *psresult address of string-result buffer
* int lenSresult length of string-result buffer
* char *rpcl address of postfix buffer
* returns
* 0 fetched successfully
* -1 fetch failed
*
* Private routine for sCalcPerform
* local_random random number generator
* returns
* double value between 0.00 and 1.00
*/
#ifdef vxWorks
#include <vxWorks.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "dbDefs.h"
#include "cvtFast.h"
#define epicsExportSharedSymbols
#include "sCalcPostfix.h"
#include "sCalcPostfixPvt.h"
static double local_random();
static int isnan(double d)
{
union { long l[2]; double d; } u;
u.d = d;
if ((u.l[0] & 0x7ff00000) != 0x7ff00000) return(0);
if (u.l[1] || (u.l[0] & 0x000fffff)) return(1);
return(0);
}
#define myNINT(a) ((int)((a) >= 0 ? (a)+0.5 : (a)-0.5))
#ifndef PI
#define PI 3.141592654
#endif
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)<(b)?(a):(b)
#define STACKSIZE 30 /* <-------------------------<<<<<<< */
struct stackElement {
double d;
char *s;
};
#define DEBUG 0
volatile int sCalcPerformDebug = 0;
#if DEBUG
int sCalcStackHW = 0;
int sCalcStackLW = 0;
#define INC(ps) {if ((int)(++(ps)-top) > sCalcStackHW) sCalcStackHW = (int)((ps)-top);}
#define DEC(ps) {if ((int)(--(ps)-top) < sCalcStackLW) sCalcStackLW = (int)((ps)-top);}
#else
#define INC(ps) ++ps
#define DEC(ps) ps--
#endif
#define isDouble(ps) ((ps)->s==NULL)
#define isString(ps) ((ps)->s)
#define cleanStringElement(ps) {free((ps)->s); (ps)->s=NULL;}
static void cleanStackElement(struct stackElement *ps)
{
if (isString(ps)) {
free(ps->s);
ps->s = NULL;
}
}
static void cleanup(struct stackElement *ps, struct stackElement *pe)
{
for (; ps <= pe; ps++) {
if (isString(ps)) {
free(ps->s);
ps->s = NULL;
}
}
}
#define toDouble(ps) {if (isString(ps)) to_double(ps);}
/* convert stack element to double */
static void to_double(struct stackElement *ps)
{
ps->d = atof(ps->s);
free(ps->s);
ps->s = NULL;
}
#define toString(ps) {if (isDouble(ps)) to_string(ps);}
/* convert stack element to string */
static void to_string(struct stackElement *ps)
{
ps->s = calloc(20, 1);
/* any precision greater than 8 results in (slow) sprintf call */
if (isnan(ps->d))
strcpy(ps->s,"NaN");
else
(void)cvtDoubleToString(ps->d, ps->s, 8);
}
static char *findConversionIndicator(char *s)
{
char *cc=NULL, *s1, *retval;
while (s && *s) {
if ((s1 = strstr(s, "%%")) != NULL) {
/* not a conversion/assignment indicator; skip over */
s = s1+2; continue;
}
if ((s = strchr(s, (int)'%')) == NULL) {
return(NULL);
}
if ((cc = strpbrk(s, "pwn$c[deEfgGiousxX")) == NULL) {
return(NULL);
}
/*
* (*cc) is a conversion character; look for suppressed assignment
* ('*' occurring after '%' and before conversion character)
*/
s1 = strchr(s, (int)'*');
if (s1 && (s1 < cc)) {
/* suppressed assignment; skip past conversion character */
s = cc+1;
if (*cc == '[') {
/* skip character set ([..], []..], or [^]..]) */
if (cc[1] == ']') {
s = &(cc[2]);
} else if ((cc[1] == '^') && (cc[2] == ']')) {
s = &(cc[3]);
}
s = strchr(s, (int)']');
if (s == NULL) {
/* bad character-set syntax */
return(NULL);
}
s++; /* skip past ']' */
}
/* keep looking for conversion/assignment character */
continue;
} else {
/* (*cc) is a conversion/assignment character */
break;
}
}
if (cc == NULL) return(NULL);
retval = cc;
/*
* (*cc) is a conversion/assignment indicator. Make sure there
* aren't any more in the format string.
*/
s = cc+1;
while (s && *s) {
if ((s1 = strstr(s, "%%")) != NULL) {
/* not a conversion/assignment indicator; skip over */
s = s1+2; continue;
}
if ((s = strchr(s, (int)'%')) == NULL) return(retval);
if ((cc = strpbrk(s, "pwn$c[deEfgGiousxX")) == NULL) return(retval);
/*
* (*cc) is a conversion character; look for suppressed assignment
* ('*' occurring after '%' and before conversion character)
*/
s1 = strchr(s, (int)'*');
if (s1 && (s1 < cc)) {
/* suppressed assignment; skip past conversion character */
s = cc+1;
if (*cc == '[') {
/* skip character set ([..], []..], or [^]..]) */
if (cc[1] == ']') {
s = &(cc[2]);
} else if ((cc[1] == '^') && (cc[2] == ']')) {
s = &(cc[3]);
}
s = strchr(s, (int)']');
if (s == NULL) return(NULL); /* bad character-set syntax */
s++; /* skip past ']' */
}
continue;
} else {
/* (*cc) assignment is not suppressed */
return(NULL);
}
}
return(retval);
}
#if DEBUG
/* Override standard EPICS expression evaluator (if we're loaded after it) */
epicsShareFunc long epicsShareAPI
calcPerform(double *parg, double *presult, char *post)
{
return(sCalcPerform(parg, 12, NULL, 0, presult, NULL, 0, post));
}
#endif
epicsShareFunc long epicsShareAPI
sCalcPerform(double *parg, int numArgs, char **psarg, int numSArgs, double *presult, char *psresult, int lenSresult, char *post)
{
struct stackElement stack[STACKSIZE], *top;
register struct stackElement *ps, *ps1, *ps2;
char *s2, tmpstr[1000];
register char *s, *s1;
register int i, j, k;
long l;
unsigned short ui;
unsigned long ul;
float f;
double d;
register double *topd, *pd;
short h, got_if;
#if DEBUG
if (sCalcPerformDebug>=10) {
int more;
printf("sCalcPerform: postfix:");
for (s=post, more=1; more;) {
printf("%2d ", *s);
switch (*s) {
case END_STACK:
more = 0;
break;
case LITERAL:
printf("(0x");
for (i=0, s++; i<8; i++, s++) printf("%2x ", (unsigned int)(unsigned char)*s);
printf(") ");
break;
case SLITERAL:
s++; /* point past code */
printf("'");
while (*s) printf("%c", *s++);
printf("' ");
s++;
break;
case FETCH:
s++; /* point past code */
printf("@%d ", *s++);
break;
case SFETCH:
s++; /* point past code */
printf("$%d ", *s++);
break;
default:
if (*s == BAD_EXPRESSION) more=0;
s++;
break;
}
}
printf("\n");
}
#endif
/* Make sure postfix expression exists and is nontrivial */
/* if ((*post == END_STACK) || (*post == BAD_EXPRESSION)) return(-1);*/
if (*post == BAD_EXPRESSION) return(-1);
if (*post++ != USES_STRING) {
topd = pd = (double *)&stack[10];
pd--;
/* No string expressions */
while (*post != END_STACK) {
switch (*post){
case FETCH:
++pd;
++post;
*pd = (*post < numArgs) ? parg[*post] : 0;
break;
case STORE:
/* not implemented */
return(-1);
case CONST_PI:
++pd;
*pd = PI;
break;
case CONST_D2R:
++pd;
*pd = PI/180.;
break;
case CONST_R2D:
++pd;
*pd = 180./PI;
break;
case CONST_S2R:
++pd;
*pd = PI/(180.*3600);
break;
case CONST_R2S:
++pd;
*pd = (180.*3600)/PI;
break;
case ADD:
--pd;
*pd = *pd + pd[1];
break;
case SUB:
--pd;
*pd = *pd - pd[1];
break;
case MULT:
--pd;
*pd = *pd * pd[1];
break;
case DIV:
--pd;
if (pd[1] == 0) /* can't divide by zero */
return(-1);
*pd = *pd / pd[1];
break;
case COND_IF:
/* if false condition then skip true expression */
if (*pd == 0.0) {
/* skip to matching COND_ELSE */
for (got_if=1; got_if>0 && *(post+1) != END_STACK; ++post) {
switch(post[1]) {
case LITERAL: post+=8; break;
case COND_IF: got_if++; break;
case COND_ELSE: got_if--; break;
case FETCH: case SFETCH: post++; break;
}
}
}
/* remove condition from stack top */
--pd;
break;
case COND_ELSE:
/* result, true condition is on stack so skip false condition */
/* skip to matching COND_END */
for (got_if=1; got_if>0 && *(post+1) != END_STACK; ++post) {
switch(post[1]) {
case LITERAL: post+=8; break;
case COND_IF: got_if++; break;
case COND_ELSE: got_if--; break;
case FETCH: post++; break;
}
}
break;
case COND_END:
break;
case ABS_VAL:
if (*pd < 0 ) *pd *= -1;
break;
case UNARY_NEG:
*pd *= -1;
break;
case SQU_RT:
/* check for neg number */
if (*pd < 0) return(-1);
*pd = sqrt(*pd);
break;
case EXP:
*pd = exp(*pd);
break;
case LOG_10:
/* check for neg number */
if (*pd < 0) return(-1);
*pd = log10(*pd);
break;
case LOG_E:
/* check for neg number */
if (*pd < 0) return(-1);
*pd = log(*pd);
break;
case RANDOM:
++pd;
*pd = local_random();
break;
case EXPON:
--pd;
if (*pd == 0) break;
if (*pd < 0) {
i = (int) pd[1];
/* is exponent an integer? */
if ((pd[1] - (double)i) != 0) return (-1);
*pd = exp(pd[1] * log(-(*pd)));
/* is value negative */
if ((i % 2) > 0) *pd = -(*pd);
} else {
*pd = exp(pd[1] * log(*pd));
}
break;
case MODULO:
--pd;
if ((int)(pd[1]) == 0)
return(-1);
*pd = (double)((int)(*pd) % (int)(pd[1]));
break;
case REL_OR:
--pd;
*pd = *pd || pd[1];
break;
case REL_AND:
--pd;
*pd = *pd && pd[1];
break;
case BIT_OR:
/* force double values into integers and or them */
--pd;
*pd = (int)(pd[1]) | (int)(*pd);
break;
case BIT_AND:
/* force double values into integers and and them */
--pd;
*pd = (int)(pd[1]) & (int)(*pd);
break;
case BIT_EXCL_OR:
/* force double values to integers to exclusive or them */
--pd;
*pd = (int)(pd[1]) ^ (int)(*pd);
break;
case GR_OR_EQ:
--pd;
*pd = *pd >= pd[1];
break;
case GR_THAN:
--pd;
*pd = *pd > pd[1];
break;
case LESS_OR_EQ:
--pd;
*pd = *pd <= pd[1];
break;
case LESS_THAN:
--pd;
*pd = *pd < pd[1];
break;
case NOT_EQ:
--pd;
*pd = *pd != pd[1];
break;
case EQUAL:
--pd;
*pd = *pd == pd[1];
break;
case RIGHT_SHIFT:
--pd;
*pd = (int)(*pd) >> (int)(pd[1]);
break;
case LEFT_SHIFT:
--pd;
*pd = (int)(*pd) << (int)(pd[1]);
break;
case MAX_VAL:
--pd;
if (*pd < pd[1]) *pd = pd[1];
break;
case MIN_VAL:
--pd;
if (*pd > pd[1]) *pd = pd[1];
break;
case ACOS:
*pd = acos(*pd);
break;
case ASIN:
*pd = asin(*pd);
break;
case ATAN:
*pd = atan(*pd);
break;
case ATAN2:
--pd;
*pd = atan2(pd[1], *pd);
break;
case COS:
*pd = cos(*pd);
break;
case SIN:
*pd = sin(*pd);
break;
case TAN:
*pd = tan(*pd);
break;
case COSH:
*pd = cosh(*pd);
break;
case SINH:
*pd = sinh(*pd);
break;
case TANH:
*pd = tanh(*pd);
break;
case CEIL:
*pd = ceil(*pd);
break;
case FLOOR:
*pd = floor(*pd);
break;
case NINT:
d = *pd;
*pd = (double)(long)(d >= 0 ? d+0.5 : d-0.5);
break;
case REL_NOT:
*pd = (*pd ? 0 : 1);
break;
case BIT_NOT:
*pd = ~(int)(*pd);
break;
case LITERAL:
++pd;
++post;
if (post == NULL) {
++post;
printf("%.7s bad constant in expression\n",post);
*pd = 0.;
break;
}
memcpy((void *)&(*pd),post,8);
post += 7;
break;
default:
break;
}
/* move ahead in postfix expression */
++post;
}
/* if everything is peachy,the stack should end at its first position */
if (pd != topd) return(-1);
#if DEBUG > 1
/* check out floating rep of numbers like NaN, Inf */
{
union { unsigned char s[8]; double d; } u;
u.d = *pd;
printf("sCalcPerform: result: %g = (0x", *pd);
for (i=0; i<8; i++) printf("%2x ", u.s[i]);
printf(") \n");
}
#endif
*presult = *pd;
if (psresult && (lenSresult > 15)) {
if (isnan(*pd))
strcpy(psresult,"NaN");
else
(void)cvtDoubleToString(*pd, psresult, 8);
}
} else {
/*** expression requires string operations ***/
top = ps = &stack[10];
ps--; /* Expression handler assumes ps is pointing to a filled element */
/* string expressions and values handled */
while (*post != END_STACK) {
switch (*post){
case FETCH:
INC(ps);
++post;
ps->s = NULL;
ps->d = (*post < numArgs) ? parg[*post] : 0;
break;
case SFETCH:
INC(ps);
++post;
if (*post < numSArgs) {
/* fetch from string variable */
ps->s = calloc(strlen(psarg[*post])+1, 1);
strcpy(ps->s, psarg[*post]);
} else {
/* fetch from variable that caller did not supply */
ps->s = calloc(1, 1);
*(ps->s) = 0;
}
break;
case STORE:
/* not implemented */
cleanup(top, ps);
return(-1);
case CONST_PI:
INC(ps);
ps->s = NULL;
ps->d = PI;
break;
case CONST_D2R:
INC(ps);
ps->s = NULL;
ps->d = PI/180.;
break;
case CONST_R2D:
INC(ps);
ps->s = NULL;
ps->d = 180./PI;
break;
case CONST_S2R:
INC(ps);
ps->s = NULL;
ps->d = PI/(180.*3600);
break;
case CONST_R2S:
INC(ps);
ps->s = NULL;
ps->d = (180.*3600)/PI;
break;
case ADD:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d + ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d + ps1->d;
} else {
/* concatenate two strings */
s = ps->s;
ps->s = calloc(strlen(ps->s) + strlen(ps1->s) + 1, 1);
strcpy(ps->s, s);
strcat(ps->s, ps1->s);
free(s);
cleanStringElement(ps1);
}
break;
case SUB:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d - ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d - ps1->d;
} else {
/* subtract ps1->s from ps->s */
s = strstr(ps->s, ps1->s);
s1 = ps->s;
s2 = ps1->s;
if (s && (strlen(s2) <= (strlen(s1) - (s - s1)))) {
for (s1=s+strlen(s2); *s1; s++, s1++) *s = *s1;
*s = '\0';
}
cleanStringElement(ps1);
}
break;
case MULT:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = ps->d * ps1->d;
break;
case DIV:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
if (ps1->d == 0) /* can't divide by zero */
return(-1);
ps->d = ps->d / ps1->d;
break;
case COND_IF:
/* if false condition then skip true expression */
toDouble(ps);
if (ps->d == 0.0) {
/* skip to matching COND_ELSE */
for (got_if=1; got_if>0 && *(post+1) != END_STACK; ++post) {
switch(post[1]) {
case LITERAL: post+=8; break;
case SLITERAL: while (*(++post)); break;
case COND_IF: got_if++; break;
case COND_ELSE: got_if--; break;
case FETCH: case SFETCH: post++; break;
}
}
}
/* remove condition from stack top */
DEC(ps);
break;
case COND_ELSE:
/* result, true condition is on stack so skip false condition */
/* skip to matching COND_END */
for (got_if=1; got_if>0 && *(post+1) != END_STACK; ++post) {
switch(post[1]) {
case LITERAL: post+=8; break;
case SLITERAL: while (*(++post)); break;
case COND_IF: got_if++; break;
case COND_ELSE: got_if--; break;
case FETCH: case SFETCH: post++; break;
}
}
break;
case COND_END:
break;
case ABS_VAL:
toDouble(ps);
if (ps->d < 0 ) ps->d *= -1;
break;
case UNARY_NEG:
toDouble(ps);
ps->d *= -1;
break;
case SQU_RT:
toDouble(ps);
/* check for neg number */
if (ps->d < 0) {cleanup(top, ps); return(-1);}
ps->d = sqrt(ps->d);
break;
case EXP:
toDouble(ps);
ps->d = exp(ps->d);
break;
case LOG_10:
toDouble(ps);
/* check for neg number */
if (ps->d < 0) {cleanup(top, ps); return(-1);}
ps->d = log10(ps->d);
break;
case LOG_E:
toDouble(ps);
/* check for neg number */
if (ps->d < 0) {cleanup(top, ps); return(-1);}
ps->d = log(ps->d);
break;
case RANDOM:
INC(ps);
ps->d = local_random();
ps->s = NULL;
break;
case EXPON:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
if (ps->d == 0) break;
if (ps->d < 0) {
i = (int) ps1->d;
/* is exponent an integer? */
if ((ps1->d - (double)i) != 0) return (-1);
ps->d = exp(ps1->d * log(-(ps->d)));
/* is value negative */
if ((i % 2) > 0) ps->d = -ps->d;
} else {
ps->d = exp(ps1->d * log(ps->d));
}
break;
case MODULO:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
if ((int)ps1->d == 0)
return(-1);
ps->d = (double)((int)ps->d % (int)ps1->d);
break;
case REL_OR:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = ps->d || ps1->d;
break;
case REL_AND:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = ps->d && ps1->d;
break;
case BIT_OR:
/* force double values into integers and or them */
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = (int)(ps1->d) | (int)(ps->d);
break;
case BIT_AND:
/* force double values into integers and and them */
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = (int)(ps1->d) & (int)(ps->d);
break;
case BIT_EXCL_OR:
/* force double values to integers to exclusive or them */
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = (int)(ps1->d) ^ (int)(ps->d);
break;
case GR_OR_EQ:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d >= ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d >= ps1->d;
} else {
/* compare ps->s to ps1->s */
ps->d = (double)(strcmp(ps->s, ps1->s) >= 0);
free(ps->s);
ps->s = NULL;
cleanStringElement(ps1);
}
break;
case GR_THAN:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d > ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d > ps1->d;
} else {
/* compare ps->s to ps1->s */
ps->d = (double)(strcmp(ps->s, ps1->s) > 0);
free(ps->s);
ps->s = NULL;
cleanStringElement(ps1);
}
break;
case LESS_OR_EQ:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d <= ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d <= ps1->d;
} else {
/* compare ps->s to ps1->s */
ps->d = (double)(strcmp(ps->s, ps1->s) <= 0);
free(ps->s);
ps->s = NULL;
cleanStringElement(ps1);
}
break;
case LESS_THAN:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d < ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d < ps1->d;
} else {
/* compare ps->s to ps1->s */
ps->d = (double)(strcmp(ps->s, ps1->s) < 0);
free(ps->s);
ps->s = NULL;
cleanStringElement(ps1);
}
break;
case NOT_EQ:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d != ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d != ps1->d;
} else {
/* compare ps->s to ps1->s */
ps->d = (double)(strcmp(ps->s, ps1->s) != 0);
free(ps->s);
ps->s = NULL;
cleanStringElement(ps1);
}
break;
case EQUAL:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
ps->d = ps->d == ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
ps->d = ps->d == ps1->d;
} else if ((isString(ps)) && (isString(ps1))) {
/* compare ps->s to ps1->s */
ps->d = (double)(strcmp(ps->s, ps1->s) == 0);
free(ps->s);
ps->s = NULL;
cleanStringElement(ps1);
}
break;
case RIGHT_SHIFT:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = (int)(ps->d) >> (int)(ps1->d);
break;
case LEFT_SHIFT:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = (int)(ps->d) << (int)(ps1->d);
break;
case MAX_VAL:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
if (ps->d < ps1->d) ps->d = ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
if (ps->d < ps1->d) ps->d = ps1->d;
} else {
/* compare ps->s to ps1->s */
if (strcmp(ps->s, ps1->s) < 0) {
s = ps->s;
ps->s = ps1->s;
ps1->s = s;
}
cleanStringElement(ps1);
}
break;
case MIN_VAL:
ps1 = ps;
DEC(ps);
if (isDouble(ps)) {
toDouble(ps1);
if (ps->d > ps1->d) ps->d = ps1->d;
} else if (isDouble(ps1)) {
to_double(ps);
if (ps->d > ps1->d) ps->d = ps1->d;
} else {
/* compare ps->s to ps1->s */
if (strcmp(ps->s, ps1->s) > 0) {
s = ps->s;
ps->s = ps1->s;
ps1->s = s;
}
cleanStringElement(ps1);
}
break;
case ACOS:
toDouble(ps);
ps->d = acos(ps->d);
break;
case ASIN:
toDouble(ps);
ps->d = asin(ps->d);
break;
case ATAN:
toDouble(ps);
ps->d = atan(ps->d);
break;
case ATAN2:
ps1 = ps;
DEC(ps);
toDouble(ps1);
toDouble(ps);
ps->d = atan2(ps1->d, ps->d);
break;
case COS:
toDouble(ps);
ps->d = cos(ps->d);
break;
case SIN:
toDouble(ps);
ps->d = sin(ps->d);
break;
case TAN:
toDouble(ps);
ps->d = tan(ps->d);
break;
case COSH:
toDouble(ps);
ps->d = cosh(ps->d);
break;
case SINH:
toDouble(ps);
ps->d = sinh(ps->d);
break;
case TANH:
toDouble(ps);
ps->d = tanh(ps->d);
break;
case CEIL:
toDouble(ps);
ps->d = ceil(ps->d);
break;
case FLOOR:
toDouble(ps);
ps->d = floor(ps->d);
break;
case NINT:
if (isDouble(ps)) {
d = ps->d;
ps->d = (double)(long)(d >= 0 ? d+0.5 : d-0.5);
} else {
/* hunt down integer and convert */
s = strpbrk(ps->s,"0123456789");
if ((s > ps->s) && (s[-1] == '.')) s--;
if ((s > ps->s) && (s[-1] == '-')) s--;
d = s ? atof(s) : 0.0;
free(ps->s); ps->s = NULL;
ps->d = (double)(long)(d >= 0 ? d+0.5 : d-0.5);
}
break;
case REL_NOT:
toDouble(ps);
ps->d = (ps->d ? 0 : 1);
break;
case BIT_NOT:
toDouble(ps);
ps->d = ~(int)(ps->d);
break;
case LITERAL:
INC(ps);
++post;
if (post == NULL) {
++post;
printf("%.7s bad constant in expression\n",post);
ps->s = NULL;
ps->d = 0.;
break;
}
memcpy((void *)&(ps->d),post,8);
ps->s = NULL;
post += 7;
break;
case SLITERAL:
INC(ps);
++post;
if (post == NULL) {
++post;
printf("%.7s bad constant in expression\n",post);
ps->s = NULL;
ps->d = 0.;
break;
}
ps->s = calloc(strlen(post)+1, 1);
strcpy(ps->s, post);
/* skip to end of string */
while (*post) post++;
break;
case TO_DOUBLE:
if (isString(ps)) {
/* hunt down number and convert */
s = strpbrk(ps->s,"0123456789");
if ((s > ps->s) && (s[-1] == '.')) s--;
if ((s > ps->s) && (s[-1] == '-')) s--;
ps->d = s ? atof(s) : 0.0;
free(ps->s); ps->s = NULL;
}
break;
case TO_STRING:
toString(ps);
break;
case PRINTF:
ps1 = ps;
DEC(ps);
if (isDouble(ps))
{cleanup(top, ps1); return(-1);}
s = ps->s;
while ((s1 = strstr(s, "%%"))) {s = s1+2;}
if (((s = strpbrk(s, "%")) == NULL) ||
((s = strpbrk(s+1, "*cdeEfgGiousxX")) == NULL)) {
/* no printf arguments needed */
sprintf(tmpstr, ps->s);
} else {
switch (*s) {
default: case '*':
cleanup(top, ps1);
return(-1);
break;
case 'c': case 'd': case 'i': case 'o':
case 'u': case 'x': case 'X':
toDouble(ps1);
l = myNINT(ps1->d);
sprintf(tmpstr, ps->s, l);
break;
case 'e': case 'E': case 'f': case 'g': case 'G':
toDouble(ps1);
sprintf(tmpstr, ps->s, ps1->d);
break;
case 's':
toString(ps1);
sprintf(tmpstr, ps->s, ps1->s);
break;
}
}
if (strlen(ps->s) < strlen(tmpstr)) {
free(ps->s);
ps->s = calloc(strlen(tmpstr)+1, 1);
}
strcpy(ps->s, tmpstr);
cleanStackElement(ps1);
break;
case SSCANF:
ps1 = ps;
DEC(ps);
if (isDouble(ps) || isDouble(ps1))
{cleanup(top, ps1); return(-1);}
s = findConversionIndicator(ps1->s);
if (s == NULL) {cleanup(top, ps1); return(-1);}
switch (*s) {
default: case 'p': case 'w': case 'n': case '$':
cleanup(top, ps1);
return(-1);
break;
case 'd': case 'i':
if (s[-1] == 'h') {
sscanf(ps->s, ps1->s, &h);
ps->d = (double)h;
} else {
sscanf(ps->s, ps1->s, &l);
ps->d = (double)l;
}
cleanStringElement(ps);
ps->s = NULL;
break;
case 'o': case 'u': case 'x': case 'X':
if (s[-1] == 'h') {
sscanf(ps->s, ps1->s, &ui);
ps->d = (double)ui;
} else {
sscanf(ps->s, ps1->s, &ul);
ps->d = (double)ul;
}
cleanStringElement(ps);
ps->s = NULL;
break;
case 'e': case 'E': case 'f': case 'g': case 'G':
if (s[-1] == 'l') {
sscanf(ps->s, ps1->s, &(ps->d));
} else {
sscanf(ps->s, ps1->s, &f);
ps->d = (double)f;
}
cleanStringElement(ps);
ps->s = NULL;
break;
case 'c': case '[': case 's':
sscanf(ps->s, ps1->s, tmpstr);
if (strlen(ps->s) < strlen(tmpstr)) {
free(ps->s);
ps->s = calloc(strlen(tmpstr)+1, 1);
}
strcpy(ps->s, tmpstr);
break;
}
cleanStringElement(ps1);
break;
case SUBRANGE:
ps2 = ps;
DEC(ps);
ps1 = ps;
DEC(ps);
toString(ps);
k = strlen(ps->s);
if (isDouble(ps1)) {
i = ps1->d;
if (i < 0) i += k;
} else {
s = strstr(ps->s, ps1->s);
i = s ? (s - ps->s) + strlen(ps1->s) : 0;
}
if (isDouble(ps2)) {
j = ps2->d;
if (j < 0) j += k;
} else {
if (*(ps2->s)) {
s = strstr(ps->s, ps2->s);
j = s ? (s - ps->s) - 1 : k;
} else {
j = k;
}
}
i = MAX(MIN(i,k),0);
j = MIN(j,k);
for (s=ps->s, s1=s+i, s2=s+j ; *s1 && s1 <= s2; )
{*s++ = *s1++;}
*s = 0;
break;
case REPLACE:
ps2 = ps;
DEC(ps);
ps1 = ps;
DEC(ps);
toString(ps);
toString(ps1);
toString(ps2);
i = strlen(ps->s);
j = strlen(ps1->s);
k = strlen(ps2->s);
s1 = strstr(ps->s, ps1->s);
s2 = ps2->s;
if (s1 >= ps->s) {
char *s_old, *s_dest;
s_old = s = ps->s;
if (k > j) ps->s = malloc(i - j + k + 1);
s_dest = ps->s;
while (s < s1) *s_dest++ = *s++;
s += j;
while (*s2) *s_dest++ = *s2++;
while (*s) *s_dest++ = *s++;
*s_dest = '\0';
if (k > j) free(s_old);
}
cleanStringElement(ps1);
cleanStringElement(ps2);
break;
default:
break;
}
/* move ahead in postfix expression */
++post;
}
/* if everything is peachy,the stack should end at its first position */
if (ps != top)
return(-1);
if (isDouble(ps)) {
if (presult) *presult = ps->d;
if (psresult) {
toString(ps);
for (i=0, s=ps->s, s1=psresult; *s && i<lenSresult; i++, *s1++ = *s++);
if (i<lenSresult)
*s1 = 0;
else
*(--s1) = 0;
/* strncpy(psresult, ps->s, lenSresult); */
psresult[lenSresult-1] = 0;
cleanStringElement(ps);
}
} else {
if (psresult) {
for (i=0, s=ps->s, s1=psresult; *s && i<lenSresult; i++)
*s1++ = *s++;
if (i < lenSresult)
*s1 = 0;
else
*(--s1) = 0;
psresult[lenSresult-1] = 0;
}
if (presult) {
toDouble(ps);
*presult = ps->d;
} else {
cleanStringElement(ps);
}
}
} /* if (*post++ != USES_STRING) {} else */
return(0);
}
/*
* RAND
*
* generates a random number between 0 and 1 using the
* seed = (multy * seed) + addy Random Number Generator by Knuth
* SemiNumerical Algorithms
* Chapter 1
* randy = seed / 65535.0 To normalize the number between 0 - 1
*/
static unsigned short seed = 0xa3bf;
static unsigned short multy = 191 * 8 + 5; /* 191 % 8 == 5 */
static unsigned short addy = 0x3141;
static double local_random()
{
double randy;
/* random number */
seed = (seed * multy) + addy;
randy = (float) seed / 65535.0;
/* between 0 - 1 */
return(randy);
}