#ifndef lint
static char *RCSid = "$Header: nstr.c,v 1.2 89/10/26 23:57:04 mr-frog Exp $";
#endif

/*
 * nstr.c
 *
 * compile and execute the item selections
 * on sectors.
 *
 * Dave Pare, 1989
 */

#include <ctype.h>
#include "struct.h"
#include "misc.h"
#include "var.h"
#include "xy.h"
#include "sect.h"
#include "nsc.h"
#include "nat.h"
#include "match.h"
#include "file.h"

/*
 * Compiles and adds "str" to the list of conditionals.
 * type is the EF typename of the item type we're selecting.
 * returns amount of "str" used by nstr_comp (i.e. how far
 * the pointer was advanced).  The last is only meaningful
 * if several conditionals are expected in one string.
 */
char *
nstr_comp(np, size, type, str)
	struct	nscstr *np;
	int	*size;
	int	type;
	char	*str;
{
	register char *bp;
	register char *cp;
	register int c;
	char	ident[80];
	char	arg[255];

	strncpy(arg, str, sizeof(arg)-1);
	arg[sizeof(arg)-1] = 0;
	cp = arg;
	bp = ident;
	while ((c = *cp++) && bp < &ident[sizeof(ident)-1]) {
		if (c == '<' || c == '=' || c == '>' || c == '#')
			break;
		*bp++ = c;
	}
	*bp = 0;
	if (c == 0) {
		pr(fmt("'%s'? -- meaningless condition?\n", arg));
		return 0;
	}
	np[*size].oper = c;
	if (encode(ident, &np[*size].fld1, type) < 0)
		return 0;
	bp = ident;
	while ((c = *cp++) && bp < &ident[sizeof(ident)-1]) {
		if (c == '&')
			break;
		*bp++ = c;
	}
	*bp = 0;
	if (encode(ident, &np[*size].fld2, type) < 0)
		return 0;
	if (c == 0)
		cp--;
	(*size)++;
	return str + (cp - arg);
}

/*
 * return true if the conditions on this item
 * are all true.
 */
int
nstr_exec(conds, ncond, ptr, type)
	struct	nscstr *conds;
	register int ncond;
	caddr_t	ptr;
	int	type;
{
	register struct nscstr *nsc;
	register int op;
	register int lhs;
	register int rhs;

	for (nsc=conds; --ncond >= 0; nsc++) {
		lhs = decode(nsc->fld1, ptr, type);
		rhs = decode(nsc->fld2, ptr, type);
		op = nsc->oper;
		if ((op == '<' && lhs >= rhs) ||
		    (op == '=' && lhs != rhs) ||
		    (op == '>' && lhs <= rhs) ||
		    (op == '#' && lhs == rhs))
			return 0;
	}
	return 1;
}

int
encode(str, val, type)
	register char *str;
	long	*val;
	int	type;
{
	register int i;
	struct	castr *cap;

	if (str == 0) {
		*val = 0;
		return 0;
	}
	if (isdigit(*str) || *str == '-' && isdigit(str[1])) {
		/* XXX silently truncate to 16 bit int */
		*val = atoi(str) & 0xffff;
		return 1;
	}
	if ((i = typematch(str, type)) >= 0) {
		*val = i;
		return 1;
	}
	if ((cap = ef_cadef(type)) != 0) {
		i = stmtch(str, (caddr_t)cap, fldoff(castr, ca_name),
			sizeof(struct castr));
		if (i >= 0) {
			*val = cap[i].ca_code;
			return 1;
		}
		if (i == M_NOTUNIQUE) {
			pr(fmt("%s -- ambiguous type selector\n", str));
			return 0;
		}
	}
	/*
	 * Only check for commodity selectors on objects which
	 * are allowed to have commodities.
	 */
	if (ef_flags(type) & EFF_COM) {
		i = stmtch(str, (caddr_t)var_ca, fldoff(castr, ca_name),
			sizeof(struct castr));
		if (i >= 0) {
			*val = var_ca[i].ca_code;
			return 1;
		}
		if (i == M_NOTUNIQUE) {
			pr(fmt("%s -- ambiguous commodity selector\n", str));
			return 0;
		}
	}
	pr(fmt("%s -- not a valid selector\n", str));
	return 0;
}

int
decode(code, addr, type)
	register long code;
	register char *addr;
	int	type;
{
	register int val;
	register int nsc_code;

	val = (code & ~NSC_MASK) & 0xffff;
	nsc_code = code & NSC_CMASK;
	if (nsc_code == NSC_VAR) {
		val = getvar(val, addr, type);
	} else if (nsc_code == NSC_OFF) {
		/*
		 * add offset to value
		 */
		addr += val;
		switch (code & NSC_TMASK) {
		case NSC_CHAR:
			val = *((char *) addr);
			break;
		case NSC_UCHAR:
			val = (int) *((unsigned char *) addr);
			break;
		case NSC_SHORT:
			val = *((short *) addr);
			break;
		case NSC_LONG:
			val = *((long *) addr);
			break;
		default:
			pr(fmt("bad type in decode: %x!\n",
				code & NSC_TMASK));
			val = 0;
			break;
		}
	}
	return val;
}
