/********************************************************/
/*							*/
/*	ro_dive.c	diversion and register 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"

/****************************************/
/* checks RLIST; creates new entry if needed;
   returns pointer to integer variable */

int *
regist( s )	 
	char *s;
	{
	struct divfd *pw;
	int *pi;
	char *pc, *s2;
	struct divfd *sptr;

	pw = find2( s, rlink );	

	if ( pw != NULL ) 
		{
		return( &( pw->val ) );
		}

	/*  else create new entry */

	if ( ( sptr = (struct divfd *) malloc( (size_t) sizeof( struct divfd ))) == NULL )
		{
		fprintf( stderr, "Fatal error: cannot allocate memory for register structure.  \n" );
		exit ( -1 );
		}
	sptr->prev = rlink;		/* save previous link	*/
	strcpy( sptr->nm, s );		/* copy register name to structure */
	sptr->bf = NULL;		/* not a stream */
	sptr->mstr = NULL;		/* and not a macro */
	rlink = sptr;			/* set new link 	*/
	pi = &(sptr->val);
	*pi = REGDEF;
	return( pi );
	}

/****************************************/
/* process .nr request                  */

dovar()
	{
	static char wbuf[MAXLINE];
	static int typ;
	int val, *pw;
	getwrd( ro_curline, wbuf );
	skip_blanks( ro_curline );
	val = get_val( ro_curline, &typ );
	getwrd( ro_curline, wbuf);
	if ( wbuf[0] == NUMSIGN && wbuf[1] == '\0' )
		{
		set( &ro_newpag, val, typ, ro_newpag, 1, 9999);
		}
	else
		{
		pw = (int *) regist(wbuf);
		set( pw, val, typ, REGDEF, 0, 9999);
		}
	}

preregister( name, value )
	char *name;
	int value;
	{
	int *pw;
	pw = (int *) regist( name );
	*pw = value;
	}

/****************************************/
/* process .di version */

dodiv()		 
	{
	char wbuf[MAXLINE], *pc, *pc1, *wb;
	struct divfd *pd;
	int *pw, p;

	getwrd( ro_curline, wbuf );
	if ( getwrd( ro_curline, wbuf) != WE_HAVE_A_WORD )
		{
		strcpy( wbuf, "div.$$$");
		fprintf( stderr,".di:  no name, %s assumed\n",
			wbuf);
		}
	if ( strlen( wbuf ) > 2 )
		{
		wbuf[ 2 ] = '\0';
		if ( ro_verbose )
			{
			fprintf( stderr,
				".di:  name over two characters shortened to <%s> \n",
				wbuf );
			}
		}	

	if ( ( pd = find2( wbuf, dlink )) != NULL ) /*if in table*/
		{
		if DEBUG
			{
			fprintf( stderr, "DEBUG:  diversion <%s> found. \n",
				wbuf );
			}
		if ( ( pd->bf == NULL ))		/* file not open */
			{
			if (( pd->bf = fopen( pd->fn, "w" )) != NULL)
				{
				if DEBUG
					{
					fprintf( stderr, "DEBUG:  .di:  <%s> reopened for diversion.\n", pd->fn );
					}
				}
			else
				{
				fprintf( stderr, "Fatal error:  <%s> cannot be rewritten\n",wbuf);
				exit( -1 );
				}
			}
		}
	else			/* not in table, build new entry */
		{

		if ( ( pd = (struct divfd *) malloc( (size_t) sizeof( struct divfd ))) == NULL )
			{
			fprintf( stderr, "Fatal error: cannot allocate memory for diversion structure.  \n" );
			exit ( -1 );
			}

		pd->prev = dlink;		/* save previous link	*/
		strcpy( pd->nm, wbuf );		/* save name		*/
		dlink = pd;			/* set new link 	*/
		pd->mstr = NULL;		/* not a macro		*/
		pd->ls = pd->cs = 0;		/* set these to 0       */
		strcpy( pd->fn, wbuf );		/* get name in filename */
		strcat( pd->fn, "_ro.div" );	/* make unique diversion name */

		if (( pd->bf = fopen( pd->fn, "w" )) == NULL )
			{
			fprintf( stderr, 
				"Fatal error:  Can't create diversion file <%s>.\n", pd->fn );
			exit( -1 );
			}
		}

	/*** from this point we may presume a valid structure and file */

	while ( ro_gets( ro_curline ) != NULL )
		{
		if (( *ro_curline == COMMAND ) && ( comtyp( ro_curline ) == DI )) 
			{

			/*** NESTING of diversions not currently supported; 
			     implementation would require testing at this point 
			     for argument to .di ***/

			break;
			}
		if ( pc = (char *) macq( ro_curline))	/* if macro	*/
			{
			pbmac( pc, ro_curline);	/* process macro */
			continue;
			}

		/*else*/

		p = strlen( ro_curline );
		ro_curline[ p ] = '\n';		/* terminate the line with CR */
		++p;
		ro_curline[ p ] = '\0';		/* and then '\0' */
		fputs( ro_curline, pd->bf );	/* and put to diversion file */
		( pd->ls )++;			/* increment line counter */
		( pd->cs ) += strlen( ro_curline ); /* and char counter */
		}
	}

/****************************************/
/* read from diversion                  */

read_div( sptr )
	struct divfd *sptr;
	{
	if ( sptr->bf != NULL )
		{
		dclose( sptr );
		}

	if DEBUG
		{
		fprintf( stderr, "DEBUG:  reading from diversion <%s>, file <%s> \n",
			sptr->nm, sptr->fn );
		}

	if ( ro_fptr < FMAX ) 
		{
		ro_fstack[ ro_fptr++ ] = instream;
		}
	else	
		{
		fprintf( stderr,"Fatal error:  ro_fstack overflow\n");
		exit( -1 );
		}

	if (( instream = fopen( sptr->fn, "r" )) != NULL ) 
		{
		return;		/* file opened successfully */
		}

	/* else the attempt has failed */

	if ( ro_verbose )
		{
		fprintf( stderr, ".%s:  can't open <%s>\n", sptr->nm, sptr->fn );
		}
	endso();

	}

/****************************************/
/* .so -- read from source file         */

source()
	{
	char name[ MAXLINE ];

	getwrd( ro_curline, name );
	if( getwrd( ro_curline, name ) != WE_HAVE_A_WORD)
		{
		if ( ro_verbose )
			{
			fprintf( stderr,".so has no name\n");
			}
		return -1;
		}

	if ( ro_fptr < FMAX ) 
		{
		ro_fstack[ ro_fptr++ ] = instream;
		}
	else	
		{
		fprintf( stderr,"Fatal error:  ro_fstack overflow\n");
		exit( -1 );
		}

	if (( instream = fopen( name, "r" )) != NULL ) 
		{
		return;
		}

	/* else the attempt has failed */

	if ( ro_verbose )
		{
		fprintf( stderr, ".so:  can't open <%s>\n", name );
		}
	endso();
	}

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

showr() /*lists register names and contents*/
	{
	struct divfd *pw;
	fprintf( stderr, "REGISTERS and <values>:\n");
	pw = rlink;
	while ( pw != NULL )
		{
		fprintf( stderr, "%s:\t<%d> \n",pw->nm, pw->val );
		pw = pw->prev;
		}
	dashes();
	}

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

showd() /*shows all diversions and status*/
	{
	struct divfd *pd;

	fprintf( stderr, "Diversion files:\n");
	pd = dlink;
	while( pd != NULL )
		{
		fprintf( stderr, "%s:\t", pd->nm );
		fprintf( stderr, "%d characters, %d lines [",
		pd->cs, pd->ls );
		if( pd->bf ) 
			{
			fprintf( stderr, "open]\n");
			}
		else	
			{
			fprintf( stderr, "closed]\n");
			}
		pd = pd->prev;
		}
	dashes();
	}

/****************************************/
/* flushes and closes all open diversions, */
/* erases diversion files */

dsclose()	 
	{
	struct divfd *pd;

	pd = dlink;
	while( pd != NULL )
		{
		if ( pd->bf != NULL ) 
			{
			dclose( pd );
			if ( unlink( pd->fn ) == -1 )
				{
				if DEBUG
					{
					fprintf( stderr, "Failed to erase <%s> \n",
						pd->fn );
					}
				}
			}
		pd = pd->prev;
		}
	}

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

dclose( pd )		/*flushes and closes diversion*/
	struct divfd *pd;
	{
	if ( pd && ( !( pd->bf ))) 
		{
		return(FALSE);
		}

	if ( ro_verbose == TRUE )
		{
		fprintf( stderr, "Closing %s ", pd->nm );
		}

	fflush( pd->bf );		/* Flush the stream		*/

	if( fclose( pd->bf ) == ERROR )	/* Close the file		*/
		{
		if ( ro_verbose == TRUE )
			{
			fprintf( stderr, "FAILED! \n" );
			}
		}
	else if ( ro_verbose == TRUE )
		{
		fprintf( stderr, "[O.K.]\n");
		pd->bf = NULL;		/* Set file pointer to NULL	*/
		}
	return( TRUE );			/* Indicate successful completion */
	}

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

ucstr(s)		/*convert s to upper case*/
	char *s;
	{
	while(*s)
		{
		*s = toupper(*s);
		s++;
		}
	}

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

endso() /*called upon EOF to return to previous input file*/
	{
	if ( ro_fptr )
		{
		fclose( instream );
		instream = ro_fstack[ --ro_fptr ];
		}
	ro_binp = 0;
	}

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

dashes()
	{
	fprintf( stderr, "-----------\n");
	}
