/* prnt.c */

#ifndef	lint
static char *rcsid = "$Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/isode-beta/pepsy/prnt.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/prnt.c,v 1.1.1.1 2018/04/24 16:12:56 root Exp $
 *
 *
 * $Log: prnt.c,v $
 * Revision 1.1.1.1  2018/04/24 16:12:56  root
 * BSD 4.3reno
 *
 * Revision 7.3  90/07/27  08:48:34  mrose
 * update
 * 
 * Revision 7.2  90/07/09  14:53:08  mrose
 * sync
 * 
 * Revision 7.1  90/07/01  20:02:00  mrose
 * update
 * 
 */

/*
 *				  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.
 *
 */


/*
 * These routines are the driving routines for printing data
 */
#include	<stdio.h>
#include	<ctype.h>
#include	"psap.h"
#include	"pepsy.h"

#define PEPYPARM	char **
#ifndef	PEPYPARM
#define PEPYPARM	char **
#endif
extern PEPYPARM NullParm;

#define PRINT_TYPES	0
#define	CHOICE_PUSH


extern PE p_setpresent();
extern IFP vfnx;
extern FILE *vfp;

extern ptpe *next_ptpe();
extern int pepsylose ();

int     xlevel = 0;
int     tabed = 0;
int     xpushed = 0;

#define NEXT_PTPE(p)	(p = next_ptpe(p))
#define CHKTAG(mod, p, pe)	p_ismatch(p, mod, pe->pe_class, pe->pe_id)

/* SUPPRESS 36 *//* for Saber C */

/*
 * to guarentee the rules that vname and a vprint-type routine are called
 * alternatively. Basically can't have two vname's in a row
 */
static vnamelock = 0;
   /* if vnamelock > 0 don't call vname */
#define VNAME(x)  vnamelock++ > 0 ? 0 : vname(x)
#define VTAG(class, tag)	vnamelock++ > 0 ? 0 : vtag(class, tag)

/* as vprint takes a variable number of arguements we have to put all of
 * the arguements inside () and remove them when we expand to vprint
 */
#define VPRINT(x)	vnamelock = 0, vprint x
#define VSTRING(x)	vnamelock = 0, vstring(x)
#define VUNKNOWN(x)	vnamelock = 0, vunknown(x)
#define VPUSH		vnamelock = 0, vpush
#define VPOP		vnamelock = 0, vpop

/*
 * Print out ASN data given in pe using the information given in the tables
 */
prnt_f(typ, mod, pe, explicit, len, buf)
/* ARGSUSED */
int     typ;			/* which type it is */
modtyp *mod;			/* ASN Module it is from */
PE      pe;
int     explicit;	/* nonzero means we are call top level 
			 * print final \n
			 */
int    *len;
char  **buf;
{
    ptpe   *p;

    if (typ < 0 || typ >= mod->md_nentries) {
	return (pepsylose (mod, NULLTPE, pe, "prnt_f:Illegal type %d\n",typ));
    }

    p = mod->md_ptab[typ];

    if (p->pe_type != PE_START) {
	return (pepsylose (mod, p, pe, "prnt_f: missing PE_START\n"));
    }

#if EXTRA_BRACKETS
    if (explicit) {
	if (p->pe_typename)
	    VNAME(p->pe_typename);
    }
    VPUSH();
#endif
    if (p_pr_obj(explicit, pe, p, mod) == NOTOK) {
#if EXTRA_BRACKETS
	VPOP();
#endif
	return (NOTOK);
    }
#if EXTRA_BRACKETS
    VPOP();
#endif
    return (OK);
}

/*
 * Parse an object. The top level of an object does not have any
 * offset field which makes it different to pr_type routine which
 * must assume that it has an offset.
 */
static int
p_pr_obj(expl, pe, p, mod)
int     expl;			/* do we look at the tag */
PE      pe;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    int     cnt = 0;

#if PRINT_TYPES
    if (p->pe_typename)
	VNAME(p->pe_typename);
#endif

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

	if (ISDTYPE(p) && expl && CHKTAG(mod, p, pe) == 0) {
	    if (DEFAULT(p)) {
		return (pepsylose (mod, p, pe,
		    "p_pr_obj:Default not implemented\n"));
	    }
	    else if (OPTIONAL(p))
		goto next;
	    else {
		return (pepsylose (mod, p, pe,
		    "p_pr_obj:missing mandatory parameter", p, mod));
	    }
	}
	if (p->pe_typename)
	    VNAME(p->pe_typename);
	switch (p->pe_type) {
	case PE_END:
	case PE_START:
	    goto bad;

	case UCODE:
	    if ((*mod->md_ducode) (pe, p, mod) != OK)
		goto bad;
	    break;

	case ETAG:
	    switch (p->pe_ucode) {
	    default:
		if (p_pr_etype(pe->pe_cons, p, mod) == NOTOK)
		    goto bad;
	    }
	    break;

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

	case SEQOF_START:
	    if (p_pr_seqof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SET_START:
	    if (p_pr_set(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SETOF_START:
	    if (p_pr_setof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case IMP_OBJ:
	    p++;
	    if (p->pe_type == EXTOBJ || p->pe_type == SEXTOBJ) {
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		    (char **) 0) == NOTOK)
		    goto bad;
	    } else {
		if (p_pr_obj(0, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
	    }
	    break;

	case SOBJECT:
	case OBJECT:
	    if (p_pr_obj(expl, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		goto bad;
	    }
	    break;

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

	case SEXTOBJ:
	case EXTOBJ:
	    if (p[1].pe_type != EXTMOD) {
		return (pepsylose (mod, p, pe, "p_pr_obj: missing EXTMOD"));
	    }
	    if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		   (char **) 0) == NOTOK)
		   goto bad;
	    break;

	default:
	    if (p_pr_type(expl, pe, p, mod) == NOTOK)
		goto bad;
	    break;
	}
	if (ISDTYPE(p) && cnt > 0)
	    return (pepsylose (mod, p, pe, "p_pr_obj:compound type found\n"));
	if (ISDTYPE(p) && pe != NULLPE) {
	    return (OK);
	}
next:
	if (NEXT_PTPE(p) == NULLPTPE)
	    goto bad;
    }

    return (OK);

bad:
    return (NOTOK);
}


/*
 * Parse a single type. If a basic type parse it, if a compound type
 * call the appropriate parsing routine
 */
static int
p_pr_type(expl, pe, p, mod)
int     expl;			/* do we look at the tag */
PE      pe;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    int     cnt = 0;
    int     i;
    OID     oid;

    while (p->pe_type != PE_END) {

	if (ISDTYPE(p) && expl && CHKTAG(mod, p, pe) == 0) {
	    if (DEFAULT(p)) {
#ifdef	PRINT_DEFAULTS
		setpval(p, p + 1, mod);
#endif
		goto next;
	    } else if (OPTIONAL(p))
		goto next;
	    else {
		dmp_ptpe("p_pr_type:missing mandatory parameter", p, mod);
		goto bad;
	    }
	}
	switch (p->pe_type) {
	case PE_END:
	case PE_START:
	    goto bad;

	case UCODE:
	    if ((*mod->md_ducode) (pe, p, mod) != OK)
		goto bad;
	    break;

	case ETAG:
	    switch (p->pe_ucode) {
	    default:
		if (p_pr_etype(pe->pe_cons, p, mod) == NOTOK)
		    goto bad;
	    }
	    break;

	case SEQ_START:
	    if (p_pr_seq(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SEQOF_START:
	    if (p_pr_seqof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SET_START:
	    if (p_pr_set(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SETOF_START:
	    if (p_pr_setof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case IMP_OBJ:
	    p++;
	    if (p->pe_type == EXTOBJ) {
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		    (char **) 0) == NOTOK)
		    goto bad;
	    } else {
		if (p_pr_obj(0, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
	    }
	    break;

	case SOBJECT:
	case OBJECT:
	    if (p_pr_obj(expl, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		goto bad;
	    }
	    break;

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

	case SEXTOBJ:
	case EXTOBJ:
	    if (p[1].pe_type != EXTMOD) {
		return (pepsylose (mod, p, pe, "p_pr_type: missing EXTMOD"));
	    }
	    if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		   (char **) 0) == NOTOK)
		   goto bad;
	    break;

	case INTEGER:
	    if (pe != NULLPE) {
		if ((i = prim2num(pe)) == NOTOK && pe->pe_errno != PE_ERR_NONE)
		    goto bad;
		VPRINT(("%d", i));
	    }
	    break;

#ifdef	PEPSY_REALS
	case REALTYPE:
	    if (pe != NULLPE) {
		double r;

		if ((r = prim2real(pe)) == NOTOK
		    && pe->pe_errno != PE_ERR_NONE)
		    goto bad;
		VPRINT(("%g", r));
	    }
	    break;
#endif

	case BOOLEAN:
	    if (pe != NULLPE) {
		if ((i = prim2flag(pe)) == NOTOK)
		    goto bad;
		VPRINT((i ? "TRUE" : "FALSE"));
	    }
	    break;

	case T_NULL:
	    VPRINT(("NULL"));
	    break;

	case SANY:
	    if (pe != NULLPE) {
		if (pe->pe_errno != PE_ERR_NONE) {
		    goto bad;
		} else
		    VUNKNOWN(pe);
	    }
	    break;


	case ANY:
	    if (pe != NULLPE) {
		if (pe->pe_errno != PE_ERR_NONE) {
		    goto bad;
		} else
		    VUNKNOWN(pe);
	    }
	    break;

	case SOCTETSTRING:
	    if (pe != NULLPE) {
		VSTRING(pe);
	    }
	    break;

	case OCTETSTRING:
	    if (pe != NULLPE) {
		VSTRING(pe);
	    }
	    break;

	case SBITSTRING:
	    if (pe != NULLPE) {
		PE	bstr;

		if ((bstr = prim2bit(pe)) == NULLPE)
		    goto bad;
		/* one day get the named bits here */
		VPRINT(("%s", bit2str(bstr, "\020")));
	    }
	    break;

	case BITSTRING:
	    if (pe != NULLPE) {
		PE	bstr;

		if ((bstr = prim2bit(pe)) == NULLPE)
		    goto bad;
		/* one day get the named bits here */
		VPRINT(("%s", bit2str(bstr, "\020")));
	    }
	    break;

	case SOBJID:
	    if ((oid = (OID) prim2oid(pe)) == NULLOID) {
		goto bad;
	    } else {
		VPRINT(("%s", oid2ode(oid)));
	    }
	    break;

	case OBJID:
	    if ((oid = (OID) prim2oid(pe)) == NULLOID) {
		goto bad;
	    } else {
		VPRINT(("%s", oid2ode(oid)));
	    }
	    break;

	default:
	    return (pepsylose (mod, p, pe, "p_pr_type: %d not implemented\n",
		p->pe_type));
	}
	if (ISDTYPE(p) && cnt > 0)
	    return (pepsylose (mod, p, pe, "p_pr_type:compound type found\n"));
	if (ISDTYPE(p) && pe != NULLPE)
	    return (OK);
next:
	if (NEXT_PTPE(p) == NULLPTPE)
	    goto bad;
    }

    return (OK);

bad:
    return (NOTOK);
}

/*
 * Parse a sequence, calling appropriate routines to parse each sub
 * type
 */
static int
p_pr_seq(head, p, mod)
PE      head;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    PE      pe;

    if (p->pe_type != SEQ_START)
	return (pepsylose (mod, p, head, "p_pr_seq: missing SEQ_START\n"));
#if PRINT_TYPES
    if (p->pe_typename)
	VNAME(p->pe_typename);
#endif
    VPUSH();

    p++;
    if (p->pe_type == DFLT_B)
	p++;


    pe = first_member(head);
    while (p->pe_type != PE_END) {
	if (ISDTYPE(p) && OPTIONAL(p)) {
	    if (pe == NULLPE || CHKTAG(mod, p, pe) == 0)
		goto next;
	} else if (ISDTYPE(p) && (pe == NULLPE || CHKTAG(mod, p, pe) == 0)) {
	    if (DEFAULT(p)) {
#ifdef	PRINT_DEFAULTS
		setpval(p, p + 1, mod);
#endif
		goto next;
	    } else {
		dmp_ptpe("p_pr_seq:missing mandatory parameter", p, mod);
		goto bad;
	    }
	}
	if (p->pe_typename)
	    VNAME(p->pe_typename);
	switch (p->pe_type) {
	case OPTL:
	    break;

	case UCODE:
	    if ((*mod->md_ducode) (pe, p, mod) != OK)
		goto bad;
	    break;

	case ETAG:
	    if (p_pr_type(1, pe, p, mod) == NOTOK)
		goto bad;
	    break;

	case SEQ_START:
	    if (p_pr_seq(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SEQOF_START:
	    if (p_pr_seqof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SET_START:
	    if (p_pr_set(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SETOF_START:
	    if (p_pr_setof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case IMP_OBJ:
	    p++;
	    if (p->pe_type == EXTOBJ) {
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		    (char **) 0) == NOTOK)
		    goto bad;
	    } else {
		if (p_pr_obj(0, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
	    }
	    break;

	case SOBJECT:
	    if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case OBJECT:
	    if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		goto bad;
	    }
	    break;

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

	case SEXTOBJ:
	    if (p[1].pe_type != EXTMOD) {
		return (pepsylose (mod, p, pe, "p_pr_seq: missing EXTMOD"));
	    }
	    if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0,NULLIP,
		(char **)0) == NOTOK)
		goto bad;
	    break;

	case EXTOBJ:
	    if (p[1].pe_type != EXTMOD) {
		return (pepsylose (mod, p, pe, "p_pr_seq: missing EXTMOD"));
	    }
	    if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		    (char **)0) == NOTOK)
		goto bad;
	    break;

	default:
	    if (p_pr_type(1, pe, p, mod) == NOTOK)
		goto bad;
	    break;
	}

	if (ISDTYPE(p) && pe != NULLPE)
	    pe = next_member(head, pe);
next:
	if (NEXT_PTPE(p) == NULLPTPE)
	    goto bad;
    }

    VPOP();
    return (OK);

bad:
    VPOP();
    return (NOTOK);
}


/*
 * Parse a set, calling appropriate routines to parse each sub type
 */
static int
p_pr_set(head, p, mod)
PE      head;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    PE      pe;

    if (p->pe_type != SET_START)
	return (pepsylose (mod, p, head, "p_pr_seq: missing SET_START\n"));
#if PRINT_TYPES
    if (p->pe_typename)
	VNAME(p->pe_typename);
#endif
    VPUSH();

    p++;
    if (p->pe_type == DFLT_B)
	p++;

    while (p->pe_type != PE_END) {

	if (ISDTYPE(p) && OPTIONAL(p)) {
	    if ((pe = (PE) p_setpresent(head, p, mod)) == NULLPE)
		goto next;
	} else if (ISDTYPE(p) && (pe = (PE) p_setpresent(head, p, mod)) == NULLPE) {
	    if (DEFAULT(p)) {
#ifdef PRINT_DEFAULTS
		setpval(p, p + 1, mod);
#endif
		goto next;
	    } else {
		dmp_ptpe("p_pr_set:missing mandatory parameter", p, mod);
		goto bad;
	    }
	}
	if (p->pe_typename)
	    VNAME(p->pe_typename);
	switch (p->pe_type) {
	case OPTL:
	    break;

	case UCODE:
	    if ((*mod->md_ducode) (pe, p, mod) != OK)
		goto bad;
	    break;

	case ETAG:
	    if (p_pr_type(1, pe, p, mod) == NOTOK)
		goto bad;
	    break;

	case SEQ_START:
	    if (p_pr_seq(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SEQOF_START:
	    if (p_pr_seqof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SET_START:
	    if (p_pr_set(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case SETOF_START:
	    if (p_pr_setof(pe, p, mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case IMP_OBJ:
	    p++;
	    if (p->pe_type == EXTOBJ) {
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		       (char **) 0) == NOTOK)
		       goto bad;
	    } else {
		if (p_pr_obj(0, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
	    }
	    break;

	case SOBJECT:
	    if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		goto bad;
	    }
	    break;

	case OBJECT:
	    if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		goto bad;
	    }
	    break;

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

	case SEXTOBJ:
	    if (p[1].pe_type != EXTMOD) {
		return (pepsylose (mod, p, pe, "p_pr_set: missing EXTMOD"));
	    }
	    if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP, (char **)0) == NOTOK)
		    return (NOTOK);
	    break;

	case EXTOBJ:
	    if (p[1].pe_type != EXTMOD) {
		return (pepsylose (mod, p, pe, "p_pr_set: missing EXTMOD"));
	    }
	    if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		(char **)0) == NOTOK)
		goto bad;
	    break;

	default:
	    if (p_pr_type(1, pe, p, mod) == NOTOK)
		goto bad;
	    break;
	}

next:
	if (NEXT_PTPE(p) == NULLPTPE)
	    goto bad;
    }

    VPOP();
    return (OK);

bad:
    VPOP();
    return (NOTOK);
}


/*
 * Parse a sequence of calling appropriate routines to parse each sub
 * type
 */

static int
p_pr_seqof(head, p, mod)
PE      head;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    PE      pe;
    ptpe   *start;		/* first entry in list */
    int     dflt = 0;

    if (p->pe_type != SEQOF_START) {
	return (pepsylose (mod, p, head, "p_pr_seqof: missing SEQOF_START\n"));
    }
#if PRINT_TYPES
    if (p->pe_typename)
	VNAME(p->pe_typename);
#endif
    VPUSH();

    p++;

    if (p->pe_type == DFLT_B)
	p++;

    start = p;


    pe = first_member(head);
    while (pe != NULLPE) {
	while (p->pe_type != PE_END) {

	    if (ISDTYPE(p) && CHKTAG(mod, p, pe) == 0) {
		if (DEFAULT(p))
		    return (pepsylose (mod, p, pe,
			"p_pr_seqof:Default not implemented\n"));
		else if (OPTIONAL(p))
		    goto next;
		else {
		    return (pepsylose (mod, p, pe,
			"p_pr_seqof:missing mandatory parameter"));
		}
	    }
	    if (p->pe_typename)
		VNAME(p->pe_typename);
	    switch (p->pe_type) {
	    case UCODE:
		if ((*mod->md_ducode) (pe, p, mod) != OK)
		    goto bad;
		break;

	    case ETAG:
		if (p_pr_type(1, pe, p, mod) == NOTOK)
		    goto bad;
		break;

		/*
		 * case SCTRL:  parm = (char *) ((char *) parm);
		 * break;
		 */

	    case SEQ_START:
		if (p_pr_seq(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SEQOF_START:
		if (p_pr_seqof(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SET_START:
		if (p_pr_set(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SETOF_START:
		if (p_pr_setof(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SOBJECT:
		if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case OBJECT:
		if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
		break;

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

	    case SEXTOBJ:
		if (p[1].pe_type != EXTMOD) {
		    return (pepsylose (mod, p, pe,"p_pr_seqof:missing EXTMOD"));
		}
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		     (char **)0) == NOTOK)
		     goto bad;
		break;

	    case EXTOBJ:
		if (p[1].pe_type != EXTMOD) {
		    return (pepsylose (mod, p, pe,"p_pr_seqof:missing EXTMOD"));
		}
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP, 
		    (char **) 0) == NOTOK)
		    goto bad;
		break;

	    default:
		if (p_pr_type(1, pe, p, mod) == NOTOK)
		    goto bad;
		break;
	    }

	    if (ISDTYPE(p) && dflt == 0)
		pe = next_member(head, pe);
    next:
	    if (NEXT_PTPE(p) == NULLPTPE)
		goto bad;
	}
	/* parm = (char *) (parm); */
	p = start;
    }

    VPOP();
    return (OK);

bad:
    VPOP();
    return (NOTOK);
}

/*
 * Parse a setof, calling appropriate routines to parse each sub type
 */
static int
p_pr_setof(head, p, mod)
PE      head;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    PE      pe;
    ptpe   *start;

    if (p->pe_type != SETOF_START)
	return (pepsylose (mod, p, head, "p_pr_setof: missing SETOF_START\n"));
#if PRINT_TYPES
    if (p->pe_typename)
	VNAME(p->pe_typename);
#endif
    VPUSH();

    p++;
    if (p->pe_type == DFLT_B)
	p++;

    start = p;

    for (pe = first_member(head); pe; pe = next_member(head, pe)) {
	while (p->pe_type != PE_END) {
	    if (pe == NULLPE || CHKTAG(mod, p, pe) == 0) {
		if (DEFAULT(p)) {
#ifdef PRINT_DEFAULTS
		    setpval(p, p + 1, mod);
#endif
		    goto next;
		} else {
		    dmp_ptpe("p_pr_setof:missing mandatory parameter", p, mod);
		    goto bad;
		}
	    }

	    if (p->pe_typename)
		VNAME(p->pe_typename);
	    switch (p->pe_type) {
	    case UCODE:
		if ((*mod->md_ducode) (pe, p, mod) != OK)
		    goto bad;
		break;

	    case ETAG:
		if (p_pr_type(1, pe->pe_cons, p, mod) == NOTOK)
		    goto bad;
		break;

		/*
		 * case SCTRL: parm = (char *) (parm); break;
		 */

	    case SEQ_START:
		if (p_pr_seq(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SEQOF_START:
		if (p_pr_seqof(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SET_START:
		if (p_pr_set(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SETOF_START:
		if (p_pr_setof(pe, p, mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case SOBJECT:
		if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
		break;

	    case OBJECT:
		if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK) {
		    goto bad;
		}
		break;

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

	    case SEXTOBJ:
		if (p[1].pe_type != EXTMOD) {
		    return (pepsylose (mod, p, pe,"p_pr_setof:missing EXTMOD"));
		}
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		    (char **) 0) == NOTOK)
		    goto bad;
		break;

	    case EXTOBJ:
		if (p[1].pe_type != EXTMOD) {
		    return (pepsylose (mod, p, pe,"p_pr_setof:missing EXTMOD"));
		}
		if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		    (char **) 0) == NOTOK)
		    goto bad;
		break;

	    default:
		if (p_pr_type(1, pe, p, mod) == NOTOK)
		    goto bad;
		break;
	    }

    next:
	    if (NEXT_PTPE(p) == NULLPTPE)
		goto bad;
	}
	/* parm = (char *)(parm); */
	p = start;
    }

    VPOP();
    return (OK);

bad:
    VPOP();
    return (NOTOK);

}

/*
 * parse a choice field. This means find which choice is taken
 */
static int
p_pr_choice(head, p, mod)
PE      head;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    if (p->pe_type != CHOICE_START) {
	return (pepsylose (mod, p, head, "p_pr_choice:missing CHOICE_START"));
    }
#if PRINT_TYPES
    if (p->pe_typename)
	VNAME(p->pe_typename);
#endif
#ifdef CHOICE_PUSH
    VPUSH();
#endif

    p++;
    if (p->pe_type == DFLT_B)
	p++;

    if (p->pe_type == SCTRL) {
	p++;
    }

    for (; p->pe_type != PE_END; NEXT_PTPE(p)) {
	if (ISDTYPE(p) && p_ismatch(p, mod, head->pe_class, head->pe_id)) {
	    if (p->pe_typename)
		VNAME(p->pe_typename);
	    if (p_pr_type(0, head, p, mod) == NOTOK)
		return (NOTOK);
#ifdef CHOICE_PUSH
	    VPOP();
#endif
	    return (OK);
	}
    }

    dmp_ptpe("p_pr_choice: no choice taken", p, mod);
#ifdef CHOICE_PUSH
	VPOP();
#endif
    return (NOTOK);
}

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

    level = 0;
    if (p->pe_type == PE_END) {
	(void) pepsylose (NULLMODTYP, p, NULLPE,
	    "next_ptpe: unexpected PE_END");
	return (NULLPTPE);
    }
    do {
again:
	switch (p->pe_type) {
	case SEQ_START:
	case SEQOF_START:
	case SET_START:
	case SETOF_START:
	case CHOICE_START:
	    level++;
	    break;

	case UCODE:
	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 SBITSTRING:
	case OCTETSTRING:
	case SOCTETSTRING:
	case OBJID:
	case SOBJID:
	case OPTL:
	case EXTMOD:
	case DFLT_B:
	    break;

	case IMP_OBJ:
	case ETAG:
	case EXTOBJ:
	case SEXTOBJ:
	case DFLT_F:
	    p++;
	    goto again;

	case PE_END:
	    level--;
	    break;

	default:
	    (void) pepsylose (NULLMODTYP, p, NULLPE,
		"next_ptpe: unknown type %d\n", p->pe_type);
	    return (NULLPTPE);
	}
	p++;
    } while (level > 0 || p->pe_type == DFLT_B);

    return (p);
}

#if 0
/*
 * check that pe is non null and that the tag and class match and
 * return zero if the don't
 */
p_chktag(mod, p, pe)
modtyp *mod;			/* Module it is from */
ptpe   *p;
PE      pe;
{
    int     cl, tag;

    if (pe == NULLPE)
	return (0);
#if 0
    if (p->pe_type == OBJECT && skip_next_tag)	/* first time we find
						 * skip */
	return (1);
    if (skip_next_tag) {	/* 2nd time reset skip */
	skip_next_tag = 0;
	return (1);
    }
#endif
    if (!p_findcltag(p, mod, &cl, &tag))
	return (0);
    if (pe->pe_id != tag || pe->pe_class != cl)
	return (0);

    return (1);
}
#endif

/*
 * Parse a single type for explicit tag If a basic type parse it, if
 * a compound type call the appropriate parsing routine
 */
static int
p_pr_etype(pe, p, mod)
PE      pe;
ptpe   *p;
modtyp *mod;			/* Module it is from */
{
    int     i;
    OID     oid;

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

    if (PRINT_TAG(p))
	VTAG (CLASS (p), TAG (p));
    p++;

    switch (p->pe_type) {
    case PE_END:
    case PE_START:
	goto bad;

    case UCODE:
	if ((*mod->md_ducode) (pe, p, mod) != OK)
	    goto bad;
	break;

    case ETAG:
	switch (p->pe_ucode) {

	default:
	    if (p_pr_etype(pe->pe_cons, p, mod) == NOTOK)
		goto bad;
	}
	break;

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

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

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

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

    case IMP_OBJ:
	p++;
	if (p->pe_type == EXTOBJ) {
	    if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
		   (char **) 0) == NOTOK)
		   goto bad;
	} else {
	    if (p_pr_obj(0, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK)
		goto bad;
	}
	break;

    case SOBJECT:
	if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK)
	    goto bad;
	break;

    case OBJECT:
	if (p_pr_obj(1, pe, mod->md_ptab[p->pe_tag], mod) == NOTOK)
	    goto bad;
	break;

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

    case SEXTOBJ:
	if (p[1].pe_type != EXTMOD) {
	    return (pepsylose (mod, p, pe, "p_pr_etype: missing EXTMOD"));
	}
	if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
	       (char **) 0) == NOTOK)
	       goto bad;
	break;

    case EXTOBJ:
	if (p[1].pe_type != EXTMOD) {
	    return (pepsylose (mod, p, pe, "p_pr_etype: missing EXTMOD"));
	}
	if (prnt_f(p->pe_tag, EXT2MOD(mod, (p + 1)), pe, 0, NULLIP,
	       (char **) 0) == NOTOK)
	       goto bad;
	break;

    case INTEGER:
	if (pe != NULLPE) {
	    if ((i = prim2num(pe)) == NOTOK && pe->pe_errno != PE_ERR_NONE)
		goto bad;
	    VPRINT(("%d", i));
	}
	break;

#ifdef	PEPSY_REALS
    case REALTYPE:
	if (pe != NULLPE) {
	    double r;

	    if ((r = prim2real(pe)) == NOTOK
		&& pe->pe_errno != PE_ERR_NONE)
		goto bad;
	    VPRINT(("%g", r));
	}
	break;
#endif


    case BOOLEAN:
	if (pe != NULLPE) {
	    if ((i= prim2flag(pe)) == NOTOK)
		goto bad;
	    VPRINT((i ? "TRUE" : "FALSE"));
	}
	break;

    case T_NULL:
	VPRINT(("NULL"));
	break;

    case ANY:
	if (pe != NULLPE) {
	    if (pe->pe_errno != PE_ERR_NONE) {
		goto bad;
	    } else
		VUNKNOWN(pe);
	}
	break;

    case SANY:
	if (pe != NULLPE) {
	    if (pe->pe_errno != PE_ERR_NONE) {
		goto bad;
	    } else
		VUNKNOWN(pe);
	}
	break;

    case SOCTETSTRING:
	if (pe != NULLPE) {
	    VSTRING(pe);
	}
	break;

    case OCTETSTRING:
	if (pe != NULLPE) {
	    VSTRING(pe);
	}
	break;

    case SBITSTRING:
	if (pe != NULLPE) {
	    PE	bstr;

	    if ((bstr = prim2bit(pe)) == NULLPE)
		goto bad;
	    /* one day get the named bits here */
	    VPRINT(("%s", bit2str(bstr, "\020")));
	}
	break;

    case BITSTRING:
	if (pe != NULLPE) {
	    PE	bstr;

	    if ((bstr = prim2bit(pe)) == NULLPE)
		goto bad;
	    /* one day get the named bits here */
	    VPRINT(("%s", bit2str(bstr, "\020")));
	}
	break;

    case SOBJID:
	if (((OID) oid = prim2oid(pe)) == NULLOID) {
	    goto bad;
	} else {
	    VPRINT(("%s", oid2ode(oid)));
	}
	break;

    case OBJID:
	if (((OID) oid = prim2oid(pe)) == NULLOID) {
	    goto bad;
	} else {
	    VPRINT(("%s", oid2ode(oid)));
	}
	break;

    default:
	return (pepsylose (mod, p, pe, "p_pr_etype: %d not implemented\n",
	    p->pe_type));
    }

    return (OK);

bad:
    return (NOTOK);
}

#if 0
/*
 * determine what the class and tag must be of the given object
 */
p_findcltag(p, mod, pcl, ptag)
ptpe   *p;
modtyp *mod;			/* Module it is from */
int    *pcl, *ptag;
{
    if (!ISDTYPE(p))
	return (0);
    if (p->pe_type != OBJECT) {
	*pcl = CLASS(p);
	*ptag = TAG(p);
	return (1);
    }
    p = mod->md_ptab[p->pe_tag] + 1;
    while (p->pe_type != PE_END) {
	if (ISDTYPE(p))
	    return (p_findcltag(p, mod, pcl, ptag));
    }
    dmp_ptpe("p_findcltag:warning:object with no data in it", p, mod);
    return (0);
}
#endif

/*
 * 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
 */
p_ismatch(p, mod, cl, tag)
ptpe   *p;
modtyp *mod;			/* Module it is from */
unsigned int cl, tag;
{
    if (!ISDTYPE(p))
	return (0);
    switch (p->pe_type) {
    case SOBJECT:
    case OBJECT:
	/* Needs to be changed for optional and default */
	return (p_ismatch(p = mod->md_ptab[p->pe_tag] + 1, mod, cl, tag));

    case SEXTOBJ:
    case EXTOBJ:
	if (p[1].pe_type != EXTMOD) {
	    (void) pepsylose (mod, p, NULLPE, "p_ismatch: missing EXTMOD");
	    return (0); /* fixup ismatch return -1 */
	}
	return (p_ismatch(EXT2MOD(mod, (p + 1))->md_ptab[p->pe_tag] + 1,
			  EXT2MOD(mod, (p + 1)), cl, tag));

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


    case SANY:
	return (1);

    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));
    }
    /* NOTREACHED */
    /* return (0); */
}

/*
 * determine if the given field is present in the data This is simple
 * if the field is a simple type with an obvious tag but in the case
 * of an object or a CHOICE type the tag is not obvious. If the
 * object is a CHOICE there are more than one possible tag that could
 * match and in this case we must try to match each one of them.
 */
PE
p_setpresent(head, p, mod)
PE      head;
ptpe   *p;
modtyp *mod;
{
    PE      pe;

    if (!ISDTYPE(p))
	return (NULLPE);
    switch (p->pe_type) {
    case OBJECT:
    case SOBJECT:
	{
	    /* Needs to be changed for optional and default */
	    return (p_setpresent(head, p = mod->md_ptab[p->pe_tag] + 1, mod));
	}

    case CHOICE_START:
	for (p++; p->pe_type != PE_END; p = NEXT_PTPE(p)) {
	    if (!ISDTYPE(p))
		continue;
	    if ((pe = (PE) p_setpresent(head, p, mod)))
		return (pe);
	}
	return (NULLPE);

    default:
	return (set_find(head, CLASS(p), TAG(p)));
    }
}

#ifdef PRINT_DEFAULTS
/*
 * set the default value to that value in the structure
 */
setpval(typ, dflt, mod)
ptpe   *typ, *dflt;
modtyp *mod;
{
    int     len, i, intval;
    char   *ptr, *optr;
    PE      pe_ptr;

    switch (typ->pe_type) {

    case INTEGER:
	intval = IVAL(mod, dflt);
	(*vfnx) (vfp, "%d (DEFAULT INTEGER)\n", intval);
	break;


#ifdef	PEPSY_REALS
    case REALTYPE:
	(*vfnx) (vfp, "%f (DEFAULT Real)\n", RVAL(mod, dflt));
	break;
#endif

    case BOOLEAN:
	intval = IVAL(mod, dflt);
	/*
	 * (*vfnx) (vfp, "%s  %d (DEFAULT BOOLEAN)\n",
	 * (typ->pe_typename) ? typ->pe_typename : "", charval);
	 */
	(*vfnx) (vfp, "%d (DEFAULT BOOLEAN)\n", intval);
	break;

    case T_NULL:
	/* Only one value */
	break;

    case SBITSTRING:
	(PE) pe_ptr = strb2bitstr(PVAL(mod, dflt), IVAL(mod, dflt), 0, 0);
	break;

    case BITSTRING:
	(PE) pe_ptr =
	   strb2bitstr(PVAL(mod, dflt), IVAL(mod, dflt), 0, 0);
	(*vfnx) (vfp, " '");
	optr = ptr = bitstr2strb((PE) pe_ptr, &len);
	for (i = 0; i < len; i += 8)
	    (*vfnx) (vfp, "%.2x", *ptr++);
	(*vfnx) (vfp, "'H (DEFAULT BITSTRING)\n");
	pe_free (pe_ptr);
	free (optr);
	break;

    case SOCTETSTRING:
    case OCTETSTRING:
        ptr = PVAL(mod, dflt);	/* array of octets */
        i = IVAL(mod, dflt);		/* length of array */
	if (printable(ptr, i)) {
	    (*vfnx) (vfp, "\"");
	    for (; *ptr && i-- > 0; ptr++)
                (void) fputc(*ptr, vfp);
	    (*vfnx) (vfp, "\"\n");
	} else {
	    (*vfnx) (vfp, "'");
	    if (ptr) {
		for (; i-- > 0; ptr++)
		    (*vfnx) (vfp, "%.2x", *ptr & 0xff);
	    }
	    (*vfnx) (vfp, "'H \n");
	}
	break;

    case OBJECT:
	setpval(mod->md_ptab[typ->pe_tag] + 1, dflt, mod);
	break;

    case SOBJECT:
	setpval(mod->md_ptab[typ->pe_tag] + 1, dflt, mod);
	break;

    case IMP_OBJ:
	typ++;

    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
	 */
	(char *) ptr = NULL;
	break;

    default:
	return (pepsylose (mod, p, pe, "setpval: type %d not implemented\n",
	    typ->pe_type));
	break;
    }

}
#endif
/*
 * return non zero if we can print out the string
 */
printable(strptr, len)
char   *strptr;
int	len;
{
    if (strptr == NULL || *strptr == '\0') {
	return (0);
    }

     while (len-- > 0) {
	if (!isprint(*strptr++))
	    return (0);
    }

    return (1);
}

/*
 * (Dump) Print out a printable entry in a human recognisable form
 */
dmp_ptpe(s, p, mod)
char   *s;
modtyp *mod;			/* Module it is from */
ptpe   *p;
{
    int     i, j;
    ptpe  **par, **prev;
    char   *name;

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

    par = NULL;
    if (mod->md_ptab != NULL && mod->md_ptab[0] < p) {
	par = mod->md_ptab;
	name = "Printing:";
    }
    if (par == NULL) {
	(void) fprintf(vfp, "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_ptpe:par == prev == 0x%x internal error\n", (int) par);
	return;
    }
    par--;
    j = p - *par;

    (void) fprintf(vfp, "%s type %d + %d ", name, par - prev, j);
    p_pr_entry(p);
}
