/*
 * output.c - basic output operations
 */

#include	<stdio.h>

#include	"etm.h"

#include	"troffcvt.h"


#define	maxTransDepth	20


/*
 * Level 2 output routines
 */


static int	inPara = 0;
static int	inOTextLine = 0;
static XChar	transTab[256];	/* transliteration table */
static int	transDepth = 0;	/* transliteration depth (loop detection) */


/*
 * Initialize transliteration table to "no transliteration", i.e.,
 * transliteration(x) = x, for all x.
 */

void
InitTransliterate (void)
{
int	i;

	for (i = 0; i < 256; i++)
		transTab[i] = i;
}


void
Transliterate (int in, XChar out)
{
	if (in < 0 || in > 255)
		ETMMsg ("Transliterate: bad in value (%ld)", in);
	else
		transTab[in] = out;
}


/*
 * Shove out a break if necessary.  Nothing is written if no paragraph
 * is active.
 *
 * A break flushes the current text output line, turns off any \c
 * continuation, and turns off the need for a space between successive
 * text lines.
 */

void
Break (void)
{
	inContinuation = 0;
	needSpace = 0;
	if (inPara)
	{
		FlushOText ();
		ControlOut ("break");
		inPara = 0;
		fieldDelimCount = 0;
	}
}


void
ControlOut (char *s)
{
	FlushOText ();
	ChOut ('\\');
	StrOut (s);
	ChOut (lf);
}


void
CommentOut (char *s)
{
char	buf[bufSiz];

	sprintf (buf, "comment %s", s);
	ControlOut (buf);
}


/*
 * Write out a control word which is really part of paragraph
 * text (e.g., for a special character).  Set inPara to note the
 * fact that a paragraph is now active.
 */

void
SpecialTextOut (char *s)
{
	FlushOText ();
	ChOut ('@');
	StrOut (s);
	ChOut (lf);
	inPara = 1;
}


/*
 * Write out an extended-char paragraph text string.
 */

void
TextXStrOut (XChar *s)
{
	if (s != (XChar *) NULL)
	{
		while (*s != '\0')
			TextXChOut (*s++);
	}
}


/*
 * Write out an extended-char paragraph text character.
 */

void
TextXChOut (XChar c)
{
char	*cp;

	cp = CharToOutputStr (c);
	if (*cp == '@')
		SpecialTextOut (cp+1);
	else
		TextStrOut (cp);
}


/*
 * Write out a paragraph text string.  No interpretation of
 * the string is done.
 */

void
TextStrOut (char *s)
{
	if (s != (char *) NULL)
	{
		while (*s != '\0')
			TextChOut (*s++);
	}
}


/*
 * Write out a paragraph text character.  Set inPara to note the fact
 * that a paragraph is now active and that there is an output text line
 * in progress.
 *
 * A few characters are treated specially because they have special meaning
 * in troffcvt output syntax (e.g., @ and / are written as @at and
 * @backslash).
 */

void
TextChOut (int c)
{
	if (Special (c) || Esc (c))
		ETMPanic ("%sTextChOut: logic error", FileInfo ());

	/*
	 * Perform transliteration.  If the resulting character is
	 * special or escaped, pass it back to a routine that can
	 * write it out properly.  However, there is the possibility
	 * of introducing a transliteration loop here, so check for that.
	 */

	c = transTab[c];
	if (Special (c) || Esc (c))
	{
		if (++transDepth > maxTransDepth)
			ETMPanic ("%stransliteration loop", FileInfo ());
		TextXChOut (c);
		--transDepth;
		return;
	}

	if (c == '\\')
		SpecialTextOut ("backslash");
	else if (c == '@')
		SpecialTextOut ("at");
	else if (c == '\t')
		SpecialTextOut ("tab");
	else if (c == 1)
		SpecialTextOut ("leader");
	else if (c == '\b')
		SpecialTextOut ("backspace");
	else
	{
		ChOut (c);
		inPara = 1;
		inOTextLine = 1;
	}
}


/*
 * Flush any output text line that may be in progress.
 */

void
FlushOText (void)
{
	if (inOTextLine)
	{
		ChOut (lf);
		inOTextLine = 0;
	}
}


/*
 * Level 1 output routines
 *
 * StrOut () - write out a string.
 * ChOut () - write out a character.  ALL output (except ETM messages)
 * comes through this routine.
 * AllowOutput () - allow or throttle output.
 */


static int	oAllow = 1;


void
StrOut (char *s)
{
	while (*s != '\0')
		ChOut (*s++);
}


void
ChOut (int c)
{
	if (oAllow && putc (c, stdout) == EOF)
		ETMPanic ("Write error, cannot continue");
}


int
AllowOutput (int yesno)
{
int	prev = oAllow;

	oAllow = yesno;
	return (prev);
}
