/* SDB - boolean expression evaluator */

#include "sdbio.h"

static struct operand *stack[STACKMAX],**sptr;
static union codecell *cptr;

/* db_interpret - interpret a boolean expression */
int db_interpret(slptr)
  struct sel *slptr;
{
    struct operand *result;
    int r;

    /* check for empty where clause */
    if ((cptr = slptr->sl_where) == NULL)
    	return (TRUE);

    /* setup stack */
    sptr = stack;

    /* execute the code */
    while ((*(*cptr++).c_operator)())
    	;

    /* get the result from the top of stack */
    result = *--sptr;
    r = result->o_value.ov_boolean;
    if (result->o_type == TEMP)
    	free(result);

    /* make sure the stack is empty */
    while (sptr != stack) {
	if ((*sptr)->o_type == TEMP)
	    free(*sptr);
	sptr -= 1;
    }

    /* return result */
    return (r);
}

int db_xstop()
{
    return (FALSE);
}

int db_xpush()
{
    *sptr++ = (*cptr++).c_operand;
}

int db_xand()
{
    return (boolean('&'));
}

int db_xor()
{
    return (boolean('|'));
}

static int boolean(opr)
{
    struct operand *lval,*rval,*result;
    int lv,rv,r;

    rval = *--sptr; lval = *--sptr;
    lv = lval->o_value.ov_boolean;
    rv = rval->o_value.ov_boolean;

    if ((result = malloc(sizeof(struct operand))) == NULL)
	return (db_ferror(INSMEM));
    result->o_type = TEMP;
    switch (opr) {
    case '&':	r = (lv && rv);
		break;
    case '|':	r = (lv || rv);
		break;
    }
    result->o_value.ov_boolean = r;
    *sptr++ = result;
    if (lval->o_type == TEMP)
	free(lval);
    if (rval->o_type == TEMP)
	free(rval);
    return (TRUE);
}

int db_xnot()
{
    struct operand *val,*result;

    val = *--sptr;
    if ((result = malloc(sizeof(struct operand))) == NULL)
	return (db_ferror(INSMEM));
    result->o_type = TEMP;
    result->o_value.ov_boolean = !val->o_value.ov_boolean;
    *sptr++ = result;
    if (val->o_type == TEMP)
	free(val);
    return (TRUE);
}

int db_xlss()
{
    return (compare(LSS));
}

int db_xleq()
{
    return (compare(LEQ));
}

int db_xeql()
{
    return (compare(EQL));
}

int db_xgeq()
{
    return (compare(GEQ));
}

int db_xgtr()
{
    return (compare(GTR));
}

int db_xneq()
{
    return (compare(NEQ));
}

static int compare(cmp)
{
    struct operand *lval,*rval,*result;
    int i;

    rval = *--sptr; lval = *--sptr;
    if ((result = malloc(sizeof(struct operand))) == NULL)
	return (db_ferror(INSMEM));
    result->o_type = TEMP;

    if (lval->o_value.ov_char.ovc_type == TCHAR)
    	i = comp(lval,rval);
    else
    	i = ncomp(lval,rval);

    switch (cmp) {
    case LSS:	i = (i < 0);
		break;
    case LEQ:	i = (i <= 0);
		break;
    case EQL:	i = (i == 0);
		break;
    case GEQ:	i = (i >= 0);
		break;
    case GTR:	i = (i > 0);
		break;
    case NEQ:	i = (i != 0);
		break;
    }
    result->o_value.ov_boolean = i;
    *sptr++ = result;
    if (lval->o_type == TEMP)
	free(lval);
    if (rval->o_type == TEMP)
	free(rval);
    return (TRUE);
}

static int comp(lval,rval)
  struct operand *lval,*rval;
{
    char *lptr,*rptr; int lctr,rctr;
    int len;

    lptr = lval->o_value.ov_char.ovc_string;
    lctr = lval->o_value.ov_char.ovc_length;
    rptr = rval->o_value.ov_char.ovc_string;
    rctr = rval->o_value.ov_char.ovc_length;

    while (lctr > 0 && (lptr[lctr-1] == 0 || lptr[lctr-1] == ' '))
	lctr--;
    while (rctr > 0 && (rptr[rctr-1] == 0 || rptr[rctr-1] == ' '))
	rctr--;

    if (lctr < rctr)
	len = lctr;
    else
	len = rctr;

    while ((len--) > 0) {
	if (*lptr++ != *rptr++)
	    if (*--lptr < *--rptr)
		return (-1);
	    else
		return (1);
    }

    if (lctr == rctr)
	return (0);
    else if (lctr < rctr)
	return (-1);
    else
	return (1);
}

static int ncomp(lval,rval)
  struct operand *lval,*rval;
{
    char lstr[NUMBERMAX+1],rstr[NUMBERMAX+1];
    int len;

    strncpy(lstr,lval->o_value.ov_char.ovc_string,
	  (len = lval->o_value.ov_char.ovc_length)); lstr[len] = EOS;
    strncpy(rstr,rval->o_value.ov_char.ovc_string,
	  (len = rval->o_value.ov_char.ovc_length)); rstr[len] = EOS;

    return (db_cmp(lstr,rstr));
}
