/*
 * xchar.c -- routines that operate on extended characters and strings
 * of extended characters.
 */

#include	<stdio.h>

#include	"etm.h"
#include	"memmgr.h"

#include	"troffcvt.h"


/*
 * Return length of an extended string
 */

int
XStrLen (XChar *xstr)
{
int	len = 0;

	while (*xstr++ != (XChar) '\0')
		++len;
	return (len);
}


/*
 * Copy an extended-char string and return a pointer to the result
 */

XChar *
XStrCpy (XChar *xdst, XChar *xsrc)
{
XChar	*xsave = xdst;

	while ((*xdst++ = *xsrc++) != (XChar) '\0')
	{
		/* loop */
	}
	return (xsave);
}


/*
 * Copy at most n bytes of an extended-char string and return a pointer
 * to the result
 */

XChar *
XStrNCpy (XChar *xdst, XChar *xsrc, long n)
{
XChar	*xsave = xdst;

	while (n-- > 0 && (*xdst++ = *xsrc++) != (XChar) '\0')
	{
		/* loop */
	}
	return (xsave);
}


/*
 * Compare two extended-char strings, returning:
 *
 *  0	xstr1 == xstr2
 * -1	xstr1 < xstr2
 *  1	xstr1 > xstr2
 */

int
XStrCmp (XChar *xstr1, XChar *xstr2)
{
int	i;

	while ((i = (*xstr2 - *xstr1)) == 0
		&& *xstr1++ != (XChar) '\0' && *xstr2++ != (XChar) '\0')
	{
		/* loop */
	}
	if (i == 0)
		return (0);
	return (i < 0 ? -1 : 1);
}


/*
 * Compare at most n bytes of two extended-char strings, returning:
 *
 *  0	xstr1 == xstr2
 * -1	xstr1 < xstr2
 *  1	xstr1 > xstr2
 */

int
XStrNCmp (XChar *xstr1, XChar *xstr2, long n)
{
int	i = 0;

	while (n-- > 0 && (i = (*xstr2 - *xstr1)) == 0
		&& *xstr1++ != (XChar) '\0' && *xstr2++ != (XChar) '\0')
	{
		/* loop */
	}
	if (i == 0)
		return (0);
	return (i < 0 ? -1 : 1);
}


/*
 * Allocate space for an extended-char string, copy the given string into
 * it, and return a pointer to the copy.
 */

XChar *
XStrAlloc (XChar *xstr)
{
int	len;
XChar	*p;

	len = XStrLen (xstr);
	p = (XChar *) VAllocNP (len + 1, sizeof (XChar));
	if (p == (XChar *) NULL)
		ETMMsg ("XStrAlloc: out of memory");
	return (XStrCpy (p, xstr));
}


/*
 * Stuff a string into an extended-char string, and return a pointer
 * to the result.
 *
 * Returns a pointer to a static buffer.  Caller should copy the
 * return value if it needs to hang onto it for a while.
 */

XChar *
StrToXStr (char *str)
{
static XChar	xstr[bufSiz];
XChar	*xp = xstr;

	while ((*xp++ = *str++) != (XChar) '\0')
	{
		/* loop */
	}
	return (xstr);
}


/*
 * Convert coded XChar value to printable ASCII representation.
 * Returns a pointer to a static buffer.  Caller should copy the
 * return value if it needs to hang onto it for a while.
 */

char *
XCharToStr (XChar c)
{
static char	buf[bufSiz];
SpChar	*sp;

	if (Special (c))
	{
		if ((sp = LookupSpCharByCode (c)) != (SpChar *) NULL)
		{
			if (XStrLen (sp->spName) == 2)
			{
				sprintf (buf, "%c(%s", escChar,
						XStrToStr (sp->spName));
			}
			else
			{
				sprintf (buf, "%c[%s]", escChar,
						XStrToStr (sp->spName));
			}
		}
		else
		{
			ETMMsg ("%sXCharToStr: bad special-char code: %ld",
							FileInfo (), c);
			buf[0] = '\0';
		}
	}
	else if (Esc (c))
		sprintf (buf, "%c%c", escChar, FromEsc (c));
	else
	{
		buf[0] = c;
		buf[1] = '\0';
	}
	return (buf);
}


/*
 * Convert XChar string to printable ASCII representation.
 * Returns a pointer to a static buffer.  Caller should copy the
 * return value if it needs to hang onto it for a while.
 */

char *
XStrToStr (XChar *xstr)
{
static char	buf[bufSiz];
char	*p, *p2;
XChar	xc;

	p = buf;
	while ((xc = *xstr++) != (XChar) '\0')
	{
		p2 = XCharToStr (xc);	/* convert XChar to string */
		(void) strcpy (p, p2);	/* add string to end of buffer */
		p += strlen (p);	/* advance to new end of buffer */
	}
	*p = '\0';
	return (buf);
}
