/* $Log:	dopage.c,v $
 * Revision 0.8  92/11/23  19:46:41  19:46:41  bt (Bo Thide')
 * Fixed resolution bug. Portable downloading. Added/changed options. PJXL color support
 * 
 * Revision 0.7  92/11/13  02:41:25  02:41:25  bt (Bo Thide')
 * More bug fixes and improvements. Support for PaintJet XL
 * 
 * Revision 0.6  92/11/10  21:47:41  21:47:41  bt (Bo Thide')
 * Bug fixes. Added -R option. Better font handling.
 * 
 * Revision 0.5  92/11/09  16:25:28  16:25:28  bt (Bo Thide')
 * Rewrite of dospecial.c. Extended \special support
 * 
 * Revision 0.4  92/11/08  02:45:44  02:45:44  bt (Bo Thide')
 * Changed to portable bit manipulations. Replaced strrstr for non-POSIX compliant C. Fixed numerous bugs. Added support for more \special's.
 * 
 * Revision 0.3  92/08/24  12:45:36  12:45:36  bt (Bo Thide')
 * Fixed 8 bit (dc font) support.
 * 
 * Revision 0.2  92/08/23  17:28:55  17:28:55  bt (Bo Thide')
 * Source cleaned up.  Changed certain function calls.  Removed globals.
 * 
 * Revision 0.1  92/08/22  23:58:47  23:58:47  bt (Bo Thide')
 * First Release.
 *  */

/*
 * This is the main printer dependent output routine, which is organized as
 * a function with side effects. The subroutine is organized as a typical
 * interpreter, with a multiway branch of the command code followed by 'goto'
 * statements leading to branches that finish up the activities common to
 * different commands.  dopage() aborts `dvi2pcl' if something unusual happens.
 *
 * The definition of dvi files refer to six registers, (h,v,w,x,y,z),  which
 * hold integer values in dvi units. In practice, we also need registers hh
 * and vv, the pixel analogs of h and v, since it is not always true that
 * hh = pixel_round(h) or vv = pixel_round(v).
 * The stack of (h,w,w,x,y,z) values is represented by eight arrays called
 * hstack,...,zstack, hhstack and vvstack.
 */

#include <stdio.h>
#include "dvi.h"
#include "globals.h"
#include "macros.h"
#include "pcl.h"

static char rcsid[] = "$Header: dopage.c,v 0.8 92/11/23 19:46:41 bt Exp $";

dopage(bitfile, dvifile, pcllevel, resolution, device)
FILE	*bitfile;
FILE	*dvifile;
short	pcllevel;
short	resolution;
short	device;
{
	unsigned char	o;
	int		k;
	int		hhh, vvv;
	bool		badchar;
	long		hh, vv;
	long		p, q;
	long		hstack[STACKSIZE], vstack[STACKSIZE], wstack[STACKSIZE];
	long		xstack[STACKSIZE], ystack[STACKSIZE], zstack[STACKSIZE];
	int		hhstack[STACKSIZE], vvstack[STACKSIZE];
	charfmt		*c;

	h_posed = v_posed = FALSE;
	s = hh = vv = h = v = w = x = y = z = 0;
	font = NULL;
	while (TRUE) {
		o = getubyte(dvifile);
		if(o >= DVI_SET1)
			p = firstpar(dvifile, o);
#ifdef DEBUG
		fprintf(stderr,"\ndopage: o = %d, p = %ld, hh = %ld", o, p, hh);
#endif
		if(o < DVI_SET1) { 
			c = drawchar(bitfile, o, hh, vv, resolution, device);
			q = c->tfm_width;
			hh += c->pxl_width;
			goto move_right;
		} else
			switch(o) { 
			case DVI_SET1:
			case DVI_SET2:
			case DVI_SET3:
			case DVI_SET4:
				c = drawchar(bitfile, p, hh, vv, resolution,
				  device);
				q = c->tfm_width;
				hh += c->pxl_width;
				goto move_right;
				break;
			case DVI_PUT1:
			case DVI_PUT2:
			case DVI_PUT3:
			case DVI_PUT4:
				drawchar(bitfile, p, hh, vv, resolution,
				  device);
				goto done;
				break;
			case DVI_SET_RULE:
				q = (long)getsquad(dvifile);
				drawrule(bitfile, rulepixels(p, conv),
				  rulepixels(q, conv), hh, vv);
				hh += rulepixels(q, conv);
				goto move_right;
				break;
			case DVI_PUT_RULE:
				q = (long)getsquad(dvifile);
				drawrule(bitfile, rulepixels(p, conv),
				  rulepixels(q, conv), hh, vv);
				goto done;
				break;
			case DVI_NOP:
				goto done;
				break;
			case DVI_BOP:
				fprintf(stderr,"\n'DVI_BOP' occurred before 'DVI_EOP'");
				goto endfalse;
				break;
			case DVI_EOP:
				if(maxpages)
					putc('\014',bitfile);  /* Formfeed */
				if(s)
					fprintf(stderr,"\nStack not empty at end of page");
				return (TRUE);
				break;
			case DVI_PUSH:
				if(s == maxssofar) { 
					maxssofar++;
					if(s ==	maxs)
						fprintf(stderr,"\nDeeper than claimed in postamble");
					if(s == STACKSIZE) { 
						fprintf(stderr,"\nStack capacity exceeded");
					goto endfalse;
					}
				}
				hstack[s] = h;
				vstack[s] = v;
				wstack[s] = w;
				xstack[s] = x;
				ystack[s] = y;
				zstack[s] = z;
				hhstack[s] = hh;
				vvstack[s] = vv;
				s++;
				goto done;
				break;
			case DVI_POP:
				if(s) { 
					s--;
					if(hh != hhstack[s]) h_posed = FALSE;
					if(vv != vvstack[s]) v_posed = FALSE;
					h = hstack[s];
					v = vstack[s];
					w = wstack[s];
					x = xstack[s];
					y = ystack[s];
					z = zstack[s];
					hh = hhstack[s];
					vv = vvstack[s];
				}
				else
					fprintf(stderr,"\nIllegal at level zero");
				goto done;
				break;
			case DVI_RIGHT1:
			case DVI_RIGHT2:
			case DVI_RIGHT3:
			case DVI_RIGHT4:
				goto out_space;
				break;
			case DVI_W0:
			case DVI_W1:
			case DVI_W2:
			case DVI_W3:
			case DVI_W4:
				w = p;
				goto out_space;
				break;
			case DVI_X0:
			case DVI_X1:
			case DVI_X2:
			case DVI_X3:
			case DVI_X4:
				x = p;
				goto out_space;
				break;
			case DVI_DOWN1:
			case DVI_DOWN2:
			case DVI_DOWN3:
			case DVI_DOWN4:
				goto move_down;
				break;
			case DVI_Y0:
			case DVI_Y1:
			case DVI_Y2:
			case DVI_Y3:
			case DVI_Y4:
				y = p;
				goto move_down;
				break;
			case DVI_Z0:
			case DVI_Z1:
			case DVI_Z2:
			case DVI_Z3:
			case DVI_Z4:
				z = p;
				goto move_down;
				break;
			case DVI_FNT_DEF1:
			case DVI_FNT_DEF2:
			case DVI_FNT_DEF3:
			case DVI_FNT_DEF4:
				skipfontdef(dvifile);
				goto done;
				break;
			case DVI_XXX1:
			case DVI_XXX2:
			case DVI_XXX3:
			case DVI_XXX4:
				badchar = FALSE;
				if((long)nextnamesfree - (long)names + p > NAMESIZE )
					prerror("Out of string space during special\n");
				for(k = 0 ; k < (int)p ; k++) { 
					q = (long)getubyte(dvifile);
					if((q < ' ') || (q > '~'))
						badchar = TRUE;
					*(nextnamesfree + k) = (char)q;
				}
				*(nextnamesfree + p) = 0;
				if(badchar)
					fprintf(stderr,"\nNon-ASCII character in xxx command");
				dospecial(bitfile, PRESCAN_OFF, pcllevel, hh,
				  vv, resolution);
				goto done;
				break;
			case DVI_PRE:
				fprintf(stderr,"\nPreamble command within a page");
				goto endfalse;
				break;
			case DVI_POST:
			case DVI_POSTPOST:
				fprintf(stderr,"\nPostamble command within a page");
				goto endfalse;
				break;
			case DVI_UNDEF0:
			case DVI_UNDEF1:
			case DVI_UNDEF2:
			case DVI_UNDEF3:
			case DVI_UNDEF4:
			case DVI_UNDEF5:
				fprintf(stderr,"\nUndefined DVI command %d.",o);
				goto done;
				break;
			default:
				font = fontptr[p];
				gfont = gfontptr[p];
				if(font->down > 0)
					fprintf(bitfile, PCL4_SELECT_FONT, font->down);
				goto done;
				break;
			}
	
out_space:
		if((font == NULL) || (p >= font->space) || (p <= -4*font->space))
			hh = round(conv*(h+p));
		else
			hh += round(conv*p);
		q = p;
		h_posed = FALSE;
move_right:
		hhh = round(conv*(h+q));
		if(abs(hhh - hh) > MAXDRIFT) { 
			h_posed = FALSE;
			hh = hhh > hh ? hhh - MAXDRIFT : hhh + MAXDRIFT;
		}
		h += q;
		if((long)abs(h) > maxhsofar) { 
			if(((long)abs(h) > maxh + 99) && verbose) { 
				fprintf(stderr,"\n|h| > %d\n", maxh);
				maxh = (long)abs(h);
			}
			maxhsofar = (long)abs(h);
		}
		goto done;

move_down:
		if((font == NULL) || ((long)abs(p) >= 5*font->space))
			vv = round(conv*(v+p));
		else
			vv += round(conv*p);
		v_posed = FALSE;
		if((v > 0) &&  (p > 0) && (v > INFINITY-p))
			fprintf(stderr,"Arithmetic overflow.  Parameter changed from %d to %d.", p, p=INFINITY-v);
		if((v < 0) && (p < 0) && (-v > INFINITY+p))
			fprintf(stderr,"\ndopage: Arithmetic overflow.  Parameter changed from %d to %d.", p, p = -(INFINITY+v));
		vvv = round(conv*(v+p));
		if(abs(vvv - vv) > MAXDRIFT)
			vv = vvv > vv ? vvv - MAXDRIFT : vvv + MAXDRIFT;
		v += p;
		if((long)abs(v) > maxvsofar) { 
			if(((long)abs(v) > maxv + 99) && verbose) { 
				fprintf(stderr,"\n|v| > %d.",maxv);
				maxv = (long)abs(v);
			}
			maxvsofar = (long)abs(v);
		}
		goto done;

done:
		;
	}
endfalse: 
	prerror("\n! Bad .pcl file: page ended unexpectedly !\n");
}
