/*
 * chartype.c - character-type checking and conversion routines
 */

#include	<stdio.h>
#include	<ctype.h>
#ifndef	STRING_H
#define	STRING_H <string.h>
#endif
#include	STRING_H

#include	"etm.h"

#include	"troffcvt.h"


/*
 * Convert a character following escChar into the equivalent
 * escape-char code, or convert an escape-char code to the regular
 * character that would follow escChar.
 *
 * The escape code for an escaped character c is the same as the ASCII
 * or 8-bit value of c, but with bit 9 turned on.  This makes escape codes
 * distinct from the regular ASCII range (0..127), 8-bit range (128-255), and
 * endOfInput.
 *
 * The character cannot be a special character code.
 */

XChar
ToEsc (XChar c)
{
	if (Special (c))
		ETMPanic ("ToEsc: logic error");
	return (c | escBase);	/* set escape-code bit */
}


XChar
FromEsc (XChar c)
{
/*
	if (Special (c))
		return (c);
*/
	if (Special (c))
		ETMPanic ("FromEsc: logic error");
	return (c &= ~escBase);	/* clear escape-code bit */
}


/*
 * Character type testers.
 *
 * Esc(c)		Whether c is an escape+char code.
 * Special(c)		Whether c is a special char code.
 * White(c)		Whether c is whitespace (isspace(c) doesn't work).
 * Eol(c)		Whether c ends a line.  EOF is considered to end
 * 			a line, since a file need not end with a linefeed-
 * 			terminated line.
 * WhiteOrEol(c)	Obvious.
 * UnitChar(c)		Whether c is a unit indicator char.
 */


int
Esc (XChar c)
{
	return (!Special (c) && (c & escBase) != 0);
}


int
Special (XChar c)
{
	return (c >= spCharBase);	/* greater than ASCII or escape codes */
}


int
Sign (XChar c)
{
	return (c == '+' || c == '-');
}


int
White (XChar c)
{
	return (c == ' ' || c == '\t');
}


int
Eol (XChar c)
{
	return (c == lf || c == endOfInput);
}


int
WhiteOrEol (XChar c)
{
	return (c == ' ' || c == '\t' || c == lf || c == endOfInput);
}


int
UnitChar (XChar c)
{
	return (c == 'x' || c == 'u' || c == 'v' || c == 'n'
			|| c == 'm' || c == 'P' || c == 'p'
			|| c == 'c' || c == 'i');
}


/*
 * Version of isdigit() suitable for XChar values.  (Don't want to pass
 * specials to native isdigit().)
 *
 * May not work on non-ASCII machines.
 */

int
Digit (XChar c)
{
	return (c >= '0' && c <= '9');
}


/*
 * Test whether an argument is empty (all white is considered empty)
 * or numeric.
 *
 * The numeric-arg tester allows for a unit indicator at the end.
 */

int
EmptyArg (XChar *arg)
{
	while (*arg != (XChar) '\0')
	{
		if (!White (*arg++))
			return (0);
	}
	return (1);
}


int
NumericArg (XChar *arg)
{
	if (Sign (*arg))
		++arg;
	if (*arg == (XChar) '\0')
		return (0);
	while (Digit (*arg))
		++arg;
	if (*arg == '.')
	{
		++arg;
		while (Digit (*arg))
			++arg;
	}
	if (UnitChar (*arg))
		++arg;
	return (*arg == (XChar) '\0');
}


/*
 * Return non-zero if string is composed completely of plain
 * characters in the ASCII range (values < 128), zero otherwise.
 */

int
AsciiStr (XChar *s)
{
XChar	c;

	while ((c = *s++) != (XChar) '\0')
	{
		/*if (c >= escBase)*/
		/*
		if (Esc (c) || Special (c))
			return (0);
		*/
		if (c > 127)			/* faster check! */
			return (0);
	}
	return (1);
}
