aboutsummaryrefslogtreecommitdiff
path: root/pkg/ecl/binop.c
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /pkg/ecl/binop.c
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'pkg/ecl/binop.c')
-rw-r--r--pkg/ecl/binop.c826
1 files changed, 826 insertions, 0 deletions
diff --git a/pkg/ecl/binop.c b/pkg/ecl/binop.c
new file mode 100644
index 00000000..34d7d334
--- /dev/null
+++ b/pkg/ecl/binop.c
@@ -0,0 +1,826 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#define import_spp
+#define import_libc
+#define import_xnames
+#define import_math
+#define import_ctype
+#define import_stdio
+#include <iraf.h>
+
+#include "config.h"
+#include "operand.h"
+#include "errs.h"
+#include "param.h"
+#include "mem.h"
+#include "task.h"
+#include "proto.h"
+
+
+
+/*
+ * BINOP.C -- Perform binary operations or expressions on two operands.
+ *
+ * Try to perform the arithmetic in native machine type, eg, don't do integer
+ * arithmetic by converting to floating and back.
+ */
+
+/* Strint() looks for an integer on the left or right side of string s.
+ * If none found return NULL, else return pointer to the first
+ * character after it if looking on leftside or pointer to
+ * first of the digit characters if looking on right side.
+ * Make a few defines to make it easier to communicate with.
+ * Used by binop() to handle fancy string arithmetic.
+ *
+ * N.B.: The use of the '+' operator to increment the number part of
+ * a string has been restricted to strings of the form "abcde0123".
+ * Hence, the "leftside" logic in the following routine is no longer used.
+ */
+
+#define LEFTSIDE 0 /* value of side */
+#define RIGHTSIDE 1
+
+#define RADIAN 57.295779513082320877
+
+
+char *
+strint (register char *s, int side)
+{
+ if (side == LEFTSIDE) {
+ while (isdigit (*s))
+ s++;
+ } else {
+ char *sstart = s;
+ while (*s)
+ s++;
+ while (s > sstart && isdigit (s[-1]))
+ --s;
+ }
+
+ return (*s == '\0' ? NULL : s);
+}
+
+
+/* BINOP -- Pop the top two operands from the stack and perform the binary
+ * operation whose code is in opcode. Push an operand with the proper result
+ * and (possibly promoted) type.
+ * If either is of type OT_STRING, result will be string and care must be
+ * taken not to pushop() the result to avoid clobbering them until done.
+ * Order of operands will be as stacked from left to right during parser
+ * recognition, eg, a-b pushes a, then b.
+ * Booleans are 0/1 arithmetically, or truestr/falsetr stringly.
+ * INDEF operands propagate through. We should never see an UNDEF operand.
+ * Call error() and do not return if internal error or undefined string
+ * operation.
+ */
+void
+binop (int opcode)
+{
+ register int typ1, typ2;
+ struct operand o1, o2, result;
+ char res[2*SZ_LINE];
+ char *o1sp;
+ double dresult=0.0;
+ int iresult=0, typecode=0; /* > 0 if real */
+ long lval;
+ extern int errorline, err_abort, err_trace, do_error;
+ extern ErrCom errcom;
+
+
+ o2 = popop(); /* operands will be on stack backwards */
+ o1 = popop();
+ typ1 = o1.o_type & OT_BASIC;
+ typ2 = o2.o_type & OT_BASIC;
+
+ if (opindef (&o1) || opindef (&o2)) {
+ setopindef (&result);
+ goto pushresult;
+ }
+
+ /* Verify that no illegal datatype conversions are implied. Arithmetic
+ * on booleans is illegal; arithmetic is legal on strings only in
+ * certain circumstances.
+ */
+ if (typ1 == OT_BOOL || typ2 == OT_BOOL)
+ switch (opcode) {
+ case OP_ADD:
+ case OP_SUB:
+ case OP_MUL:
+ case OP_DIV:
+ case OP_POW:
+ cl_error (E_UERR,
+ "Illegal boolean operand in arithmetic expression");
+ break;
+
+ case OP_MAX:
+ case OP_MIN:
+ case OP_MOD:
+ case OP_RADIX:
+ case OP_ATAN2:
+ case OP_DATAN2:
+ case OP_STRIDX:
+ case OP_STRLDX:
+ case OP_STRSTR:
+ case OP_STRLSTR:
+ case OP_STRDIC:
+ case OP_BAND:
+ case OP_BOR:
+ case OP_BXOR:
+ case OP_FPEQUAL:
+ case OP_HYPOT:
+ cl_error (E_UERR,
+ "Intrinsic function called with illegal boolean argument");
+ break;
+
+ case OP_CONCAT:
+ ; /* bool -> string ok. */
+ }
+
+ if (typ1 == OT_REAL || typ2 == OT_REAL)
+ typecode = OT_REAL;
+ else
+ typecode = OT_INT;
+
+ switch (opcode) {
+ case OP_ADD:
+ break; /* any datatype is ok here */
+ case OP_CONCAT:
+ typecode = OT_STRING;
+ break; /* any datatype is ok here */
+ case OP_RADIX:
+ if (typ2 != OT_INT)
+ cl_error (E_UERR, "radix: second arg must be integer radix");
+ typecode = OT_STRING;
+ break;
+ case OP_STRIDX:
+ if (typ1 != OT_STRING || typ2 != OT_STRING)
+ cl_error (E_UERR, "stridx: both args must be of type string");
+ typecode = OT_INT;
+ break;
+ case OP_STRLDX:
+ if (typ1 != OT_STRING || typ2 != OT_STRING)
+ cl_error (E_UERR, "strldx: both args must be of type string");
+ typecode = OT_INT;
+ break;
+ case OP_STRSTR:
+ if (typ1 != OT_STRING || typ2 != OT_STRING)
+ cl_error (E_UERR, "strstr: both args must be of type string");
+ typecode = OT_INT;
+ break;
+ case OP_STRLSTR:
+ if (typ1 != OT_STRING || typ2 != OT_STRING)
+ cl_error (E_UERR, "strlstr: both args must be of type string");
+ typecode = OT_INT;
+ break;
+ case OP_STRDIC:
+ if (typ1 != OT_STRING || typ2 != OT_STRING)
+ cl_error (E_UERR, "strdic: both args must be of type string");
+ typecode = OT_INT;
+ break;
+ case OP_SUB:
+ case OP_MUL:
+ case OP_DIV:
+ case OP_POW:
+ case OP_MAX:
+ case OP_MIN:
+ case OP_MOD:
+ case OP_ATAN2:
+ case OP_DATAN2:
+ case OP_HYPOT:
+ case OP_FPEQUAL:
+ if (typ1 == OT_STRING || typ2 == OT_STRING) {
+ if (typ1 == OT_STRING)
+ cl_error (E_UERR, e_badstrop, o1.o_val.v_s);
+ else
+ cl_error (E_UERR, e_badstrop, o2.o_val.v_s);
+ }
+ break;
+
+ case OP_BAND:
+ if (typ1 != OT_INT || typ2 != OT_INT)
+ cl_error (E_UERR, "and(): both arguments must be of type int");
+ break;
+ case OP_BOR:
+ if (typ1 != OT_INT || typ2 != OT_INT)
+ cl_error (E_UERR, "or(): both arguments must be of type int");
+ break;
+ case OP_BXOR:
+ if (typ1 != OT_INT || typ2 != OT_INT)
+ cl_error (E_UERR, "xor(): both arguments must be of type int");
+ break;
+
+ default:
+ cl_error (E_IERR, e_badsw, opcode, "binop()");
+ }
+
+ /* The following code deals with operations which take string type
+ * operands or which produce a string result.
+ */
+ if (typ1 == OT_STRING || typ2 == OT_STRING || typecode == OT_STRING) {
+ switch (opcode) {
+ case OP_ADD:
+ o1sp = o1.o_val.v_s;
+
+ if (typ1 != OT_STRING)
+ cl_error (E_UERR,
+ "Illegal expression of the form 'number + string'");
+
+ if (typ2 == OT_STRING) {
+ strcpy (res, o1sp);
+ strcat (res, o2.o_val.v_s);
+ } else if (typ2 == OT_REAL) {
+ cl_error (E_UERR, e_strplusreal, o1sp);
+
+ } else { /* typ2 is OT_INT */
+ char *cp, format[MAX_DIGITS];
+ int newnum;
+
+ cp = strint (o1sp, RIGHTSIDE);
+ if (cp != NULL) {
+ /* Crack numeric string on rightside of string
+ * operand; add integer; reformat new string,
+ * trying to maintain number of digits in number.
+ */
+ strncpy (res, o1sp, cp - o1sp);
+ newnum = atoi(cp) + (int)VALU(&o2);
+ sprintf (format, "%%0%dd", strlen (cp));
+ sprintf ((char *)(res + (cp - o1sp)),
+ format, newnum);
+ if (newnum < 0)
+ cl_error (E_UERR,
+ "String + integer expression produces '%s' ", res);
+
+ } else {
+ strcpy (res, o1sp);
+ for (cp=res; *cp; cp++)
+ ;
+ sprintf (cp, "%d", (int)VALU(&o2));
+ }
+ }
+ break;
+
+ case OP_CONCAT:
+ /* Convert operands to type string if necessary.
+ */
+ {
+ char s2[SZ_LINE];
+
+ if (typ1 != OT_STRING) {
+ /* Save the o2 string since the operand cast here
+ * will overwrite it.
+ */
+ if (typ2 == OT_STRING)
+ strcpy (s2, o2.o_val.v_s);
+ pushop (&o1);
+ opcast (OT_STRING);
+ o1 = popop();
+ }
+ strcpy (res, o1.o_val.v_s);
+
+ if (typ2 != OT_STRING) {
+ pushop (&o2);
+ opcast (OT_STRING);
+ o2 = popop();
+ }
+
+ /* If we had to convert the first operand, use the saved
+ * string.
+ */
+ if (typ1 != OT_STRING && typ2 == OT_STRING)
+ strcat (res, s2);
+ else
+ strcat (res, o2.o_val.v_s);
+
+ break;
+ }
+
+ case OP_RADIX:
+ if (typ1 == OT_STRING) {
+ if (sscanf (o1.o_val.v_s, "%ld", &lval) != 1)
+ cl_error (E_UERR, "Cannot coerce '%s' to integer",
+ o1.o_val.v_s);
+ } else if (typ1 == OT_REAL) {
+ lval = (long) o1.o_val.v_r;
+ } else
+ lval = (long) o1.o_val.v_i;
+
+ sprintf (res, "%r*", o2.o_val.v_i, lval);
+ break;
+
+ case OP_STRIDX:
+ /* index = stridx (chars, string); "chars" may be a string.
+ * Return index of first occurence of any of the "chars"
+ * in "string", or ZERO if none found.
+ */
+ {
+ char *ip, *cp, ch;
+
+ iresult = 0;
+ for (ip=o2.o_val.v_s; !iresult && (ch = *ip) != EOS; ip++) {
+ for (cp=o1.o_val.v_s; *cp != EOS; cp++) {
+ if (*cp == ch) {
+ iresult = (ip - o2.o_val.v_s + 1);
+ break;
+ }
+ }
+ }
+ }
+
+ result.o_val.v_i = iresult;
+ result.o_type = OT_INT;
+ goto pushresult;
+ break;
+
+ case OP_STRLDX:
+ /* index = strldx (chars, string); "chars" may be a string.
+ * Return index of last occurence of any of the "chars"
+ * in "string", or ZERO if none found.
+ */
+ {
+ char *ip, *cp, ch;
+ short len;
+
+ iresult = 0;
+ len = strlen (o2.o_val.v_s);
+ for (ip=&o2.o_val.v_s[len-1];
+ !iresult && (ch = *ip) != EOS && ip >= o2.o_val.v_s;
+ ip--) {
+ for (cp=o1.o_val.v_s; *cp != EOS; cp++) {
+ if (*cp == ch) {
+ iresult = (ip - o2.o_val.v_s + 1);
+ break;
+ }
+ }
+ }
+ }
+
+ result.o_val.v_i = iresult;
+ result.o_type = OT_INT;
+ goto pushresult;
+ break;
+
+ case OP_STRSTR:
+ /* index = strstr (s1, s2);
+ * Return index of first occurance of the string 's1' in 's2',
+ * or ZERO if none found.
+ */
+ {
+ char *ip, *cp, *fp, *tp, first_char, ch;
+
+ first_char = o1.o_val.v_s[0];
+
+ /* Null patterns match any string. */
+ if (first_char == NULL) {
+ result.o_val.v_i = 1;
+ result.o_type = OT_INT;
+ goto pushresult;
+ } else
+ iresult = 0;
+
+ /* Search s2 for first_char, if found check for complete
+ * match of s1, else move on.
+ */
+ for (ip=o2.o_val.v_s; !iresult && (ch = *ip) != EOS; ip++) {
+ if (ch == first_char) {
+ fp = ip;
+ cp = o1.o_val.v_s;
+ tp = ip;
+ while (*cp != EOS && *cp == *tp) {
+ cp++; tp++;
+ }
+ if (*cp == EOS) {
+ iresult = (fp - o2.o_val.v_s + 1);
+ break;
+ }
+ }
+ }
+ }
+
+ result.o_val.v_i = iresult;
+ result.o_type = OT_INT;
+ goto pushresult;
+
+ case OP_STRLSTR:
+ /* index = strstr (s1, s2);
+ * Return index of last occurance of the string 's1' in 's2',
+ * or ZERO if none found.
+ */
+ {
+ char *ip, *cp, *fp, first_char, ch;
+ int len;
+
+ first_char = o1.o_val.v_s[0];
+
+ /* Null patterns match any string. */
+ if (first_char == NULL) {
+ result.o_val.v_i = 1;
+ result.o_type = OT_INT;
+ goto pushresult;
+ } else
+ iresult = 0;
+
+ /* Search s2 for first_char, if found check for complete
+ * match of s1, else move on.
+ */
+ len = strlen (o2.o_val.v_s);
+ for (ip=&o2.o_val.v_s[len-1];
+ !iresult && (ch = *ip) != EOS && ip >= o2.o_val.v_s;
+ ip--) {
+ if (ch == first_char) {
+ fp = ip;
+ cp = o1.o_val.v_s;
+ while (*cp != EOS && *cp == *ip) {
+ cp++; ip++;
+ }
+ if (*cp == EOS) {
+ iresult = (fp - o2.o_val.v_s + 1);
+ break;
+ } else
+ ip = fp;
+ }
+ }
+ }
+
+ result.o_val.v_i = iresult;
+ result.o_type = OT_INT;
+ goto pushresult;
+
+ case OP_STRDIC:
+ /* index = strdic (str, dicstr); "str" must be a string,
+ * 'dicstr' is a dictionary string where the first character
+ * is used as a delimiter. Return a 1-based index of
+ * occurence of any of the "str" in "dicstr", or ZERO if not
+ * found.
+ */
+ {
+ char *ip, *cp, *fp, ch, delim, first_char;
+ short len, index;
+
+ iresult = 0;
+ index = 0;
+ len = strlen (o2.o_val.v_s);
+
+ delim = o2.o_val.v_s[0];
+ first_char = o1.o_val.v_s[0];
+
+ /* Search s2 for first_char, if found check for complete
+ * match of s1, else move on.
+ */
+ ch = o2.o_val.v_s;
+ for (ip=o2.o_val.v_s; !iresult && (ch=*ip) != EOS; ip++) {
+ if (ch == delim) {
+ index++;
+ } else if (*ip == first_char) {
+ fp = ip;
+ cp = o1.o_val.v_s;
+ while (*cp != EOS && *cp == *ip && *ip != delim ) {
+ cp++; ip++;
+ }
+ if (*cp == EOS) {
+ iresult = index;
+ break;
+ } else if (*ip == delim) {
+ index++;
+ }
+ }
+ }
+ }
+
+ result.o_val.v_i = iresult;
+ result.o_type = OT_INT;
+ goto pushresult;
+ break;
+
+ }
+
+ /* Cannot "goto pushresult" because would lose res core */
+ result.o_type = OT_STRING;
+ result.o_val.v_s = res;
+ pushop (&result);
+ return;
+ }
+
+
+ /* Hereafter, we only deal with operands of type int or real.
+ */
+ if (typecode != OT_REAL)
+ typecode = 0;
+
+ switch (opcode) {
+ case OP_ADD:
+ if (typecode) dresult = VALU(&o1) + VALU(&o2);
+ else iresult = o1.o_val.v_i + o2.o_val.v_i;
+ break;
+
+ case OP_SUB:
+ if (typecode) dresult = VALU(&o1) - VALU(&o2);
+ else iresult = o1.o_val.v_i - o2.o_val.v_i;
+ break;
+
+ case OP_MUL:
+ if (typecode) dresult = VALU(&o1) * VALU(&o2);
+ else iresult = o1.o_val.v_i * o2.o_val.v_i;
+ break;
+
+ case OP_DIV:
+ erract_init();
+ if (typecode) {
+ if (VALU(&o2) == 0.0) {
+ if (err_abort == NO || do_error == NO) {
+ /* If we're not aborting errors try to recover
+ * from a divide-by-zero using the err_dzvalue
+ * fake param.
+ */
+ struct param *pp =
+ paramfind (firstask->t_pfp, "$err_dzvalue",
+ 0, YES);
+ dresult = (double) pp->p_val.v_i;
+ if (err_trace == YES) {
+ eprintf("Warning on line %d of %s: %s = %d\n",
+ errorline, errcom.script,
+ e_fdzvalue, pp->p_val.v_i);
+ }
+
+ } else
+ cl_error (E_UERR, e_fdivzero, opcode, "binop()");
+ } else
+ dresult = VALU(&o1) / VALU(&o2);
+
+ } else {
+ if (o2.o_val.v_i == 0) {
+ if (err_abort == NO || do_error == NO) {
+ /* If we're not aborting errors try to recover
+ * from a divide-by-zero using the err_dzvalue
+ * fake param.
+ */
+ struct param *pp =
+ paramfind (firstask->t_pfp, "$err_dzvalue",
+ 0, YES);
+ iresult = pp->p_val.v_i;
+ if (err_trace == YES) {
+ eprintf("Warning on line %d of %s: %s = %d\n",
+ errorline, errcom.script,
+ e_idzvalue, pp->p_val.v_i);
+ }
+
+ } else
+ cl_error (E_UERR, e_idivzero, opcode, "binop()");
+ } else
+ iresult = o1.o_val.v_i / o2.o_val.v_i;
+ }
+ break;
+
+ case OP_POW:
+ { /* VMS & inconsistancy */
+ double val1 = VALU(&o1),val2 = VALU(&o2);
+ double sign = 1;
+
+ /* Exponentiation of negative numbers to real powers
+ * is not defined in general, so if we have coerced
+ * an integer exponent to real we change the mantissa to
+ * positive and deal with the sign separately.
+ */
+ if ((o2.o_type == OT_INT) && (val1 < 0)) {
+ sign = (o2.o_val.v_i % 2) ? -1 : 1 ;
+ if (val1 < 0)
+ val1 = -val1;
+ }
+
+ dresult = sign * pow (val1, val2);
+ if (!typecode)
+ iresult = dresult+0.5*sign; /* round */
+ }
+ break;
+
+ case OP_MAX:
+ if (typecode) {
+ /* ritchie compiler doesn't seem to allow ?: here.
+ * result = (VALU(&o1) > VALU(&o2)) ? o1 : o2;
+ */
+ if (VALU(&o1) > VALU(&o2))
+ result = o1;
+ else
+ result = o2;
+ } else {
+ if (o1.o_val.v_i > o2.o_val.v_i)
+ result = o1;
+ else
+ result = o2;
+ }
+ goto pushresult;
+
+ case OP_MIN:
+ if (typecode) {
+ /* ritchie compiler doesn't seem to allow ?: here.
+ * result = (VALU(&o1) < VALU(&o2)) ? o1 : o2;
+ */
+ if (VALU(&o1) < VALU(&o2))
+ result = o1;
+ else
+ result = o2;
+ } else {
+ if (o1.o_val.v_i < o2.o_val.v_i)
+ result = o1;
+ else
+ result = o2;
+ }
+ goto pushresult;
+
+ case OP_MOD:
+ if (typecode) {
+ double x1 = VALU(&o1), x2 = VALU(&o2);
+ dresult = x1 - ((int)(x1/x2))*x2;
+ } else
+ iresult = o1.o_val.v_i % o2.o_val.v_i;
+ break;
+
+ case OP_BAND:
+ iresult = o1.o_val.v_i & o2.o_val.v_i;
+ break;
+ case OP_BXOR:
+ { int a = o1.o_val.v_i,
+ b = o2.o_val.v_i,
+ na = ~a,
+ nb = ~b;
+ iresult = (a & nb) | (na & b);
+ }
+ break;
+ case OP_BOR:
+ iresult = o1.o_val.v_i | o2.o_val.v_i;
+ break;
+
+ case OP_ATAN2:
+ case OP_DATAN2:
+ { /* VMS & inconsistancy. */
+ double val1 = VALU(&o1), val2 = VALU(&o2);
+ dresult = atan2 (val1, val2);
+ if (opcode == OP_DATAN2)
+ dresult *= RADIAN;
+ }
+ typecode++; /* force real result */
+ break;
+
+ case OP_FPEQUAL:
+ /* Note: need to move fp_equald() to libc */
+ if (typecode) {
+ double x1 = VALU(&o1), x2 = VALU(&o2);
+ iresult = btoi (fpequd_ (&x1, &x2));
+ } else {
+ double x1 = o1.o_val.v_i, x2 = o2.o_val.v_i;
+ iresult = btoi (fpequd_ (&x1, &x2));
+ }
+ typecode = 0; /* force integer result */
+ break;
+
+ case OP_HYPOT:
+ if (typecode)
+ dresult = sqrt (VALU(&o1)*VALU(&o1) + VALU(&o2)*VALU(&o2));
+ else
+ iresult = sqrt (o1.o_val.v_i*o1.o_val.v_i +
+ o2.o_val.v_i*o2.o_val.v_i);
+ break;
+
+ default:
+ cl_error (E_IERR, e_badsw, opcode, "binop()");
+ }
+
+ if (typecode) {
+ result.o_val.v_r = dresult;
+ result.o_type = OT_REAL;
+ } else {
+ result.o_val.v_i = iresult;
+ result.o_type = OT_INT;
+ }
+
+pushresult:
+ pushop (&result);
+}
+
+
+/* BINEXP -- pop top two operands and push result of applying operand.
+ * result o_type will be OT_BOOL and o_val.v_i as returned from relation.
+ * both or neither operand may be a string; cannot be mixed.
+ * order of operands will be as stacked from left to right during parser
+ * recognition, eg, a<b pushes a, then b.
+ * INDEF operands propagate through. we should never see an UNDEF operand.
+ * all error() and do not return on internal error or bad string operations.
+ */
+void
+binexp (int opcode)
+{
+ register int typ1, typ2;
+ struct operand o1, o2, result;
+ int strres = NULL, dostr;
+
+ o2 = popop(); /* operands will be on stack backwards */
+ o1 = popop();
+ typ1 = o1.o_type & OT_BASIC;
+ typ2 = o2.o_type & OT_BASIC;
+ dostr = 0;
+
+ if ((typ1 != OT_BOOL || typ2 != OT_BOOL) &&
+ (opcode == OP_OR || opcode == OP_AND))
+ cl_error (E_UERR,
+ "Non-boolean operand in a boolean expression");
+
+ if (opcode != OP_EQ && opcode != OP_NE)
+ if (opindef (&o1) || opindef (&o2)) {
+ result.o_type = OT_BOOL;
+ /*
+ result.o_val.v_i = 0;
+ printf ("Warning: INDEF operand value in a boolean expression");
+ */
+ setopindef (&result);
+ goto pushresult;
+ }
+
+ if ((typ1 == OT_STRING) && (typ2 == OT_STRING)) {
+ strres = strcmp (o1.o_val.v_s, o2.o_val.v_s);
+ dostr++;
+
+ } else if ((typ1 == OT_STRING) || (typ2 == OT_STRING)) {
+ if (typ1 == OT_STRING)
+ cl_error (E_UERR, e_badstrop, o1.o_val.v_s);
+ else
+ cl_error (E_UERR, e_badstrop, o1.o_val.v_s);
+ }
+
+
+ switch (opcode) {
+ case OP_LT:
+ if (dostr)
+ result.o_val.v_i = strres < 0;
+ else
+ result.o_val.v_i = VALU(&o1) < VALU(&o2);
+ break;
+
+ case OP_GT:
+ if (dostr)
+ result.o_val.v_i = strres > 0;
+ else
+ result.o_val.v_i = VALU(&o1) > VALU(&o2);
+ break;
+
+ case OP_LE:
+ if (dostr)
+ result.o_val.v_i = (strres <= 0);
+ else
+ result.o_val.v_i = (VALU(&o1) <= VALU(&o2));
+ break;
+
+ case OP_GE:
+ if (dostr)
+ result.o_val.v_i = (strres >= 0);
+ else
+ result.o_val.v_i = (VALU(&o1) >= VALU(&o2));
+ break;
+
+ case OP_EQ:
+ if (opindef (&o1) || opindef (&o2))
+ result.o_val.v_i = (opindef (&o1) == opindef (&o2));
+ else {
+ if (dostr)
+ result.o_val.v_i = (strres == 0);
+ else
+ result.o_val.v_i = (VALU(&o1) == VALU(&o2));
+ }
+ break;
+
+ case OP_NE:
+ if (opindef (&o1) || opindef (&o2))
+ result.o_val.v_i = (opindef (&o1) != opindef (&o2));
+ else {
+ if (dostr)
+ result.o_val.v_i = (strres != 0);
+ else
+ result.o_val.v_i = (VALU(&o1) != VALU(&o2));
+ }
+ break;
+
+ case OP_OR:
+ if (dostr)
+ result.o_val.v_i = strlen (o1.o_val.v_s) ||
+ strlen (o2.o_val.v_s);
+ else
+ result.o_val.v_i = (o1.o_val.v_i || o2.o_val.v_i);
+ break;
+
+ case OP_AND:
+ if (dostr)
+ result.o_val.v_i = strlen (o1.o_val.v_s) &&
+ strlen (o2.o_val.v_s);
+ else
+ result.o_val.v_i = (o1.o_val.v_i && o2.o_val.v_i);
+ break;
+
+ default:
+ cl_error (E_IERR, e_badsw, opcode, "binexp()");
+
+ }
+
+ result.o_type = OT_BOOL;
+
+pushresult:
+ pushop (&result);
+}