/********************************************************/
/*							*/
/*	ro.c		main program file 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"

extern  char *ro_gets();

int ro_iline = 0;
int ro_deno = 0;

/*****************MAIN************MAIN*********/

main( argc, argv )
	int argc;
	char **argv;
	{
	register int n;
	int fs;
	char option, *pc;
	char filename[20];
	struct divfd *pd;

	ro_lastch = NULL;
	debug = FALSE;
	ro_verbose = FALSE;

	init_defaults();

	/***    First process any flags         ***/

	for ( n = 1; n < argc; ++n )
		{ 
		strcpy( filename, argv[ n ] );

		if ( filename[0] == '-' )
			{
			option = filename[1];
			if      ( option == 's' ) ro_pagestop = TRUE;
			else if ( option == 'o' ) range( &filename[2] );
			else if ( option == 'f' ) ro_useff = TRUE;
			else if ( option == 'x' ) 
				{
				debug = TRUE;
				ro_verbose = TRUE;
				}
			else if ( option == 'v' ) ro_verbose = TRUE;
			continue;
			}
		}

	if ( ro_verbose == TRUE )
		{
		fprintf( stderr, "ro, version 1.00 \n" );
		}

	if DEBUG
		{
		fprintf( stderr, "DEBUG:  initial .ls setting is %d. \n",
			ro_lsval[0] );
		}

	/* Now process all files named */

	fs = 0;

	for ( n = 1; n < argc; ++n )
		{ 
		strcpy( filename, argv[ n ] );
		if ( filename[0] != '-' )
			{

			if( pd = find2( filename, dlink ))
				{
				dclose( pd );
				}

			if (( instream = fopen( filename, "r" )) == NULL )
				{
				fprintf( stderr, "Can't open <%s> for input.\n", filename );
 				}
			else
				{
				++fs;		/* inc. number of files */
				if ( ro_verbose == TRUE )
					{
					fprintf( stderr, "Processing <%s>\n", filename );
					}
				dolns();
				}
			}
		}

	/* No files opened; take input from stdin */

	if ( fs == 0 )
		{
		if ( ro_verbose && ro_pagestop )
			{
			fprintf( stderr, "ERROR:  one cannot use -s (page stop) with standard input. \n" );
			}
		ro_pagestop = FALSE;	/* Cannot use page stop if stdin */
		instream = stdin;
		dolns();
		}

	ro_brk();
	ro_vlineno = ro_plval[ 0 ];
	padv();
	if ( ro_useff ) putchar( FORMF );
	dsclose();                      /* Close all diversions */
	}				/* end main()		 */

/****************************************/
/* do processing of lines 		*/
/****************************************/

dolns() 
	{
	char *pc;
	struct divfd *sptr;
	static char name[ 12 ];
	ro_binp = 0;

	while ( !feof( instream ) | ro_fptr | ro_binp )
		{
		ro_gets( ro_curline );
		++ro_iline;

		if DEBUG
			{
			fprintf( stderr, "DEBUG:  input line # %d <%s> \n",
				ro_iline, ro_curline );
			fprintf( stderr, "DEBUG:  ro_curline[0] is <%c> (0x%x)\n", 
				ro_curline[0], ro_curline[0] );
			}

		if ( ro_curline[ 0 ] == COMMAND )
			{
			name[ 0 ] = ro_curline[ 1 ];
			if ( class( ro_curline[ 2 ] ) == BLACK )
				{
				name[ 1 ] = ro_curline[ 2 ];
				name[ 2 ] = '\0';
				}
			else
				{
				name[ 1 ] = '\0';
				}
			if ( ( pc = macq( ro_curline )) != NULL )
				{
				pbmac( pc, ro_curline );
				}
			else if ( ( sptr = find2( name, dlink )) != NULL )
				{
				read_div( sptr );
				}
			else
				{
				command( ro_curline );
				}
			}
		else
			{
			text( ro_curline );
			}
		if ( feof( instream) )
			{
			endso();
			}
		}
	}

char *
ro_gets( line )
	char *line;
	{
	char *l;

	l = line;
	do
		{
		*l = ro_getch();
		++l;
		}
	while( *(l - 1) != '\n' );

	*( l - 1 ) = '\0';

	if DEBUG
		{
		fprintf( stderr, "DEBUG:  ro_gets() <%s> \n", line );
		}

	return line;
	}

char
ro_getch()
	{
	register int c;
	static int bflag = FALSE;	/* was last character BACKSLASH? */

	while ( TRUE )
		{
		if ( ro_binp == 0 )
			{
			if ( feof( instream ))
				{
				return '\n';
				}
			c = fgetc( instream );
			}
		else
			{
			c = ro_backbuf[ ro_binp-- ];
			}
		switch ( c )
			{
			case EOF:
				bflag = FALSE;
				return '\n';
				break;
			case '\r':
				bflag = FALSE;
				break;
			case BACKSLASH:
				if ( !bflag )
					{
					bflag = TRUE;
					if ( ro_expand() == PASSBACK )
						{
						return BACKSLASH;
						}
					else
						{
						return ro_getch();
						}
					}
				else
					{
					bflag = FALSE;
					return c;
					}
				break;
			default:
				bflag = FALSE;
				return c;
				break;
			}
		}
	}

/**************************************************************
initializes the global variables governing the execution of the
 format commands.
**************************************************************/

init_defaults()
	{
	static time_t now;
	struct tm *ltime;

	initsk( ro_fill,  FI_DEF);	/* yes we want filled lines */
	initsk( ro_lsval, LS_DEF);	/* line spacing = 1 */
	initsk( ro_inval, IN_DEF);	/* left margin indent	0 */
	initsk( ro_rmval, RM_DEF);	/* right margin = page width	*/
	initsk( ro_tcval, TC_DEF);
	initsk( ro_plval, PL_DEF);
	initsk( ro_m1val, M1_DEF);
	initsk( ro_m2val, M2_DEF);
	initsk( ro_m3val, M3_DEF);
	initsk( ro_m4val, M4_DEF);
	initsk( ro_scval, SC_INI);
	initsk( ro_tabsiz, TS_DEF);
	initsk( ro_cfval, CF_DEF);
	initsk( ro_icval, IC_DEF);

	ro_tival = IN_DEF; 	/* left margin temporary indent	0 */
	ro_ceval = 0;		/* next n lines to be centered - 0 */
	ro_pagestop = FALSE;
	ro_useff = FF_INI;
	ro_firstpage = 1;
	ro_lastpage = 30000;	/*infinite*/
	ro_adjust = JU_INI;
	ro_poval = PO_DEF;

	ro_curpag = 0;
	ro_newpag = 1;
	ro_frq = 0;
	ro_frstring = ro_whstring = NULL;
	ro_frval = 1;
	ro_vflineno = ro_pflineno = ro_plineno = 0;
	ro_vlineno = -1;
	ro_bottom = ro_plval[0] - ro_m3val[0] - ro_m4val[0];
	ro_outw = ro_outpos = ro_outtop = ro_outbot = ro_oldln = ro_oldbot = ro_outwrds = 0;
	ro_outbuf [0] = '\0';
	ro_dir = 0;
	ro_eh2[0] = ro_eh3[0] = ro_ehead[0] = '\0';
	ro_oh2[0] = ro_oh3[0] = ro_ohead[0] = '\0';
	ro_ef2[0] = ro_ef3[0] = ro_efoot[0] = '\0';
	ro_of2[0] = ro_of3[0] = ro_ofoot[0] = '\0';
	memfill( ro_cptr, 2*(128-' '), 0);
	memfill( ro_tptr, 2*(128-' '), 0);

	ro_out2buf[ 0 ] = ro_bpos = 0;
	initxu();		/* Initialize overstrike and other variables */
	ro_mcnt=1;
	ro_uf = ro_xf = FALSE;
	memfill( ro_dbuf, LSZ, FALSE);
	ro_dpos = -1;
	ro_fptr = 0;			 
	mlink = dlink = rlink = slink = NULL;
	ro_kptr = ro_kline;
	*ro_kline=0;
	ro_keybd=FALSE;

	/***	now set up some pre-defined registers ***/ 

	time( &now );
	ltime = localtime( &now );
	preregister( "dy", ltime->tm_mday );
	preregister( "mo", ltime->tm_mon );
	preregister( "yr", ltime->tm_year );
	preregister( "%", ro_curpag );
	}

/**************************************************************
performs the formatting command returned by comtyp -sets global
	variables ( indenting, underlining, etc. )
**************************************************************/

command( line )
	char *line;
	{
	int c_type;	/* command type	*/
	int arg_val;	/* argument value, if any */
	static int arg_typ;    /* relative (+ or -) or absolute */
	char wbuf[20], *l;
	register int i;

	c_type = comtyp (line);

	if DEBUG
		{
		fprintf( stderr, "DEBUG:  command is %d \n", c_type );
		}

	if ( c_type == UNKNOWN )
		{
		if ( ro_verbose )
			fprintf( stderr, "%s: unknown command \n", line);
		return;
		}
	arg_val = get_val( line, &arg_typ );

	if DEBUG
		{
		fprintf( stderr, "DEBUG:  get_val returned arg_val = %d, arg_typ = %c\n",
			arg_val, arg_typ );
		fprintf( stderr, "DEBUG:  c_type is now %d \n", c_type );
		}

	switch ( c_type )
		{
		case EM :
		case IG : 
			break;		/* ignore remark */

		case FI :	 	/* filled lines	*/
			ro_brk();
			ro_fill[0] = YES;
			break;

		case NF:               /* non-filled lines */
			ro_brk();
			ro_fill[0] = NO;
			break;

		case AD :	 	/* adjusted (justified) lines	*/
			ro_adjust = TRUE;
			break;

		case NA :		/* non-adjusted lines 	*/
			ro_adjust = FALSE;
			break;

		case BR :	 	/* just cause a break */
			ro_brk();
			break;

		case LS :	 	/* set line spacing value */
			setS( ro_lsval, arg_val, arg_typ, LS_DEF, 1, HUGE );
			break;

		case TI :	 	/* set temporary left indent */
			ro_brk();
			set( &ro_tival, arg_val, arg_typ, TI_DEF, 0, ro_rmval );
			break;

		case IN :	 	/* set left indent */
			setS( ro_inval, arg_val, arg_typ, IN_DEF, 0, ro_rmval-1 );
			ro_tival = ro_inval[0];
			break;

		case LL :		/* set line length (right margin) */
			setS( ro_rmval, arg_val, arg_typ, RM_DEF, ro_tival+1, 256 );
			break;

		case CE :	 /* center next arg_val lines */
			ro_brk();
			set( &ro_ceval, arg_val, arg_typ, CE_DEF, 0, HUGE);
			break;

		case SP :	 /* space down arg_val blank lines */
			set( &ro_spval, arg_val, arg_typ, 1, 0, HUGE);
			do_space ( ro_spval );
			break;

		case BP :	 /* set pageno arg_val - begin page */
			ro_brk();
			if(((ro_vlineno<=0)||(ro_vlineno>=ro_bottom))&&
				(arg_val==NO_VAL)) 
				{
				break;
				}
			if ( ro_vlineno > 0 )
				{
				do_space (HUGE);
				}
			set( &ro_curpag, arg_val, arg_typ, ro_curpag+1, 0, 9999);
			ro_newpag = ro_curpag;
			break;

		case NE :	 /*"need"*/
			if ( arg_val == NO_VAL ) 
				{
				arg_val = 2;	/*default*/
				}
			need( arg_val );
			break;

		case PL :	 /* set page length */
			setS( ro_plval, arg_val, arg_typ, PL_DEF,
				ro_m1val[0]+ro_m2val[0]+ro_m3val[0]+ro_m4val[0]+1, HUGE);
			ro_bottom = ro_plval[0] - ro_m3val[0] - ro_m4val[0];
			break;

		case TA :	 /*tabsize*/
			setS( ro_tabsiz, arg_val, '0', TS_DEF, 1, HUGE);
			break;

		case TC :	 /* tab character */
			if ( arg_typ ) 
				{
				arg_val=arg_typ;
				}
			setS( ro_tcval, arg_val, '0', TC_DEF, BLANK+1, 127);
			break;

		case FT :	/* Set font */
			switch( arg_typ )
				{
				case 'R':
					putback( '\n' );
					putback( ROMAN );
					putback( ESCAPE );
					break;
				case 'I':
					putback( '\n' );
					putback( ITALIC );
					putback( ESCAPE );
					break;
				case 'B':
					putback( '\n' );
					putback( BOLD );
					putback( ESCAPE );
					break;
				default: 
					if ( ro_verbose )
						{
						fprintf( stderr, 
							"ft:  unrecognized font name \"%c\". \n", 
							arg_typ );
						}
				}
			break;

		case TR :	 /*translation string defined here*/
			gettr(); 
			break;

		case DS :	 /*define string*/
			insert(); 
			break;

		case DE :	 /*define macro*/
			++ro_deno;
			if DEBUG
				{
				fprintf( stderr, "DEBUG:  .de number %d \n",
					ro_deno );
				}
			minsert();
			break;

		case NR :        /*register variable*/
			dovar(); 
			break;

		case DI :	 /*diversion to file*/
			dodiv(); 
			break;

		case SO :	 /*source from file*/
			source(); 
			break;

		case PM :	/* print macro definitions */
			showm();
			break;

		case PO :	/* page offset */
			set( &ro_poval, arg_val, arg_typ, 1, 0, HUGE );
			break;

		case TM :	 /* send message to terminal */
			getwrd(ro_curline, wbuf);	/*skip command*/
			skip_blanks(ro_curline);
			trunc_bl(ro_curline);
			fprintf( stderr, "<%s>\n", ro_curline);
			break;

#ifdef	NONROFF

		case M1:		/* set topmost margin */
			setS( ro_m1val, arg_val, arg_typ, M1_DEF, 0, HUGE);
			break;

		case M2:		/* set second top margin */
			setS( ro_m2val, arg_val, arg_typ, M2_DEF, 0, HUGE);
			break;

		case M3:		/* set first bottom margin */
			setS( ro_m3val, arg_val, arg_typ, M3_DEF, 0, HUGE);
			ro_bottom = ro_plval[0] - ro_m3val[0] - ro_m4val[0];
			break;

		case M4:		/* set bottom-most margin */
			setS( ro_m4val, arg_val, arg_typ, M4_DEF, 0, HUGE);
			ro_bottom = ro_plval[0] - ro_m3val[0] - ro_m4val[0];
			break;

		case HE :	 /* get header title for pages */
			gettl3 ( line, ro_ehead, ro_eh2, ro_eh3 );
			gettl3 ( line, ro_ohead, ro_oh2, ro_oh3 );
			break;

		case OH :	 /*get odd header title*/
			gettl3 ( line, ro_ohead, ro_oh2, ro_oh3 );
			break;

		case EH :	 /*get even header title*/
			gettl3 ( line, ro_ehead, ro_eh2, ro_eh3 );
			break;

		case FO :	 /* get footer title for pages */
			gettl3 ( line, ro_efoot, ro_ef2, ro_ef3 );
			gettl3 ( line, ro_ofoot, ro_of2, ro_of3 );
			break;

		case OF :	 /* get odd page footer title*/
			gettl3 ( line, ro_ofoot, ro_of2, ro_of3 );
			break;

		case EF :	 /* get even page footer title*/
			gettl3 ( line, ro_efoot, ro_ef2, ro_ef3 );
			break;

		case ST :	 /* stop(pause) at each page?*/
			set( &ro_pagestop, arg_val, '0', YES, NO, YES);
			break;

		case BJ :	 /*break with right justification*/
			if(ro_fill)/*not applicable otherwise*/
				{
				spread(ro_outbuf,
				ro_min(ro_rmval-ro_tival, MAXLINE-1)-ro_outw+1,
				ro_outwrds);
				ro_brk();
				}
			break;

		case FF :	 /*formfeed*/
			set( &ro_useff, arg_val, '0', FF_DEF, NO, YES);
			break;

		case SC :	 /*space character*/
			if ( arg_typ ) 
				{
				arg_val=arg_typ;
				}
			setS( ro_scval, arg_val, '0', SC_INI, BLANK, 127);
			break;

		case EX :	 /* exit (abort) */
			if ( ro_verbose )
				fprintf( stderr, ".ex:  user abort.  \n");
			exit(-1);		 /* tac */

		case CF :	 /*translate character flag*/
			if ( arg_typ ) 
				{
				arg_val=arg_typ;
				}
			setS( ro_cfval, arg_val, '0', CF_DEF, BLANK+1, 127);
			break;

		case IC :	 /* insert character for macro replace */
			if ( arg_typ ) 
				{
				arg_val = arg_typ;
				}
			setS( ro_icval, arg_val, '0', IC_DEF, BLANK+1, 127 );
			break;

		case SR :       /* print register definitions */
			showr();
			break;

		case SS :       /* print string definitions */
			showit();
			break;

		case DB :	 /* debug */
			set( &debug, arg_val, '0', NO, NO, YES);
			if DEBUG 
				{
				fprintf( stderr, "Debug on...\n");
				}
			else 
				{
				fprintf( stderr, "...end of debug. \n");
				}
			break;
#endif

		default :
			if ( ro_verbose )
				{
				fprintf( stderr, "Command %d not found.\n", c_type );
				fprintf( stderr, "        line: <%s> \n", line );
				}
			break;
		}
	}

range( s )
	char *s;
	{ 
	int num;
	num=0;
	while(isdigit(*s)) num=num*10+(*(s++)-'0');
	if(num) ro_firstpage=num;
	if(*s=='-')
		{
		s++; 
		num=0;
		while(isdigit(*s)) num=num*10+(*(s++)-'0');
		if(num) ro_lastpage=num;
		}
	else	ro_lastpage = ro_firstpage;
	}

ro_min( n1, n2 )
	int n1, n2;
	{
	if ( n1 > n2 )
		{
		return n2;
		}
	else
		{
		return n1;
		}
	}

ro_max( n1, n2 )
	int n1, n2;
	{
	if ( n1 < n2 )
		{
		return n2;
		}
	else
		{
		return n1;
		}
	}

memfill( b, n, c )
	char *b;
	int n;
	char c;
	{
	register int x;
	char *y;

	y = b;
	for ( x = 0; x < n; ++x )
		{
		*y = c;
		}
	}

