4.4BSD/usr/src/contrib/dipress/src/bin/dipress/ipress.c

Compare this file to the similar file:
Show the results in this format:


/*-----------------------------------------------------------------------------
 * Copyright (c) 1984, 1985, 1986 Xerox Corp.
 *
 *  ipress - most of the code directly dependent on interpress used by dipress
 *	     to produce an interpress file from device independent troff
 *	     intermediate code.  
 *
 *  William LeFebvre
 *
 *
 * HISTORY
 * 12-Aug-86  Lee Moore (lee) at Xerox Webster Research Center
 *	Added positioning option to the RES command.
 *	
 *
 * 07-Jul-86  Lee Moore (lee) at Xerox Webster Research Center
 *	Updated IPDeviceType for services 10.0 .
 *
 * 24-Feb-86  Lee Moore (lee) at Xerox Webster Research Center
 *	Added a subroutine to emit the SequenceInsertFile command.
 *
 * John Mellor-Crummey 28-aug-1985
 *	restructuring and minor modifications
 *
 * ed flint 10-may-1985
 *	coerce device.num_char_wid to unsigned char, change
 *	ch argument in outputChar to unsigned int 
 *	since we now have > 128 special characters
 *---------------------------------------------------------------------------*/


#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <math.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>

#include "deviceinfo.h"	/* typesetter characteristics */

#include "iptokens.h"	/* \					*/
#include "literal.h"	/*  > interface levels for interpress	*/
#include "operator.h"	/* /					*/

#include "defs.h"	/* constant and macro definitions */
#include "externs.h"	/* declarations for global variables */



/* initialize device */
initDevice()		
{
	int  lines = 0;
	int  timapf;
	int  ret;
	register char *ptr;
	register char **ipp;
	register char **trp;
	char temp[60];
	struct stat stbuf;

	if (dbg) printf("initDevice called\n");

	/* start the preamble */
	ip_select(outputfile);
	/* special master instructions go here... */
	AppendOp(OP_beginBlock);
	AppendOp(OP_beginBody);

	/* save scaling transform that uses a mica co-ordinate system */
	AppendRational(1L, 100000);
	AppendOp(OP_scale);
	AppendInteger((long) F_transform);
	AppendOp(OP_fset);

	/* select file that holds page bodies */
	ip_select(pagebodyfile);

	/* open file that maps troff names to interpress names */
	(void) sprintf(temp, "%s/dev%s/interpress-fonts", fontdirectory, devicename);
	if ((timapf = open(temp, O_RDONLY,0)) == -1)
		reportError(QUIT, "can't open %s (%s)", temp, sys_errlist[errno]);

	/* read in the whole thing */
	ret = fstat(timapf, &stbuf);
	if (dbg) printf("stat returned %d, errno %d\n", ret, errno);
	timap = malloc((unsigned)(stbuf.st_size + 1));
	if (dbg) printf("reading %d bytes from timapf\n", stbuf.st_size);
	ret = read(timapf, timap, (int)stbuf.st_size);
	if (dbg) printf("read returned %d, errno %d, timapf %d\n", ret, errno, timapf);
	timap[(int)stbuf.st_size] = '\0';
	(void) close(timapf);

	/* count the newlines */
	if (dbg) printf("pointer starts at %08x ... ", timap);

	for (ptr = timap; *ptr != '\0'; ptr++)
		if (*ptr == '\n') lines++;

	if (dbg) printf("ends at %08x\n", ptr);
	if (dbg) printf("found %d lines\n", lines);

	/* allocate the mapping arrays */
	trp = trname = (char **)malloc((unsigned)(lines * 2 * sizeof(char *)));
	ipp = ipname = trname + lines;

	/* break out the strings and store pointers in the arrays */
	ptr = timap;
	mapcnt = 0;
	while (*ptr)
	{
		if (dbg) printf("loop: ptr = %08x, *ptr = %c\n", ptr, *ptr);
		*trp++ = ptr;
		while (!white(*ptr)) ptr++;
		*ptr++ = '\0';
		while (white(*ptr)) ptr++;
		*ipp++ = ptr;
		while (*++ptr != '\n') /* nothing */;
		*ptr++ = '\0';
		mapcnt++;
	}

	if (dbg)
	{
		int i;

		for (i = 0; i < lines; i++)
			printf("%s\t%s\n", trname[i], ipname[i]);
	}

	/* reset vertical and horizontal positions */
	hor_pos = ver_pos = old_hor = old_ver = 0;

	/* reset the font information */
	bzero((char *) currfonts, sizeof(currfonts));
}

setScale(spi)		/* set resolution */

int spi;

{
	/* set the scaling variable used in all x and y calculations */
	scale = floor(2540.0 / (double)spi + 0.5);
	if (dbg) printf("setScale(%d) sets scale to %e\n", spi, scale);

	/*
	     *  Set the drawing scale based on the scale.  This factor is applied to
	     *	all points drawn in the bitmap for graphical objects.  It is scaled
	     *	down from micas to 508 dpi so that the bitmaps aren't of unwieldy
	     *	size, but still retain enough information to look decent on a good
	     *	device.  508/2540 == 0.2
	     */
	drawscale = scale * .2;
	if (dbg) printf("setScale(%d) sets drawscale to %e\n", spi, drawscale);
}

pushCurrentEnv()	/* begin a new block */
{
	statep->ssize = size;
	statep->sfont = font;
	statep->shorig = hor_orig;
	statep->svorig = ver_orig;
	statep->shpos = hor_pos;
	statep->svpos = ver_pos;
	hor_orig = hor_pos;
	ver_orig = ver_pos;
	hor_pos = ver_pos = 0;
	if (statep++ >= state + MAXSTATE)
	{
		reportError(QUIT, "{ nested too deep");
	}
	hor_pos = ver_pos = 0;
}

popSavedEnv()	/* pop to previous state */
{
	if (--statep < state)
	{
		reportError(QUIT, "extra }");
	}
	size = statep->ssize;
	font = statep->sfont;
	hor_pos = statep->shpos;
	ver_pos = statep->svpos;
	hor_orig = statep->shorig;
	ver_orig = statep->svorig;
}

newpage(n)		/* new page */
int n;
{
	int i;
	char buff[15];

	/* print any pending bitmap */

	/* terminate previous page if outputting */
	if (outputflag)
	{
		print_bitmap();
		AppendOp(OP_endBody);
	}
	else flush_bitmap();

	/* reset vertical positions */
	ver_pos = old_ver = 0;

	/* check new page number against those found in the nPageRanges */
	if (nPageRanges == 0)
	{
		/* no -o specified -- do all pages */
		outputflag = 1;
	}
	else
	{
		/* see if new page has been selected for output */
		outputflag = 0;
		for (i = 0; i < nPageRanges; i++)
		{
			if ((n >= pagerange[i][0]) && (n <= pagerange[i][1]))
			{
				outputflag = 1;
				break;
			}
		}
	}

	/* start new page */
	if (outputflag)
	{
		AppendOp(OP_beginBody);
		(void) sprintf(buff, "Page %d", n);
		AppendComment(buff);
		Fget(F_transform);
		AppendOp(OP_concatt);
		AppendInteger(2L);
		AppendInteger((long) I_strokeEnd);
		AppendOp(OP_iset);
	}

	/* font/size no longer valid -- force a new assignment */
	oldftsz = -1;
}

newLine()		/* new line (no vertical motion implied) */
{
	if (dbg == 3)
		putchar('\n');
	flushbuff();
	endcorrect();
	hor_pos = 0;
	virgin_line = 1;
}

internalSize(number)		/* convert integer to internal size number */
int number;
{
	int index;

	if (number >= pointsizeTab[device.num_sizes - 1])
	{
		/* larger than largest -- use largest */
		return(device.num_sizes-1);
	}
	else if (number <= pointsizeTab[0])
	{
		/* smaller than smallest -- use smallest */
		return(0);
	}

	/* else find the size in pointsizeTab and return index */
	for (index = 0; number > pointsizeTab[index]; index++);
	return(index);
}





/* handle device stop command */
resetDevice()		
{
	int amt;
	static int is_reset = 0;
	char bigbuff[1024];

	if (is_reset) return; /* ignore multiple resets */

	print_bitmap();

	/* this is the absolute last thing that we do */
	/* wrap up the preamble and the body */
	ip_select(outputfile);
	AppendOp(OP_endBody);
	ip_select(pagebodyfile);		
	AppendOp(OP_endBody);
	AppendOp(OP_endBlock);
	ip_close();			/* close the body */

	/*
	     *  Reopen the body and copy it onto the end of the real file (which is
	     *	where we have been building the preamble).  We don't need to ip_flush
	     *	the preamble since that is done everytime we ip_select the body.
	     *	Conveniently enough, "tempfilename" still holds the name of the body
	     *	temporary.
	     */
	pagebodyfile = open(tempfilename, O_RDONLY,0);
	while ((amt = read(pagebodyfile, bigbuff, sizeof(bigbuff))) != 0)
	{
		(void) write(outputfile, bigbuff, amt);
	}

	/* close and unlink the body temporary file */
	(void) close(pagebodyfile);
	(void) unlink(tempfilename);

	/* send the file off to the printer */
	tempfilename[strlen(tempfilename) - 1] = '\0';
	if (outputfile != 1)
	{
		IPprint(tempfilename);
	}

	/* we are now reset */
	is_reset = 1;
}

outputString(character)		/* print a "funny" character */
char *character;
{
	int i;

	if (!outputflag)
		return;
	if (dbg > 2) printf("\\(%s", character);
	if (dbg > 3) putchar(' ');
	for (i = 0; i < device.spec_char_num; i++)
		if (strcmp(&specCharStrTab[specCharTab[i]], character) == 0)
			break;
	if (i < device.spec_char_num) {
		/*	printf(" i = %d so i+128 = %d\n", i, i+128);	*/
		outputChar((unsigned int) i + 128);
	}
	else {
		if (dbg > 3)
			printf("-- character not found");
	}

	if (dbg > 2)
		putchar('\n');
}

outputChar(character)		/* put a character */
unsigned int character;
{
	unsigned char *widp;	/* pointer to appropriate width table */
	register char *codep;	/* pointer to appropriate table of codes */
	register int i, old_font, fnt_index;
	int j, value;

	if (!outputflag)
		return;

	if (character <= 32)
	{
		if (dbg) printf("non-existent character 0%o\n", character);
		charw = charWidthTab[font][0] * pointsizeTab[size-1] / device.width_units;
		return;
	}
	character -= 32;

	old_font= font;
	i = fontIndexTab[font][character] & 255;
	if (i != 0)				/* it's on this font */
	{
		codep = charCodeTab[font];
		widp = charWidthTab[font];
	}
	else if (specFontPos > 0)			/* on special (we hope) */
	{
		/* assertion:  i == 0 */
		fnt_index= specFontPos;
		for (j=0; j <= device.num_fonts; j++)
		{
			struct font_entry *fb;

			fnt_index= (fnt_index+1) % (device.num_fonts+1);

			if ((fb = fontPtr[fnt_index]) != NULL)
			{
				if (fb->special_flag && (i = fontIndexTab[fnt_index][character] & 255) != 0)
				{
					codep = charCodeTab[fnt_index];
					widp = charWidthTab[fnt_index];
					setFont(fnt_index);
					break;
				}
			}
		}
		/* assertion:  if j > device.num_fonts then i == 0 and character was not found */
	}

	value= codep[i] & 255;

	if (i == 0 || value == 0)
	{
		if (dbg) printf("character not found 0%o\n", character+32);
		return;
	}

	/* remember this character's width */
	/* This MUST be done before calling showchar */
	charw = (widp[i] * pointsizeTab[size-1] + device.width_units/2) / device.width_units;
	if (dbg == 3)
	{
		if (isprint(character+32))
			putchar(character+32);
	}
	if (dbg > 3)
	{
		if (isprint(character+32))
			printf("character %c %d\n", character+32, value);
		else
			printf("character %03o %d\n", character+32, value);
	}

	if (value == 0377)
	{
		/* special escape to an extended code */
		value = getexcode(i);
	}

	if (dbg < 6)
		showchar(value);

	if (font != old_font)
	{
		setFont(old_font);
	}
}


/*
 * set point size to n
 */
setPointSize(n)

int n;			/* internal value:  index into pointsizeTab */

{
	size = n;
	ftsz = ((long)font << 16) | ((long)size);
}


/*
 * set the current font to number
 */
setFont(n)

int n;			/* internal index */

{
	font = n;
	ftsz = ((long)font << 16) | ((long)size);
}


/*
 *	reportError	an error reporting hack that uses dummy parameters 
 *			as place holders for arguments that may or may not 
 *			exist, fprintf will sort out how many should be there
 */
/*VARARGS 2*/
reportError(f, s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) 
char *s, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7, *arg8;
{
	fprintf(stderr, "dipress: ");
	fprintf(stderr, s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
	fprintf(stderr, "\nerror encountered near line %d\n", linenumber);
	if (f == QUIT) goodbye();
}




/*
 *  Graphics drawing primitives.  These use the vector drawing capabilities of
 *  interpress to draw straight lines.  All other primitive objects (circle,
 *  ellipse, etc.) are built in a bitmap and printed with a pixel vector.
 */

drawline(dh, dv)
int dh,dv;
{

	if(!outputflag) return;
	AppendInteger((long) curr_strokewidth);
	AppendInteger((long) I_strokeWidth);
	AppendOp(OP_iset);
	Moveto(xloc(hor_pos), yloc(ver_pos));
	hor_pos += dh;
	ver_pos += dv;
	Lineto(xloc(hor_pos), yloc(ver_pos));
	AppendOp(OP_maskstroke);
}

/* routines used by interpress dependent routines */

char showbuff[Showbuff_size + 1];
char *showp = showbuff;
int  showcnt = 0;

showchar(ch)		/* buffer "ch" for use in a "show" command */
int ch;
{
	char *framep;
	register int hdiff, vdiff;

	/* set correct position */
	vdiff = ver_pos - old_ver;
	hdiff = hor_pos - old_hor;
	if (dbg > 4)
	{
		printf("old_hor %d, hor_pos %d, hdiff %d;  old_ver %d, ver_pos %d, vdiff %d %s\n",
		old_hor, hor_pos, hdiff, old_ver, ver_pos, vdiff,
		virgin_line ? "(virgin)" : "");
	}

	/* NOTE:  this expression depends on boolean true being 1! */
	/* See K&R, Appendix A, section 7.7, page 190 */
	switch (((vdiff != 0) << 1) | (hdiff != 0))
	{
	case 0:		/* no change */
		break;
	default:
		flushbuff();
		Setxy(xloc(hor_pos), yloc(ver_pos));
		break;
	}

	/*
	     *  Update old_hor and old_ver.  Account for character width in old_hor but not in
	     *	hor_pos.  If the next hInc call is for the width of the character, the
	     *	next time showchar gets called, old_hor will equal hor_pos.
	     */
	old_ver = ver_pos;
	old_hor = hor_pos + charw;

	/* line is no longer virgin */
	virgin_line = 0;

	/* font and point still the same? */
	if (ftsz != oldftsz)
	{
		flushbuff();
		if ((framep = currfonts[font]->frames) == NULL)
		{
			/* previously unused -- give it a frame table */
			framep = currfonts[font]->frames = malloc((unsigned)(device.num_sizes * sizeof(char)));
			bzero(framep, device.num_sizes * sizeof(char));
		}

		if (framep[size] == 0)
		{
			/* make a new font */
			ip_select(outputfile);
			SetupFont(currfonts[font]->uname,
			floor(pointsizeTab[size-1] * 35.28 + .5),
			frameindex);
			ip_select(pagebodyfile);
			framep[size] = frameindex++;
		}

		/* switch to new font/size combo */
		Setfont(framep[size]);
		oldftsz = ftsz;
	}

	/* adjust for character codes > 0377 */
	if (ch > 0377)
	{
		if (dbg > 4)
		{
			printf("processing large code: 0%o (%d)\n", ch, ch);
		}

		if (showcnt + 5 > Showbuff_size)
		{
			flushbuff();
		}
		*showp++ = '\377';
		*showp++ = (ch & 0177400) >> 8;
		*showp++ = ch & 255;
		*showp++ = '\377';
		*showp++ = '\0';
		showcnt += 5;
	}
	else
	{
		*showp++ = ch;
		if (++showcnt > Showbuff_size)
		{
			flushbuff();
		}
	}
}

/*
 *  getexcode(findex) - get the extended code for the character "findex"
 */

getexcode(findex)
int findex;
{
	register int extfd;
	register int i;
	register unsigned short *tab;
	char temp[132];

	if (dbg > 4)
	{
		printf("getexcode(%d)\n", findex);
	}

	if ((tab = currfonts[font]->extab) == NULL)
	{
		/* load in the extended code table */

		(void) sprintf(temp, "%s/dev%s/%s.out.ext",
		fontdirectory, devicename, currfonts[font]->name);
		if (dbg > 4)
		{
			printf("opening and reading %s\n", temp);
		}
		if ((extfd = open(temp, O_RDONLY,0)) == -1)
		{
			reportError(CONTINUE, "can't open %s (%s)", temp, sys_errlist[errno]);
			return(0);
		}
		currfonts[font]->extab = tab = (unsigned short *)
			malloc( (unsigned)(i = (device.spec_char_num + 128-32) * sizeof(short)) );
		(void) read(extfd, (char *)tab, i); /* should test result! */
		(void) close(extfd);
	}

	if (dbg > 4)
	{
		printf("getexcode returning %.7o\n", tab[findex]);
	}
	return(tab[findex]);
}

flushbuff()		/* flush and reset "showbuff" */
{
	if (showcnt == 0)
		return;

	if (!in_correct)
	{
		startcorrect();
	}

	/* we must do the append_Sequence explicitly, */
	/* because showbuff might have nulls in it.   */
	append_Sequence(sequenceString, showcnt, (unsigned char *)showbuff);
	AppendOp(OP_show);
	showp = showbuff;
	showcnt = 0;
}

int hstart;

startcorrect()
{
#ifdef CORRECT_BLOCKS
	AppendOp(OP_correct);
	AppendOp(OP_beginBody);
#endif
	in_correct = 1;
	hstart = hor_pos;
}

endcorrect()
{
	/* append a Setcorrectmeasure operation */
	/* "hor_pos" or "old_hor"???  Make it "old_hor" for now */
#ifdef CORRECT_BLOCKS
	Setcorrectmeasure(xloc(old_hor), 0.0);
	AppendOp(OP_endBody);
#endif
	in_correct = 0;
}

/*
 *  IPprint(filename) - send the file "filename" to the interpress printer.
 *			 This routine is *very* dependent on local
 *			 environments.
 */

IPprint(filename)
char *filename;
{
	if (dbg)
	{
		printf("interpress file saved in %s.\n", filename);
		return;
	}

	if (vfork() == 0)
	{
		/* is child */
		execl("/usr/local/bin/qip", "qip", "-nc", "-nk", filename, 0);
		exit(1);
	}
}

/* bitmap graphics object sizing functions */

g_sizearc(x1, y1, xc, yc, x2, y2)
int x1, y1, xc, yc, x2, y2;
{
	int minx;
	int miny;
	int maxx;
	int maxy;
	int quad1;
	int quad2;
	int radius;
	int axc;
	int ayc;
	int i;

	/* the center and the second point are offsets from the first */
	/* calculate actual center and radius */
	axc = x1 + xc;
	ayc = y1 + yc;
	radius = (int)(hypot((double)xc, (double)yc) + .5);
	if (dbg > 1)
	{
		printf("g_sizearc(%d, %d, %d, %d, %d, %d): radius is %d\n",
		x1, y1, xc, yc, x2, y2, radius);
	}

	/* preset the minmal and maximal points -- this is our first guess */
	if ((minx = x1 + xc + x2) > x1)
	{
		maxx = minx;
		minx = x1;
	}
	else
	{
		maxx = x1;
	}
	if ((miny = y1 + yc + y2) > y1)
	{
		maxy = miny;
		miny = y1;
	}
	else
	{
		maxy = y1;
	}

	/* calculate the offset from the center to the first point */
	x1 = -xc;
	y1 = -yc;		/* now all three arguments are offsets */

	/* calculate the quadrant of each endpoint */
	quad1 = quadrant(x1, y1);
	quad2 = quadrant(x2, y2);
	if (dbg > 1)
	{
		printf("(%d, %d) in quadrant %d ... ", x1, y1, quad1);
		printf("(%d, %d) in quadrant %d\n", x2, y2, quad2);
	}

	/* insure that quad1 < quad2 */
	if (quad2 < quad1)
	{
		quad2 += 4;
	}

	/* compensate for arc at each quadrant boundary */
	for (i = quad1 + 1; i <= quad2; i++)
	{
		switch (i & 3)
		{
		case 0:		/* 1st quadrant */
			maxx = axc + radius;
			break;

		case 1:		/* 2nd quadrant */
			miny = ayc - radius;
			break;

		case 2:		/* 3rd quadrant */
			minx = axc - radius;
			break;

		case 3:		/* 4th quadrant */
			maxy = ayc + radius;
			break;
		}
	}

	/* now set the extremes */
	if (dbg > 1)
	{
		printf("extremes are %d, %d, %d, %d\n", minx, miny, maxx, maxy);
	}
	gobj_size(minx, miny, maxx, maxy);
}

quadrant(dx, dy)
int dx,dy;
{
	register int yplus;

	yplus = dy > 0;
	if (dx > 0)
	{
		return(yplus ? 3 : 0);
	}
	else
	{
		return(yplus ? 2 : 1);
	}
}


g_sizeWigglyLine(str)
char *str;
{
	int minx;
	int miny;
	int maxx;
	int maxy;
	int currx;
	int curry;
	int incx;
	int incy;

	currx = minx = maxx = hor_pos;
	curry = miny = maxy = ver_pos;

	while(white(*str)) str++; /* trim leading white space */

	while (*str)
	{

		(void) readNumber(&str,&incx);
		(void) readNumber(&str,&incy);
		currx += incx;
		curry += incy;
		if (currx > maxx)
			maxx = currx;
		else if (currx < minx)
			minx = currx;
		if (curry > maxy)
			maxy = curry;
		else if (curry < miny)
			miny = curry;
	}
	gobj_size(minx, miny, maxx, maxy);
}


/*
 * Request the insertion of an Interpress master
 */

doSequenceInsertIP(fileName)
char *fileName; {
	AppendOp(OP_dosavesimplebody);
	AppendOp(OP_beginBody);
	/* set the IP position at the current troff position */
	Setxy(xloc(hor_pos), yloc(ver_pos));

	/* undo the Troff scaling */
	AppendRational(spotsPerInch*10000L, 254L);
	AppendOp(OP_scale);
	AppendOp(OP_concatt);
	AppendOp(OP_trans);

	AppendInsertFile(fileName);
	AppendOp(OP_endBody);
}


#define SAME	0

/*
 * define frame variables for the RES image
 */
#define IMAGE_EDIT	47L
#define IMAGE_COLOR_OP	46L
#define IMAGE_COLOR	45L
#define IMAGE_MASK	44L
#define IMAGE_Y		43L
#define IMAGE_X		42L
#define IMAGE_SCALE	41L

/*
 * Request the insertion of an RES file
 */

doSequenceInsertRES(anchor, resolutionString, fileName) 
char *anchor,
     *resolutionString,
     *fileName; {
	int resolution;

	resolution = atoi(resolutionString);

	AppendOp(OP_dosavesimplebody);
	AppendOp(OP_beginBody);
	/* set the IP position at the current troff position */
	Setxy(xloc(hor_pos), yloc(ver_pos));

	AppendInsertFile(fileName);

	/* pop and store */
	AppendOp(OP_pop);		/* for now, don't check the signature */
	AppendInteger(IMAGE_EDIT);
	AppendOp(OP_fset);
	AppendInteger(IMAGE_COLOR_OP);
	AppendOp(OP_fset);
	AppendInteger(IMAGE_COLOR);
	AppendOp(OP_fset);
	AppendOp(OP_pop);			/* discard mask image */
	AppendInteger(IMAGE_Y);
	AppendOp(OP_fset);
	AppendInteger(IMAGE_X);
	AppendOp(OP_fset);
	AppendInteger(IMAGE_SCALE);
	AppendOp(OP_fset);

	/* undo the Troff scaling */
	AppendRational(spotsPerInch*10000L, 254L);
	AppendOp(OP_scale);

	/* set the resolution */
	if( resolution != 0 ) {
		/* display the RES file at the specified resolution */
		AppendRational(254L, resolution*10000L);
		AppendOp(OP_scale); }
	else 
		/* get the default scale from the RES file */
		/* can the device do a "get" operator? */
		if( IPDeviceType == Xerox8044_Services8  ||
		    IPDeviceType == Xerox8044_Services9  ||
		    IPDeviceType == Xerox8044_Services10 )
			reportError(CONTINUE, "requested device can't read resolution from an RES file");
		else {
			/* Yes!  Use the imageScale suggested by the image */
			Fget(IMAGE_SCALE);
			Get(1L);
			Fget(IMAGE_SCALE);
			Get(2L);
			AppendOp(OP_scale2); }

	AppendOp(OP_concat);		/* concat undo-scale with image scale */

	if( strcmp(anchor, "bl") == SAME )		/* bottom left */
		;
	else if( strcmp(anchor, "tl") == SAME ) {	/* top left */
		AppendInteger(-1L);		/* invert scale */
		AppendOp(OP_scale);
		AppendOp(OP_concat);
		AppendOp(OP_concatt);

		FGet(IMAGE_Y);
		AppendOp(OP_setyrel);

		AppendInteger(-1L);
		AppendOp(OP_scale);
	}
	else if( strcmp(anchor, "c") == SAME ) {	/* center */
		AppendRational(-1L, 2L);
		AppendOp(OP_scale);
		AppendOp(OP_concat);
		AppendOp(OP_concatt);	/* half normal scale for centering */

		FGet(IMAGE_X);
		FGet(IMAGE_Y);
		AppendOp(OP_setxyrel);

		AppendRational(-2L, 1L);
		AppendOp(OP_scale);
	}
	else if( strcmp(anchor, "br") == SAME ) {	/* bottom right */
		AppendInteger(-1L);		/* invert scale */
		AppendOp(OP_scale);
		AppendOp(OP_concat);
		AppendOp(OP_concatt);

		FGet(IMAGE_X);
		AppendOp(OP_setxrel);

		AppendInteger(-1L);		/* invert scale */
		AppendOp(OP_scale);
	}
	else if( strcmp(anchor, "tr") == SAME ) {	/* top right */
		AppendInteger(-1L);		/* invert scale */
		AppendOp(OP_scale);
		AppendOp(OP_concat);
		AppendOp(OP_concatt);

		FGet(IMAGE_X);
		FGet(IMAGE_Y);
		AppendOp(OP_setxyrel);

		AppendInteger(-1L);		/* invert scale */
		AppendOp(OP_scale);
	}
	else
		reportError(CONTINUE, "unknown position in RES command: %s", anchor );

	AppendOp(OP_concatt);

	AppendOp(OP_trans);

	FGet(IMAGE_COLOR);
	AppendOp(OP_maskpixel);
	AppendOp(OP_endBody);
}