DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T i

⟦bf370c8ae⟧ TextFile

    Length: 22668 (0x588c)
    Types: TextFile
    Names: »isoaddrs.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z« 
        └─⟦de7628f85⟧ 
            └─⟦this⟧ »isode-6.0/compat/isoaddrs.c« 

TextFile

/* isoaddrs.c - simple parsing of ISODE addresses */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/compat/RCS/isoaddrs.c,v 7.1 90/01/11 18:35:10 mrose Exp $";
#endif

/* 
 * $Header: /f/osi/compat/RCS/isoaddrs.c,v 7.1 90/01/11 18:35:10 mrose Exp $
 *
 *
 * $Log:	isoaddrs.c,v $
 * Revision 7.1  90/01/11  18:35:10  mrose
 * real-sync
 * 
 * Revision 7.0  89/11/23  21:23:05  mrose
 * Release 6.0
 * 
 */

/*
 *				  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 <ctype.h>
#include <stdio.h>
#include "general.h"
#include "manifest.h"
#include "isoaddrs.h"
#include "internet.h"
#include "tailor.h"

/* \f

   DATA */

static char *isomacros = "isomacros";

#define	MBUCKETS	128
#define	MHASH(nm) \
    (((nm)[1]) ? (((chrcnv[((nm)[0])] - chrcnv[((nm)[1])]) & 0x1f) \
		  	+ ((chrcnv[(nm)[2]]) & 0x5f)) \
	       : (chrcnv[(nm)[0]]) & 0x7f)

struct macro {
    char   *m_name;
    char   *m_value;

    struct macro *m_chain;
};

static int inited = 0;
static struct macro *Mbuckets[MBUCKETS];

/* \f

   MACROS */

static struct macro *name2macro (name)
char   *name;
{
    register struct macro *m;

    read_macros ();

    for (m = Mbuckets[MHASH (name)];
	     m && lexequ (m -> m_name, name);
	     m = m -> m_chain)
	continue;

    if (m)
	LLOG (addr_log, LLOG_DEBUG,
	      ("MACRO \"%s\" VALUE \"%s\"", m -> m_name, m -> m_value));
    else
	LLOG (addr_log, LLOG_DEBUG,
	      ("lookup of MACRO \"%s\" failed", name));

    return m;
}

/* \f

 */

static struct macro *value2macro (value)
char   *value;
{
    register int   i,
		   j,
		   k;
    register struct macro *m,
			  *p,
			 **np,
			 **pp;

    read_macros ();

    p = NULL, i = 0;
    k = strlen (value);
    for (pp = (np = Mbuckets) + MBUCKETS; np < pp; np++)
	for (m = *np; m; m = m -> m_chain)
	    if ((j = strlen (m -> m_value)) <= k
		    &&  j > i
		    && strncmp (value, m -> m_value, j) == 0)
		p = m, i = j;

    if (p)
	LLOG (addr_log, LLOG_DEBUG,
	      ("MACRO \"%s\" VALUE \"%s\" differential %d",
	       p -> m_name, p -> m_value, k - strlen (p -> m_value)));
    else
	LLOG (addr_log, LLOG_DEBUG,
	      ("lookup of VALUE \"%s\" failed", value));

    return p;
}

/* \f

 */

static int  read_macros ()
{
    register char *hp;
    char    buffer[BUFSIZ];

    if (inited)
	return;
    inited = 1;

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

    read_file (isodefile (isomacros, 0));

    if ((hp = getenv ("HOME")) == NULL)
	hp = ".";
    (void) sprintf (buffer, "%s/.isode_macros", hp);
    read_file (buffer);
}

/* \f

 */

static int  read_file (file)
char   *file;
{
    register char *cp;
    char    buffer[BUFSIZ + 1],
	   *vec[NVEC + NSLACK + 1];
    register FILE *fp;

    if ((fp = fopen (file, "r")) == NULL)
	return;

    while (fgets (buffer, sizeof buffer, fp)) {
	if (*buffer == '#')
	    continue;
	if (cp = index (buffer, '\n'))
	    *cp  = NULL;
	if (str2vec (buffer, vec) < 2)
	    continue;

	if (add_macro (vec[0], vec[1]) == NOTOK)
	    break;
    }

    (void) fclose (fp);
}

/* \f

 */

static int  add_macro (name, value)
char   *name,
       *value;
{
    int	    i;
    register char  *cp;
    char    buffer[BUFSIZ];
    register struct macro *m,
			  *p;

    if (cp = index (value, '=')) {
	*cp++ = NULL;
	if ((p = name2macro (value)) == NULL) {
	    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
		  ("macro \"%s\" references non-existant macro \"%s\"",
		   name, value));
	    return OK;
	}

	(void) sprintf (value = buffer, "%s%s", p -> m_value, cp);
    }

    if ((m = (struct macro *) calloc (1, sizeof *m)) == NULL) {
	SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
	      ("calloc of macro structure failed"));
	return NOTOK;
    }
    if ((m -> m_name = malloc ((unsigned) (strlen (name) + 1))) == NULL
		|| (m -> m_value = malloc ((unsigned) (strlen (value) + 1)))
	    == NULL) {
	SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
	      ("malloc of alias structure failed"));
	if (m -> m_name)
	    free (m -> m_name);
	free ((char *) m);
	return NOTOK;
    }
    (void) strcpy (m -> m_name, name);
    (void) strcpy (m -> m_value, value);

    m -> m_chain = Mbuckets[i = MHASH (m -> m_name)];
    Mbuckets[i] = m;

    return OK;
}

/* \f

 */

char   *macro2str (name)
char   *name;
{
    register struct macro *m = name2macro (name);

    return (m ? m -> m_value : NULLCP);
}

/* \f

   STR2PADDR */

#define	PS_INIT	0	/* <selector> or <network-address> */
#define	PS_SEL1	1	/*   .. got one selector already */
#define	PS_SEL2	2	/*   .. got two selectors already */
#define	PS_SEL3	3	/* <network-address> */


static struct pair {
    char   *p_name;
    char   *p_value;
}	afi_entries[] = {
    "X121",  "36",
    "DCC",   "38",
    "TELEX", "54",
    "PSTN",  "56",
    "ISDN",  "58",
    "ICD",   "46",
    "LOCAL", "48",

    NULL
};


static char sel1[TSSIZE];
static char sel2[TSSIZE];
static char sel3[TSSIZE];
static char *sels[3] = {
    sel1, sel2, sel3
};


#define	IMPLODE(intres,octres,octval,intval) \
{ \
    register int   z = (intval); \
    register char *y = (octval); \
    register char *zp = y + z; \
 \
    while (zp-- > y) \
	if (!isxdigit (*zp)) { \
	    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP, \
		  ("invalid hexstring: \"%*.*s\"", \
		   z, z, y)); \
	} \
    (intres) = implode ((u_char *) (octres), y, z); \
}

/* \f

 */

#ifdef	notdef
/* An interim approach to use of Network Addresses... */

#define	INTERIM_IDP		"5400728722"
#endif


struct PSAPaddr *str2paddr (str)
char   *str;
{
    register int    state,
		   *lp;
    int	    j,
	    lens[3];
    register char  *cp,
		   *dp,
		   *ep,
		   *np,
		  **sp;
    char    buf1[BUFSIZ],
	    buf2[BUFSIZ],
	    nsap[NASIZE * 2 + 1];
    register struct macro *m;
    register struct pair *pp;
    static int i = 0;
    static struct PSAPaddr pas[2];
    register struct PSAPaddr *pa = &pas[i++];
    register struct SSAPaddr *sa = &pa -> pa_addr;
    register struct TSAPaddr *ta = &sa -> sa_addr;
    register struct NSAPaddr *na = ta -> ta_addrs;

    i = i % 2;

    bzero ((char *) pa, sizeof *pa);
    (void) strcpy (buf1, str);

    state = PS_INIT;
    sp = sels, lp = lens;

    for (cp = buf1; *cp; )
	switch (state) {
	    case PS_INIT:	
	    case PS_SEL1:
	    case PS_SEL2:
		switch (*cp) {
		    case '"':		/* '"' <otherstring> '"' */
		        if ((cp = index (dp = cp + 1, '"')) == NULL) {
			    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
				  ("missing double-quote in selector: %s",
				   str));
			    return NULLPA;
			}
			*cp++ = NULL;
			(void) strcpy (*sp, dp);
			*lp = strlen (dp);
			break;

		    case '#':		/* '#' <digitstring> */
			j = 0;
			for (cp++; isdigit (*cp); cp++)
			    j = j * 10 + *cp - '0';
			if (j > 0xffff) {
			    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
				  ("invalid #-style selector: %s", str));
			    return NULLPA;
			}
			(*sp)[0] = (j >> 8) & 0xff;
			(*sp)[1] = j & 0xff;
			*lp = 2;
			break;

		    case '\'':		/* "'" <hexstring> "'H" */
			if ((cp = index (dp = cp + 1, '\'')) == NULL) {
missing_quoteH: ;
			    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
				  ("missing 'H in selector: %s",str));
			    return NULLPA;
			}
			*cp++ = NULL;
			if (*cp++ != 'H')
			    goto missing_quoteH;
			IMPLODE (*lp, *sp, dp, strlen (dp));
			break;

		    case '/':		/* empty selector */
			*lp = 0;
			break;

		    default:
			goto stuff_selectors;
		}
		sp++, lp++;
		if (*cp++ != '/') {
		    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
			  ("missing selector seperator at position %d: %s",
			   cp - buf1, str));
		    return NULLPA;
		}
		state++;
		break;

stuff_selectors: ;
		state = PS_SEL3;
		/* and fall */

	    case PS_SEL3:
		if ((cp = index (ep = cp, '|')) == NULL)
		    cp = ep + strlen (ep);
		else
		    *cp++ = NULL;

		if (dp = index (ep, '=')) {
		    *dp++ = NULL;
		    if ((m = name2macro (ep)) == NULL) {
			SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
			      ("non-existant macro \"%s\"", ep));
			return NULLPA;
		    }
		    (void) sprintf (ep = buf2, "%s%s", m -> m_value, dp);
		}

		{
		    register int    k,
				    l,
				    n;
		    register struct ts_interim *ts,
					       *tp;

		    tp = NULL, n = 0;
		    k = strlen (ep);
		    for (ts = ts_interim; ts -> ts_name; ts++)
			if (ts -> ts_value
				&& (l = strlen (ts -> ts_value)) <= k
			        && l > n
			        && strncmp (ep, ts -> ts_value, l) == 0)
			    tp = ts, n = l;
		    if (tp)
			na -> na_subnet = tp -> ts_subnet;
		    else
							/* XXX: what a hack! */
			if (strncmp (ep, "X121+", sizeof "X121+" - 1) == 0)
			    na -> na_subnet = SUBNET_INT_X25;
			else {
			    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
				  ("unable to determine community for %s",ep));
			    return NULLPA;
			}
		}

		if ((ep = index (dp = ep, '+')) == NULL) {
missing_seperator: ;
		    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
			  ("missing network-address seperator: %s", str));
		    return NULLPA;
		}
		*ep++ = NULL;
		if (ta -> ta_naddr >= NTADDR) {
#ifdef	h_addr
too_many: ;
#endif
		    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
			  ("too many network addresses starting at position %d: %s",
			   dp - buf1 + 1, str));
		    return pa;
		}

		na -> na_type = NA_NSAP;
		if (lexequ (dp, "NS") == 0) {
		    IMPLODE (na -> na_addrlen, na -> na_address, ep,
			     strlen (ep));
		}
		else {
		    for (pp = afi_entries; pp -> p_name; pp++)
			if (lexequ (pp -> p_name, dp) == 0)
			    break;
		    if (!pp -> p_name) {
			SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
			      ("unknown AFI \"%s\": %s", dp, str));
			return NULLPA;
		    }
		    if ((ep = index (dp = ep, '+')) == NULL)
			ep = dp + strlen (dp);
		    else
			*ep++ = NULL;
		    if (lexequ (pp -> p_name, "X121") == 0) {
			/* X121 form -- should be more general */
		        (void) strcpy (nsap, dp);
			if ((na -> na_dtelen = strlen (nsap)) > NSAP_DTELEN) {
			    dp = nsap;
			    goto invalid_dte;
			}
			(void) strcpy (na -> na_dte, nsap);
#ifdef	BRIDGE_X25
			na -> na_type = bridgediscrim (na) ? NA_BRG : NA_X25;
#else
			na -> na_type = NA_X25;
#endif
			na -> na_subnet = SUBNET_INT_X25;
			if (*ep != NULL) {
			    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
				  ("bad X121 form \"%s\"", ep));
			    return NULLPA;
			}
			goto next;
		    }
		    else
		        (void) sprintf (nsap, "%s%s", pp -> p_value, dp);
		    switch (*ep) {
			case 'd':
			    (void) strcpy (nsap + strlen (nsap), ep + 1);
			    /* and fall */
			case 'x':
			case 'l':
			case NULL:
			    np = nsap, dp = na -> na_address;
			    while (*np) {
				*dp = (*np++ - '0') << 4;
				if (*np)
				    *dp++ |= (*np++ - '0') & 0x0f;
				else
				    *dp++ |= 0x0f;
			    }
			    na -> na_addrlen = dp - na -> na_address;
			    if (*ep == 'x') {
				IMPLODE (j, dp, ep + 1, strlen (ep + 1));
				na -> na_addrlen += j;
			    }
			    else
				if (*ep == 'l') {
				    (void) strcpy (dp, ep + 1);
				    na -> na_addrlen += strlen (ep + 1);
				}
			    break;

		        default:
			    if (strncmp ("RFC-1006+", ep,
					 sizeof "RFC-1006+" - 1) == 0) {
#ifdef	h_addr
				register char **ap;
#endif
				register struct hostent *hp;

				na -> na_type = NA_TCP;
#ifdef	notdef
				if (strcmp (nsap, INTERIM_IDP)) {
wrong_idp: ;
				    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
					  ("wrong IDP \"%s\" for DSP \"%s\"",
					   nsap, ep));
				    return NULLPA;
				}
#endif
				ep += sizeof "RFC-1006+" - 1;
				if ((ep = index (dp = ep, '+')) == NULL)
				    goto missing_seperator;
				*ep++ = NULL;
#ifdef	notdef
				na -> na_subnet = atoi (dp);
#endif
				if ((ep = index (dp = ep, '+')) == NULL)
				    ep = dp + strlen (dp);
				else
				    *ep++ = NULL;

				if ((hp = gethostbystring (dp)) == NULL) {
				    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
					  ("%s: unknown host", dp));
				    return NULLPA;
				}
				(void) strcpy (na -> na_domain,
					       inet_ntoa (*(struct in_addr *)
							        hp -> h_addr));
				if (*ep) {
				    if ((ep = index (dp = ep, '+')) == NULL)
					ep = dp + strlen (dp);
				    else
					*ep++ = NULL;
				    na -> na_port = htons ((u_short) atoi(dp));

				    if (*ep)
					na -> na_tset = atoi (ep);
				}
#ifdef	h_addr
				for (ap = hp -> h_addr_list + 1; *ap; ap++) {
				    ta -> ta_naddr++, na++;

				    if (ta -> ta_naddr >= NTADDR)
					goto too_many;
				    bcopy ((char *) (na - 1), (char *) na,
					   sizeof *na);
				    (void) strcpy (na -> na_domain,
					  inet_ntoa (*(struct in_addr *) *ap));
				}
#endif
				break;
			    }
			    if (strncmp ("X.25(80)+", ep,
					 sizeof "X.25(80)+" - 1) == 0) {
				na -> na_type = NA_X25;
#ifdef	notdef
				if (strcmp (nsap, INTERIM_IDP))
				    goto wrong_idp;
#endif
				ep += sizeof "X.25(80)+" - 1;
				if ((ep = index (dp = ep, '+')) == NULL)
				    goto missing_seperator;
				*ep++ = NULL;
#ifdef	notdef
				na -> na_subnet = atoi (dp);
#endif
				if ((ep = index (dp = ep, '+')) == NULL)
				    ep = dp + strlen (dp);
				else
				    *ep++ = NULL;
				for (np = dp; *np; np++)
				    if (!isdigit (*np)) {
invalid_dte: ;
					SLOG (addr_log, LLOG_EXCEPTIONS,
					      NULLCP,
					      ("invalid DTE \"%s\": %s",
					       dp, str));
					return NULLPA;
				    }
				if (np - dp > NSAP_DTELEN + 1)
				    goto invalid_dte;
				(void) strcpy (na -> na_dte, dp);
				na -> na_dtelen = strlen (na -> na_dte);
				if (*ep) {
				    char   *cudf,
					   *clen;

				    if ((ep = index (dp = ep, '+')) == NULL)
					goto missing_seperator;
				    *ep++ = NULL;
				    
				    if (lexequ (dp, "CUDF") == 0) {
					cudf = na -> na_cudf;
					clen = &na -> na_cudflen;
					j = sizeof na -> na_cudf;
				    }
				    else
					if (lexequ (dp, "PID") == 0) {
					    cudf = na -> na_pid;
					    clen = &na -> na_pidlen;
					    j = sizeof na -> na_pid;
					}
					else {
invalid_field: ;
					    SLOG (addr_log, LLOG_EXCEPTIONS,
						  NULLCP,
						  ("invalid field \"%s\": %s",
						   dp, str));
					    return NULLPA;
					}
				    if (j * 2 < strlen (ep))
					goto invalid_field;
				    IMPLODE (j, cudf, ep, strlen (ep));
				    *clen = j & 0xff;
				}
#ifdef	BRIDGE_X25
				na -> na_type = bridgediscrim (na) ? NA_BRG
								   : NA_X25;
#endif
				break;
			    }
#ifdef	notdef
			    if (lexequ ("ECMA-117-Binary", ep) == 0) {
				/* some day support this... */
				break;
			    }
			    if (lexequ ("ECMA-117-Decimal", ep) == 0) {
				/* some day support this... */
				break;
			    }
#endif
			    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
				  ("unknown DSP \"%s\": %s", ep, str));
			    return NULLPA;
		    }
		}
next: ;
		ta -> ta_naddr++, na++;
		break;
	}
    
    switch (sp - sels) {
        case 3:	/* PSEL+SSEL+TSEL */
	    bcopy (*--sp, ta -> ta_selector,
		   ta -> ta_selectlen = *--lp);
	    bcopy (*--sp, sa -> sa_selector,
		   sa -> sa_selectlen = *--lp);
	    bcopy (*--sp, pa -> pa_selector,
		   pa -> pa_selectlen = *--lp);
	    break;

	case 2:	/* SSEL+TSEL */
	    bcopy (*--sp, ta -> ta_selector,
		   ta -> ta_selectlen = *--lp);
	    bcopy (*--sp, sa -> sa_selector,
		   sa -> sa_selectlen = *--lp);
	    break;

	case 1:	/* TSEL */
	    bcopy (*--sp, ta -> ta_selector,
		   ta -> ta_selectlen = *--lp);
	    break;

	default:
	    break;
    }
    
    return pa;
}

/* \f

 */

int	macro2comm (name, ts)
char   *name;
register struct ts_interim *ts;
{
    int	    j;
    register char  *ap,
		   *cp,
		   *dp,
		   *ep,
		   *fp,
		   *np;
    char    addr[NASIZE * 2 + 1],
	    buffer[BUFSIZ];
    register struct pair *pp;

    ts -> ts_length = 0, ts -> ts_syntax = NA_NSAP;
    if ((cp = macro2str (name)) == NULLCP)
	return NOTOK;
    ts -> ts_value = cp;
    (void) strcpy (buffer, cp);
    ap = addr;

    if ((ep = index (dp = buffer, '+')) == NULL)
	ep = dp + strlen (dp);
    else
	*ep++ = NULL;

    if (lexequ (dp, "NS") == 0) {
	IMPLODE (ts -> ts_length, ts -> ts_prefix, ep, strlen (ep));

	return OK;
    }
    
    for (pp = afi_entries; pp -> p_name; pp++)
	if (lexequ (pp -> p_name, dp) == 0)
	    break;
    if (!pp -> p_name) {
	SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
	      ("unknown AFI \"%s\": %s", dp, cp));
	return NOTOK;
    }

    (void) strcpy (ap, pp -> p_value);
    ap += strlen (ap);

    if (!ep)
	goto out;

    if ((ep = index (dp = ep, '+')) == NULL)
	ep = dp + strlen (dp);
    else
	*ep++ = NULL;

    for (fp = dp; *fp; fp++)
	if (!isdigit (*fp))
	    break;
    if (*fp) {
	SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
	      ("invalid AFI suffix \"%s\": %s", dp, cp));
	return NOTOK;
    }
    (void) strcpy (ap, dp);
    ap += strlen (ap);

    if (lexequ (pp -> p_name, "X121") == 0) {
	if (*ep) {
	    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
		  ("invalid DTE \"%s\": %s", dp, cp));
	    return NOTOK;
	}

	ts -> ts_syntax = NA_X25;
	ts -> ts_subnet = SUBNET_INT_X25;
	goto out;
    }

    switch (*ep) {
	case 'd':
	    (void) strcpy (ap, ep + 1);
	    /* and fall */
	case 'x':
	case 'l':
	case NULL:
	    break;

	default:
	    if ((ep = index (dp = ep, '+')) == NULL)
		ep = dp + strlen (dp);
	    else
		*ep++ = NULL;
	    if (lexequ (dp, "RFC-1006") == 0)
		ts -> ts_syntax = NA_TCP;
	    else
		if (lexequ (dp, "X.25(80)") == 0)
		    ts -> ts_syntax = NA_X25;
		else {
		    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
			  ("unknown DSP \"%s\": %s", dp, cp));
		    return NOTOK;
		}
	    if ((ep = index (dp = ep, '+')) == NULL)
		ep = dp + strlen (dp);
	    else
		*ep++ = NULL;

	    (void) strcpy (ap, dp);
	    ap += strlen (ap);

	    if (*ep) {
		SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
		      ("invalid MACRO for community \"%s\": %s", name, cp));
		return NOTOK;
	    }
	    break;
    }

out: ;
    ap = addr, np = ts -> ts_prefix;
    while (*ap) {
	*np = (*ap++ - '0') << 4;
	if (*ap)
	    *np++ |= (*ap++ - '0') & 0x0f;
	else
	    *np++ |= 0x0f;
    }
    switch (*ep) {
	case 'x':
	    IMPLODE (j, np, ep + 1, strlen (ep + 1));
	    np += j;
	    break;

	case 'l':
	    (void) strcpy (np, ep + 1);
	    np += strlen (ep + 1);
	    break;

       default:
	    break;
    }
    ts -> ts_length = np - ts -> ts_prefix;

    return OK;
}

/* \f

   PADDR2STR */

static char   *SEL2STR (sel, len)
char   *sel;
int	len;
{
    register char  *cp,
		   *dp,
		   *ep;
    static char buffer[PSSIZE * 2 + 4];

    if (len <= 0)
	return "";

    cp = buffer;
    *cp++ = '"';
    for (ep = (dp = sel) + len; dp < ep; dp++) {
	switch (*dp) {
	    case '+':
	    case '-':
	    case '.':
	        break;

	    default:
		if (!isalnum (*dp)) {
		    cp = buffer;
		    *cp++ = '\'';
		    cp += explode (cp, (u_char *) sel, len);
		    (void) strcpy (cp, "'H");
		    return buffer;
		}		
		break;
	}

	*cp++ = *dp;
    }
    *cp++ = '"';
    *cp = NULL;

    return buffer;
}

/* \f

 */

char    *_paddr2str (pa, na, compact)
register struct PSAPaddr *pa;
register struct NSAPaddr *na;
int	compact;
{
    register int   n;
    int	    first;
    register char *bp,
		  *cp,
		  *dp;
    register struct macro *m;
    register struct SSAPaddr *sa;
    register struct TSAPaddr *ta;
    register struct NSAPaddr *ca;
    static int    i = 0;
    static char buf1[BUFSIZ],
		buf2[BUFSIZ];
    static char *bufs[] = { buf1, buf2 };

    bp = cp = bufs[i++];
    i = i % 2;

    if (pa == NULLPA) {
bad_pa: ;
	(void) strcpy (bp, "NULLPA");
	return bp;
    }
    sa = &pa -> pa_addr;
    ta = &sa -> sa_addr;

    if (na)
	n = 1;
    else
	if ((n = ta -> ta_naddr) > 0)
	    na = ta -> ta_addrs;

    if (pa -> pa_selectlen > 0) {
	(void) sprintf (cp, "%s/",
			SEL2STR (pa -> pa_selector, pa -> pa_selectlen));
	cp += strlen (cp);
    }
    if (sa -> sa_selectlen > 0 || bp != cp) {
	(void) sprintf (cp, "%s/",
			SEL2STR (sa -> sa_selector, sa -> sa_selectlen));
	cp += strlen (cp);
    }
    if (ta -> ta_selectlen > 0 || bp != cp) {
	(void) sprintf (cp, "%s/",
			SEL2STR (ta -> ta_selector, ta -> ta_selectlen));
	cp += strlen (cp);
    }

    for (first = 1; n > 0; na++, n--) {
	register struct ts_interim *ts;

	if (first)
	    first = 0;
	else
	    *cp++ = '|';

	if (compact > 0) {
	    if ((ca = na2norm (na)) == NULLNA)
		goto bad_pa;

	    (void) strcpy (cp, "NS+");
	    cp += strlen (cp);

	    cp += explode (cp, (u_char *) ca -> na_address, ca -> na_addrlen);
	    *cp = NULL;
	    continue;
	}
	
	for (ts = ts_interim; ts -> ts_name; ts++)
	    if (ts -> ts_subnet == na -> na_subnet)
		break;
	if (!ts -> ts_name) {
	    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
		  ("unable to find community #%d", na -> na_subnet));
	    goto bad_pa;
	}
	if (!ts -> ts_value) {
	    SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
		  ("community \"%s\" (subnet #%d) has no corresponding MACRO",
		   ts -> ts_name, na -> na_subnet));
	    goto bad_pa;
	}
	(void) strcpy (dp = cp, ts -> ts_value);
	cp += strlen (cp) - 1;
	if (*cp != '+')
	    *++cp = '+', *++cp = NULL;
	else
	    cp++;

	switch (na -> na_type) {
	    case NA_NSAP:
		cp += explode (cp, (u_char *) na -> na_address,
			       na -> na_addrlen);
		*cp = NULL;
		break;

	    case NA_TCP:
		(void) strcpy (cp, na -> na_domain);
		cp += strlen (cp);
		if (na -> na_port) {
		    (void) sprintf (cp, "+%d", (int) ntohs (na -> na_port));
		    cp += strlen (cp);

		    if (na -> na_tset) {
			(void) sprintf (cp, "+%d", (int) na -> na_tset);
			cp += strlen (cp);
		    }
		}
		break;

	    case NA_X25:
	    case NA_BRG:
		if (na -> na_subnet == SUBNET_INT_X25
		        && na -> na_cudflen == 0
		        && na -> na_pidlen == 0
		        && na -> na_dte[0] != '0') {
		    (void) sprintf (cp = dp, "X121+%s", na -> na_dte);
		    cp += strlen (cp);
		}
		else {
		    (void) strcpy (cp, na -> na_dte);
		    cp += strlen (cp);
		    if (na -> na_pidlen > 0) {
		        (void) strcpy (cp, "+PID+");
		        cp += strlen (cp);
		        cp += explode (cp, (u_char *) na -> na_pid,
				       (int) na -> na_pidlen);
		    }
		    else
		        if (na -> na_cudflen > 0) {
			    (void) strcpy (cp, "+CUDF+");
			    cp += strlen (cp);
			    cp += explode (cp, (u_char *) na -> na_cudf,
					   (int) na -> na_cudflen);
			    cp += strlen (cp);
		        }
		}
		break;

	    default:
		SLOG (addr_log, LLOG_EXCEPTIONS, NULLCP,
		      ("unknown address type 0x%x", na -> na_type));
		goto bad_pa;
	}

	SLOG (addr_log, LLOG_DEBUG, NULLCP, ("dp = %s",dp));

	if (!compact && (m = value2macro (dp))) {
	    char    buffer[BUFSIZ];

	    (void) sprintf (buffer, "%s=%s", m -> m_name,
			    dp + strlen (m -> m_value));
	    (void) strcpy (dp, buffer);
	    cp = dp + strlen (dp);
	}
    }
    *cp = NULL;

    return bp;
}