/********************************************************/
/*							*/
/*	ro_outp.c	output routines for ro		*/
/*							*/
/*	ro version 1.00					*/
/*							*/
/*	Portions copyright (c) 1989 by Ted A. Campbell	*/
/*		Bywater Software			*/
/*		P. O. Box 4023				*/
/*		Duke Station				*/
/*		Durham, NC  27706			*/
/*							*/
/*	Contains portions of ROFF4, Version 1.60	*/
/*      (c) 1983, 4 by Ernest E. Bergmann               */
/*		Physics, Building #16			*/
/*		Lehigh University			*/
/*		Bethlehem, Pa. 18015			*/
/*							*/
/*	Contains portions of ROFF4, Version 1.61	*/
/*      (c) 1985 by Konrad Kwok                         */
/*		20 3rd Street, Section M		*/
/*		Fariview Park,				*/
/*		Hong Kong				*/
/*							*/
/*	ro and its predecessor ROFF4 are based on 	*/
/*	the ROFF text processor described in Kernigan	*/
/*	and Plauger's now-classic text <Software Tools> */
/*							*/
/* Permission is hereby granted for all commercial and	*/
/* non-commercial reproduction and distribution of this */
/* material provided this notice is included.		*/
/*							*/
/********************************************************/

#include "ro.h"

/*assuming REVSCROLL is FALSE*/
/*output ro_out2buf with the vertical height of the mainline
specified by ro_vlineno,ro_vflineno[they must not be changed here].
Excessive superscripting will be pushed down.*/

printout()
	{
	int level, top, bot;       /* "up" is negative; units fractional */
	int lsave;
	register int n;

	ro_out2buf[ ro_bpos ] = '\0';           /* terminate with '\0' */
	lsave = ro_vlineno;
	level = ro_plineno - ro_vlineno;

	if ( !ro_oldbot )
		{
		level++;
		}

	excurs( &ro_out2buf[0], &top, &bot );

	if ( top > level )
		{
		level=top;
		}

	padv();

	/* output offset spaces at beginning of line */

	for ( n = 0; n < ro_poval; ++n )
		{
		putchar( ' ' );
		}

	for ( ; level <= bot; level++ )
		{
		ro_ocnt = 0;
		do
			{
			ro_ocnt++; 
			flp( level, FALSE );
			}
		while ( retype() );
		}

	ro_out2buf[0] = ro_bpos = 0;
	ro_oldln = ro_vlineno = lsave;
	ro_oldbot = bot;
	}

/****************************************/
/*moves printer vertically so that its position is specified
by ro_vlineno,ro_vflineno*/

padv()
	{
	int w;

	w = ro_vlineno - ro_plineno;
	if ( w < 0 )
		{
		if (ro_verbose )
			{
			fprintf( stderr,"padv(): VL=%d, PL=%d\n",
				ro_vlineno, ro_plineno);
			}
		ro_vlineno += w;
		}
	while( w-- )
		{
		putchar('\n');
		ro_plineno++;
		}
	}

/**************************************************/
/* finds the topmost and bottommost line
positions of str */

excurs( str, t, b)
	char *str;
	int *t, *b;
	{
	int l;
	char c;
	*t = *b = l = 0;        /*current line position */
	c = *str;
	while ( c )
		{
		if ( c == ro_cfval[0])
			{
			if ( c = *(++str) )
				{
				switch ( c )
					{
				case '+':
					l--; 
					if ( l < *t )
						{
						*t = l;
						}
					c = *( ++str );
					break;
				case '-':
					l++; 
					if ( l >* b)
						{
						*b = l;
						}
					c = *( ++str );
					break;
				default : 
					c = *( ++str );
					break;
					}
				}
			}
		else c = *( ++str );
		}
	}

/**************************************************/
/*fancy line print at a given vertical level
the string in ro_out2buf[] with backspacing,
underlining, and strikout.	To permit boldface
it modifies ro_dbuf[], ro_dpos so that retype can be
used to patch up ro_out2buf for resubmittal to
flp()*/

flp( level, updat )
	int level;	/* current vertical level to print*/
	int updat;	/* boolean for update of ro_uf,ro_xf,ro_mcnt*/
	{
	int i;
	ro_blkcnt=lbc(level,ro_out2buf);
	ro_first=TRUE;
	while((ro_blkcnt>0)||updat)
		{
		prpass(level,updat); 
		putchar('\r');
		updat=ro_first=FALSE;
		}
	if(ro_xcol>-1)	{
		for(i=0;i<=ro_xcol;i++)
			putchar(ro_xbuf[i]);
		putchar('\r');
		}
	if(ro_ucol>-1)	{
		for(i=0;i<=ro_ucol;i++)
			putchar(ro_ubuf[i]);
		putchar('\r');
		}
	if((ro_ucol>-1)||(ro_xcol>-1)) initxu();
	}

/**************************************************/
retype()		/*restores characters into ro_out2buf from ro_dbuf
			that need to be overstruck again*/
	{
	int i;
	if ( ro_dpos == -1 )
		{
		return(FALSE);
		}
	else
		{
		for(i=0;i<=ro_dpos;i++)
			{
			if(ro_dbuf[i])
				{
				ro_out2buf[i]=ro_dbuf[i];
				ro_dbuf[i]=FALSE;
				}
			}
		ro_dpos = -1;
		return( TRUE );
		}
	}

/**************************************************/
/*counts printable chars in line level and
above; parity must be reset*/

int lbc( lev, str ) 
	int lev; /*=0 main line,=-1 superscripts,=+1 subscripts, etc.*/
	char *str;
	{
	char c;
	int l, n;
	l = n = 0;
	c = *str;
	while ( c )
		{
		if(c == ro_cfval[0])
			{
			if ( c = *(++str) )
				{
				switch(c)
					{
				case '+':
					l--;
					c = *(++str);
					break;
				case '-':
					l++;
					c = *(++str);
					break;
				default: 
					c = *(++str);
					break;
					}
				}
			}
		else
			{
			if((c>' ')&&(l<=lev))
				{
				if(c!=ro_tcval[0])
					{
					n++;
					}
				}
			c = *( ++str );
			}
		}
	return(n);
	}

/**************************************************/
/*printer pass initial cr; no lf anywhere*/

prpass( lev, updat ) 
	int lev; /*=0 main line,=-1 superscripts,=+1 subscripts, etc.*/
	int updat;/*boolean to update ro_uf,ro_xf,ro_mcnt*/
	{
	char ch;
	int l;
	int xfs,ufs,mcnts;	/*save variables*/
	int p1,p2,p3;		 /*position holders*/
	int cp2;		/*for tabulation calculation*/
	xfs=ro_xf; 
	ufs=ro_uf; 
	mcnts=ro_mcnt;
	p1=p2=p3=l=ro_bpos=ro_cp=ro_pp=0;
	while(ch=ro_out2buf[ro_bpos])
		{
		switch (class(ch))
			{
		case 	ESCAPE:
		case	BLACK:	/*print it if posssible*/
			if ( ( ro_pp > ro_cp ) || ( l > lev ) )	
				{
				ro_cp++;
				ro_bpos++;
				break;
				}
			else		{
				while(ro_cp>ro_pp)	{
					putchar(' ');
					ro_pp++;
					}
				if(ch==ro_scval[0])putchar(' ');
				else putchar(ch);
				ro_pp++;
				if(ro_mcnt>ro_ocnt)
					{
					ro_dbuf[ro_bpos]=ro_out2buf[ro_bpos];
					if(ro_bpos>ro_dpos) ro_dpos=ro_bpos;
					}
				ro_out2buf[ro_bpos++]=' ';
				if(ro_uf&&ro_first)ro_ubuf[ro_ucol=ro_cp]=UCHAR;
				if(ro_xf&&ro_first)ro_xbuf[ro_xcol=ro_cp]=XCHAR;
				ro_blkcnt--; 
				ro_cp++;
				} 
			break;
		case	WHITE:/*assume blank*/
			ro_cp++;
			ro_bpos++;
			break;
		case	TRANSLATE:/*similar to BLACK and WHITE*/
			ch=ro_out2buf[++ro_bpos];
			if((ro_pp>ro_cp)||(l>lev)||(ch==' '))
				{
				ro_cp++;
				ro_bpos++;
				break;
				}
			else
					{
				while(ro_cp>ro_pp)	{
					putchar(' ');
					ro_pp++;
					}
				trch(ch);
				ro_pp++;
				if(ro_mcnt>ro_ocnt)
					{
					ro_dbuf[ro_bpos]=ro_out2buf[ro_bpos];
					ro_dbuf[ro_bpos-1]=ro_out2buf[ro_bpos-1];
					if(ro_bpos>ro_dpos) ro_dpos=ro_bpos;
					}
				ro_out2buf[ro_bpos++]=' ';
				if(ro_uf&&ro_first)ro_ubuf[ro_ucol=ro_cp]=UCHAR;
				if(ro_xf&&ro_first)ro_xbuf[ro_xcol=ro_cp]=XCHAR;
				ro_blkcnt--; 
				ro_cp++;
				} 
			break;

		case	SENTINEL: 
			ro_out2buf[ro_bpos]=0;
			break;
		case	HTAB: 
			for(cp2=0;ro_cp>=0;cp2+=ro_tabsiz[0])ro_cp-=ro_tabsiz[0];
			ro_cp=cp2; 
			ro_bpos++; 
			break;
		case	OTHERS:
			if ( ro_verbose )
				fprintf( stderr,"\nweird character value[octal]: %o\n",ch);
			ro_bpos++;
			break;
			}
		}
	if(!updat)	{/*restore original values*/
		ro_newxf=ro_xf;
		ro_xf=xfs;
		ro_newuf=ro_uf;
		ro_uf=ufs;
		ro_newmcnt=ro_mcnt;
		ro_mcnt=mcnts;
		}
	}

/**************************************************/
updatef()	/* 3rd Mar, 85		 */
	{		/* By Conrad Kwok	*/
	ro_xf=ro_newxf;
	ro_uf=ro_newuf;
	ro_mcnt=ro_newmcnt;
	}

/**************************************************/

int class( c )
	char c;
	{
	if ( c == ro_tcval[0] ) return(TRANSLATE);
	if ( c == ESCAPE ) return(ESCAPE);
	if ( c > ' ' ) return(BLACK);
	if ( c == ' ') return(WHITE);
	if ( c == '\n' ) return(SENTINEL);
	if ( c == '\r' ) return(SENTINEL);
	if ( c == TAB ) return(HTAB);
	if (!c) return(SENTINEL);
	return ( OTHERS );
	}

/**************************************************/
fraction()	/*put printer in fractional spcing mode;
				set ro_frq*/
	{
	if(!ro_frq && ro_frstring && (ro_frval!=1))
		{
		outstr(ro_frstring);
		ro_frq = TRUE;
		}
	}
/**************************************************/
whole()		 /*put printer in whole line spacing;
				reset ro_frq */
	{
	if(ro_frq && ro_whstring)
		{
		outstr(ro_whstring);
		ro_frq = FALSE;
		}
	}
/**************************************************/
trch(c) /*output string translation of c*/
char c;
	{
	char *p;
	if(c<' ') 
		{
		putchar(ro_tcval[0]);
		putchar(c);
		return;
		}
	p = ro_tptr[c-' '];
	if(p) outstr(p);
	else		
		{/*not initialized*/
		putchar(ro_tcval[0]);
		putchar('?');
		}
	}
/****************************************/
pcont(c) /*output printer control string for c*/
char c;
	{
	char *p;
	if(c<' ') 
		{
		putchar(ro_cfval[0]);
		putchar(c);
		return;
		}
	p = ro_cptr[c-' '];
	if(p) outstr(p);
	else	
		{/*not initialized*/
		putchar(ro_cfval[0]);
		putchar('?');
		}
	}
