/* enc.c */

#ifndef	lint
static char *rcsid = "$Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/isode-beta/pepsy/enc.c,v 1.1.1.1 2018/04/24 16:12:56 root Exp $";
#endif

/* 
 * $Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/isode-beta/pepsy/enc.c,v 1.1.1.1 2018/04/24 16:12:56 root Exp $
 *
 *
 * $Log: enc.c,v $
 * Revision 1.1.1.1  2018/04/24 16:12:56  root
 * BSD 4.3reno
 *
 * Revision 7.2  90/07/27  08:49:34  mrose
 * update
 * 
 * Revision 7.1  90/07/09  14:52:27  mrose
 * sync
 * 
 * Revision 7.0  90/07/01  19:54:16  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	<stdio.h>
#include	<ctype.h>
#include	"psap.h"
#include	"pepsy.h"
#include 	"tailor.h"

#ifndef	PEPYPARM
#define PEPYPARM	char *
#endif


extern tpe *next_tpe();
char   *idname(), *clname();

#define NEXT_TPE(p) (p = next_tpe(p))
#define CHKTAG(mod, p, pe)	ismatch(p, mod, pe->pe_class, pe->pe_id)

static char oomsg[] = "Out of memory";
#define oom(a,b)	pepsylose ((a), (b), NULLPE, oomsg);
#define RET_OK(rpe, pe)		*(rpe) = (pe), (OK)

/*
 * encode the specified type of the specified module into the given
 * pe
 */
enc_f(typ, mod, pe, explicit, len, buf, parm)
/* ARGSUSED */
int     typ;			/* which type it is */
modtyp *mod;			/* Module it is from */
register PE *pe;
int     explicit;
int     len;
char   *buf;
char	*parm;
{
    register tpe *p;

    if (typ < 0 || typ >= mod->md_nentries) {
	(void) pepsylose (mod, NULLTPE, NULLPE, "enc_f:Illegal typ %d", typ);
	return NOTOK;
    }

    p = mod->md_etab[typ];
    if (p->pe_type != PE_START) {
	return (pepsylose (mod, NULLTPE, NULLPE, "enc_f: missing PE_START"));
    }
    p++;

    return (en_obj(parm, p, mod, pe));
}

/*
 * Encode an object. If the object is a simple type it may have a
 * compressed type reference. If it is a compound type it will not
 * have an offset. This is very important as it means we cannot just
 * use en_type to handle this which must always assume the field can
 * have an offset.
 */
static int
en_obj(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    PE      pe = NULLPE;	/* for pepsylose calls */
    int     cnt = 0;
    tpe    *tmp;

    DLOG (psap_log, LLOG_DEBUG, ("en_obj: type %d", p->pe_type));

    *rpe = NULLPE;	/* default case */

    while (p->pe_type != PE_END) {

	switch (p->pe_type) {
	case PE_END:
	case PE_START:
	    return (pepsylose (mod, p, pe, "en_obj:END/START type"));

	case UCODE:
	    break;

	case ETAG:
	    if ((pe = pe_alloc(CLASS(p), PE_FORM_CONS, TAG(p))) == NULLPE)
		return oom (mod, p);

	    switch (p->pe_ucode) {

	    default:
		p++;
		if (en_obj(parm, p, mod, &pe->pe_cons) == NOTOK)
		    goto bad;
	    }
	    break;

	case SEQ_START:
	   if (en_seq(parm, p, mod, &pe) == NOTOK)
	       goto bad;
	    break;

	case SEQOF_START:
	    if (en_seqof(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SET_START:
	    if (en_set(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SETOF_START:
	    if (en_setof(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case IMP_OBJ:
	    tmp = p++;
	    if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1,
		      0, (char *)0, (parm)) == NOTOK)
		      return (NOTOK);
	    } else if (en_obj(parm, mod->md_etab[p->pe_tag]+1, mod, &pe)==NOTOK)
		    goto bad;
	    pe->pe_class = CLASS(tmp);
	    pe->pe_id = TAG(tmp);
	    break;

	case SOBJECT:
	    if (en_obj(parm, mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case OBJECT:
	    if (en_obj(parm, mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case CHOICE_START:
	    if (en_choice(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	default:
	    if (en_type(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;
	}
	if (ISDTYPE(p) && cnt++ > 0)
	    return pepsylose (mod, p, NULLPE, "en_obj:compound type found");

	if (ISDTYPE(p)) {
	    if (pe == NULLPE)
		return pepsylose (mod, p, NULLPE,
				  "en_obj: missing mandatory value");
	}
	if (ISDTYPE(p) && pe != NULLPE)
	    return (RET_OK(rpe, pe));

	if (NEXT_TPE(p) == NULLTPE)
	    goto bad;
    }

    return (RET_OK(rpe, pe));

bad:
    return (NOTOK);
}

/*
 * Encode a single type. If a basic type encode it, if a compound
 * type call the appropriate encoding routine
 */
static int
en_type(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    PE      pe = NULLPE;
    int     cnt = 0;
    int     i;			/* Integer for encoding type */
    tpe    *tmp;
    char   *cp;

    DLOG (psap_log, LLOG_DEBUG, ("Encoding the type %d", p->pe_type));

    *rpe = NULLPE;
    while (p->pe_type != PE_END) {

	switch (p->pe_type) {
	case PE_END:
	case PE_START:
	    return (pepsylose (mod, p, pe, "en_type:END/START type"));

	case DFLT_F:
	    p++;
	    if ((i = same(p, p - 1, parm, mod)) == NOTOK)
		return (NOTOK); /* Error */
	    if (i)
		return (RET_OK(rpe, NULLPE));/* don't encode it */
	    continue;

	case UCODE:
	    break;

	case ETAG:
	    if ((pe = pe_alloc(CLASS(p), PE_FORM_CONS, TAG(p))) == NULLPE)
		return oom (mod, p);

	    switch (p->pe_ucode) {

	    default:
		p++;
		if (en_etype(parm, p, mod, &pe->pe_cons) == NOTOK)
		    goto bad;
	    }
	    break;

	case SEQ_START:
	    if (en_seq(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SEQOF_START:
	    if (en_seqof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SET_START:
	    if (en_set(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SETOF_START:
	    if (en_setof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case IMP_OBJ:
	    tmp = p++;
	    if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1,
		      0, (char *)0, *(char **) (parm + p->pe_ucode)) == NOTOK)
		      return (NOTOK);
	    } else if (p->pe_type == SOBJECT) {
		if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1, mod, &pe)
		  == NOTOK)
		     goto bad;;
	    } else
		if (en_obj(*(char **) (parm + p->pe_ucode),
			mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		    goto bad;

	    pe->pe_class = CLASS(tmp);
	    pe->pe_id = TAG(tmp);
	    break;

	case SOBJECT:
	    if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1, mod, &pe)
	      == NOTOK)
		goto bad;
	    break;

	case OBJECT:
	    if (en_obj(*(char **) (parm + p->pe_ucode),
	      mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case CHOICE_START:
	    if (en_choice(*(char **) (parm + p->pe_ucode), p, mod, &pe) ==NOTOK)
		goto bad;
	    break;

	case SEXTOBJ:
	    if (p[1].pe_type != EXTMOD)
		return pepsylose (mod, &p[1], NULLPE,
				  "en_seq: missing EXTMOD");
	    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		  (char *) parm) == NOTOK)
		  return (NOTOK);
	    break;

	case EXTOBJ:
	    if (p[1].pe_type != EXTMOD)
		return pepsylose (mod, &p[1], NULLPE,
				  "en_seq: missing EXTMOD");
	    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		  *(char **) (parm + p->pe_ucode)) == NOTOK)
		  return (NOTOK);
	    break;

	case INTEGER:
	    DLOG (psap_log, LLOG_DEBUG,
		("en_type:INTEGER offset is %d, value is %d",
				 p->pe_ucode, *(int *) (parm + p->pe_ucode)));

	    if ((pe = num2prim(*(int *) (parm + p->pe_ucode),
			       CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    break;

#ifdef	PEPSY_REALS
	case REALTYPE:
	    DLOG (psap_log, LLOG_DEBUG, ("en_type:REAL: offset %d valus %d",
					 p->pe_ucode
					 *(int *) (parm + p->pe_ucode)));

	    if ((pe = real2prim(*(double *) (parm + p->pe_ucode),
			       CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    break;

#endif
	case BOOLEAN:
	    DLOG (psap_log, LLOG_DEBUG, ("en_type:BOOLEAN:offset %d value %d",
					 p->pe_ucode,
					 *(char *) (parm + p->pe_ucode)));
	    if ((pe = flag2prim(*(char *) (parm + p->pe_ucode),
				CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    break;

	case T_NULL:
	    DLOG (psap_log, LLOG_DEBUG, ("en_type:NULL:offset %d",p->pe_ucode));

	    if ((pe = pe_alloc(CLASS(p), PE_FORM_PRIM,
			       TAG(p))) == NULLPE)
		return oom(mod,p);

	    break;

	case SANY:
	    (pe = (PE) parm)->pe_refcnt++;
	    break;

	case ANY:
	    if ((parm + p->pe_ucode) == 0 || *(PE *) (parm + p->pe_ucode) == 0)
#if ROSAP_HACK
		/* hack for ROSAP. expects this strangeness */
		pe = pe_alloc(PE_CLASS_UNIV, PE_FORM_PRIM, PE_PRIM_NULL);
#else
		pe = NULLPE;
#endif
	    else
		(pe = *(PE *) (parm + p->pe_ucode))->pe_refcnt++;
	    break;

	case SOCTETSTRING:
	    if ((pe = qb2prim((struct qbuf *) parm, CLASS(p), TAG(p)))
		== NULLPE)
		return oom(mod, p)
	    break;

	case OCTETSTRING:
	    if ((pe = qb2prim(*(struct qbuf **) (parm + p->pe_ucode),
			      CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    break;

	case SBITSTRING:
	    if ((cp = bitstr2strb((PE) parm, &i)) == NULL)
		return oom(mod, p);
	    if ((pe = strb2bitstr(cp, i, CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    free(cp);
	    if ((pe = bit2prim(pe)) == NULLPE)
		return oom(mod, p);
	    break;

	case BITSTRING:
	    if ((cp = bitstr2strb(*(PE *) (parm + p->pe_ucode), &i))
		== NULL)
		return oom(mod, p);

	    if ((pe = strb2bitstr(cp, i, CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);

	    free(cp);
	    if ((pe = bit2prim(pe)) == NULLPE)
		return oom(mod, p);
	    break;

	case SOBJID:
	    if ((pe = obj2prim((OID) (parm), CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    break;

	case OBJID:
	    if ((pe = obj2prim(*(OID *) (parm + p->pe_ucode), CLASS(p), TAG(p)))
		== NULLPE)
		return oom(mod, p);
	    break;

	default:
	    return pepsylose (mod, p, NULLPE, "en_type: type not implemented");
	}
	if (ISDTYPE(p) && cnt++ > 0)
	    return pepsylose (mod, p, NULLPE, "en_type:compound type found");

	if (ISDTYPE(p)) {
	    if (pe == NULLPE)
		return pepsylose (mod, p, NULLPE,
				  "en_type: missing mandatory value");
	}
	if (ISDTYPE(p) && pe != NULLPE)
	    return (RET_OK(rpe, pe));
	if (NEXT_TPE(p) == NULLTPE)
	    goto bad;
    }

    return (RET_OK(rpe, pe));

bad:
    return (NOTOK);
}

/*
 * Build a sequence, calling appropriate routines to build each sub
 * type
 */
static int
en_seq(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    PE      head;
    PE      pe = NULLPE;
    tpe    *tmp;		/* first entry in list */
    int    *popt = NULL;	/* Pointer to optional field */
    int     optcnt = 0;		/* Number of optionals bits so far */
    int	    val;

    if (p->pe_type != SEQ_START)
	    return (pepsylose (mod, p, pe, "en_seq: missing SEQ_START\n"));

    if ((head = pe_alloc(CLASS(p), PE_FORM_CONS, TAG(p))) == NULLPE)
	return oom (mod, p);
    p++;

    while (p->pe_type != PE_END) {

	DLOG (psap_log, LLOG_DEBUG, ("en_seq type%d", p->pe_type));

	if (ISDTYPE(p) && OPTIONAL(p)) {
	    switch (p->pe_type) {
	    case INTEGER:
	    case REALTYPE:
	    case BOOLEAN:
	    case T_NULL:
		if (!TESTBIT(*popt, optcnt++))
		    goto next;	/* Missing so skip */
		break;

	    case ETAG:
		if ((val = hasdata(parm, p + 1, mod, popt, optcnt)) == NOTOK)
		    goto bad;
		if (val == 0)
		    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 SOBJECT:
		if (((char *) parm) == NULL)
		    goto next;
		break;

	    default:
		if (*((char **) (parm + p->pe_ucode)) == NULL)
		    goto next;
		break;
	    }
	}
	switch (p->pe_type) {
	case OPTL:
	    popt = (int *) (parm + p->pe_ucode);
	    break;

	case UCODE:
	    break;

	case ETAG:
	    if (en_type(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SEQ_START:
	    if (en_seq(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SEQOF_START:
	    if (en_seqof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SET_START:
	    if (en_set(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SETOF_START:
	    if (en_setof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case IMP_OBJ:
	    tmp = p++;
	    if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1,
		      0, (char *)0, *(char **) (parm + p->pe_ucode)) == NOTOK)
		      return (NOTOK);
	    } else if (p->pe_type == SOBJECT) {
		if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1, mod,
		      &pe) == NOTOK)
		    goto bad;
	    } else
		if (en_obj(*(char **) (parm + p->pe_ucode),
			mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		    goto bad;
	    pe->pe_class = CLASS(tmp);
	    pe->pe_id = TAG(tmp);
	    break;

	case SOBJECT:
	    if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1, mod, &pe)
		    == NOTOK)
		goto bad;
	    break;

	case OBJECT:
	    if (en_obj(*(char **) (parm + p->pe_ucode),
		    mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case CHOICE_START:
	    if (en_choice(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SEXTOBJ:
	    if (p[1].pe_type != EXTMOD)
		return pepsylose (mod, &p[1], NULLPE, "en_seq: missing EXTMOD");
	    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		  (char *) parm) == NOTOK)
		  return (NOTOK);
	    break;

	case EXTOBJ:
	    if (p[1].pe_type != EXTMOD)
		return pepsylose (mod, &p[1], NULLPE, "en_seq: missing EXTMOD");

	    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		  *(char **) (parm + p->pe_ucode)) == NOTOK)
		  return (NOTOK);
	    break;

	default:
	    if (en_type(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;
	}

	if (ISDTYPE(p) && pe != NULLPE) {
	    if (seq_add(head, pe, -1) == NOTOK)
		return pepsylose (mod, p, NULLPE, "en_seq bad sequence: %s",
		       pe_error(pe->pe_errno));
	}
next:
	if (NEXT_TPE(p) == NULLTPE)
	    return (NOTOK);
    }

    return (RET_OK(rpe, head));

bad:
    return (NOTOK);
}


/*
 * Parse a set, calling appropriate routines to parse each sub type
 */
static int
en_set(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    PE      head;
    PE      pe = NULLPE;
    tpe    *tmp;
    int    *popt = NULL;	/* Pointer to optional field */
    int     optcnt = 0;		/* Number of optionals bits so far */
    int	    val;

    if (p->pe_type != SET_START)
	return pepsylose (mod, p, pe, "en_set: missing SET_START");

    if ((head = pe_alloc(CLASS(p), PE_FORM_CONS, TAG(p))) == NULLPE)
	return oom(mod, p);

    p++;
    while (p->pe_type != PE_END) {

	DLOG (psap_log, LLOG_DEBUG, ("en_set type %d", p->pe_type));

	if (ISDTYPE(p) && OPTIONAL(p)) {
	    switch (p->pe_type) {
	    case INTEGER:
	    case REALTYPE:
	    case BOOLEAN:
	    case T_NULL:
		if (!TESTBIT(*popt, optcnt++))
		    goto next;	/* Missing so skip */
		break;

	    case ETAG:
		if ((val = hasdata(parm, p + 1, mod, popt, optcnt)) == NOTOK)
		    goto bad;
		if (val == 0)
		    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 SOBJECT:
		if (((char *) parm) == NULL)
		    goto next;
		break;

	    default:
		if (*((char **) (parm + p->pe_ucode)) == NULL)
		    goto next;
		break;
	    }
	}
	switch (p->pe_type) {
	case OPTL:
	    popt = (int *) (parm + p->pe_ucode);
	    break;

	case UCODE:
	    break;

	case ETAG:
	    if (en_type(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SEQ_START:
	    if (en_seq(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SEQOF_START:
	    if (en_seqof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SET_START:
	    if (en_set(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case SETOF_START:
	    if (en_setof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case IMP_OBJ:
	    tmp = p++;
	    if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1,
		      0, (char *)0, *(char **) (parm + p->pe_ucode)) == NOTOK)
		      return (NOTOK);
	    } else if (p->pe_type == SOBJECT) {
		if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1, mod,
			&pe) == NOTOK)
		    goto bad;
	    } else
		if (en_obj(*(char **) (parm + p->pe_ucode),
			mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		    goto bad;
	    pe->pe_class = CLASS(tmp);
	    pe->pe_id = TAG(tmp);
	    break;

	case SOBJECT:
	    if (en_obj(parm, mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case OBJECT:
	    if (en_obj(*(char **) (parm + p->pe_ucode),
		    mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		goto bad;
	    break;

	case CHOICE_START:
	    if (en_choice(*(char **) (parm + p->pe_ucode), p, mod, &pe) ==NOTOK)
		goto bad;
	    break;

	case SEXTOBJ:
	    if (p[1].pe_type != EXTMOD)
		return pepsylose (mod, p, "en_set: missing EXTMOD");

	    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		  parm) == NOTOK)
		  return (NOTOK);
	    break;

	case EXTOBJ:
	    if (p[1].pe_type != EXTMOD) 
		return pepsylose (mod, p, "en_set: missing EXTMOD");

	    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		  *(char **) (parm + p->pe_ucode)) == NOTOK)
		  return (NOTOK);
	    break;

	default:
	    if (en_type(parm, p, mod, &pe) == NOTOK)
		goto bad;
	    break;
	}

	if (ISDTYPE(p) && pe != NULLPE) {
	    if (set_add(head, pe) == NOTOK)
		return pepsylose (mod, p, NULLPE, "en_set bad set: %s",
				  pe_error(pe->pe_errno));
	}
next:
	NEXT_TPE(p);
    }

    return (RET_OK(rpe, head));

bad:
    return (NOTOK);
}


/*
 * Parse a sequence of calling appropriate routines to parse each sub
 * type
 */
static int
en_seqof(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    PE      head;
    PE      pe = NULLPE;
    tpe    *start;		/* first entry in list */
    tpe    *tmp;

    if (p->pe_type != SEQOF_START)
	return pepsylose (mod, p, NULLPE, "en_seqof: missing SEQOF_START");

    if ((head = pe_alloc(CLASS(p), PE_FORM_CONS, TAG(p))) == NULLPE)
	return oom(mod, p);

    start = p;
    while ((char *) parm != NULL) {
	p++;
	while (p->pe_type != PE_END) {

	    DLOG (psap_log, LLOG_DEBUG, ("en_seqof type%d", p->pe_type));

	    switch (p->pe_type) {
	    case UCODE:
		break;

	    case ETAG:
		if (en_type(parm, p, mod, &pe) == NOTOK)
		    goto bad;
		break;

	    case SEQ_START:
		if (en_seq(*(char **) (parm + p->pe_ucode), p, mod, &pe)==NOTOK)
		    goto bad;
		break;

	    case SEQOF_START:
		if (en_seqof(*(char **) (parm + p->pe_ucode), p, mod, &pe)
			== NOTOK)
		    goto bad;
		break;

	    case SET_START:
		if (en_set(*(char **) (parm + p->pe_ucode), p, mod, &pe)==NOTOK)
		    goto bad;
		break;

	    case SETOF_START:
		if (en_setof(*(char **) (parm + p->pe_ucode), p, mod, &pe)
			== NOTOK)
		    goto bad;
		break;

	    case IMP_OBJ:
		tmp = p++;
		if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
		    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1,
		       0, (char *)0, *(char **) (parm + p->pe_ucode)) == NOTOK)
		       return (NOTOK);
		} else if (p->pe_type == SOBJECT) {
		    if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1,
			    mod, &pe) == NOTOK)
			goto bad;
		} else if (en_obj(*(char **) (parm + p->pe_ucode),
			    mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
			goto bad;
		pe->pe_class = CLASS(tmp);
		pe->pe_id = TAG(tmp);
		break;

	    case SOBJECT:
		if (en_obj(parm, mod->md_etab[p->pe_tag] + 1, mod, &pe) ==NOTOK)
		    goto bad;
		break;

	    case OBJECT:
		if (en_obj(*(char **) (parm + p->pe_ucode),
			mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		    goto bad;
		break;

	    case CHOICE_START:
		if (en_choice(*(char **) (parm + p->pe_ucode), p, mod, &pe)
			== NOTOK)
		    goto bad;
		break;

	    case SEXTOBJ:
		if (p[1].pe_type != EXTMOD)
		    return pepsylose (mod, p+1, NULLPE,
				      "en_seqof: missing EXTMOD");
		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		      parm) == NOTOK)
		      return (NOTOK);
		break;

	    case EXTOBJ:
		if (p[1].pe_type != EXTMOD) 
		    return pepsylose (mod, p+1, NULLPE,
				      "en_seqof: missing EXTMOD");

		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		      *(char **) (parm + p->pe_ucode)) == NOTOK)
		      return (NOTOK);
		break;

	    default:
		if (en_type(parm, p, mod, &pe) == NOTOK)
		    goto bad;
		break;
	    }
	    if (ISDTYPE(p) && pe != NULLPE) {
		if (seq_add(head, pe, -1) == NOTOK)
		    return pepsylose (mod, p, NULLPE,
				      "en_seqof bad sequence: %s",
				      pe_error(pe->pe_errno));
	    }
	    if (NEXT_TPE(p) == NULLTPE)
		goto bad;
	}
	parm = *(char **) (parm + p->pe_ucode);	/* Any more ? */
	p = start;
    }

    return (RET_OK(rpe, head));

bad:
    return (NOTOK);
}

/*
 * Parse a setof, calling appropriate routines to parse each sub type
 */
static int
en_setof(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    PE      head;
    PE      pe = NULLPE, last = NULLPE;
    tpe    *start;
    tpe    *tmp;

    if (p->pe_type != SETOF_START)
	return pepsylose (mod, p, NULLPE, "en_setof: missing SETOF_START");

    if ((head = pe_alloc(CLASS(p), PE_FORM_CONS, TAG(p))) == NULLPE)
	return oom(mod,p);

    start = p;
    while ((char *) parm != NULL) {
	p++;
	while (p->pe_type != PE_END) {
	    DLOG (psap_log, LLOG_DEBUG, ("en_setof type%d",
					 p->pe_type));

	    switch (p->pe_type) {
	    case UCODE:
		break;

	    case ETAG:
		if (en_type(parm, p, mod, &pe) == NOTOK)
		    goto bad;
		break;

	    case SEQ_START:
		if (en_seq(*(char **) (parm + p->pe_ucode), p, mod, &pe)==NOTOK)
		    goto bad;
		break;

	    case SEQOF_START:
		if (en_seqof(*(char **) (parm + p->pe_ucode), p, mod, &pe)
			== NOTOK)
		    goto bad;
		break;

	    case SET_START:
		if (en_set(*(char **) (parm + p->pe_ucode), p, mod, &pe)==NOTOK)
		    goto bad;
		break;

	    case SETOF_START:
		if (en_setof(*(char **) (parm + p->pe_ucode), p, mod, &pe)
			== NOTOK)
		    goto bad;
		break;

	    case IMP_OBJ:
		tmp = p++;
		if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
		    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1,
		       0, (char *)0, *(char **) (parm + p->pe_ucode)) == NOTOK)
		       return (NOTOK);
		} else if (p->pe_type == SOBJECT) {
		    if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1,
			    mod, &pe) == NOTOK)
			goto bad;
		} else
		    if (en_obj(*(char **) (parm + p->pe_ucode),
			    mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
			goto bad;
		pe->pe_class = CLASS(tmp);
		pe->pe_id = TAG(tmp);
		break;

	    case SOBJECT:
		if (en_obj(parm, mod->md_etab[p->pe_tag] + 1, mod, &pe) ==NOTOK)
		    goto bad;
		break;

	    case OBJECT:
		if (en_obj(*(char **) (parm + p->pe_ucode),
			mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		    goto bad;
		break;

	    case CHOICE_START:
		if (en_choice(*(char **) (parm + p->pe_ucode), p, mod, &pe)
			== NOTOK)
		    goto bad;
		break;

	    case SEXTOBJ:
		if (p[1].pe_type != EXTMOD)
		    return pepsylose (mod, p + 1, NULLPE,
				      "en_setof: missing EXTMOD");
		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		      parm) == NOTOK)
		      return (NOTOK);
		break;

	    case EXTOBJ:
		if (p[1].pe_type != EXTMOD)
		    return pepsylose (mod, p + 1, NULLPE,
				      "en_setof: missing EXTMOD");

		if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
		      *(char **) (parm + p->pe_ucode)) == NOTOK)
		      return (NOTOK);
		break;

	    default:
		if (en_type(parm, p, mod, &pe) == NOTOK)
		    goto bad;
		break;
	    }

	    if (ISDTYPE(p) && pe != NULLPE) {
		if (set_addon(head, last, pe) == NOTOK)
		    return pepsylose (mod, p, NULLPE, "en_setof bad set: %s",
				      pe_error(pe->pe_errno));
		else
		    last = pe;
	    }

	    if (NEXT_TPE(p) == NULLTPE)
		goto bad;;
	}
	parm = *(char **) (parm + p->pe_ucode);	/* Any more ? */
	p = start;
    }

    return (RET_OK(rpe, head));


bad:
    return (NOTOK);
}

/*
 * encode a choice field. This means find which choice is taken and
 * call en_type to encode it
 */
static int
en_choice(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    int     cnt;

    if (p->pe_type != CHOICE_START)
	return pepsylose (mod, p, NULLPE, "en_choice:missing CHOICE_START");
    p++;
    if (p->pe_type != SCTRL)
	return pepsylose (mod, p, NULLPE, "en_choice:missing SCTRL");

    cnt = *(int *) (parm + p->pe_ucode);
    DLOG (psap_log, LLOG_DEBUG, ("cnt %d", cnt));

    if (cnt != 0)
	cnt--;
    if (cnt < 0)
	return pepsylose (mod, p, NULLPE, "en_choice:offset %d negative", cnt);

    for (p++; p->pe_type != PE_END; NEXT_TPE(p)) {
	if (ISDTYPE(p)) {
	    if (cnt == 0) {
		if (en_etype(parm, p, mod, rpe) == NOTOK)
		    return (NOTOK);
		return (OK);
	    }
	    cnt--;
	}
    }

    return pepsylose (mod, p, NULLPE, "en_choice: no choice taken");
}


/*
 * check to see if the object is present or not
 */
static int
chkobj(mod, p, head)
modtyp *mod;
tpe    *p;
PE      head;
{

    for (; p->pe_type != PE_END; NEXT_TPE(p)) {
	if (!ISDTYPE(p))
	    continue;

	if (p->pe_type == OBJECT) {
	    if (chkobj(mod, p, head))
		return (1);
	} else if (CHKTAG(mod, p, head))
	    return (1);

	if (OPTIONAL(p) || DEFAULT(p))
	    continue;

	return (0);
    }
    return (0);
}

#if 0
/*
 * print the PE structure pointed to by pe
 */
print_pe(pe, n)
PE      pe;
int     n;
{

    if (pe == NULL)
	return;
    (void) printf("%*s", 4 * n, "");
#if 0
    (void) printf("error = %d, context = %x, class = %x, form = %x, id = %x\n",
	   pe->pe_errno, pe->pe_context, pe->pe_class, pe->pe_form, pe->pe_id);
#endif
    if (pe->pe_errno)
	(void) printf(" errno = %d", pe->pe_errno);
    if (pe->pe_class == PE_CLASS_UNIV)
	(void) printf(" %s", idname( (int )pe->pe_id));
    else if (pe->pe_class == PE_CLASS_CONT)
	(void) printf("[%d]", pe->pe_id);
    else
	(void) printf("[%s %d]", clname( (int )pe->pe_class), pe->pe_id);

    (void) printf("\n");

#if 0
    (void) printf("%*s", 4 * n, "");
    (void) printf("cardinality = %d offset = %d\n", pe->pe_cardinal, pe->pe_offset);
#endif
    if (pe->pe_form != 0x0) {
	if (pe->pe_cons != NULLPE)
	    print_pe(pe->pe_cons, n + 1);
    } else {
	(void) printf("%*s", 4 * n, "");
	switch (pe->pe_id) {
	case PE_PRIM_BOOL:
	    (void) printf("%d", prim2flag(pe));
	    break;

	case PE_PRIM_INT:
	    (void) printf(" %d", prim2num(pe));
	    break;
	case PE_PRIM_BITS:
	    prntbits(pe);
	    break;

	case PE_PRIM_OCTS:
	    (void) prntos(pe);
	    break;

	case PE_PRIM_NULL:
	    break;


	case PE_DEFN_NUMS:
	case PE_DEFN_PRTS:
	case PE_DEFN_T61S:
	case PE_DEFN_VTXS:
	case PE_DEFN_IA5S:
	case PE_DEFN_GFXS:
	case PE_DEFN_VISS:
	case PE_DEFN_GENS:
	case PE_DEFN_CHRS:
	    (void) prntstr(pe);
	    break;


	case PE_PRIM_OID:
	case PE_CONS_EXTN:
	case PE_PRIM_REAL:
	case PE_PRIM_ENUM:
	case PE_PRIM_ENCR:

	case PE_CONS_SEQ:
	case PE_CONS_SET:

	case PE_DEFN_UTCT:
	case PE_DEFN_GENT:
	default:
	    (void) printf("Unimplemented %d ", pe->pe_id);
	    break;
	}
	(void) printf("\n");
    }
    if (pe->pe_next != NULLPE) {
	(void) printf("%*s", 4 * n, "pe_next:\n");
	print_pe(pe->pe_next, n);
    }
}

/*
 * return the string describing that class
 */
static char   *
clname(cl)
int     cl;
{
    char   *p;
    static char buf[30];

    switch (cl) {
    case PE_CLASS_UNIV:
	p = "Universal";
	break;

    case PE_CLASS_APPL:
	p = "Application";
	break;

    case PE_CLASS_CONT:
	p = "Context";
	break;

    case PE_CLASS_PRIV:
	p = "Private";
	break;

    default:
	(void) sprintf(buf, "Unknown Class %d", cl);
	p = buf;
	break;
    }
    return (p);
}


/*
 * return the string describing that identity or the number itself
 * Assuming a Universal class
 */
static char   *
idname(id)
int     id;
{
    char   *p;
    static char buf[40];

    switch (id) {
    case PE_PRIM_BOOL:
	p = "Boolean";
	break;

    case PE_PRIM_INT:
	p = "Integer";
	break;

    case PE_PRIM_BITS:
	p = "Bit String";
	break;

    case PE_PRIM_OCTS:
	p = "Octet String";
	break;

    case PE_PRIM_NULL:
	p = "Null";
	break;

    case PE_PRIM_OID:
	p = "Object Descriptor";
	break;

    case PE_CONS_EXTN:
	p = "External";
	break;

    case PE_PRIM_REAL:
	p = "Real";
	break;

    case PE_PRIM_ENUM:
	p = "Enumerated Type";
	break;

    case PE_PRIM_ENCR:
	p = "Encrypted Type";
	break;

    case PE_CONS_SEQ:
	p = "Sequence";
	break;

    case PE_CONS_SET:
	p = "Set";
	break;

    case PE_DEFN_NUMS:
	p = "Numeric String";
	break;

    case PE_DEFN_PRTS:
	p = "Printable String";
	break;

    case PE_DEFN_T61S:
	p = "T.61 String";
	break;

    case PE_DEFN_VTXS:
	p = "Videotex String";
	break;

    case PE_DEFN_IA5S:
	p = "IA5 String";
	break;

    case PE_DEFN_UTCT:
	p = "UTC Time";
	break;

    case PE_DEFN_GENT:
	p = "Generalised Time";
	break;

    case PE_DEFN_GFXS:
	p = "Graphics String";
	break;

    case PE_DEFN_VISS:
	p = "Visable String";
	break;

    case PE_DEFN_GENS:
	p = "General String";
	break;

    case PE_DEFN_CHRS:
	p = "Character String";
	break;

    default:
	(void) sprintf(buf, "Unknown Universal %d", id);
	p = buf;
	break;
    }
    return (p);
}
#endif

/*
 * Encode a single type for an explicit tag field If a basic type
 * encode it, if a compound type call the appropriate encoding
 * routine. Similar to en_type except we do the indirection on the
 * ucode field
 */
static int
en_etype(parm, p, mod, rpe)
PEPYPARM parm;
tpe    *p;
modtyp *mod;			/* Module it is from */
PE	*rpe;		/* Return value PE */
{
    tpe    *tmp;
    PE      pe = NULLPE;

    switch (p->pe_type) {
    case PE_END:
    case PE_START:
	return (pepsylose (mod, p, pe, "en_etype:END/START type"));

    case UCODE:
	break;

    case ETAG:
	if ((pe = pe_alloc(CLASS(p), PE_FORM_CONS, TAG(p))) == NULLPE)
	    return oom(mod, p);
	switch (p->pe_ucode) {
	default:
	    p++;
	    if (en_etype(parm, p, mod, &pe->pe_cons) == NOTOK)
		goto bad;
	}
	break;

    case SEQ_START:
	if (en_seq(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
	    goto bad;
	break;

    case SEQOF_START:
	if (en_seqof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
	    goto bad;
	break;

    case SET_START:
	if (en_set(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
	    goto bad;
	break;

    case SETOF_START:
	if (en_setof(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
	    goto bad;
	break;

    case IMP_OBJ:
	tmp = p++;
	if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
	    if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1,
		  0, (char *)0, *(char **) (parm + p->pe_ucode)) == NOTOK)
		  return (NOTOK);
	} else if (p->pe_type == SOBJECT) {
	    if (en_obj((char *) parm, mod->md_etab[p->pe_tag] + 1, mod, &pe)
		    == NOTOK)
		goto bad;
	} else
	    if (en_obj(*(char **) (parm + p->pe_ucode),
		    mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
		goto bad;
	pe->pe_class = CLASS(tmp);
	pe->pe_id = TAG(tmp);
	break;

    case SOBJECT:
	if (en_obj(parm, mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
	    goto bad;
	break;

    case OBJECT:
	if (en_obj(*(char **) (parm + p->pe_ucode),
		mod->md_etab[p->pe_tag] + 1, mod, &pe) == NOTOK)
	    goto bad;
	break;

    case CHOICE_START:
	if (en_choice(*(char **) (parm + p->pe_ucode), p, mod, &pe) == NOTOK)
	    goto bad;
	break;

    case INTEGER:
	DLOG (psap_log, LLOG_DEBUG, ("offset %d value %d",
				     p->pe_ucode,
				     *(int *) (parm + p->pe_ucode)));
	if ((pe = num2prim(*(int *) (parm + p->pe_ucode), CLASS(p), TAG(p))) == NULLPE)
	    return oom (mod, p);

	break;

#ifdef	PEPSY_REALS
    case REALTYPE:
	DLOG (psap_log,  LLOG_DEBUG, ("offset %d value %g",
				      p->pe_ucode,
				      *(double *) (parm + p->pe_ucode)));
	    if ((pe = real2prim(*(double *) (parm + p->pe_ucode),
			       CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    break;

#endif
    case BOOLEAN:
	DLOG (psap_log, LLOG_DEBUG, ("offset %d value %d",
				     p->pe_ucode,
				     *(char *) (parm + p->pe_ucode)));

	if ((pe = flag2prim(*(char *) (parm + p->pe_ucode), CLASS(p), TAG(p))) == NULLPE)
	    return oom(mod, p);
	break;

    case T_NULL:
	DLOG (psap_log, LLOG_DEBUG, ("offset %d", p->pe_ucode));
	if ((pe = pe_alloc(CLASS(p), PE_FORM_PRIM, TAG(p))) == NULLPE)
	    return oom(mod, p);
	break;

    case SANY:
	(pe = (PE) parm)->pe_refcnt++;
	break;

    case ANY:
	if ((parm + p->pe_ucode) == 0 || *(PE *) (parm + p->pe_ucode) == 0)
#if ROSAP_HACK
	    /* hack for ROSAP. expects this strangeness */
	    pe = pe_alloc(PE_CLASS_UNIV, PE_FORM_PRIM, PE_PRIM_NULL);
#else
	    pe = NULLPE;
#endif
	else
	    (pe = *(PE *) (parm + p->pe_ucode))->pe_refcnt++;
	break;

    case SEXTOBJ:
	if (p[1].pe_type != EXTMOD)
	    return pepsylose (mod, p+1, NULLPE, "en_etype: missing EXTMOD");
	if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
	    parm) == NOTOK)
	    return (NOTOK);
	break;

    case EXTOBJ:
	if (p[1].pe_type != EXTMOD)
	    return pepsylose (mod, p+1, NULLPE, "en_etype: missing EXTMOD");
	if (enc_f(p->pe_tag, EXT2MOD(mod, (p + 1)), &pe, 1, 0, (char *)0,
	      *(char **) (parm + p->pe_ucode)) == NOTOK)
	      return (NOTOK);
	break;

    case SOCTETSTRING:
	if ((pe = qb2prim((struct qbuf *) parm, CLASS(p), TAG(p))) == NULLPE)
	    return oom(mod, p);
	break;

    case SBITSTRING:
	{
	    char   *cp;
	    int     i;

	    if ((cp = bitstr2strb((PE) parm, &i)) == NULL)
		return oom(mod, p);
	    if ((pe = strb2bitstr(cp, i, CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    free(cp);
	}
	break;

    case OCTETSTRING:
	if ((pe = qb2prim(*(struct qbuf **) (parm + p->pe_ucode), CLASS(p), TAG(p))) == NULLPE)
	    return oom(mod, p);
	break;

    case BITSTRING:
	{
	    char   *cp;
	    int     i;

	    if ((cp = bitstr2strb(*(PE *) (parm + p->pe_ucode), &i)) == NULL)
		return oom(mod, p);
	    if ((pe = strb2bitstr(cp, i, CLASS(p), TAG(p))) == NULLPE)
		return oom(mod, p);
	    free(cp);
	}
	break;

    case SOBJID:
	if ((pe = obj2prim((OID) (parm), CLASS(p), TAG(p))) == NULLPE)
	    return oom(mod, p);
	break;

    case OBJID:
	if ((pe = obj2prim(*(OID *) (parm + p->pe_ucode), CLASS(p), TAG(p)))
	    == NULLPE)
	    return oom(mod, p);
	break;

    default:
	return pepsylose (mod, p, NULLPE, "en_etype: type not implemented");
    }
    return (RET_OK(rpe, pe));

bad:
    return (NOTOK);
}
#if 0
/*
 * Print out the value of a bits string
 */
static prntbits(pe)
PE      pe;
{
    int     len, i;

    if ((len = pe->pe_nbits) < 0) {
	(void) printf("prntbits:Bad bistring\n");
	return;
    }
    (void) printf("Bits:");
    for (i = 0; i < len; i++)
	if (bit_test(pe, i))
	    (void) printf(" %d", i);

    (void) putchar('\n');
}

/*
 * Dump a bunch of hex digits printing out those that are printable
 * Print out a given length of octets as hex (with the ASCII
 * characters given if they have any
 */
static pclen(s, len)
register char *s;
register int len;
{
    register int cnt = 0;

    while (len-- > 0) {
	if (cnt % 8 == 0)
	    (void) printf("\n%d:", cnt / 8 + 1);
	if (isprint(*s & 0x7f))
	    (void) printf("\t%02x(%c)", *s & 0xff, *s & 0x7f);
	else
	    (void) printf("\t%02x", *s & 0xff);
	s++;
	cnt++;
    }
    (void) putchar('\n');
}

/*
 * print out an octet string
 */
static prntos(pe)
PE      pe;
{
    struct qbuf *qb;

    if ((qb = prim2qb(pe)) == NULL) {
bad:
	(void) printf("prntos:bad octet string\n");
	return (NOTOK);
    }
    if (qb_pullup(qb) == NOTOK)
	goto bad;

    if (qb->qb_forw->qb_data == NULL || qb->qb_forw->qb_len < 0)
	goto bad;

    pclen(qb->qb_forw->qb_data, qb->qb_forw->qb_len);
    return (OK);
}

/*
 * print out a string which should be printable
 */
static prntstr(pe)
PE      pe;
{
    struct qbuf *qb;

    if ((qb = prim2qb(pe)) == NULL) {
bad:
	(void) printf("prntstr:bad string\n");
	return (NOTOK);
    }
    if (qb_pullup(qb) == NOTOK)
	goto bad;

    if (qb->qb_forw->qb_data == NULL || qb->qb_forw->qb_len < 0)
	goto bad;

    (void) printf("\"%s\"", qb->qb_forw->qb_data);
    return (OK);
}
#endif
