Net2/usr/src/contrib/isode/pepsy/util.c

Compare this file to the similar file:
Show the results in this format:

/* util.c */

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

/* 
 * $Header: /f/osi/pepsy/RCS/util.c,v 7.7 91/02/22 09:50:13 mrose Interim $
 *
 *
 * $Log:	util.c,v $
 * Revision 7.7  91/02/22  09:50:13  mrose
 * Interim 6.8
 * 
 * Revision 7.6  90/12/11  10:41:13  mrose
 * sync
 * 
 * Revision 7.5  90/11/04  19:21:19  mrose
 * update
 * 
 * Revision 7.4  90/10/23  20:43:20  mrose
 * update
 * 
 * Revision 7.3  90/08/18  00:44:30  mrose
 * touch-up
 * 
 * Revision 7.2  90/08/08  14:14:45  mrose
 * update
 * 
 * Revision 7.1  90/07/09  14:53:23  mrose
 * sync
 * 
 * Revision 7.0  90/07/01  19:54:33  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.
 *
 */


/* LINTLIBRARY */

#include	<stdio.h>
#include	"pepsy-driver.h"
#include	"psap.h"
#include	"pepsy.h"
#include	 <varargs.h>
#include 	"tailor.h"

#ifndef	PEPYPARM
#define PEPYPARM	char *
#endif

static char *pr_petype ();

extern void exit();

#ifdef lint
/* VARARGS4 */

int	pepsylose (module, p, pe, str)
modtyp	*module;
tpe	*p;
char	*str;
PE	pe;
{
	return pepsylose (module, p, pe, str);
}

#else
int	pepsylose (va_alist)
va_dcl
{
	va_list	ap;
	int	type;
	modtyp	*module;
	tpe	*p;
	char	*cp;
	PE	pe;
	char	buffer[BUFSIZ];

	va_start (ap);

	module = va_arg (ap, modtyp *);
	p = va_arg (ap, tpe *);
	pe = va_arg (ap, PE);

	_asprintf (buffer, NULLCP, ap);
	(void) sprintf (PY_pepy, "%s: module %s",
			buffer, module ? module -> md_name : "<none>");
	if (p) {
	    cp = PY_pepy + strlen (PY_pepy);
	    (void) sprintf (cp, " %s/class=%s/id=%d",
			    pr_petype (p -> pe_type),
			    pe_classlist[p -> pe_flags & FL_CLASS],
			    p -> pe_tag);
	}
	if (pe && pe -> pe_class >= 0 && pe -> pe_class < pe_maxclass) {
	    cp = PY_pepy + strlen (PY_pepy);
	    (void) sprintf (cp, " got %s/%d", pe_classlist[pe -> pe_class],
			    pe -> pe_id);
	}

	SLOG (psap_log, LLOG_EXCEPTIONS, NULLCP, ("%s", PY_pepy));

	va_end (ap);
	return NOTOK;
}
#endif

#ifdef lint
/* VARARGS4 */

int	ppepsylose (module, p, pe, str)
modtyp	*module;
ptpe	*p;
char	*str;
PE	pe;
{
	return ppepsylose (module, p, pe, str);
}

#else
int	ppepsylose (va_alist)
va_dcl
{
	va_list	ap;
	int	type;
	modtyp	*module;
	ptpe	*p;
	char	*cp;
	PE	pe;
	char	buffer[BUFSIZ];

	va_start (ap);

	module = va_arg (ap, modtyp *);
	p = va_arg (ap, ptpe *);
	pe = va_arg (ap, PE);

	_asprintf (buffer, NULLCP, ap);
	(void) sprintf (PY_pepy, "%s: module %s",
			buffer, module ? module -> md_name : "<none>");
	if (p) {
	    cp = PY_pepy + strlen (PY_pepy);
	    (void) sprintf (cp, " %s/class=%s/id=%d",
			    pr_petype (p -> pe_type),
			    pe_classlist[p -> pe_flags & FL_CLASS],
			    p -> pe_tag);
	    if (p->pe_typename)
		(void) sprintf (cp, "(%s)", p -> pe_typename);
	}
	if (pe && pe -> pe_class >= 0 && pe -> pe_class < pe_maxclass) {
	    cp = PY_pepy + strlen (PY_pepy);
	    (void) sprintf (cp, " got %s/%d", pe_classlist[pe -> pe_class],
			    pe -> pe_id);
	}

	SLOG (psap_log, LLOG_EXCEPTIONS, NULLCP, ("%s", PY_pepy));

	va_end (ap);
	return NOTOK;
}
#endif

/*
 * Useful little routines
 */
/*
 * print out the message and if the arguement is greater than 0
 * terminate
 */
ferr(n, mesg)
char   *mesg;
{
    (void) printf(mesg);
    if (n > 0)
	exit(n);
}
/*
 * print out the message and number and if the arguement is greater
 * than 0 terminate
 */
ferrd(n, mesg, d)
char   *mesg;
int     d;
{
    (void) printf(mesg, d);
    if (n > 0)
	exit(n);
}

/*
 * 0 = Encoding table, 1 = Decoding table, 2 = Printing table
 */
#define TYP_ENC		0
#define TYP_DEC		1
#define TYP_PRINT	2
#define TYP_LAST	2

dmp_tpe(s, p, mod)
char   *s;
modtyp *mod;			/* Module it is from */
tpe    *p;
{
    int     typ, i, j;
    tpe   **par, **prev;
    char   *name;

    (void) printf("%s: (%s)", s, mod->md_name);
    /*
     * Calculate what table it is in - we assume they are in order of
     * increasing address
     */

    par = NULL;
    for (typ = 0; typ <= TYP_LAST; typ++) {
	switch (typ) {
	case TYP_ENC:
	    if (mod->md_etab != NULL && mod->md_etab[0] < p) {
		par = mod->md_etab;
		name = "Encoding:";
	    }
	    break;

	case TYP_DEC:
	    if (mod->md_dtab != NULL && mod->md_dtab[0] < p) {
		par = mod->md_dtab;
		name = "Decoding:";
	    }
	    break;

	case TYP_PRINT:
	    if (mod->md_ptab != NULL && mod->md_ptab[0] < (ptpe *) p) {
		(ptpe **) par = mod->md_ptab;
		name = "Printing:";
	    }
	    break;

	default:
	    (void) pepsylose (mod, p, NULLPE, "dmp_tpe:typ = %d internal error\n",
		typ);
	    return;
	}
    }
    if (par == NULL) {
	(void) printf("can't find entry 0x%x\n", p);
	return;
    }
    prev = par;
    for (i = mod->md_nentries; i > 0; i--) {
	if (*par > p)
	    break;
	par++;
    }
    if (par == prev)
	(void) pepsylose (mod, p, NULLPE,
	    "dmp_tpe:par == prev == 0x%x internal error\n", (int) par);
    par--;
    j = p - *par;

    (void) printf("%s type %d + %d ", name, par - prev, j);
    pr_entry(p);
}
#define NENTRY(x)	((sizeof (x)/sizeof (x[0])))
/*
 * Print out a tpe entry
 */
static char	*ntypes[] = { "PE_START", "PE_END", "illegal 1", "illegal 2",
    "XOBJECT", "illegal 4", "illegal 5", "UCODE", "MALLOC", "SCTRL", "CH_ACT",
    "OPTL", "BOPTIONAL", "FFN_CALL",},

       *otypes[] = { "ANY", "INTEGER", "BOOLEAN", "OBJECT",
    "BITSTRING", "OCTETSTRING", "SET_START", "SEQ_START", "SEQOF_START",
    "SETOF_START", "CHOICE_START", "UNKNOWN", "T_NULL", "T_OID",
    "ETAG", "IMP_OBJ", "EXTOBJ", "EXTMOD", "OBJID", "DFLT_F", "DFLT_B",
    "T_STRING", "OCTET_PTR", "OCTET_LEN", "BITSTR_PTR", "BITSTR_LEN",
    "FN_CALL" };

static char *
pr_petype (type)
int	type;
{
    static char nbuf[30];

    if (type >= PE_START && type < NENTRY(ntypes) - 1)
	return ntypes[type + 1];
    else if (type >= TYPE_DATA && type < NENTRY(otypes) + TYPE_DATA)
	return otypes[type - TYPE_DATA];
    (void) sprintf (nbuf, "%d", type);
    return nbuf;
}

pr_entry(p)
tpe    *p;
{
    (void) printf ("%s, ", pr_petype (p -> pe_type));
    (void) printf("%d, %d, %d}\n", p->pe_ucode, p->pe_tag, p->pe_flags);
}

p_pr_entry(p)
ptpe    *p;
{
    if (p->pe_type >= PE_START && p->pe_type < NENTRY(ntypes) - 1)
        (void) printf("{%s, ", ntypes[p->pe_type + 1]);
    else if (p->pe_type >= TYPE_DATA && p->pe_type < NENTRY(otypes) + TYPE_DATA)
        (void) printf("{%s, ", otypes[p->pe_type - TYPE_DATA]);
    else
        (void) printf("{%d, ", p->pe_type);

    (void) printf("%d, %d, %d}\n", p->pe_ucode, p->pe_tag, p->pe_flags);
}


/*
 * null function for what evr purposes
 */
f_null()
{
}

/*
 * compare a given number of bits pointed to by the two character
 * pointers return 0 if they are the same non zero otherwise
 */
bitscmp(p1, p2, len)
register char *p1, *p2;
int     len;
{
    register int i;
    register unsigned int mask;

    if (len >= 8 && bcmp(p1, p2, len / 8))
	return (1);

    if (len % 8 == 0)
	return (0);
    /* Check those last few bits */
    i = len / 8;
    mask = (0xff00 >> len % 8) & 0xff;
    if ((p1[i] & mask) != (p2[i] & mask))
	return (1);

    return (0);
}

#define MIN(a, b)	(a < b ? a : b)
/*
 * compare an octet string and a qb and return 0 if they are the same
 * and non zero otherwise
 */
ostrcmp(p, len, qb)
register char *p;
register int len;
register struct qbuf *qb;
{
    register struct qbuf *qp;

    if (len < 0 || qb == NULL || p == NULL)
	return (1);
    qp = qb;
    do {
	if (qp->qb_data != NULL) {
	    if (qp->qb_len < 0)
		ferrd(1, "ostrcmp:qb_len %d < 0", qp->qb_len);
	    if (qp->qb_len > len)
		return (1);
	    if (bcmp(qp->qb_data, p, qp->qb_len))
		return (1);
	    if ((len -= qp->qb_len) == 0)
		return (0);
	    p += qp->qb_len;
	}
	qp = qp->qb_forw;
    } while (qp != qb);

    return (len);
}

/*
 * Is data present for the optional item? 1 for yes 0 for no
 */
hasdata(parm, p, mod, popt, optcnt)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
int    *popt, optcnt;
{
    int	val;

    switch (p->pe_type) {
    case INTEGER:
    case REALTYPE:
    case BOOLEAN:
    case T_NULL:
	if (DEFAULT(p)) {
	    /* Default's don't have bit map */
	    if (p[1].pe_type == DFLT_B && same(p, p + 1, parm, mod)
	    || p[-1].pe_type == DFLT_F && same(p, p - 1, parm, mod))
		goto next;
	    break;
	}
	if (!TESTBIT(*popt, optcnt++))
	    goto next;		/* Missing so skip */
	break;

    case ETAG:
	if (!hasdata(parm, p + 1, mod, popt, optcnt))
	    goto next;
	break;

    case IMP_OBJ:
	if (p[1].pe_type == SOBJECT && parm == NULL
	    || *((char **) (parm + p[1].pe_ucode)) == NULL)
	    goto next;
	break;

    case FN_CALL:	/* function call */
	if ((val = (FN_PTR(mod, p))(parm, (PE *)0)) == NOTOK)
	    return pepsylose (mod, p, NULLPE,
			      "hasdata:FN_CALL:call failed");
	if (val != OK)
	    goto next;
	break;

    default:
	if (*((char **) (parm + p->pe_ucode)) == NULL)
	    goto next;
	break;
    }
    return (1);

next:
    return (0);
}

/*
 * determine if the default value is the same as the value in the
 * structure and if so return greater than zero (meaning don't encode this
 * item). On error return NOTOK
 */
same(typ, dflt, parm, mod)
tpe    *typ, *dflt;
char   *parm;
modtyp *mod;			/* Module it is from */
{
    int     val;
    int	len;
    char   *p1;
    PE      pe;
    struct qbuf *qb;

    switch (typ->pe_type) {
    case INTEGER:
	val = IVAL(mod, dflt) == *(integer *) (parm + typ->pe_ucode);
	break;

#ifdef	PEPSY_REALS
    case REALTYPE:
	val = RVAL(mod, dflt) == *(double *) (parm + typ->pe_ucode);
	break;
#endif

    case BOOLEAN:
	val = IVAL(mod, dflt) == *(char *) (parm + typ->pe_ucode);
	break;

    case T_NULL:
	val = 1;		/* Only one value */
	break;

    case SBITSTRING:
	if ((pe = (PE) parm) == NULL) {
	    val = 1;
	    break;
	}
	goto bstring;

    case BITSTRING:
	if ((pe = *(PE *) (parm + typ->pe_ucode)) == NULL) {
	    val = 1;
	    break;
	}
bstring:
	if ((p1 = bitstr2strb(pe, &val)) == NULL) {
	    (void) pepsylose (mod, typ, pe, "same:bad bitstring\n");
	    return (NOTOK);
	    /* Should really abort encoding here but how can we comunicate this
	     * to the routine that calls us?
	     */
	}
bstring2:
	if (val != IVAL(mod, dflt) || bitscmp(PVAL(mod, dflt), p1, val))
	    val = 0;
	else
	    val = 1;
	if (typ->pe_type != BITSTR_PTR)
	    free(p1);
	break;

    case BITSTR_PTR:
	if (typ[1].pe_type != BITSTR_LEN)
	    return pepsylose (mod, typ, pe, "same:missing BITSTR_LEN\n");
	if ((p1 = *(char **) (parm + typ->pe_ucode)) == NULL) {
	    val = 1;
	    break;
	}
	val = *(int *) (parm + (typ + 1)->pe_ucode);
	goto bstring2;

    case SOCTETSTRING:
	if ((qb = (struct qbuf *) parm) == NULL) {
	    val = 1;
	    break;
	}
	goto ostring;

    case OCTETSTRING:
	if ((qb = *(struct qbuf **) (parm + typ->pe_ucode)) == NULL) {
	    val = 1;
	    break;
	}
ostring:
	if (ostrcmp(PVAL(mod, dflt), (int ) IVAL(mod, dflt), qb))
	    val = 0;
	else
	    val = 1;
	break;

    case OCTET_PTR:
	if (typ[1].pe_type != OCTET_LEN)
	    return pepsylose (mod, typ, pe, "same:missing OCTET_LEN\n");
	if ((p1 = *(char **) (parm + typ->pe_ucode)) == NULL) {
	    val = 1;
	    break;
	}
	len = *(int *) (parm + (typ + 1)->pe_ucode);
	goto o1string;

    case T_STRING:
	if ((p1 = *(char **) (parm + typ->pe_ucode)) == NULL) {
	    val = 1;
	    break;
	}
	len = strlen(p1);
o1string:
	if (len != IVAL(mod, dflt)) {
	    val = 0;
	    break;
	}
	if (bcmp(PVAL(mod, dflt), p1, len))
	    val = 0;
	else
	    val = 1;
	break;

    case OBJECT:
	if (*(char **) (parm + typ->pe_ucode) == NULL) {
	    val = 1;		/* to conform with pepy's way of
				 * doing default */
	    break;
	}
	val = same(mod->md_etab[typ->pe_tag] + 1, dflt,
		   *(char **) (parm + typ->pe_ucode), mod);
	break;

    case SOBJECT:
	if ((char *) parm == NULL) {
	    val = 1;		/* to conform with pepy's way of
				 * doing default */
	    break;
	}
	val = same(mod->md_etab[typ->pe_tag] + 1, dflt, parm, mod);
	break;

    case IMP_OBJ:
	typ++;			/* fall through */

    case ANY:
    case SANY:
    case SEXTOBJ:
    case EXTOBJ:
    case OBJID:
    case SOBJID:
    case SEQ_START:
    case SET_START:
    case -1:			/* Just use the pepy method of null
				 * pointers */
	/*
	 * This is the posy/pepy hack way of doing things at the
	 * moment
	 */
	val = *(char **) (parm + typ->pe_ucode) == NULL;
	break;

    case FN_CALL:	/* function call */
	if ((val = (FN_PTR(mod, typ))(parm, (PE *)0)) == NOTOK)
	    return pepsylose (mod, typ, NULLPE,
			      "same:FN_CALL:call failed");
	if (val != OK)
	    val = 1;
	else
	    val = 0;
	break;


    default:
	(void) pepsylose (mod, typ, NULLPE, "same: %d not implemented\n",
	    typ->pe_type);
	return (NOTOK);
    }

    return (val);
}

/*
 * Calculate the next tpe entry in the sequence. Count a sequence as
 * one element
 */
tpe    *
next_tpe(p)
tpe    *p;
{
    int     level;



    level = 0;
    if (p->pe_type == PE_END) {
	(void) pepsylose (NULLMODTYP, p, NULLPE,
	    "next_tpe:internal error: unexpected PE_END found");
	return (p);
    }
    do {
again:
	switch (p->pe_type) {
	case SSEQ_START:
	case SSEQOF_START:
	case SSET_START:
	case SSETOF_START:
	case SCHOICE_START:
	case SEQ_START:
	case SEQOF_START:
	case SET_START:
	case SETOF_START:
	case CHOICE_START:
	    level++;
	    break;

	case UCODE:
	case MEMALLOC:
	case SCTRL:
	case CH_ACT:
	case INTEGER:
	case REALTYPE:
	case BOOLEAN:
	case SANY:
	case ANY:
	case T_NULL:
	case OBJECT:
	case SOBJECT:
	case BITSTRING:
	case BITSTR_LEN:
	case SBITSTRING:
	case OCTETSTRING:
	case T_STRING:
	case OCTET_LEN:
	case SOCTETSTRING:
	case OBJID:
	case SOBJID:
	case OPTL:
	case EXTMOD:
	case DFLT_B:
	case FN_CALL:
	case FFN_CALL:
	    break;

	case IMP_OBJ:
	case ETAG:
	case EXTOBJ:
	case SEXTOBJ:
	case DFLT_F:
	case OCTET_PTR:
	case BITSTR_PTR:
	case BOPTIONAL:
	case FREE_ONLY:
	    p++;
	    goto again;

	case PE_END:
	    level--;
	    break;

	default:
	    ferrd(1, "next_tpe: unknown type %d\n", p->pe_type);
	}
	p++;
    } while (level > 0 || p->pe_type == DFLT_B);

    return (p);
}

/*
 * Is there a match at for this tag and class pair. Return 1 if yes 0
 * if no We will search through contained objects and through choices
 */
ismatch(p, mod, cl, tag)
tpe    *p;
modtyp *mod;			/* Module it is from */
unsigned int cl, tag;
{
    while (!ISDTYPE(p))
	p++;

    switch (p->pe_type) {
    case SOBJECT:
    case OBJECT:
	/* Needs to be changed for optional and default */
	return (ismatch(p = mod->md_dtab[p->pe_tag] + 1, mod, cl, tag));

    case SEXTOBJ:
    case EXTOBJ:
	if (p[1].pe_type != EXTMOD) {
	    dmp_tpe("ismatch: missing EXTMOD", p, mod);
	    ferr(1, "ismatch:internal error\n");
	}
	return (ismatch(EXT2MOD(mod, (p + 1))->md_dtab[p->pe_tag] + 1,
			EXT2MOD(mod, (p + 1)), cl, tag));

    case CHOICE_START:
    case SCHOICE_START:
	for (p++; p->pe_type != PE_END; p = next_tpe (p)) {
	    if (!ISDTYPE(p))
		continue;
	    if (ismatch(p, mod, cl, tag))
		return (1);
	}
	return (0);

    case SANY:
	return (1);

    case FN_CALL:
    case ANY:
	if (STAG(p) == -1)
	    return (1);
	/* else fall through - not sure if this is needed */

    default:
	return (tag == TAG(p) && cl == CLASS(p));
    }
}

/*
 * find the data entry that goes with this DFLT_F entry
 * bascially skip over any ETAGS that (an arbitary number but almost always 1)
 */
tpe	*
fdflt_f(p)
register tpe	*p;
{
    if (p->pe_type != DFLT_F)
	ferr(1, "fdlt_f:Internal Error missing DFLT_F\n");
    
    for (p++; p->pe_type != PE_END; p++) {
	if (p->pe_type != ETAG)
		return (p);
    }
    ferr(1, "fdlt_f:Internal Error PE_END found\n");
    /*NOTREACHED*/
}

/*
 * find the DFLT_B entry
 */
tpe	*
fdflt_b(p)
register tpe	*p;
{
    for (p++; p->pe_type != PE_END; p++) {
	if (p->pe_type == DFLT_B)
		return (p);
    }
    ferr(1, "fdflt_b:Internal Error PE_END found\n");
    /*NOTREACHED*/
}