#ifndef lint
static char *sccsid = "@(#)tpscript.c	1.8 (UKC) 24/11/88";
#endif  lint

/*
 *	tpscript.c
 *	Troff post-processor for postscript devices
 *
 *	Original program by Stephen Frede (stephenf@elecvax.oz)
 *		Dept. Comp. Sci., University of NSW, Sydney, Australia.
 *					...!seismo!munnari!elecvax!stephenf
 *
 *	Extensive modifications by Cameron Davidson (probe@mm730.uq.oz)
 *				University of Queensland, Brisbane, Australia
 *
 *	Other changes by Michael Rourke (michaelr@elecvax.oz) UNSW.
 */

/* NOTES:
 *
 * Originally, changes to a new font would not take effect until
 * characters from that font were required to be printed, but this
 * means that commands passed through to postscript directly (via \!!)
 * may end up with the wrong font. So now font changes actually happen
 * when requested (or needed in the case of the special font).
 *
 */

/*	The language that is accepted by this program is produced by the new
 *	device independent troff, and consists of the following statements,
 *
 *
 *	sn		set the point size to n
 *	fn		set the typesetter font to the one in position n
 *	cx		output the ASCII character x 
 *	Cxyz		output the code for the special character xyz. This
 *			command is terminated by white space.
 *	Hn		go to absolute horizontal position n
 *	Vn		go to absolute vertical position n ( down is positive )
 *	hn		go n units horizontally from current position
 *	vn		go n units vertically from current position
 *	nnc		move right nn units, then print the character c. This
 *			command expects exactly two digits followed by the
 *			character c.
 *			( this is an optimisation that shrinks output file
 *			size by about 35% and run-time by about 15% while
 *			preserving ascii-ness)
 *	w		paddable word space - no action needed
 *	nb a		end of line ( information only - no action needed )
 *			b = space before line, a = space after line
 *	pn		begin page n
 *	in		stipple as no. from 1 to n (BERK).
 *	P		spread ends -- output it (put in by rsort) (BERK).
 *	# ...\n		comment - ignore.
 *	! ...\n		pass through uninterpreted (LOCAL MOD).
 *	Dt ...\n	draw operation 't':
 *
 *		Dl dx dy		line from here to dx, dy
 *		Dc d		circle of diameter d, left side here
 *		De x y		ellipse of axes diameter x,y, left side here
 *		Da dx1 dy1 dx2 dy2	arc counter-clockwise, start here,
 *					centre is dx1, dy1 (relative to start),
 *					end is dx2, dy2 (relative to centre).
 *		D~ x y x y ...	wiggly line (spline) by x,y then x,y ...
 *		Dt d		set line thickness to d pixels (BERK).
 *		Ds d		set line style mask to d (BERK).
 *		Dg x y x y ...	gremlin (BERK).
 *
 *	x ... \n	device control functions:
 *
 *		x i		initialize the typesetter
 *		x T s		name of device is s
 *		x r n h v	resolution is n units per inch. h is
 *				min horizontal motion, v is min vert.
 *				motion in machine units.
 *		x p		pause - can restart the typesetter
 *		x s		stop - done forever
 *		x t		generate trailer
 *		x f n s		load font position n with tables for 
 *				font s. Referring to font n now means
 *				font s.
 *		x H n		set character height to n
 *		x S n		set character slant to n
 *
 *		Subcommands like i are often spelled out as "init"
 *
 *	Commands marked "BERK" are berzerkeley extensions.
 *
 */

#include	"tpscript.h"

#define	FONTDIR	"/usr/lib/font"		/* where font directories live */

FILE	*Debug = NULL;		/* debugging stream if non-null */
char	*fontdir = FONTDIR;	/* where the fonts live */
char	*ifile = 0;		/* current input file name */
int	lineno,			/* line no. in current input file */
	leftmost=	0x7FFFFFFF,	/* current left margin */
	npages = 0;			/* no. pages printed so far */
char	device[100],		/* device name, eg "alw" */
	errbuf[100];		/* tmp buffer for error messages */
int	hpos = 0,		/* current horizontal position */
	vpos = 0;		/* current vertical position (rel. TOP pg.) */
int	res,			/* resolution in THINGS/inch */
	hor_res,		/* min horizontal movement (in THINGS) */
	vert_res,		/* min vertical movement (in THINGS) */
	respunits;
float	rotation = 0;		/* page orientation (degrees) */
int	currtfont = DEF_FONT,	/* current font number selected by troff */
	papertype = 		/* paper type (different imageable regions) */
#ifdef	ALW
		PT_A4;
#else
		PT_DEFAULT;
#endif
#ifdef LPS
	int blowup = 0;		/* ==1 -> blow up A4 to A3 */
#endif
bool	manualfeed = FALSE;	/* normally auto-feed */

/* due to an obscure bug in ditroff, sometimes no initial 'p' command
 * is generated, so we have to remember if any output has happened
 * to decide if a 'p' causes a page print or not.
 */
bool	firstpage = TRUE;	/* nothing yet printed anywhere */

/* font parameters */
struct	fontparam 
	tfp,		/* current troff font parameters */
	pfp;		/* current postscript font parameters */


/* table of font descriptions */
struct fontdesc 
	*fontd = NOFONTDESC,
	*spcfnt1 = NOFONTDESC,	/* special font */
	*spcfnt2 = NOFONTDESC;	/* special font 2 */

/* font mount table - array of pointers to font descriptions */
struct fontdesc	**fontmount;

/* mapping between troff font names and builtin font names
 * This should go in the internal name part of the font description
 * itself, but there is only 10 bytes allocated (see dev.h).
 * Structure initialised from railmag file by initfonts()
 */
struct fontmap  fontmap[MAXFONTS] = 0;

struct dev	dev;

short	*chartab = NULL;	/* char's index in charname array */
char	*charname = NULL;	/* special character names */
int	ncharname;		/* no. special character names */
int	nfonts = 0;		/* no. of fonts mounted */
int	nfontmount;		/* no. of font mount positions */

	/*
	 * this is the width that the printer will have moved following
	 * the last printed character, if troff then says to move a
	 * different amount we will shift the difference
	 */
int	width_pending	= 0;

bool	word_started	= FALSE;	/* we are in middle of word string */


int		strcmp();
char		*emalloc();
struct fontdesc *findfont();
struct fontmap	*getfmap();

main(argc, argv)
int		argc;
register char	**argv;
{
	register FILE	*istr;
	extern 	double	atof();
#ifdef SPACING
	float		spacing;
#endif SPACING

	strcpy(device, DEF_DEV); /* just in case we get a "Di" before a "DT" */
	argv++;
	while(*argv && **argv == '-')
	{
		char	c;

		(*argv)++;	/* skip the '-' */
		c = **argv;
		(*argv)++;	/* skip the character */
		switch(c)
		{
			case 'D':	/* debug */
				Debug = stderr;
				break;

#ifdef SPACING
			case 'h':
				spacing = atof(*argv);
				break;
#endif SPACING
			case 'r':	/* rotate */
				if(**argv == '\0')
					rotation = 90.0;
				else
					rotation = atof(*argv);
				break;

			case 'S':	/* manual feed */
				manualfeed = TRUE;
				break;

			case 'L':	/* legal paper type */
				papertype = PT_LEGAL;
				break;

			case 't':
				postr = stdout;
				break;

#ifdef LPS
			case 'B':	/* BIG mode - select A3 tray and
					 * blow up by 1.41 in both directions.
					 * Then reduce it on the photocopier.
					 */
				blowup = 1;
				break;
#endif
			default:
				break;
		}
		argv++;
	}

	if (postr == NULL)
	{
#ifdef	GRIS
		postr = popen("exec sendfile -AC -aprinter -dbasser -ugris -e\"-R -qd\" -ntroff-alw", "w");
		if (postr == NULL)
			error(ERR_SNARK, "can't popen spooler");
#else	GRIS
		postr = stdout;
#endif	GRIS
	}

	if(! *argv)
	{
		ifile = "stdin";
		process(stdin);
	}
	else while(*argv)
	{
		if((istr=fopen(*argv, "r")) == NULL)
		{
			sprintf(errbuf,"Can't open input file %s",*argv);
			error(ERR_FATAL,errbuf);
		}
		else
		{
			ifile = *argv;
			process(istr);
			fclose(istr);
		}
		argv++;
	}
	if (postr != stdout)
		exit(pclose(postr));
	else
		exit(0);
	/* NOTREACHED */
}

process(istr)
FILE	*istr;
{
	int	ch;
	char	str[50];
	int	n;
	register int	i;

	lineno = 1;	/* start processing 1st input line */

	while((ch=getc(istr)) != EOF)
	{
			/*
			 * the first switch group can safely be scanned without
			 * having to first ensure the horizontal position is
			 * up to date.
			 */
		switch(ch)
		{
			/* noise */
			case ' ':
			case '\0':
				continue;

			case '\n':
				lineno++;
				continue;

			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				ungetc(ch, istr);
				fscanf(istr, "%2d", &n);

				width_pending -= n;
				hpos += n;

				/* drop through to process the next char */

			case 'c':	/* ascii character */

					/*
					 * if this char and preceeding were
					 * not simply successive chars in the
					 * same word then we need some
					 * horizontal motion to reset position
					 */
				if ( width_pending != 0 )
					hgoto( );

				ch = getc(istr);

				width_pending += GETWIDTH( tfp.fp_font,
					(i = tfp.fp_font->f_fitab[ch - NUNPRINT] ));

				if(ch != ' ')
					putch(tfp.fp_font->f_codetab[i] & BMASK);
				else
					putch(' ');	/* no code for ' ' */
				continue;

			case 'C':	/* troff character */

				if ( width_pending != 0 )
					hgoto( );

				fscanf(istr, "%s", str);
				putspec(str);
				continue;

			case 'h':	/* relative horizontal movement */
				fscanf(istr, "%d", &n);

				/*
				 * we continually accumulate horizontal
				 * motions and all relative requests are
				 * translated into absolute ones.
				 * This avoids accumulation of character
				 * width rounding errors
				 * beyond a single word. (These errors arise
				 * because troff requires widths to be
				 * integral to the unit resolution whereas in
				 * the printer they may be fractional).
				 */

				hpos += n;
				if ( ( width_pending -= n ) != 0 )
					hgoto( );	/* most likely end of word */

				continue;

			case 'w':
				firstpage = FALSE;
				CLOSEWORD();
				continue;

			case 'n':	/* newline */
				fscanf(istr, "%*f %*f");
				width_pending = 0;	/* doesn't matter now */
				continue;

			case 'f':	/* select font no. */
				fscanf(istr, "%d", &n);
				if(n > nfonts || n < 0 || fontmount[n] == NULL)
				{
					sprintf(errbuf, "ERROR: font %d not mounted",
						n);
					error(ERR_WARN, errbuf);
				}
				else
				{
					tfp.fp_font = fontmount[n];
					currtfont = n;
				}
				continue;

			case 's':	/* size in points */
				fscanf(istr, "%d", &n);
				if(n <= 0)
				{
					sprintf(errbuf, "Illegal point size %d\n", n);
					error(ERR_WARN, errbuf);
				}
				else
				{
					tfp.fp_size = n;
					tfp.fp_height = (float) n;
				}
				continue;

			case 'H':	/* absolute horizontal position */

				fscanf(istr, "%d", &hpos);
				hgoto();
				continue;

			case 'V':	/* absolute vertical position */
				fscanf(istr, "%d", &vpos);
				vgoto();
				continue;

			case 'v':	/* relative vertical movement */
				fscanf(istr, "%d", &n);
				vmot(n);
				continue;

		}
			/*
			 * If the input char is in the second group
			 * then we must make sure the printer is positioned
			 * where troff thinks it is
			 * and close any word currently being printed
			 */
		if ( width_pending != 0 )
			hgoto( );
		else
			CLOSEWORD();

		switch(ch)
		{
			case 'x':	/* device control function */
				devcntrl(istr);
				break;

			case 'D':	/* draw */
				draw(istr);
				break;

			case 'p':	/* new page */
				fscanf(istr, "%d", &n);
				page(n);
				break;

			case '#':	/* comment */
				while((ch=getc(istr)) != '\n' && ch != EOF);
				lineno++;
				break;

			case 't':	/* text */
				text(istr);
				break;

# ifdef HASH
			/*
			 * debug - to be manually inserted in input stream if needed
			 * if n >= 0 && n <= HASH_SIZE
			 *	then will print entire hash contents
			 * otherwise will dump just names in hash_tab[n] entry
			 */
			case 'Z':
				fscanf(istr, "%d", &n);
				dumphash( n );
				break;
				
# endif

			case '!':	/* pass through uninterpreted */
				setfont(FALSE);	/* ensure current font is set */
				putc('\n', postr);
				while((ch=getc(istr)) != '\n' && ch != EOF)
					putc(ch, postr);
				break;

			default:
				sprintf(errbuf, "Unknown command '%c'", ch);
				error(ERR_FATAL, errbuf);
		}
	}
}

devcntrl(istr)
FILE	*istr;
{
	char		str[50];
	int		fontn,
			ch;
	float		f;

	fscanf(istr, "%s", str);
	switch(*str)
	{
		case 'i':	/* device initialisation */
			initfonts(device);
			devinit();
			break;

		case 'T':	/* we had better get this before an 'init' */
			fscanf(istr, "%s", device);
			break;

		case 'r':	/* resolution */
			fscanf(istr, "%d %d %d", &res, &hor_res, &vert_res);
			respunits = res / PU_INCH;
			break;

		case 'f':	/* load font */
			fscanf(istr, "%d %s", &fontn, str);
			loadfont(str, fontn);
			break;

		case 's':	/* stop */
			finish(0);
			break;

		case 'p':	/* pause */
			break;

		case 't':	/* trailer */
			break;

		case 'H':	/* character height (in points) */
			fscanf(istr, "%f", &f);
			if(f <= 0 || f > 1000)
			{
				sprintf(errbuf,
					"Illegal character height %.1f", f);
				error(ERR_WARN, errbuf);
			}
			else
				tfp.fp_height = f;
			break;

		case 'S':
			fscanf(istr, "%f", &f);
			if(f < -80 || f > 80)
			{
				sprintf(errbuf, "Illegal character slant %.1f degrees", f);
				error(ERR_WARN, errbuf);
			}
			else
				tfp.fp_slant = f;
			break;

		case 'X':	/* pass through uninterpreted */
			setfont(FALSE);	/* ensure current font is set */
			putc('\n', postr);
			while((ch=getc(istr)) != '\n' && ch != EOF)
				putc(ch, postr);
			/* I've just eaten the newline expected below!
			 * Better return now (after bumping line count)
			 */
			lineno++;
			return;

		case 'o':	/* overlay PostScript file */
			overlay(istr);
			break;

		case 'd':	/* dtf include */
			if (!strcmp(str,"dtf"))
			   { Include_file (istr);
			     break;
			   }
			/* No break here */
		default:
			sprintf(errbuf, "Unknown device control '%s'", str);
			error(ERR_WARN, errbuf);
			break;
	}
	while((ch=getc(istr)) != '\n' && ch != EOF);	/* skip rest of input line */
	lineno++;
}

error(errtype, errmsg)
int	errtype;
char	*errmsg;
{
	switch(errtype)
	{
		case ERR_WARN:
			fprintf(stderr, "Warning");
			break;

		case ERR_FATAL:
			fprintf(stderr, "Error");
			break;

		case ERR_SNARK:
			fprintf(stderr, "Snark");
			break;
	}
	fprintf(stderr, "\t%s pscript input, line %d of '%s'\n",
		errtype == ERR_SNARK ? "at" : "in",
		lineno, ifile);
	if(errmsg && *errmsg)
		fprintf(stderr, "\t%s\n", errmsg);
	if(errtype != ERR_WARN)
		finish(2);
}

finish(status)
int	status;
{
	page(-1);
	pcommfinish(npages, "");
	if(status != 0)
		fprintf(stderr, "\t... aborted processing\n");
	exit(status);
}

/*
 *	Output the postscript "prologue" that is the start of each program
 *	generated. This sets up definitions, sets the scale to be troff
 *	units, etc.
 *	By convention, single character variables are procedure names,
 *	while multi-character variables are local to procedures.
 */

char	*inittab[] = {
	/* initialise current path to non-null */
	"0 0 moveto",
	/* fix to make "joined" lines better */
	"2 setlinecap",
	/* routine for RELATIVE HORIZONTAL RIGHT */
	/* need no more
	"/x { 0 rmoveto } bind def",
	/* routine for RELATIVE VERTICAL DOWN */
	"/y { neg 0 exch rmoveto } bind def",
	/* routine for ABSOLUTE HORIZONTAL (rel left edge page) */
	"/X { currentpoint exch pop moveto } bind def",
	/* routine for ABSOLUTE VERTICAL (rel top of page) */
	"/Y { pgtop exch sub currentpoint pop exch moveto } bind def",
#ifdef	SPACING
	"/s { currentpoint spacing 0 5 -1 roll ashow moveto } bind def",
#else
	"/s { show } bind def",
#endif	SPACING
	"/l { neg rlineto currentpoint stroke moveto } bind def",
	/* circle - arg is diameter.
	 * Current point is left edge
	 */
	"/c {",
	/* save radius and current position */
	"2 div /rad exch def currentpoint /y0 exch def /x0 exch def",
	/* draw circle */
	"newpath x0 rad add y0 rad 0 360 arc stroke",
	/* move to right edge of circle */
	"x0 rad add rad add y0 moveto",
	" } bind def",
	/* Arc anticlockwise, currentpoint is start;
	 * args are dx1, dy1 (centre relative to here)
	 * and dx2, dy2 (end relative to centre).
	 */
	"/a {",
	/* save all parameters */
	"/y2 exch neg def /x2 exch def /y1 exch neg def /x1 exch def",
	/* move to centre, push pos((unsigned)nw);
		fd->f_fitab = emalloc((unsigned)(ncharname+NASCPRINT));
		/* remember if font is special */
		if(f.specfont == 1)
		{
			if(spcfnt1 == NOFONTDESC )
				spcfnt1 = fd;
			else if ( spcfnt2 == NOFONTDESC )
				spcfnt2 = fd;
			else
			{
				sprintf( errbuf,
					"Too many special fonts, %s ignored",
					fd->f_extname );
				error(ERR_WARN, errbuf );
			}
		}

		fm = getfmap(f.namefont);
		if(fm)
		{
			fd->f_intname = fm->fm_intname;
			fd->f_extname = fm->fm_extname;
			fd->f_mounted = TRUE;
		}
		else
			fprintf(stderr, "font name '%s' not known\n",
				f.namefont);

		efread(fd->f_widthtab, sizeof(char), nw, fstr);
		efseek(fstr, 1*nw);	/* skip kern tables */
		efread(fd->f_codetab, sizeof(char), nw, fstr);
		efread(fd->f_fitab, sizeof(char), ncharname+NASCPRINT, fstr);
	}

	fclose(fstr);

	for(i=0; i < nfontmount; i++)
		fontmount[i] = NOFONTDESC;

	/* zeroth font desc entry reserved for "extra" fonts */
	fd = &fontd[0];
	fd->f_intname = "";	/* not NULL */
	fd->f_extname = "";	/* not NULL */
	fd->f_codetab = emalloc((unsigned)MAXCHARS);
	fd->f_fitab = emalloc((unsigned)(ncharname+NASCPRINT));
	fd->f_nent = MAXCHARS;

	/* sentinel fontdesc entry */
	fd = &fontd[nfonts+1];
	fd->f_intname = (char *)NULL;
	fd->f_extname = (char *)NULL;
	fd->f_nent = 0;
	fd->f_codetab = (char *)NULL;
	fd->f_fitab = (char *)NULL;
}

loadfont(extname, fpos)
char	*extname;	/* troff font name */
int	fpos;		/* font position */
{
	register struct fontdesc	*font;

	if(fpos > nfontmount || fpos < 0)
	{
		sprintf(errbuf, "Illegal font mount position %d\n", fpos);
		error(ERR_WARN, errbuf);
		return;
	}
	if ( (font = findfont(extname)) == (struct fontdesc *) NULL )
	{
		sprintf(errbuf, "No such font '%s'\n", extname);
		error(ERR_WARN, errbuf);
		return;
	}
	fontmount[fpos] = font;
}

struct fontmap *
getfmap(extname)
char	*extname;
{
	struct fontmap	*fm;

	fm = fontmap;
	while(fm->fm_intname[0] && strcmp(fm->fm_extname, extname) != 0)
		fm++;
	if(fm->fm_intname[0])
		return(fm);
	else
		return((struct fontmap *)NULL);
}

#ifndef	UQMINMET

struct fontdesc *
findfont(extname)
char	*extname;
{
	struct fontdesc	*fd;

	fd = fontd;
	while(fd->f_intname && strcmp(fd->f_extname, extname) != 0)
		fd++;
	if(fd->f_intname)
		return(fd);
	else
		return((struct fontdesc *)NULL);
}

#else	UQMINMET
		/*
		 * find font including from possible synonym
		 * - use internal name instead of troff name.
		 * troff names need not uniquely correspond to a given
		 * internal name
		 */
struct fontdesc *
findfont(extname)
char	*extname;
{
	struct fontmap	*fm;
	struct fontdesc	*fd;

	if ( (fm = getfmap( extname )) == (struct fontmap *)NULL )
		return((struct fontdesc *)NULL);
	fd = fontd;
	while(fd->f_intname && strcmp(fd->f_intname, fm->fm_intname) != 0)
		fd++;
	if(fd->f_intname)
		return(fd);
	else
		return((struct fontdesc *)NULL);
}
#endif UQMINMET

char *
emalloc(size)
unsigned size;
{
	char		*malloc();
	register char	*s;

	s = malloc(size);
	if(s == NULL)
	{
		sprintf(errbuf, "Malloc failed for %u bytes", size);
		error(ERR_SNARK,errbuf);
	}
	return(s);
}

efread(buf, size, nel, istr)
char	*buf;
int	size,
	nel;
FILE	*istr;
{
	register int n;

	if((n=fread(buf, size, nel, istr)) != nel)
	  fprintf(stderr, "Bad format font file\n");
	return(n);
}

efseek(istr, offset)
FILE	*istr;
int	offset;
{
	if(fseek(istr, (long)offset, 1) != 0)
		fprintf(stderr, "Snark: Bad seek on font file\n");
}


putch(ch)
int	ch;
{
	setfont(FALSE);	/* ensure correct font */

	if ( word_started == FALSE ) {
		word_started = TRUE;
		putc('(', postr);
	}
	pch(ch);
}

#define	NOERR		0
#define	ERR		(-1)
#define	MXTKNLN		255
#define	VALIDCH(s)	(sym!=' ' && sym!='\t' && sym!='\n' && sym!=EOF)

static	char		tknbuf[MXTKNLN+1];
	
char *
Get_token (istr,str,mln)
	  FILE		*istr;
	  char		*str;
	  int		mln;
	  
	  { int		cnt	=	0,
	  		sym;
	  
	    do sym=getc(istr);
	    while (sym==' ' || sym=='\t');
	    while (VALIDCH(sym) && cnt<mln)
	          { str[cnt++]=(char) sym;
	            sym=getc(istr);
	          }
	    if (sym=='\n') ungetc(sym,istr);
	    if (!cnt || (cnt>=mln && VALIDCH(sym)))
	       return ((char *) 0);
	    str[cnt]='\0';
	    return (str);
	  }	/* Gets a token of maximum length "mln" from "istr" */

int
overlay(istr)
	FILE *istr;
	{	FILE *newistr;
		char cpb[BUFSIZ];
		int cnt;

		if (!Get_token(istr,tknbuf,MXTKNLN))
			{ error(ERR_WARN,"Unacceptable overlay file name");
			  return;
			}
		if ((newistr=fopen(tknbuf,"r"))!=NULL)
			{ while((cnt = fread(cpb,1,BUFSIZ,newistr)) > 0)
				fwrite(cpb,1,cnt,postr);
			  fclose(newistr);
			}
	}

int
Include_file (istr)
	     FILE	*istr;

	     { char		*name;
	       FILE		*newistr;
	       int		sln,llx,lly,urx,ury;
	       short		found;

	       if (!Get_token(istr,tknbuf,MXTKNLN-strlen(".ps")))
		  { error(ERR_WARN,"Unacceptable PostScript image file name");
		    return;
		  }
		/* If the file name ends with .dtf, change to .ps */
		/* If it ends in .ps already, do not change it */
	       sln=strlen(tknbuf);
	       if (sln<3 || strcmp(&tknbuf[sln-3],".ps"))
	          { if (sln>3 && !strcmp(&tknbuf[sln-4],".dtf"))
	               name=(&tknbuf[sln-4]);
	               else name=(&tknbuf[sln]);
	            strcpy (name,".ps");
	          }
	       if ((newistr=fopen(tknbuf,"r"))!=NULL)
		  { found=Find_bbox (newistr,&llx,&lly,&urx,&ury);
		    fseek (newistr,0,0);
		    if (Find_bplot (newistr))
		       { fprintf (postr,"\n\nsave\n");
		         fprintf (postr,"%d X\n",leftmost);
		         fprintf (postr,"currentpoint translate\n");
		         fprintf (postr,"10 dup scale\n");
		         if (found)
		            fprintf (postr,"%d %d translate\n",-llx,-ury);
		         Put_psfile (newistr,postr);
		         fprintf (postr,"\nrestore\n");
		       }
		       else { error(ERR_WARN,"Missing %%begin(plot) in PostScript image file");
		              return;
		       	    }
		    fclose (newistr);
		  }
		  else {sprintf(errbuf,"Can't open '%s' (PostScript image file)",tknbuf);
		        error(ERR_WARN,errbuf);
		        return;
		       }
	     }	/* The format of the postscript image file is the same as */
	     	/* the one specified for dvialw, so that we have some */
	     	/* compatibility. */


Put_psfile (istr,ostr)
	   FILE		*istr,
	   		*ostr;
	   
	   { int	ch;
	     short	newline	=	TRUE;
	     long	pos;
	   
	     while ((ch=getc(istr))!=EOF)
		   { if (ch=='\n')
			newline=TRUE;
			else { if (ch=='%' && newline)
			          { pos=ftell(istr);
			            if (Get_token(istr,tknbuf,MXTKNLN) &&
			                !strcmp(tknbuf,"end(plot)"))
			               return;
			               else fseek (istr,pos,0);
			          }
			       newline=FALSE;
			     }
		     putc(ch,ostr);
		   }
	   }

int 
Find_bplot (istr)
	   FILE		*istr;
	   
	   { int	ch;
	     short	newline	=	TRUE;
	   
	     while ((ch=getc(istr))!=EOF)
		   { if (ch=='\n')
			{ newline=TRUE;
			  continue;
			}
		     if (ch=='%' && newline &&
			 Get_token(istr,tknbuf,MXTKNLN) &&
			 !strcmp(tknbuf,"begin(plot)"))
			return (TRUE);
		     newline=FALSE;
		   }
 	     return (FALSE);
	   }

     
int 
Find_bbox (istr,llx,lly,urx,ury)
	   FILE		*istr;
	   int		*llx,*lly,*urx,*ury;
	   
	   { int	ch;
	     short	newline	=	TRUE,
	     		atend	=	FALSE;
	     long	pos;
	   
	     while ((ch=getc(istr))!=EOF)
		   { if (ch=='\n')
			{ newline=TRUE;
			  continue;
			}
		     if (ch=='%' && newline &&
			 getc(istr)=='%' && 
			 Get_token(istr,tknbuf,MXTKNLN) &&
			 !strcmp(tknbuf,"BoundingBox:"))
			{ if (!atend)
			     { pos=ftell(istr);
			       if (Get_token(istr,tknbuf,MXTKNLN) &&
			           !strcmp(tknbuf,"(atend)"))
			          { fseek (istr,-1001,2);
			            atend=TRUE;
			            newline=FALSE;
			            continue;
			          }
			       fseek (istr,pos,0);
			     }
			  if (fscanf(istr,"%d %d %d %d",llx,lly,urx,ury)==4)
			     return (TRUE);
			 }
		     newline=FALSE;
		   }
 	     return (FALSE);
	   }	     

/* CODE MAY BE MISSING HERE DUE TO TAPE READ ERRORS. -martin 28 Oct 04 */
