Net2/usr/src/contrib/isode/snmp/eval.c

/* eval.c - MIB realization of the EVAL group */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/snmp/RCS/eval.c,v 7.7 91/02/22 09:43:13 mrose Interim $";
#endif

/* 
 * $Header: /f/osi/snmp/RCS/eval.c,v 7.7 91/02/22 09:43:13 mrose Interim $
 *
 *
 * $Log:	eval.c,v $
 * Revision 7.7  91/02/22  09:43:13  mrose
 * Interim 6.8
 * 
 * Revision 7.6  91/01/13  11:05:42  mrose
 * update
 * 
 * Revision 7.5  91/01/12  21:38:32  mrose
 * typo
 * 
 * Revision 7.4  91/01/12  21:25:41  mrose
 * again
 * 
 * Revision 7.3  91/01/12  21:22:49  mrose
 * update
 * 
 * Revision 7.2  90/12/18  10:13:19  mrose
 * update
 * 
 * Revision 7.1  90/11/20  15:31:59  mrose
 * update
 * 
 * Revision 7.0  90/11/18  09:30:47  mrose
 * *** empty log message ***
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include <ctype.h>
#include <stdio.h>
#include "mib.h"

/*    FUNCTION MIB */

#define	NSTACK	10

static	integer	*tos;
static	integer	*roof;
static	integer	 fstack[NSTACK + 1];


#define	NEXPR	10

struct expr {
    PStream e_ps;

    int	    e_eval;	/* exprEval */

    char   *e_expr;	/* exprExpr */
    int	    e_size;

    int	    e_status;	/* exprStatus */
#define	E_noError	0
#define	E_divide	1
#define	E_overflow	2
#define	E_underflow	3
#define	E_noSuchName	4
#define	E_notAnInteger	5
#define	E_other		6

			/* exprHints */
    char    e_hints[255 + 1];

    struct {
	char   *expr;

	int	size;
    }	    e_save;
};

static integer	exprNumber = 0;

static struct expr exprs[NEXPR];
static struct expr *curexpr = NULL;
static struct expr *roofexpr;

/*  */

#define	functAdd	 0
#define	functSub	 1
#define	functMul	 2
#define	functDiv	 3
#define	functMod	 4
#define	functNeg	 5
#define	functXch	 6
#define	functClr	 7
#define	functDup	 8
#define	functPop	 9
#define	functAbs	10
#define	functSgn	11
#define	functMin	12
#define	functAnd	13
#define	functOr		14
#define	functNot	15


static int  o_funct (oi, v, offset)
OI	oi;
register struct type_SNMP_VarBind *v;
int	offset;
{
    int	    ifvar;
    integer arg1,
	    arg2;
    register OT	    ot = oi -> oi_type;

    ifvar = (int) ot -> ot_info;
    switch (offset) {
	case type_SNMP_PDUs_get__request:
	    if (curexpr == NULL)
		return int_SNMP_error__status_noSuchName;
	    break;

	case type_SNMP_PDUs_get__next__request:
	    if (curexpr == NULL)
		return NOTOK;
	    break;

	default:
	    return int_SNMP_error__status_genErr;
    }

#define	get_arg(a) \
    if (tos <= fstack + 1) { \
	curexpr -> e_status = E_underflow; \
	(void) strcpy (curexpr -> e_hints, "stack underflow"); \
	return NOTOK; \
    } \
    (a) = *--tos;

    switch (ifvar) {
	case functAdd:
	case functSub:
	case functMul:
	case functDiv:
	case functMod:
	case functXch:
	case functDup:
	case functMin:
	case functAnd:
	case functOr:
		get_arg (arg2);
		get_arg (arg1);
		break;

	case functNeg:
	case functPop:
	case functAbs:
	case functSgn:
	case functNot:
		get_arg (arg1);
		break;

	case functClr:
		arg1 = 0;
		break;

	default:
	    return int_SNMP_error__status_genErr;
    }
#undef	get_arg

    switch (ifvar) {
	case functAdd:
	    arg1 += arg2;
	    break;

	case functSub:
	    arg1 -= arg2;
	    break;

	case functMul:
	    arg1 *= arg2;
	    break;

	case functDiv:
	    if (arg2 == 0) {
		curexpr -> e_status = E_divide;
		(void) strcpy (curexpr -> e_hints, "division by zero");
		return NOTOK;
	    }
	    arg1 /= arg2;
	    break;

	case functMod:
	    if (arg2 == 0) {
		curexpr -> e_status = E_divide;
		(void) strcpy (curexpr -> e_hints, "modulus by zero");
		return NOTOK;
	    }
	    arg1 %= arg2;
	    break;

	case functNeg:
	    arg1 = -arg1;
	    break;

	case functXch:
	    *tos++ = arg2;
	    break;

	case functClr:
	    tos = fstack;
	    return NOTOK;

	case functDup:
	    *tos++ = arg1;
	    break;

	case functPop:
	    arg1 = tos <= fstack ? 0 : *--tos;
	    return NOTOK;

	case functAbs:
	    if (arg1 < 0)
		arg1 = -arg1;
	    break;

	case functSgn:
	    arg1 = arg1 > 0 ? 1 : arg1 < 0 ? -1 : 0;
	    break;

	case functMin:
	    if (arg2 < arg1)
		arg1 = arg2;
	    break;

	case functAnd:
	    arg1 &= arg2;
	    break;

	case functOr:
	    arg1 |= arg2;
	    break;

	case functNot:
	    arg1 = !arg1;
	    break;

	default:
	    return int_SNMP_error__status_noSuchName;
    }

    return o_integer (oi, v, arg1);
}

/*  */

/* assumes that exprEval occurs first in variable-bindings of get... */

#define	exprIndex	0
#define	exprEval	1
#define	exprExpr	2
#define	exprStatus	3
#define	exprHints	4


static int  o_expressions (oi, v, offset)
OI	oi;
register struct type_SNMP_VarBind *v;
int	offset;
{
    int	    ifnum,
	    ifvar;
    register OID    oid = oi -> oi_name;
    register OT	    ot = oi -> oi_type;
    register struct expr *e;

    ifvar = (int) ot -> ot_info;
    switch (offset) {
	case type_SNMP_PDUs_get__request:
	    if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1)
		return int_SNMP_error__status_noSuchName;
	    if ((ifnum = oid -> oid_elements[oid -> oid_nelem - 1]) == 0
		    || ifnum > exprNumber)
		return int_SNMP_error__status_noSuchName;
	    if ((e = exprs + ifnum - 1) -> e_expr == NULL)
		return int_SNMP_error__status_noSuchName;
	    break;

	case type_SNMP_PDUs_get__next__request:
	    if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
		OID	new;

		for (e = exprs; e < roofexpr; e++)
		    if (e -> e_expr)
			break;
		if (e >= roofexpr)
		    return NOTOK;
		ifnum = (e - exprs) + 1;

		if ((new = oid_extend (oid, 1)) == NULLOID)
		    return NOTOK;
		new -> oid_elements[new -> oid_nelem - 1] = ifnum;

		if (v -> name)
		    free_SNMP_ObjectName (v -> name);
		v -> name = new;
	    }
	    else {
		int	i = ot -> ot_name -> oid_nelem;

		if ((ifnum = oid -> oid_elements[i]) >= NEXPR)
		    return NOTOK;
		for (e = exprs + ifnum; e < roofexpr; e++)
		    if (e -> e_expr)
			break;
		if (e >= roofexpr)
		    return NOTOK;
		ifnum = (e - exprs) + 1;

		oid -> oid_elements[i] = ifnum;
		oid -> oid_nelem = i + 1;
	    }
	    break;

	default:
	    return int_SNMP_error__status_genErr;
    }

    switch (ifvar) {
	case exprIndex:
	    return o_integer (oi, v, ifnum);

	case exprEval:
	    e -> e_eval = 0, e -> e_status = E_noError, e -> e_hints[0] = NULL;
	    (void) eval_expr (curexpr = e);
	    curexpr = NULL;
	    return o_integer (oi, v, e -> e_eval);

	case exprExpr:
	    return o_string (oi, v, e -> e_expr, e -> e_size);

	case exprStatus:
	    return o_integer (oi, v, e -> e_status);

	case exprHints:
	    return o_string (oi, v, e -> e_hints, strlen (e -> e_hints));

	default:
	    return int_SNMP_error__status_noSuchName;
    }
}

/*  */

static int  eval_expr (e)
register struct expr *e;
{
    PElementClass class;
    PElementForm  form;
    PElementID	  id;
    PElementLen	  len;
    PS	    ps = &e -> e_ps;

    roof = (tos = fstack) + (sizeof fstack / sizeof fstack[0]);
    tos++;

    bzero ((char *) ps, sizeof *ps);
    if (str_open (ps) == NOTOK) {
	e -> e_status = E_other;
	(void) strcpy (e -> e_hints, "str_open failed");
	return NOTOK;
    }
    if (str_setup (ps, e -> e_expr, e -> e_size, 1) == NOTOK) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "str_setup failed: %s",
			ps_error (ps -> ps_errno));
	return NOTOK;
    }

    if (read_tl (e, &class, &form, &id, &len) == NOTOK)
	return NOTOK;
    if (PE_ID (class, id) != PE_ID (PE_CLASS_UNIV, PE_CONS_SEQ)) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "unexpected TAG: %d/%d", class, id);
	return NOTOK;
    }

    while (ps -> ps_cnt > 0) {
	integer	i;
	OID	oid;

	if (read_tl (e, &class, &form, &id, &len) == NOTOK)
	    return NOTOK;
	switch (PE_ID (class, id)) {
	    case PE_ID (PE_CLASS_UNIV, PE_PRIM_INT):
		if (read_long (e, ps -> ps_ptr, len, form, &i) == NOTOK)
		    return NOTOK;
		break;

	    case PE_ID (PE_CLASS_UNIV, PE_PRIM_OID):
		if (read_oid (e, ps -> ps_ptr, len, form, &oid) == NOTOK)
		    return NOTOK;
		if (get_var_value (e, oid, &i) == NOTOK)
		    return NOTOK;
		break;

	    default:
		e -> e_status = E_other;
		(void) sprintf (e -> e_hints, "unexpected TAG: %d/%d",
				class, id);
		return NOTOK;
	}
	ps -> ps_ptr += len, ps -> ps_cnt -= len;

	if (tos < roof)
	    *tos++ = i;
	else {
	    e -> e_status = E_overflow;
	    (void) strcpy (e -> e_hints, "stack overflow");
	    return NOTOK;
	}
    }

    if (tos <= fstack) {
	e -> e_status = E_underflow;
	(void) strcpy (e -> e_hints, "stack underflow");
	return NOTOK;
    }
    e -> e_eval = *--tos;

    if (tos > fstack + 1 && e -> e_hints[0] == NULL)
	(void) sprintf (e -> e_hints,
		"%d items left on stack after evaluating expression",
		tos - fstack - 1);

    return OK;
}

/*  */

static int  read_tl (e, class, form, id, len)
struct expr *e;
PElementClass *class;
PElementForm  *form;
PElementID    *id;
PElementLen   *len;
{
    PS	    ps = &e -> e_ps;

    if (ps_read_id (ps, 0, class, form, id) == NOTOK) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "error reading TAG info: %s",
			ps_error (ps -> ps_errno));
	return NOTOK;
    }
    if (ps_read_len (ps, len) == NOTOK) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "error reading LEN info: %s",
			ps_error (ps -> ps_errno));
	return NOTOK;
    }

    return OK;
}

/*  */

static int  read_long (e, base, len, form, result)
struct expr *e;
char   *base;
int	len;
PElementForm  form;
integer *result;
{
    register integer    i;
    register PElementData dp,
			  ep;

    if (form != PE_FORM_PRIM) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "integer: %s", pe_error (PE_ERR_PRIM));
	return NOTOK;
    }
    if (len > sizeof (i)) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "integer: %s", pe_error (PE_ERR_OVER));
	return NOTOK;
    }

    i = (*(dp = (PElementData) base) & 0x80) ? (-1) : 0;
    for (ep = dp + len; dp < ep;)
	i = (i << 8) | (*dp++ & 0xff);

    *result = i;

    return OK;
}

/*  */

static int  read_oid (e, base, len, form, ox)
struct expr *e;
char   *base;
int	len;
PElementForm  form;
OID   *ox;
{
    register unsigned int i,
			 *ip;
    register PElementData dp,
			  ep;
    static OIDentifier oid;
    register OID	o = &oid;

    if (form != PE_FORM_PRIM
	    || (dp = (PElementData) base) == NULLPED
	    || len == 0) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "oid: %s", pe_error (PE_ERR_PRIM));
	return NOTOK;
    }
    ep = dp + len;

    if (o -> oid_elements)
	free ((char *) o -> oid_elements);

    for (i = 1; dp < ep; i++) {	/* another whacko OSI encoding... */
	if (*dp == 0x80) {
	e -> e_status = E_other;
	    (void) sprintf (e -> e_hints, "oid: %s", pe_error (PE_ERR_OID));
	    return NOTOK;
	}

	while (*dp++ & 0x80)
	    if (dp > ep) {
		e -> e_status = E_other;
		(void) sprintf (e -> e_hints, "oid: %s",
				pe_error (PE_ERR_OID));
		return NOTOK;
	    }
    }

    if ((ip = (unsigned int *) malloc ((i + 1) * sizeof *ip)) == NULL) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "oid: %s", pe_error (PE_ERR_NMEM));
	return NOTOK;
    }
    o -> oid_elements = ip, o -> oid_nelem = i;
    
    for (dp = (PElementData) base; dp < ep; ) {
	i = 0;
	do {
	    i <<= 7; 
	    i |= *dp & 0x7f;
	} while (*dp++ & 0x80);

	if (ip != o -> oid_elements)
	    *ip++ = i;
	else
	    if (i < 40)
		*ip++ = 0, *ip++ = i;
	    else
		if (i < 80)
		    *ip++ = 1, *ip++ = i - 40;
		else
		    *ip++ = 2, *ip++ = i - 80;
    }

    *ox = o;

    return OK;
}

/*  */

static int  get_var_value (e, oid, i)
struct expr *e;
OID	oid;
integer *i;
{
    int	    status;
    integer *result;
    OI	    oi;
    OS	    os;
    OT	    ot;
    struct type_SNMP_VarBind *v;

    if ((oi = name2inst (oid)) == NULL) {
	e -> e_status = E_noSuchName;
	(void) sprintf (e -> e_hints, "variable %s unknown", oid2ode (oid));
	return NOTOK;
    }
    if ((ot = oi -> oi_type) == NULL) {
	e -> e_status = E_noSuchName;
	(void) sprintf (e -> e_hints, "no object type for variable %s",
			oid2ode (oid));
	return NOTOK;
    }
    if ((os = ot -> ot_syntax) == NULL) {
	e -> e_status = E_noSuchName;
	(void) sprintf (e -> e_hints, "no object syntax for variable %s",
			oid2ode (oid));
	return NOTOK;
    }

    if (!os -> os_data2) {
	e -> e_status = E_notAnInteger;
	(void) sprintf (e -> e_hints, "variable %s is not integer-valued",
			oid2ode (oid));
	return NOTOK;
    }

    if (ot -> ot_getfnx == NULL) {
	e -> e_status = E_noSuchName;
	(void) sprintf (e -> e_hints, "no get method for variable %s",
			oid2ode (oid));
	return NOTOK;
    }

    if ((v = (struct type_SNMP_VarBind *) calloc (1, sizeof *v)) == NULL
	    || (v -> name = oid_cpy (oid)) == NULL
	    || (v -> value = pe_alloc (PE_CLASS_UNIV, PE_FORM_PRIM,
				       PE_PRIM_NULL)) == NULL) {
	if (v)
	    free_SNMP_VarBind (v);
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "out of memory");
	return NOTOK;
    }
    
    if ((status = (*ot -> ot_getfnx) (oi, v, type_SNMP_PDUs_get__request))
	    != int_SNMP_error__status_noError) {
	if (e -> e_hints[0] == NULL)
	    (void) sprintf (e -> e_hints, "%s: %d", oid2ode (oid), status);
losing: ;
	free_SNMP_VarBind (v);
	return NOTOK;
    }

    if ((*os -> os_decode) (&result, v -> value) == NOTOK) {
	e -> e_status = E_other;
	(void) sprintf (e -> e_hints, "%s: decoding error!", oid2ode (oid));
	goto losing;
    }
    *i = *result;
    free ((char *) result);
    free_SNMP_VarBind (v);

    return OK;
}

/*  */

static int  s_expressions (oi, v, offset)
OI	oi;
register struct type_SNMP_VarBind *v;
int	offset;
{
    int	    ifnum
#ifndef	lint
		 ,
	    ifvar
#endif
		 ;
    register OID    oid = oi -> oi_name;
    register OT	    ot = oi -> oi_type;
    register OS	    os = ot -> ot_syntax;
    register struct expr *e;
    struct qbuf *qb;

#ifndef	lint
    ifvar = (int) ot -> ot_info;
#endif
    switch (offset) {
	case type_SNMP_PDUs_set__request:
	case type_SNMP_PDUs_commit:
	case type_SNMP_PDUs_rollback:
	    if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1)
		return int_SNMP_error__status_noSuchName;
	    if ((ifnum = oid -> oid_elements[oid -> oid_nelem - 1]) == 0
		    || ifnum > exprNumber + 1)
		return int_SNMP_error__status_noSuchName;
	    e = exprs + ifnum - 1;
	    break;

	default:
	    return int_SNMP_error__status_genErr;
    }

    if (os == NULLOS) {
	advise (LLOG_EXCEPTIONS, NULLCP,
		"no syntax defined for object \"%s\"", ot -> ot_text);

	return int_SNMP_error__status_genErr;
    }

    switch (offset) {
	case type_SNMP_PDUs_set__request:
	    if (e -> e_save.expr)
		free (e -> e_save.expr), e -> e_save.expr = NULL;
	    if ((*os -> os_decode) ((caddr_t *) &qb, v -> value) == NOTOK)
		return int_SNMP_error__status_badValue;
	    e -> e_save.expr = qb2str (qb);
	    e -> e_save.size = qb -> qb_len;
	    (*os -> os_free) (qb);
	    if (e -> e_save.expr == NULL)
		return int_SNMP_error__status_genErr;
	    if (e -> e_save.size == 0)
		free (e -> e_save.expr), e -> e_save.expr = NULL;
	    break;

	case type_SNMP_PDUs_commit:
	    if (e -> e_expr)
		free (e -> e_expr);
	    e -> e_expr = e -> e_save.expr, e -> e_save.expr = NULL;
	    e -> e_size = e -> e_save.size;
	    for (e = exprs + NEXPR - 1; e >= exprs; e--)
		if (e -> e_expr)
		    break;
	    exprNumber = (e - exprs) + 1;
	    break;

	case type_SNMP_PDUs_rollback:
	    if (e -> e_save.expr)
		free (e -> e_save.expr), e -> e_save.expr = NULL;
	    break;
    }

    return int_SNMP_error__status_noError;
}

/*  */

init_eval () {
    register OT	    ot;

    roof = (tos = fstack) + (sizeof fstack / sizeof fstack[0]);
    roofexpr = exprs + NEXPR;

    bzero ((char *) exprs, sizeof exprs);

    {
	OS	os;

	if (os = text2syn ("INTEGER"))
	    os -> os_data2 = 1;

	if (os = text2syn ("Counter"))
	    os -> os_data2 = 1;

	if (os = text2syn ("Gauge"))
	    os -> os_data2 = 1;

	if (os = text2syn ("TimeTicks"))
	    os -> os_data2 = 1;
    }

    if (ot = text2obj ("functAdd"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functAdd;
    if (ot = text2obj ("functSub"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functSub;
    if (ot = text2obj ("functMul"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functMul;
    if (ot = text2obj ("functDiv"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functDiv;
    if (ot = text2obj ("functMod"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functMod;
    if (ot = text2obj ("functNeg"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functNeg;
    if (ot = text2obj ("functXch"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functXch;
    if (ot = text2obj ("functClr"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functClr;
    if (ot = text2obj ("functDup"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functDup;
    if (ot = text2obj ("functPop"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functPop;
    if (ot = text2obj ("functAbs"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functAbs;
    if (ot = text2obj ("functSgn"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functSgn;
    if (ot = text2obj ("functMin"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functMin;
    if (ot = text2obj ("functAnd"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functAnd;
    if (ot = text2obj ("functOr"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functOr;
    if (ot = text2obj ("functNot"))
	ot -> ot_getfnx = o_funct,
	ot -> ot_info = (caddr_t) functNot;

    if (ot = text2obj ("exprNumber"))
	ot -> ot_getfnx = o_generic,
	ot -> ot_info = (caddr_t) &exprNumber;
    if (ot = text2obj ("exprIndex"))
	ot -> ot_getfnx = o_expressions,
	ot -> ot_info = (caddr_t) exprIndex;
    if (ot = text2obj ("exprEval"))
	ot -> ot_getfnx = o_expressions,
	ot -> ot_info = (caddr_t) exprEval;
    if (ot = text2obj ("exprExpr"))
	ot -> ot_getfnx = o_expressions,
	ot -> ot_setfnx = s_expressions,
	ot -> ot_info = (caddr_t) exprExpr;	
    if (ot = text2obj ("exprStatus"))
	ot -> ot_getfnx = o_expressions,
	ot -> ot_info = (caddr_t) exprStatus;
    if (ot = text2obj ("exprHints"))
	ot -> ot_getfnx = o_expressions,
	ot -> ot_info = (caddr_t) exprHints;
}

/*  */

int	f_expression (vec)
char  **vec;
{
    int	    i;
    register char *cp;
    register struct expr *e;
    PE	    pe;
    PS	    ps;

    vec++;

    if (sscanf (*vec, "%d", &i) != 1) {
invalid: ;
	advise (LLOG_EXCEPTIONS, NULLCP, "invalid expression index: %s", *vec);
	return NOTOK;
    }
    if (i <= 0 || i > NEXPR)
	goto invalid;
    vec++;

    e = exprs + i - 1;
    if (e -> e_expr)
	free (e -> e_expr), e -> e_expr = NULL;

    if ((pe = pe_alloc (PE_CLASS_UNIV, PE_FORM_CONS, PE_CONS_SEQ)) == NULL)
	adios (NULLCP, "pe_alloc: out of memory");
    while (cp = *vec++) {
	OID	oid;
	PE	p;

	if (isdigit (*cp)) {
	    if (sscanf (cp, "%ld", &i) != 1) {
		advise (LLOG_EXCEPTIONS, NULLCP, "bad integer-value: %s", cp);
		return NOTOK;
	    }
	    p = num2prim ((integer) i, PE_CLASS_UNIV, PE_PRIM_INT);
	}
	else {
	    if ((oid = text2oid (cp)) == NULL) {
		advise (LLOG_EXCEPTIONS, NULLCP, "unknown variable: %s", cp);
		return NOTOK;
	    }
	    p = obj2prim (oid, PE_CLASS_UNIV, PE_PRIM_OID);
	    oid_free (oid);
	}

	if (seq_add (pe, p, NOTOK) == NOTOK)
	    adios (NULLCP, "seq_add: out of memory");
    }

    if ((ps = ps_alloc (str_open)) == NULLPS)
	adios (NULLCP, "ps_alloc: failed");
    if (str_setup (ps, NULLCP, BUFSIZ, 0) == NOTOK)
	adios (NULLCP, "std_setup: %s", ps_error (ps -> ps_errno));
    if (pe2ps (ps, pe) == NOTOK)
	adios (NULLCP, "pe2ps: %s", ps_error (ps -> ps_errno));

    e -> e_size = ps -> ps_ptr - (e -> e_expr = ps -> ps_base);

    ps -> ps_base = NULL, ps -> ps_cnt = 0;
    ps -> ps_ptr = NULL, ps -> ps_bufsiz = 0;

    ps_free (ps);

    if (debug)
	vunknown (pe);
    pe_free (pe);

    if (i > exprNumber)
	exprNumber = i;

    return OK;
}