:i	static char d_symaddr_sccs_id[] = "%W% %G%";
/*
* Here are routines to convert an arbitrary-length address to symbolic  (i.e.,
* printable) notation. There are basically two routines here: decaddr(x,n) and
* hexaddr(x,n).   They  differ  in  format:   The  decaddr  routine   produces
* "dotted-decimal"  notation,  i.e., each byte is treated as an 8-bit unsigned
* integer, and '.' is used as  a  separator.   The  hexaddr  routine  produces
* "hex-colon" notation, i.e., two hex digits and a colon for each byte, with a
* null replacing the final colon.
*
* The symaddr() routine choses one of the other two, depending on the value of
* the  symfmt variable.  The idea is that symaddr() can be used as a "generic"
* address formatter, and the caller can decide globally which notation  is  to
* be used.
*
* Special kludge: if n<0, its absolute value is used, but final zero bytes are
* trimmed away.
*/
:1#include "V.h"
#include "mem.h"
#include "sys_socket.h"

#define NB 16
static CP  symdotb[NB];
static int symdotn = 0;	/* The last-used buffer */
global int symfmt  = 'D';	/* 0/d/D mean dec; 1/h/H mean hex */

/* * * * * * * * * * * * * * * * * * * * * * * * * *
* Return the length of x minus any final nulls.
*/
int trimnull(x,n)
	BP x;
{
	if (n < 0) n = - n;	/* Use abs value */
	while (n > 0 && x[n-1] == 0) --n;	/* Trim away nulls */
	return n;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * *
*/
CP getsymdotb(n)
{	CP r;
	if (!(r = symdotb[n])) {
:7		V7 "Allocate symdotb[%d] ...",n D;
		r = symdotb[n] = (CP)GetChunk(NETADDRLEN+1,"symdotb");
:7		V7 "Allocate symdotb[%d]=%08lX",n,r D;
	}
	return r;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * *
*/
CP symaddr(x,n)
	BP  x;	/* Use unsigned to prevent sign extension */
	int n;	/* Length (bytes) of address */
{
	Switch(symfmt) {
	  default:
	  case 0: case 'd': case 'D': return decaddr(x,n);
	  case 1: case 'h': case 'H': return hexaddr(x,n);
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * *
* This routine generates dotted-decimal output.
*/
CP decaddr(x,n)
	BP  x;
	int n;
{	int i;
	CP  r;	/* Static buf for building the result */
	CP  p;	/* Current byte in the buf */
	CP  q;	/* End of buf */
:5	Fpush("decaddr");
	p = q = r = getsymdotb(symdotn);
	if (!x) return m_null;
	if (n < 0) n = trimnull(x,n);
	if (n > NETADDRLEN) {		/* Truncate excessively-long addresses */
:5		V3 "### Can't handle %d-byte address, truncated to %d bytes.",
:5			n,NETADDRLEN D;
		n = NETADDRLEN;
	}
	symdotn = (symdotn + 1) % NB;	/* Advance for next call */
	for (i=0; i<n; i++) {
		p = encodei(*x++,p,q);
		*p++ = '.';
	}
	*--p = '\0';
:5	Fpop;
	return r;
}
/*
* This routine generates hex-colon output.
*/
CP hexaddr(x,n)
	BP  x;
	int n;
{	int c, i;
	CP  r;	/* Static buf for building the result */
	CP  p;	/* Current byte in the buf */
	CP  q;	/* End of buf */
:5	Fpush("hexaddr");
	p = q = r = getsymdotb(symdotn);
	if (!x) return m_null;
	if (n < 0)
		n = trimnull(x,n);
	if (n > NETADDRLEN) {		/* Truncate excessively-long addresses */
:5		V2 "### Can't handle %d-byte address, truncated to %d bytes.",
:5			n,NETADDRLEN D;
		n = NETADDRLEN;
	}
	symdotn++; symdotn %= NB;	/* Advance for next call */
	for (i=0; i<n; i++) {
		c = *x++;
		*p++ = hex_dig[0x0F & (c >> 4)];
		*p++ = hex_dig[0x0F & c];
		*p++ = ':';
	}
	*--p = '\0';
:5	Fpop;
	return r;
}
/*
* Given a sockaddr, try to produce a printable string.  What we do for now  is
* to  produce  a.b.c.d.pp  for  Internet addresses, where a.b.c.d is the usual
* dotted-decimal notation and pp is the port number.  For others,  we  produce
* the hex value of the address.  Add cases if you can ...
*/
CP symsockaddr(ap)
	SKAD* ap;
{	CP    r=0;
	CP    p=0;
	int   i;
	SKin* ip;
:f	Fenter("symsockaddr");
	r = getsymdotb(symdotn);
	symdotn = (symdotn + 1) % NB;
:7	V7 "ap=%08lX symdotn=%d r=%08lX.",ap,symdotn,r D;
	if (!ap) {
		Sprintf(r,"0.0.0.0:0");
:f		Fexit;
		return r;
	}
:7	V7 "ap->sa_family=%d.",ap->sa_family D;
	Switch(ap->sa_family) {
	case 0:		/* Kludge for missing address family */
	case AF_INET:
		ip = (SKin*) ap;
:7		V7 "ip=%08lX symdotn=%d r=%08lX.",ip,symdotn,r D;
:7		V7 "IPdot gives %s",IPdot(&ip->sin_addr.s_addr) D;
:7		V7 "sin_port is %04X=%d.",ip->sin_port,ntohs(ip->sin_port) D;
:7		V7 "r=%08lX: %s [before Sprintf]",r,N(r) D;
		Sprintf(r,"%s:%u",IPdot(&ip->sin_addr.s_addr),(unsigned)ntohs(ip->sin_port));
:7		V7 "r=%08lX: %s [after Sprintf]",r,N(r) D;
		break;
	default:
		p = (CP)ap;
		for (i=0; i<sizeof(SKAD); i++) {
			r[3*i  ] = hex_dig[(p[i] >> 4) & 0x04];
			r[3*i+1] = hex_dig[(p[i]     ) & 0x04];
			r[3*i+2] = ':';
		}
		r[3*i-1] = 0;	/* Replace final colon with null terminator */
		break;
	}
:7	V7 "r=%08lX: %s [return value]",r,N(r) D;
:f	Fexit;
	return r;
}
