[net.sources.mac] MacDraw to Imagen program, 1 of 2

weber@brand.UUCP (Allan G. Weber) (12/19/85)

This is part 1 of 2 of my MacDraw to imPress program for printing MacDraw
pictures on Imagen laser printers.

Allan Weber
USC Signal and Image Processing Institute
Arpa:	Weber%Brand@USC-ECL
Usenet:	...sdcrdcf!oberon!brand!weber

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	Makefile
#	drawimp.h
#	macdraw.info
#	drawimp.c
#	drawimp.man
#	error.c
#	impress.c
#	machint.s
#	pxl.c
# This archive created: Wed Dec 18 15:12:15 1985
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
		    README for drawimp distribution

			 Last edit: 18-Dec-85

This is the fourth version of the MacDraw to Impress program, "drawimp".
The program is used to convert a MacDraw picture to a close approximation
that will print on an Imagen laser printer.  The following things have not
been implemented yet but hopefully will be eventually.

	Smoothed polygons
	PICT objects from MacPaint
	Clipping of objects that cross 8x10 inch page boundaries
	Rotated, centered, or flushed-right text

Various notes about the program (in no particular order):

1.  The file patterns.c contains the data for the 36 patterns available for
filling and drawing in MacDraw.  Some of the patterns that represent a 1/2
or 1/4 density grey level have been entered at the higher resolution level
so the pattern will look different than that from a MacPaint image.  The
patterns are also slightly smaller than they should be since they have been
expanded by a factor of 4 whereas the rest of the image has been expanded by
about 4.17.  Because of this, any image that relies on the phase of the
pattern being correct at some point in the image will not come out right.

2.  Impress on the 8/300 has a limit of 14 patterns that can be downloaded,
not counting clear, white, and black.  It is up to the user to make sure the
picture does not exceed this limit.

3.  The file impress.c contains functions to output the Impress command
strings.  So far it only contains the function needed by drawimp, others
will be added when required.

4.  The text output uses the fonts supplied with the Unix TeX distribution.
If you don't have the TeX "am" fonts, it probably won't work.  The program
will look for fonts in the directory pointed to by the environment variable
TEXFONTS.  If TEXFONTS is not defined, it will use the default path specifed
in pxl.h.

6.  The routines for handling the text fonts were taken from the Imagen
driver supplied with the Unix Tex distribution.  These files (including one
VAX machine language routine) may not be too portable to other non-VAX
systems.  The rest of drawimp should run on non-VAX systems with few
changes.  The program can be run without the text routines by defining
NO_TEXT in drawimp.c and linking just drawimp.o, patterns.o, and impress.o:
	% cc -o drawimp -DNO_TEXT drawimp.c patterns.o impress.o -lm

7.  Currently all MacDraw fonts default to the same times-roman type of TeX
font.  Bold and Italic are supported as are most of the special characters
that can be printed with one character (no vowels with accent marks, etc.).
The selection of which character to use for each MacDraw character is done
in mactext.c and can be changed to suit individual tastes.  

8.  The TeX characters are slightly different sizes than the Mac characters
so text strings will not come out the same length.  Things like tables where
it is necessary to line things up should be done with multiple short text
strings on each line rather than one long line that uses spaces or tabs to
achieve the alignment.  I recommend using the New York font when putting
text in the drawing since it appears to be the closest in size and will give
the best approximation to the correct length of text strings.

8.  IMPORTANT!  Check the font filename definitions at the beginning of
mactext.c to make sure the font files that will be required are on the
system.  The parameters in the tables can be changed to match existing font
files.  It's all documented in mactext.c near the tables.  The way fonts are
specified is a bit crude but it works.

9.  The -t option is used to generate imPress files that do not have a
header and is used for drawings that are to be included in a LaTex document.
This allows one to print a LaTeX document on the Imagen, complete with
figures, so as to avoid doing any cutting and pasting afterwards.  The
results generally look great and we have high hopes it.  However, the
process is still being fine-tuned so I haven't included any of the software
for combining LaTeX and MacDraw output files.  If somebody is really
desperate to do this, let me know and I'll send what we have.

10.  Some changes in the user interface (by popular demand) since the last
version.  Drawimp now accepts multiple input files and will process them one
after the other to create a single output stream.  The imPRESS data will
have ENDPAGE commands separating the data from different files.  Input from
stdin is no longer supported.  In normal mode, all output goes to stdout (-o
option has been removed).  The -d option now causes the debugging
information to be written to stderr, and does not inhibit the imPRESS output
from being written to stdout.  If all you want is a list of objects in the
file, use "drawimp -d myfile.data >/dev/null".

999.  Please send any question, comments or bug reports to me at one of the
addresses shown below.  Note that this is a different address than where I
was for the previous distributions.

Allan Weber
USC Signal & Image Processing Institute
Powell Hall 306, MC-0272
Los Angeles, CA 90089
(213) 743-5519

Arpa:	Weber%Brand@USC-ECL
Usenet: ...sdcrdcf!oberon!brand!weber
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
drawimp:  drawimp.o impress.o patterns.o mactext.o textimp.o pxl.o scaletfm.o error.o machint.o
	cc -o drawimp drawimp.o impress.o patterns.o mactext.o textimp.o pxl.o scaletfm.o error.o machint.o -lm

drawimp.o:   drawimp.c drawimp.h
impress.o:   impress.c
patterns.o:  patterns.c
mactext.o:   mactext.c drawimp.h
textimp.o:   textimp.c pxl.h types.h drawimp.h
pxl.o:       pxl.c pxl.h
scaletfm.o:  scaletfm.c pxl.h types.h
error.o:     error.c
machint.o:   machint.s
SHAR_EOF
fi # end of overwriting check
if test -f 'drawimp.h'
then
	echo shar: will not over-write existing file "'drawimp.h'"
else
cat << \SHAR_EOF > 'drawimp.h'
/*
	This is an include file for the MacDraw file reading program.
	Some of the structs are not really used but are here to show the
	way data is stored in the file.
	In the structs, char = 1 byte, short = 2 bytes.

	Allan Weber (Weber%Brand@USC-ECL)
	USC Signal and Image Processing Institute

	Last edit: 5-Dec-85
*/

#define DEF_RES		300		/* default Imagen resolution */
#define	H_SHIFT		18		/* shifts to center page on paper */
#define	V_SHIFT		36
#define TEXTURE_FAMILY	95
#define FONT_FAMILY_TOP	(TEXTURE_FAMILY - 1)
#define	TEMP_PREFIX	"/tmp/McDXXXXXX"
#define TEX_EXT		".imp"		/* file extension for LaTex files */
#define MAC_EXT		".data"		/* file extension for MacDraw file */

#define	MAC_H_SIZE	576
#define MAC_V_SIZE	720
#define MAC_H_PAGES	12
#define MAC_V_PAGES	5
#define	HEADER_SIZE	512
#define	ARROW_ANGLE	15

/*
The following #define values relate to the different attributes used by
MacDraw for various objects.
*/

/* Text style */
#define	PLAIN		0
#define BOLD		1
#define	ITALIC		2
#define	UNDERLINE	4
#define	HOLLOW		8
#define	SHADOW	       16

/* Font type */
#define CHICAGO		1
#define GENEVA		2
#define	NEW_YORK	3

/* Font size */
#define	SIZE_9		1
#define SIZE_10		2
#define	SIZE_12		3
#define	SIZE_14		4
#define	SIZE_18		5

/* Text spacing */
#define	SINGLE		1
#define THREE_HALF	2
#define	DOUBLE		3

/* Text alignment */
#define	LEFT		1
#define	CENTER		2
#define	RIGHT		3

/* Line width */
#define LINE_0		1
#define	LINE_1		2
#define	LINE_2		3
#define	LINE_4		4
#define	LINE_6		5

/* Arrow direction */
#define NO_ARROW	0
#define	RIGHT_ARROW	1
#define	LEFT_ARROW	2
#define	BOTH_ARROW	3

/*
The following structs are for various data structures used in the
MacDraw data records.
*/

struct lcoord {		/* long coordinate - radix point between halves */
	unsigned short i,f;
};

struct lpoint {		/* long point */
	struct lcoord v,h;
};

struct lrect {		/* long rectangle */
	struct lcoord top, left, bottom, right;
};

struct srect {		/* short rectangle */
	short top, left, bottom, right;
};

struct frect {		/* float rectangle */
	float top, left, bottom, right;
};

struct bpoint {	/* incremental point */
	char x,y;
};

/*
The following are structs for the data records.
Fields with unknown purposes are named Z1, Z2, etc.
*/

struct MDheader {	/* record header for each object */
	char code;
	char Z1,Z2,Z3;
	char line;
	char pen;
	char fill;
	char special;
};

struct MDtext {		/* Text record */
	short Z1,Z2;
	char style;
	char font;
	char size;
	char spacing;
	char alignment;
	char angle;
	short count;
	struct srect rect;
};

struct MDvector {	/* Vector record (right angle and sloped) */
	struct lpoint start, stop;
};

struct MDbox {		/* Rectangle, Ellipse, and RoundRect record */
	struct lrect rect;
};

struct MDarc {		/* Arc record */
	struct lrect rect;
	unsigned short start, angle;
};

struct MDgroup {	/* Group identifier record */
	struct lrect rect;
	unsigned short Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8;
};

struct MDpolygon {	/* Polygon record */
	unsigned short Z1;
	unsigned short rec_size;
	unsigned short points;
	struct lrect rect;
	char closed;
	char Z2;
};

struct MDcurve {	/* Curve record */
	unsigned short Z1;
	unsigned short rec_size;
	unsigned short points;
	struct lrect rect;
	char closed;
	char Z2;
	struct lpoint start;
};

#define MAX_RECORD 40
SHAR_EOF
fi # end of overwriting check
if test -f 'macdraw.info'
then
	echo shar: will not over-write existing file "'macdraw.info'"
else
cat << \SHAR_EOF > 'macdraw.info'
	MacDraw data file information

	Allan Weber (Weber@USC-ECLC)
	USC Signal and Image Processing Institute

	Last edit: 16-Dec-85

This file contains a description of the data records produced by "Macdraw
Version 1.7 3/18/85".  Some of the information in the data records has not
yet been deciphered and is indicated below by question marks.

Note:  Many of the data structures for points and rectangles use 4-byte
"fixed-point numbers" instead of the normal 2-byte integers.  Fixed-point
numbers are described in "Inside Macintosh", page MI-11.  They are similar
to integers with the addition of a 2-byte fractional part, thus yielding a
number with the same range but greater precision.


A MacDraw file starts with a 512 byte header.  There does not appear to be
any information in the header required for recreating the image on a device
like a laser printer.  

			File header (512 bytes)

Offset
0..213		?
214..229	Enclosing rectangle for entire drawing (Fixed-point)
230..511	?



After the file header is a sequence of data records, one for each object in
the image.  Each object data record starts with an 8-byte record header,
followed in most cases by varible length object dependent data.  The first
byte in each of the record headers indicates the type of object.  At the end
of the file is a terminator (type 0) record.


		       Record header (8 bytes)

Offset
0	code 	0 = terminator		1 = text
		2 = right angle vector	3 = sloped vector
		4 = rectangle		5 = round rectangle
		6 = ellipse		7 = arc
		8 = curve		9 = polygon
		10= group	       11 = PICT data (from MacPaint)
1	lock	0 = unlocked, 1 = locked
2	?
3	?
4	line	width code:  1 = 0 pixels, 2 = 1 pixel, 3 = 2 pixels,
		4 = 4 pixels, 5 = 6 pixels
5	pen	pattern number: 1..36
6	fill	pattern number: 1..36
7	special
		for vectors, the arrow type
		 0 = ------, 1 = ----->, 2 = <-----, 3 = <----->
		for round rectangles, the corner radius:
		1 = 0", 2 = 1/8, 3 = 3/16, 4 = 1/4, 5 = 5/16, 6 = 3/8
8..	An object-specific record (if any) follows after the header


	     Object Specific Data (follows record header)

		    0: Terminator record (0 bytes)

A terminator record is used to mark the end of the list of objects or
the end of a set of objects that have been grouped together.


	     1: Text record (20 bytes + length of string)

0..3	?
4	style	0 = plain, 1 = bold, 2 = italic, 4 = underline, 8 = hollow,
		16 = shadow
5	font	1 = Chicago, 2 = Geneva, 3 = New York, 4 = Monaco, 5 = Venice,
		6 = London, 7 = Athens
6	size	1 = 9 pt, 2 = 10 pt, 3 = 12 pt, 4 = 14 pt, 5 = 18 pt, etc.
7	spacing	1 = single, 2 = three halves, 3 = double
8	align	1 = left, 2 = center, 3 = right
9	angle	0 = normal		4 = flip horizontal
		1 = rotate right	5 = flip vertical
		2 = upsidedown		6 = rotate right and flip horizontal
		3 = rotate left		7 = rotate left and flip horizontal
10:11	Number of characters in text string
12:19	Rectangle enclosing text (Integer)
	(Note: the rectangle gives the location of the text BEFORE doing any
	rotating and/or flipping according to byte 9.)
20	Start of text string (not terminated with null)


		     2,3: Vector record (16 bytes)

0:7	Start point (Fixed-point)
8:15	End point (Fixed-point)


	    4,5,6: Rectangles and Ellipse record (16 bytes)

0:15	Rectangle enclosing object (Fixed-point)


		       7: Arc record (20 bytes)

0:15	Rectangle enclosing ellipse used to generate arc (Fixed-point)
16:17	Start angle (degrees)
18:19	Extent of arc (degrees)


	      8: Curve record (32 bytes + 2 bytes/point)

0..1	?
2:3	Number of bytes in rest of record
4:5	Number of points in curve including start point and ending null point
6:21	Rectangle enclosing curve (Fixed-point)
22	1 = make closed (add final point same as first point)
23	?
24:31	Start point (Fixed-point)
32	Start of X,Y increment pairs (2 bytes/pair), 2's complement,
	terminated by a pair of zero bytes.


	     9: Polygon record (24 bytes + 8 bytes/point)

0..1	?
2:3	Number of bytes in rest of record
4:5	Number of points in polygon
6:21	Rectangle enclosing curve (Fixed-point)
22	1 = make closed (add final point same as first point)
	2 = smoothed polygon
23	?
24	Start of list of points in the polygon (Fixed-point), 8 bytes/pnt


		      10: Group record (32 bytes)

A group record is used to indicate the beginning of a collection of objects
that have been grouped together using the Group command under the Arrange
menu.  The group contains all the following objects until a terminator 
record is encountered.

0:15	Rectangle enclosing all members in the group (Fixed-point)
16..31	?


			 11: PICT record (42+)

0..3	?
4:11	? Rectangle (Integer)
12:27	Rectangle enclosing picture (Fixed-point)
28..31	?
32:33	Width of picture in bytes
34:41	? Rectangle (Integer)
42..	Bitmap
SHAR_EOF
fi # end of overwriting check
if test -f 'drawimp.c'
then
	echo shar: will not over-write existing file "'drawimp.c'"
else
cat << \SHAR_EOF > 'drawimp.c'
/*
	drawimp - MacDraw to Impress translator

	This program will read a MacDraw file and output a sequence of
	Impress commands to draw the picture on an Imagen laser printer.
	Program is compatible with MacDraw files created
	by "MacDraw Version 1.7 3/18/85".  

	Drawimp has two processing modes.  The normal mode causes
	the MacDraw files listed on the command line to be processed
	in order listed with the Impress data written to stdout with
	ENDPAGE commands between data from each file.  This will put
	each file on separate pages.

	In TeX mode (with -t switch) each input file, is processed
	and the results are written to a separate output file with
	the extension (if any) changed to .imp.  The output files have
	no header or trailing ENDPAGE or EOF commands.

	The -d switch causes debugging information to be written to 
	stderr.  This consists of a list of objects and some info about
	them.

	The -p switch is used to select which pages of the MacDraw file
	to output.  Syntax is: -pr1-r2:c1-c2[,r1-r2:c1-c2]

	The -R switch is used to specify the Image resolution in dots per
	inch.  The default is set in drawimp.h

	A few examples:

		drawimp Picture.data >Picture.imp
		drawimp -p1:2 Picture.data >Picture.imp
		drawimp -d Picture.data >/dev/null
		drawimp -d Picture.data >Picture.imp
		drawimp -t Picture1.data Picture2.data
		drawimp -R240 Picture1.data | ipr

	Not (yet) implemented:
		Smoothed polygons
		PICT objects from MacPaint
		Clipping of objects that cross 8x10 inch page boundaries

	Please send any bug reports to Weber%Brand@USC-ECL.ARPA.

	Allan Weber (Weber%Brand@USC-ECL)
	USC Signal and Image Processing Institute

	History:
	16-Apr-85	Version 1
	23-Apr-85	Version 2 - Fixed bug in arcs, added arrows,
			added rest of patterns, changed cvtpnt to use
			32-bit coordinates, added -p switch for page select
	28-Aug-85	Version 3 - Added text using TeX fonts and routines
			from the Unix TeX distribution.	 Added fix to arc
			routine from Richard Roy (dick@su-dit).
	16-Dec-85	Version 4
			Added -t switch to produce impress file without
			header, endpage, or eof bytes for including
			output file in TeX documents going to Imagen.
			Also moves whatever is on page to upper left corner.
			More fixes to arcs to handle filled arcs and arcs
			of other than 90 degrees.
			Implemented different radius corners for the rounded
			rectangles.
*/

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "drawimp.h"

/* #define NO_TEXT */		/* define NO_TEXT to build without
				   text capability */

FILE *infp, *outfp, *fontfp;
int gdepth, done;
int debug = 0;
int tex_output = 0;
int draw_top, draw_left;
int line_table[] = { 0, 0, 1, 8, 16, 20 };	/* line width table */
int ar_size[] = { 0, 0, 10, 15, 20, 25};	/* arrowhead size table */
int corner_rad[] = { 0, 0, 9, 14, 18, 23, 27 }; /* corner radius table */
int texture_table[37];
char *ProgName;
char fheader[HEADER_SIZE];
char tmp[MAX_RECORD];
char filename[80];
struct MDheader rheader;
struct srect cur_page;
double ar_angle, ar_size2[6], ar_radius[6];
extern char pattern[37][128];

/*
This array contains info about each page of the file begin drawn.  The objects
in the MacDraw file can occur in any order and we have to sort them out into
separate page for output.  The .flag indicates whether this page is to be 
output or not (from -p option).  The .font field is used to store the ImFamily
value from the textimp.c file that was in use the last time we were doing that
page.  By remembering which font was in use on a page, we don't have to send
the imPress SetFamily commands each time we go back to put more stuff on that
page if the font hasn't changed.  The .name field holds the name of the 
temporary file so we can delete it later.  The file pointer is in .fp and is
0 if no file open for that page yet.  The page_ptr variable points to the
entry for the page currently being worked on.
*/
struct page {		/* table of drawing pages */
	int flag;	/* flag for page in use */
	int font;	/* font in use on this page */
	char name[20];	/* file name of where the data went */
	FILE *fp;	/* file pointer */
} pagetbl[MAC_V_PAGES][MAC_H_PAGES], *page_ptr;

/* This table contains the values used to convert from MacDraw units
(1/72 inch) to the resolution of the Imagen.  The .res field is the
Imagen resolution in pixels/inch.  The .num and .den fields are the 
numerator and denoninator used to do the multiplication, as in:
	Imagen = MacDraw * .num / .den
The scaling factor is split into separate numerator and denominator
to allow conversion without overflow problems.
*/
struct {
	int res;
	int num,den;
} restbl[] = {
	240, 10, 3,
	300, 25, 6,
	-1, 0, 0
	};
int md2im_num, md2im_den;
int resolution = DEF_RES;

char *getpages();
int terminal(), text(), vector(), rectangle(), roundrect();
int ellipse(), arc(), curve(), polygon(), group();
int (*opfun[])() = {terminal, text, vector, vector, rectangle, roundrect,
		    ellipse, arc, curve, polygon, group };

char *USAGE = "[-Rres] [-d] [-t] [-ppages] in_file > out_file";

extern char *malloc();
extern char *mktemp();
extern char *strcpy();
extern FILE *impout();
#ifndef NO_TEXT
extern int ImFamily;	/* current Imagen font number from textimp */
#endif

main(argc,argv)
int argc;
char *argv[];
{	
	int i;
	int h,h1,h2;
	int v,v1,v2;
	int gotpages = 0;
	char *s,c;
	struct lrect r;
	struct page *pp;
	ProgName = argv[0];

	while(--argc > 0 && (*++argv)[0] == '-') {
		for (s = argv[0]+1; *s != '\0'; s++)
			switch(*s) {
			case 'd':	/* debug */
				debug = 1;
				break;
			case 'p':	/* page select */
				++s;
				while (*s != '\0') {
					v1 = 1; v2 = 5;
					s = getpages(s,&v1,&v2);
					if (*s != ':') {
						fprintf(stderr,
						"%s: error in page list\n",
						ProgName);
						argc = -1;
						while (*s != '\0')
							s++;
						break;
					}
					else
						s++;
					h1 = 1; h2 = 12;
					s = getpages(s,&h1,&h2);
					if (v1 == 0)
						v1 = 1;
					if (h1 == 0)
						h1 = 1;
					for (v = v1; v <= v2; v++)
						for (h = h1; h <= h2; h++)
						    pagetbl[v-1][h-1].flag=1;
					if (*s == ',')
						s++;
				}
				s--;	/* back pointer up one place */
				gotpages = 1;
				break;
			case 't':
				tex_output = 1;
				break;
			case 'R':	/* Image resolution */
 				s++;
				if (sscanf(s,"%d",&resolution) != 1) {
				    fprintf(stderr,"%s: Bad resolution - %s\n",
					ProgName,s);
				    argc = -1;
				}
				while (*s != '\0')
					s++;
				s--;
				break;
			default:
				fprintf(stderr,"%s: illegal option - %c\n",
				    ProgName,*s);
				argc = -1;
				break;
		}
	}

	if (argc <= 0) {
		usage();
		exit(1);
	}

	if (tex_output) {
		if (gotpages == 0)
			pagetbl[0][0].flag = 1;	/* only first page for tex */
		else {
			fprintf(stderr,
				"Cannot use -t and -p options at same time\n");
			usage();
			exit(1);
		}
	}
	else
		if (gotpages == 0) {
			for (v = 0; v < MAC_V_PAGES; v++)  /* do all */
				for (h = 0; h < MAC_H_PAGES; h++)
					pagetbl[v][h].flag = 1;
		}

	/* figure out what resolution and conversion factors to use */
	i = 0;
	while (restbl[i].res > 0) {
		if (restbl[i].res == resolution) {
			md2im_num = restbl[i].num;
			md2im_den = restbl[i].den;
			break;
		}
		i++;
	}
	if (md2im_num == 0) {
		fprintf(stderr,"%s: Unknown resolution - %d\n",
			ProgName,resolution);
		exit(1);
	}

	/* calculate some things for doing arrows */
	ar_angle = ARROW_ANGLE * 2 * 3.14159 / 360;
	for (i = 0; i <= 5; i++) {
		ar_radius[i] = md2im(ar_size[i]);
		ar_size2[i] = pow(ar_radius[i] * cos(ar_angle), (float) 2);
	}

	/* calculate some things for doing rectangle corners */
	for (i = 1; i <= 6; i++) {
		corner_rad[i] = md2im(corner_rad[i]);
	}

	if (tex_output == 0) {
		printf("@document(language impress)");
		impout(stdout);
		imP_set_abs_h(md2im(H_SHIFT));		/* shift origin */
		imP_set_abs_v(md2im(V_SHIFT));
		imP_set_hv_system(3,0,0);	/* set new origin */
	}

	while (argc-- > 0) {
		if ((infp = fopen(*argv,"r")) == NULL) {
			fprintf(stderr,"%s: can't open input file %s\n",
			    ProgName,*argv);
			exit(1);
		}
		if (tex_output) {
			makename(*argv,filename);
			if ((outfp = fopen(filename,"w")) == NULL) {
				fprintf(stderr,
				    "%s: can't open output file %s\n",
				    ProgName,filename);
				exit(1);
			}
			fontfp = outfp;	/* put font info at front */
		}
		else {
			outfp = stdout;
			fontfp = stdout;
		}
		argv++;

		page_ptr = NULL;

		fread(fheader,1,HEADER_SIZE,infp);	/* read header */
		if (debug) {
			makelrect(fheader+214,&r);
			fprintf(stderr,
				"Drawing rectangle: t=%d, l=%d, b=%d, r=%d\n",
				r.top.i,r.left.i,r.bottom.i,r.right.i);
		}

		draw_top = draw_left = 0;
		if (tex_output != 0)
			cvtpnt(&r.top, &r.left, &draw_top, &draw_left);

		/* read the MacDraw objects and process them */
		done = gdepth = 0;
		while (fread((char *)&rheader, sizeof(struct MDheader),
			1, infp) == 1) {
			c = rheader.code;
			if (c >= 0 && c <= 10)
				(opfun[c])();
			else {
				fprintf(stderr,"Unrecognized type - %d\n",c);
				break;
			}
			if (done)
				break;
		}
		fclose(infp);

		/* now output all the collected picture data */
		impout(outfp);
		if (tex_output)
			imP_set_hv_system(3,0,0);	/* set new origin */
		for (v = 0; v < MAC_V_PAGES; v++)
			for (h = 0; h < MAC_H_PAGES; h++) {
				pp = &pagetbl[v][h];
				if (pp->fp != NULL) {
					fseek(pp->fp,0L,0);
					while ((c = getc(pp->fp)) != EOF)
						putc(c,outfp);
					fclose(pp->fp);
					pp->fp = NULL;
					unlink(pp->name);
					if (tex_output == 0)
						imP_endpage();
				}
			}
		
#ifndef NO_TEXT
		reset_text();	/* reset text for next file */
#endif
		if (tex_output) {
#ifndef NO_TEXT
			reset_fonts();	/* set fonts as not downloaded yet */
#endif
			reset_textures(); /* same for texture glyphs */
			fclose(outfp);
		}
	}
	/* finish the file off */
	if (tex_output == 0)
		imP_eof();
}

usage()
{
	fprintf(stderr,"Usage: %s %s\n",ProgName, USAGE);
}

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

terminal()
{
	if (debug)
		fprintf(stderr, "Terminator: depth = %d\n",gdepth);
	if (gdepth > 0)
		gdepth--;
	else
		done = 1;
}

text()
{
	int n, doit;
	int style, font, size, spacing, align, angle;
	int top, left, bottom, right;
	int v[5], h[5], tv, th;
	char *s, *s0;
	struct lrect r;
	fread(tmp,sizeof(struct MDtext),1,infp);
	style   = makenum(1,tmp+4);
	font    = makenum(1,tmp+5);
	size    = makenum(1,tmp+6);
	spacing = makenum(1,tmp+7);
	align   = makenum(1,tmp+8);
	angle   = makenum(1,tmp+9);
	n       = makenum(2,tmp+10);
	makelrect0(tmp+12,&r);
	doit = dopage(&r.top,&r.left) != 0;
	if (debug && doit) {
		fprintf(stderr, "Text: %d characters, rect: t=%d, l=%d, b=%d, r=%d\n",
			n,r.top.i,r.left.i,r.bottom.i,r.right.i);
		fprintf(stderr, "\tstyle=%d, font=%d, size=%d, spacing=%d\n",
			style, font, size, spacing);
		fprintf(stderr, "\talign=%d, angle=%d, fill=%d\n",
			align, angle, rheader.fill);
	}
	if ((s = s0 = malloc(n+1)) == 0)
		fprintf(stderr,"Unable to malloc %d byte\n",n+1);
	while (n--)
		*s++ = getc(infp);
	*s = '\0';
	if (debug && doit)
		fprintf(stderr, "\"%s\"\n",s0);
	if (doit) {
		if (rheader.fill > 1) {
			cvtpnt(&r.top,&r.left,&top,&left);
			cvtpnt(&r.bottom,&r.right,&bottom,&right);
			h[0] = h[3] = h[4] = left;
			v[0] = v[1] = v[4] = top;
			h[1] = h[2] = right - 1;
			v[3] = v[2] = bottom - 1;
			imP_create_path(5,h,v);
			imP_fill_path(use_pattern(rheader.fill));
		}
		cvtpnt(&r.top,&r.left,&tv,&th);
#ifndef NO_TEXT
		mactext(s0,tv,th,style,font,size,spacing,align,angle);
#endif
	}
	free(s0);	
}

vector()
{
	struct lpoint pnt1, pnt2;
	int h[2], v[2], ha[3], va[3];
	int pat, ar, s;
	double dh, dv, t;
	fread(tmp,sizeof(struct MDvector),1,infp);
	makelpoint(tmp+0,&pnt1);
	makelpoint(tmp+8,&pnt2);
	if (dopage(&pnt1.v,&pnt1.h) == 0)
		return;
	if (debug) {
		fprintf(stderr, "Vector: From (%dv %dh) to (%dv %dh), ",
			pnt1.v.i,pnt1.h.i,pnt2.v.i,pnt2.h.i);
		fprintf(stderr, "line=%d, pen=%d, fill=%d, arrow=%d\n",
			rheader.line,rheader.pen,rheader.fill,rheader.special);
	}
	if (onpage(&pnt1.v,&pnt1.h) && onpage(&pnt2.v,&pnt2.h) &&
	    rheader.line > 1) {
		cvtpnt(&pnt1.v,&pnt1.h,v,h);
		cvtpnt(&pnt2.v,&pnt2.h,v+1,h+1);
		if (rheader.pen > 1)
			pat = use_pattern(rheader.pen);
		if ((ar = rheader.special) > 0) {
			dh = h[1] - h[0];
			dv = v[1] - v[0];
			s = rheader.line;
			if (dh*dh + dv*dv > ar_size2[s]) {
				t = atan2(dv,dh);
				if (ar == 1 || ar == 3) {
					make_arrow(h+1,v+1,t,s,ha,va);
					imP_create_path(3,ha,va);
					imP_fill_path(pat);
				}
				if (ar == 2 || ar == 3) {
					t += 3.14159;
					make_arrow(h,v,t,s,ha,va);
					imP_create_path(3,ha,va);
					imP_fill_path(pat);
				}
			}
		}
		imP_create_path(2,h,v);
		imP_set_pen(use_line(rheader.line));
		imP_draw_path(pat);
	}
}

rectangle()
{
	struct lrect r;
	int top, left, bottom, right;
	int h[5], v[5];
	fread(tmp,sizeof(struct MDbox),1,infp);
	makelrect(tmp,&r);
	if (dopage(&r.top,&r.left) == 0)
		return;
	if (debug) {
		fprintf(stderr, "Rectangle: t=%d, l=%d, b=%d, r=%d, ",
			r.top.i,r.left.i,r.bottom.i,r.right.i);
		fprintf(stderr, "line=%d, pen=%d, fill=%d, corner=%d\n",
			rheader.line,rheader.pen,rheader.fill,rheader.special);
	}
	if (onpage(&r.top,&r.left) && onpage(&r.bottom,&r.right)) {
		cvtpnt(&r.top,&r.left,&top,&left);
		cvtpnt(&r.bottom,&r.right,&bottom,&right);
		h[0] = h[3] = h[4] = left;
		v[0] = v[1] = v[4] = top;
		h[1] = h[2] = right - 1;
		v[3] = v[2] = bottom - 1;
		if (h[0] >= h[1])	/* vertical line? */
			imP_create_path(2,h+1,v+1);
		else if (v[1] >= v[2])	/* horizontal line? */
			imP_create_path(2,h,v);
		else			/* rectangle */
			imP_create_path(5,h,v);
		if (rheader.fill > 1)
			imP_fill_path(use_pattern(rheader.fill));
		if (rheader.line > 1) {
			imP_set_pen(use_line(rheader.line));
			imP_draw_path(use_pattern(rheader.pen));
		}
	}
}

roundrect()
{
	struct lrect r;
	int top, left, bottom, right, ra, rb, rad, corner;
	int h[9], v[9];
	fread(tmp,sizeof(struct MDbox),1,infp);
	makelrect(tmp,&r);
	if (dopage(&r.top,&r.left) == 0)
		return;
	if (debug) {
		fprintf(stderr, "RoundRect: t=%d, l=%d, b=%d, r=%d, ",
			r.top.i,r.left.i,r.bottom.i,r.right.i);
		fprintf(stderr, "line=%d, pen=%d, fill=%d, corner=%d\n",
			rheader.line,rheader.pen,rheader.fill,rheader.special);
	}
	if (onpage(&r.top,&r.left) && onpage(&r.bottom,&r.right)) {
		cvtpnt(&r.top,&r.left,&top,&left);
		cvtpnt(&r.bottom,&r.right,&bottom,&right);
		ra = (right-1 - left) / 2;
		rb = (bottom-1 - top) / 2;
		rad = corner_rad[rheader.special];
		if (ra > rad)
			ra = rad;
		if (rb > rad)
			rb = rad;
		corner = (ra != 0) || (rb != 0);
		h[0] = h[5] = h[8] = left + ra;
		h[1] = h[4] = right-1 - ra;
		h[2] = h[3] = right-1;
		h[6] = h[7] = left;
		v[0] = v[1] = v[8] = top;
		v[2] = v[7] = top + rb;
		v[3] = v[6] = bottom-1 - rb;
		v[4] = v[5] = bottom-1;
		if (h[0] < h[1])
			imP_create_path(2,h,v);
		imP_set_pum(1);
		if (corner) {
			imP_set_abs_h(h[1]);
			imP_set_abs_v(v[2]);
			imP_ellipse_arc(ra,rb,0,12288,16383);
		}
		if (v[2] < v[3])
			imP_create_path(2,h+2,v+2);
		if (corner) {
			imP_set_abs_h(h[4]);
			imP_set_abs_v(v[3]);
			imP_ellipse_arc(ra,rb,0,0,4096);
		}
		if (h[5] < h[4])
			imP_create_path(2,h+4,v+4);
		if (corner) {
			imP_set_abs_h(h[5]);
			imP_set_abs_v(v[6]);
			imP_ellipse_arc(ra,rb,0,4096,8192);
		}
		if (v[7] < v[6])
			imP_create_path(2,h+6,v+6);
		if (corner) {
			imP_set_abs_h(h[0]);
			imP_set_abs_v(v[7]);
			imP_ellipse_arc(ra,rb,0,8192,12288);
		}
		if (rheader.fill > 1)
			imP_fill_path(use_pattern(rheader.fill));
		if (rheader.line > 1) {
			imP_set_pen(use_line(rheader.line));
			imP_draw_path(use_pattern(rheader.pen));
		}
		imP_set_pum(0);
	}
}

ellipse()
{
	struct lrect r;
	int top, left, bottom, right, ra, rb;
	fread(tmp,sizeof(struct MDbox),1,infp);
	makelrect(tmp, &r);
	if (dopage(&r.top,&r.left) == 0)
		return;
	if (debug) {
		fprintf(stderr, "Ellipse: t=%d, l=%d, b=%d, r=%d, ",
			r.top.i,r.left.i,r.bottom.i,r.right.i);
		fprintf(stderr, "line=%d, pen=%d, fill=%d\n",
			rheader.line,rheader.pen,rheader.fill,rheader.special);
	}
	if (onpage(&r.top,&r.left) && onpage(&r.bottom,&r.right)) {
		cvtpnt(&r.top,&r.left,&top,&left);
		cvtpnt(&r.bottom,&r.right,&bottom,&right);
		imP_set_abs_h((left + right-1) / 2);
		imP_set_abs_v((top + bottom-1) / 2);
		ra = (right-1 - left) / 2;
		rb = (bottom-1 - top) / 2;
		imP_ellipse_arc(ra,rb,0,0,16383);
		if (rheader.fill > 1)
			imP_fill_path(use_pattern(rheader.fill));
		if (rheader.line > 1) {
			imP_set_pen(use_line(rheader.line));
			imP_draw_path(use_pattern(rheader.pen));
		}
	}	
}

arc()
{
	struct lrect r;
	int top, left, bottom, right, ra, rb, ch, cv;
	int start, extent;
	int alpha0, alpha1;
	fread(tmp,sizeof(struct MDarc),1,infp);
	makelrect(tmp, &r);
	start  = makenum(2,tmp+16);
	extent = makenum(2,tmp+18);
	if (dopage(&r.top,&r.left) == 0)
		return;
	if (debug) {
		fprintf(stderr, "Arc: t=%d, l=%d, b=%d, r=%d, ",
			r.top.i,r.left.i,r.bottom.i,r.right.i);
		fprintf(stderr, "line=%d, pen=%d, fill=%d\n",
			rheader.line,rheader.pen,rheader.fill);
		fprintf(stderr, "\tstart = %d, extent = %d\n",start,extent);
	}
	if (onpage(&r.top,&r.left) && onpage(&r.bottom,&r.right)) {
		cvtpnt(&r.top,&r.left,&top,&left);
		cvtpnt(&r.bottom,&r.right,&bottom,&right);
		ch = (left + right-1) / 2;
		cv = (top + bottom-1) / 2;
		imP_set_abs_h(ch);
		imP_set_abs_v(cv);
		ra = (right-1 - left) / 2;
		rb = (bottom-1 - top) / 2;
/* changed 8/22/85 by rhr - apparently MacDraw allows arcs to be traversed
 * in negative direction (Imagen does not)! Debug output gave extent=65446!
 * which for 16 bit 2's complement would be about -90!  So, this fix assumes
 * all arcs are 90 degrees in extent, plus or minus, and adjusts start 
 * accordingly */
/* changed again 11/4/85 by AGW to allow arcs of other than 90 degrees */
		if (extent > 32768) {	/* negative direction? */
			extent = 65536 - extent;
			start = start - extent;
		}
		if (rb > ra)	/* v axis = major axis */
			start = (start + 270) % 360;
		alpha0 = ((start - 90) * 4096) / 90;
		if (alpha0 < 0)
			alpha0 += 16384;
		if (extent == 360)
			alpha1 = alpha0 + 16383;
		else
			alpha1 = alpha0 + ((extent * 4096) / 90);
		if (rheader.fill > 1) {
			imP_create_path(1, &ch, &cv);
			imP_set_pum(1);
			imP_ellipse_arc(ra,rb,0,alpha0,alpha1);
			imP_fill_path(use_pattern(rheader.fill));
			imP_set_pum(0);
		}
		if (rheader.line > 1) {
			imP_ellipse_arc(ra,rb,0,alpha0,alpha1);
			imP_set_pen(use_line(rheader.line));
			imP_draw_path(use_pattern(rheader.pen));
		}	
	}
}

curve()
{
	int n, n0, dx, dy;
	struct lpoint pnt;
	int *h, *h0, *v, *v0;
	int doit;
	struct lrect r;
	fread(tmp,sizeof(struct MDcurve),1,infp);
	n = makenum(2,tmp+4);
	makelrect(tmp+6, &r);
	doit = dopage(&r.top,&r.left) != 0;
	if (debug && doit) {
		fprintf(stderr, "Curve: n=%d, t=%d, l=%d, b=%d, r=%d, ",
			n,r.top.i,r.left.i,r.bottom.i,r.right.i);
		fprintf(stderr, "line=%d, pen=%d, fill=%d\n",
			rheader.line,rheader.pen,rheader.fill);
	}
	makelpoint(tmp+24,&pnt);
	/* null point at end gets discarded which gives room in array
	   for point to close region if needed */
	h = h0 = (int *) malloc((unsigned) sizeof(int) * n);
	v = v0 = (int *) malloc((unsigned) sizeof(int) * n);
	n0 = 0;
	while (--n) {
		if (debug && doit)
			fprintf(stderr, "\t%d: (%dv %dh)\n",
				n0,pnt.v.i,pnt.h.i);
		cvtpnt(&pnt.v,&pnt.h,v++,h++);
		n0++;
		dx = getc(infp);
		dy = getc(infp);
		if (dx > 127)
			dx -= 256;
		if (dy > 127)
			dy -= 256;
		pnt.h.i += dx;
		pnt.v.i += dy;
	}
	if (debug && doit)
		fprintf(stderr, "\t%d: (%dv %dh)\n",n0,pnt.v.i,pnt.h.i);
	if (tmp[22] == 1) {	/* check for closed curve */
		*h = *h0;
		*v = *v0;
		n0++;
	}
	if (doit) {
		if (onpage(&r.top,&r.left) && onpage(&r.bottom,&r.right)) {
			imP_create_path(n0,h0,v0);
			if (rheader.fill > 1)
				imP_fill_path(use_pattern(rheader.fill));
			if (rheader.line > 1) {
				imP_set_pen(use_line(rheader.line));
				imP_draw_path(use_pattern(rheader.pen));
			}
		}
	}
	free((char *) h0);
	free((char *) v0);
}

polygon()
{
	int n, n0;
	struct lpoint pnt;
	int *h, *h0, *v, *v0;
	int doit;
	struct lrect r;
	fread(tmp,sizeof(struct MDpolygon),1,infp);
	n = makenum(2,tmp+4);
	makelrect(tmp+6, &r);
	doit = dopage(&r.top,&r.left) != 0;
	if (debug && doit) {
		fprintf(stderr, "Polygon: n=%d, t=%d, l=%d, b=%d, r=%d, ",
			n,r.top.i,r.left.i,r.bottom.i,r.right.i);
		fprintf(stderr, "line=%d, pen=%d, fill=%d\n",
			rheader.line,rheader.pen,rheader.fill);
	}
	h = h0 = (int *) malloc((unsigned) sizeof(int) * (n+1));
	v = v0 = (int *) malloc((unsigned) sizeof(int) * (n+1));
	n0 = 0;
	while (n--) {
		fread(tmp,1,8,infp);
		makelpoint(tmp,&pnt);
		if (debug && doit)
			fprintf(stderr, "\t%d: (%dv %dh)\n",
				n0,pnt.v.i,pnt.h.i);
		cvtpnt(&pnt.v,&pnt.h,v++,h++);
		n0++;
	}
	if (tmp[22] == 1) {	/* check for closed polygon */
		*h = *h0;
		*v = *v0;
		n0++;
	}
	if (doit) {
		if (onpage(&r.top,&r.left) && onpage(&r.bottom,&r.right)) {
			imP_create_path(n0,h0,v0);
			if (rheader.fill > 1)
				imP_fill_path(use_pattern(rheader.fill));
			if (rheader.line > 1) {
				imP_set_pen(use_line(rheader.line));
				imP_draw_path(use_pattern(rheader.pen));
			}
		}
	}
	free((char *) h0);
	free((char *) v0);
}

group()
{
	struct lrect r;
	fread(tmp,sizeof(struct MDgroup),1,infp);
	makelrect(tmp, &r);
	gdepth += 1;
	if  (debug) {
		fprintf(stderr, "Group start: depth = %d, ", gdepth);
		fprintf(stderr, "rectangle: t=%d, l=%d, b=%d, r=%d\n",
			gdepth,r.top.i,r.left.i,r.bottom.i,r.right.i);
	}
}

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

makenum(i,p)		/* make a number from bytes in 68000 order */
int i;
char *p;
{
	int n = 0;
	while (i--) 
		n = (n << 8) + (*p++ & 0xff);
	return(n);
}

makelpoint(cp, pp)	/* swap bytes 4 times to make a lpoint struct */
char *cp;
struct lpoint *pp;
{
	swapbyte(cp, (char *)pp, 4);
}

makelrect(cp, rp)	/* swap bytes 8 times to make a lrect struct */
char *cp;
struct lrect *rp;
{
	swapbyte(cp, (char *)rp, 8);
}

makelrect0(cp, rp)	/* same as makelrect except fractional part = 0 */
char *cp;
struct lrect *rp;
{
	swapbyte(cp+0, (char *)&rp->top.i, 1);
	swapbyte(cp+2, (char *)&rp->left.i, 1);
	swapbyte(cp+4, (char *)&rp->bottom.i, 1);
	swapbyte(cp+6, (char *)&rp->right.i, 1);
	rp->top.f = rp->left.f = rp->bottom.f = rp->right.f = 0;
}

swapbyte(p1, p2, n)
register char *p1, *p2;
register int n;
{
	while (n-- > 0) {
		*(p2+1) = *p1++;
		*p2 = *p1++;
		p2 += 2;
	}
}

cvtpnt(mv,mh,iv,ih)	/* convert point from MacDraw to Imagen coord. */
struct lcoord *mv, *mh;
int *iv, *ih;
{
	int a,b;
	a = mv->i - cur_page.top;
	b = mv->f;
	*iv = (md2im((a << 8) + (b >> 8 & 0xff)) >> 8) - draw_top;
	a = mh->i - cur_page.left;
	b = mh->f;
	*ih = (md2im((a << 8) + (b >> 8 & 0xff)) >> 8) - draw_left;
#ifdef DEBUG
	fprintf(stderr, "\tv.i=%d v.f=%d v=%d, h.i=%d h.f=%d h=%d\n",
		mv->i,mv->f,*iv,mh->i,mh->f,*ih); */
#endif
}

md2im(x)	/* convert a value from MacDraw to Imagen */
int x;
{
	return(x * md2im_num / md2im_den);
}

onpage(pv,ph)
struct lcoord *pv, *ph;
{
	return(pv->i >= cur_page.top && pv->i <= cur_page.bottom &&
	       ph->i >= cur_page.left && ph->i <= cur_page.right);
}

use_pattern(f)
char f;
{
	if (f == 2)	/* white */
		return(0);
	else if (f == 3)	/* black */
		return(15);
	else {			/* something else */
		load_texture(f); 
		return(3);
	}
}

use_line(n)
char n;
{
	if (n < 1 || n > 5)
		return(1);
	else
		return(line_table[n]);
}

load_texture(n)
int n;
{
	FILE *oldfp;
	if (n < 1 || n > 36)
		return;
	if (texture_table[n] == 0) {
		oldfp = impout(fontfp);	/* send textures out to font file */
		imP_bgly(0,TEXTURE_FAMILY,n,32,32,0,32,32,pattern[n]);
		impout(oldfp);
		texture_table[n] = 1;
	}
	imP_set_texture(TEXTURE_FAMILY,n);
}

reset_textures()	/* mark all textures as not yet loaded */
{
	int i;
	for (i = 1; i <= 36; i++)
		texture_table[i] = 0;
}

dopage(pv, ph)
struct lcoord *pv, *ph;
{
	struct page *pp;
	int r,c;
	char s[20];
	r = pv->i / MAC_V_SIZE;
	c = ph->i / MAC_H_SIZE;
	pp = &pagetbl[r][c];
	if (r > MAC_V_PAGES || c > MAC_H_PAGES)
		return(0);
	else if (pp->flag == 0)
		return(0);
	else {
		if (pp->fp == NULL) {
			strcpy(s,mktemp(TEMP_PREFIX));
			sprintf(pp->name,"%s.%01d%02d",s,r+1,c+1);
			pp->fp = fopen(pp->name,"w+");
			pp->font = -1;	/* force a imP_set_family() */
		}
		impout(pp->fp);
#ifndef NO_TEXT
		if (page_ptr != NULL)
			page_ptr->font = ImFamily; /* font for last page */
		ImFamily = pp->font;	/* font in use on new page */
#endif
		page_ptr = pp;		/* points to current page */
		cur_page.bottom = (cur_page.top= r * MAC_V_SIZE) + MAC_V_SIZE;
		cur_page.right = (cur_page.left= c * MAC_H_SIZE) + MAC_H_SIZE;
		return(1);
	}
}

/*
This routine parses a page select specification of the form n-m where
n is the first one to do and m is the last one to do.  If either is
missing, the value in n or m is left unchanged.  If only one number 
is given, m and n will both be set equal to it.  The parameter s is
a pointer to the string and the function returns an updated pointer
to the next character in the string after doing the parsing.
*/
char *
getpages(s,n,m)
char *s;
int *n,*m;
{
	int x;
	if (isdigit(*s)) {
		x = 0;
		while (isdigit(*s))
			x = x * 10 + (*s++ - '0');
		*n = x;
	}
	if (*s == '-') {
		if (isdigit(*++s)) {
			x = 0;
			while (isdigit(*s))
				x = x * 10 + (*s++ - '0');
			*m = x;
		}
	}
	else
		*m = *n;
	return(s);
}

/*
This routine take the endpoint of the vector (*h, *v), its angle (t), and
the line size (n) as input and fills the ha[] and va[] arrays with the
three points needed to draw the arrowhead.  It also modifies the endpoint
location to move it inside the arrowhead.  If this isn't done, the line
will show around the arrow tip when using wide line sizes.
*/
make_arrow(h,v,t,n,ha,va)
int *h, *v, n, ha[3], va[3];
double t;
{
	double tp, tm ,r;
	r = ar_radius[n];
	tp = t + ar_angle;
	tm = t - ar_angle;
	ha[0] = *h;			/* make triangle for the arrow	*/
	va[0] = *v;
	ha[1] = *h - r * cos(tm);
	va[1] = *v - r * sin(tm);
	ha[2] = *h - r * cos(tp);
	va[2] = *v - r * sin(tp);
	*h -= r * cos(t) * 0.5;		/* move endpoint of vector back	*/
	*v -= r * sin(t) * 0.5;		/* away from tip of arrowhead	*/
}

/* Create a filename for storing output for later inclusion with a dvi file */
makename(s1, s2)
char *s1, *s2;
{
	int n;
	char *p;
	p = s1;
	while (*p != '\0') {	/* get rid of leading path name */
		if (*p == '/')
			s1 = p+1;
		p++;
	}
	p = s1 + strlen(s1);	/* point to null byte */

	while (p > s1 && *--p != '.')	/* back up looking for a . */
		;
	if (*p == '.' && strcmp(p, MAC_EXT) == 0) {
		n = p - s1;
		strncpy(s2, s1, n);
		s2[n] = '\0';
		strcat(s2, TEX_EXT);
	}
	else {		/* wrong or no extension so just add to end */
		strcpy(s2, s1);
		strcat(s2, TEX_EXT);
	}

}
SHAR_EOF
fi # end of overwriting check
if test -f 'drawimp.man'
then
	echo shar: will not over-write existing file "'drawimp.man'"
else
cat << \SHAR_EOF > 'drawimp.man'
.TH DRAWIMP LOCAL "17 December 1985"
.SH NAME
drawimp \- convert MacDraw files to imPRESS format
.SH SYNOPSIS
.B drawimp
[ options ] files
.SH DESCRIPTION
.vs -1p
.I Drawimp
converts the named MacDraw format files into imPRESS format for printing on
an Imagen laser printer.
.I Drawimp
can be run in two modes.  In the normal mode, imPRESS output from 
all the files listed on the command line will be written to the standard
output.
The imPRESS output contains the required headers and 
should be ready to print with no changes or additions.  If
.I drawimp
is run with the 
.B \-t
option, the program will create a separate output file for each input file.
These output files will be in the proper format 
for merging with 
.I LaTeX
output files for putting figures in documents.  
.PP
The following options may be used
.TP
.B  \-d
Write debugging information to standard error.
This consists of a list of the objects in the file, their location in
MacDraw coordinates, and various attributes.
.TP
.BI \-p list
Print only pages whose row and column numbers appear in a comma-separated
.I list
of paired row and column numbers in the form
.I r:c,
or paired rows and columns ranges in the form
.I r1-r2:c1-c2.
A range
.IB r1 \- r2
means rows
.I r1
through
.I r2
inclusive; an initial
.I \-r2
means rows 1 though
.I r2
inclusive; and a final
.IR r1 \-
means from
.I r1
to the last row.  The same applies for the column specifications.
.TP
.B \-t
Write imPRESS output to separate output files (one for each input file)
without a header or trailing
.I Endpage
or
.I Eof
bytes.  This option should be used if the output is intended for combining
with other imPRESS data.
In this mode, the page select option
.B \-p
is not allowed and only the upper left
page of the drawing will be processed.
The picture on this page be shifted on the coordinate system as if it had
been in the upper left corner of the 8x10 page.
If the name of an input file ends with
.I \.data 
then the output file will be the same name as the input file with the
.I \.data
replaced by
.I \.imp.
Otherwise, the output file name will be the input file name with
.I \.imp
appended to it.
.TP
.BI \-R resolution
Sets assumed printer resolution (in dots per inch).
.SH FILES
/tmp/McD*.\c
.I rcc
- temporary file for imPRESS data for the page at row
.I r
and column
.I cc
.SH BUGS
Multiple page objects, PICT objects (things from MacPaint via the clipboard),
and smoothed polygons are not currently supported.
.PP
All MacDraw files containing pictures to be included in a single
.I LaTeX
document must be processed by
.I drawimp
(with the
.B \-t
option)
at the same time.  If this is not done, the fonts used for text in the 
pictures will get mixed up.
.PP
The program ignores any information in the file about paper size or 
orientation.  It assumes a paper size of 8x10 inches and will 
ignore any object that crosses an 8x10 inch page boundary,
Because of this, it is best to use that paper size when creating the drawing
to better see how the output will be broken up.
.PP
The program is designed to convert MacDraw files which are in the format
produced by \*(lqMacDraw Version 1.7 3/18/85\*(rq and may not be compatible
with files produced by other versions of MacDraw.
.SH AUTHOR
Allan G. Weber (Weber%Brand@USC-ECL.ARPA), University of Southern California,
Signal and Image Processing Institute
SHAR_EOF
fi # end of overwriting check
if test -f 'error.c'
then
	echo shar: will not over-write existing file "'error.c'"
else
cat << \SHAR_EOF > 'error.c'
#ifndef lint
static char rcsid[] = "$Header: error.c,v 1.1 84/05/20 23:11:37 chris Exp $";
#endif

/* Error message routine */

#include <stdio.h>

#ifdef lint
/* VARARGS */
/* ARGSUSED */
error (quit, e, fmt)
int quit, e;
char *fmt;
{
}

#else lint

extern char *ProgName;
extern char *sys_errlist[];
extern int   sys_nerr;

#ifdef pyr	/* pyramid hacks */
#include <varargs.h>
#endif pyr

/* Print an error message with an optional system error number and optionally
   quit */
error (quit, e, fmt, arg)
int quit, e;
char *fmt;
{
#ifdef pyr
    va_buf _va;
    va_list l;

    fprintf (stderr, "%s: ", ProgName);
    _vastart (l = (va_list)_va, &arg);
    _doprnt (fmt, l, stderr);
#else pyr
    fprintf (stderr, "%s: ", ProgName);
    _doprnt (fmt, &arg, stderr);
#endif pyr
    if (e) {
	register char *s = e < sys_nerr ? sys_errlist[e] : "Unknown error";
	fprintf (stderr, ": %s", s);
    }
    putc ('\n', stderr);
    fflush (stderr);		/* just in case */
    if (quit)
	exit (quit);
}

#endif lint
SHAR_EOF
fi # end of overwriting check
if test -f 'impress.c'
then
	echo shar: will not over-write existing file "'impress.c'"
else
cat << \SHAR_EOF > 'impress.c'
/*
This file contains functions for outputting Impress codes to a file.
Not all functions have been implemented, only those needed so far.
*/

#include <stdio.h>

/*
The following #defines are copied from the Imagen supplied file "imPcodes.h"
*/
#define	imP_SP			128
#define	imP_SP1			129
#define	imP_OLD_MMOVE		130
#define	imP_MPLUS		131
#define	imP_MMINUS		132
#define	imP_MMOVE		133
#define	imP_SMOVE		134

#define	imP_SET_ABS_H		135
#define	imP_SET_REL_H		136
#define	imP_SET_ABS_V		137
#define	imP_SET_REL_V		138

#define	imP_SRULE		192
#define	imP_BRULE		193

#define	imP_SET_HPOS		195
#define	imP_SET_VPOS		196
#define	imP_CRLF		197
#define	imP_SGLY		198
#define	imP_BGLY		199
#define	imP_DELG		200
#define	imP_DELC		201
#define	imP_DELF		202
#define	imP_MAKE_TEXTURE	203

#define	imP_SET_HV_SYSTEM	205
#define	imP_SET_ADV_DIRS	206
#define	imP_SET_FAMILY		207
#define	imP_SET_IL		208
#define	imP_SET_BOL		209
#define	imP_SET_SP		210
#define	imP_PUSH		211
#define	imP_POP			212
#define	imP_PAGE		213
#define	imP_SET_PUSH_MASK	214
#define	imP_ENDPAGE		219

#define	imP_CREATE_FAMILY_TABLE	221
#define	imP_CREATE_MAP		222

#define	imP_SET_PUM		225
#define	imP_CIRC_ARC		150
#define	imP_ELLIPSE_ARC		151
#define	imP_CIRC_SEGM		160
#define	imP_CREATE_PATH		230
#define	imP_SET_TEXTURE		231
#define	imP_SET_PEN		232
#define	imP_FILL_PATH		233
#define	imP_DRAW_PATH		234
#define	imP_BITMAP		235
#define	imP_SET_MAGN		236
#define	imP_FORCE_GLY_DEL	240
#define	imP_DEFINE_MACRO	242
#define	imP_EXEC_MACRO		243
#define	imP_DEFINE_FILE		244
#define	imP_EXEC_FILE		245
#define	imP_NOOP		254
#define	imP_EOF			255

static FILE *impfp;

FILE *impout(fp)
FILE *fp;
{
	FILE *oldfp;
	oldfp = impfp;
	impfp = fp;
	return(oldfp);
}

static outb(x)
int x;
{
	putc(x & 0xff, impfp);
}

static outw(x)
int x;
{
	outb(x >> 8);
	outb(x);
}

static outs(s,n)
char *s;
int n;
{
	fwrite(s,1,n,impfp);
}

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

imP_bgly(rotation,family,member,adv_wid,width,left_off,height,top_off,mask)
int rotation,family,member,adv_wid,width,left_off,height,top_off;
char *mask;
{
	int n;
	outb(imP_BGLY);
	outw(((rotation&0x03) << 14) + ((family&0x7f) << 7) + (member&0x7f));
	outw(adv_wid);
	outw(width);
	outw(left_off);
	outw(height);
	outw(top_off);
	if (mask != NULL) {
		n = height * ((width + 7) / 8);
		while (n--)
			outb(*mask++);
	}
}

imP_create_path(vertex_count, h, v)
int vertex_count, *h, *v;
{
	outb(imP_CREATE_PATH);
	outw(vertex_count);
	while (vertex_count--) {
		outw(*h++);
		outw(*v++);
	}
}

imP_crlf()
{	outb(imP_CRLF); }

imP_draw_path(operation_type)
int operation_type;
{
	outb(imP_DRAW_PATH);
	outb(operation_type);
}

imP_ellipse_arc(radiusa,radiusb,alphaoff,alpha0,alpha1)
int radiusa,radiusb,alphaoff,alpha0,alpha1;
{
	outb(imP_ELLIPSE_ARC);
	outw(radiusa);
	outw(radiusb);
	outw(alphaoff);
	outw(alpha0);
	outw(alpha1);
}

imP_endpage()
{	outb(imP_ENDPAGE); }

imP_eof()
{	outb(imP_EOF); }

imP_fill_path(operation_type)
int operation_type;
{
	outb(imP_FILL_PATH);
	outb(operation_type);
}

imP_member(code)
int code;
{
	outb(code);
}

imP_mminus()
{	outb(imP_MMINUS); }

imP_mmove(deltam)
{
	outb(imP_MMOVE);
	outw(deltam);
}

imP_mplus()
{	outb(imP_MPLUS); }

imP_noop()
{	outb(imP_NOOP); }

imP_set_abs_h(new_h)
int new_h;
{
	outb(imP_SET_ABS_H);
	outw(new_h);
}

imP_set_abs_v(new_v)
int new_v;
{
	outb(imP_SET_ABS_V);
	outw(new_v);
}

imP_set_bol(line_begin)
int line_begin;
{
	outb(imP_SET_BOL);
	outw(line_begin);
}

imP_set_family(family)
int family;
{
	outb(imP_SET_FAMILY);
	outb(family);
}

imP_set_hv_system(origin,axes,orientation)
int origin, axes, orientation;
{
	int x;
	x = ((origin & 3) << 5) + ((axes & 3) << 3) + (orientation & 1);
	outb(imP_SET_HV_SYSTEM);
	outb(x);
}

imP_set_il(inter_line)
int inter_line;
{
	outb(imP_SET_IL);
	outw(inter_line);
}

imP_page()
{	outb(imP_PAGE); }

imP_set_pen(diameter)
int diameter;
{
	outb(imP_SET_PEN);
	outb(diameter);
}

imP_set_pum(mode)
int mode;
{
	outb(imP_SET_PUM);
	outb(mode & 1);
}

imP_set_rel_h(delta_h)
int delta_h;
{
	outb(imP_SET_REL_H);
	outw(delta_h);
}

imP_set_rel_v(delta_v)
int delta_v;
{
	outb(imP_SET_REL_V);
	outw(delta_v);
}

imP_set_texture(family,member)
int family, member;
{
	outb(imP_SET_TEXTURE);
	outw(((family & 0x7f) << 7) + (member & 0x7f)); 
}

imP_set_sp(space_size)
int space_size;
{
	outb(imP_SET_SP);
	outw(space_size);
}

imP_smove(deltas)
int deltas;
{
	outb(imP_SMOVE);
	outw(deltas);
}

imP_sp()
{	outb(imP_SP); }


SHAR_EOF
fi # end of overwriting check
if test -f 'machint.s'
then
	echo shar: will not over-write existing file "'machint.s'"
else
cat << \SHAR_EOF > 'machint.s'
rcsid:	.asciz	"$Header: /ful/chris/ctex/lib/RCS/machint.s,v 1.1 84/05/26 01:53:01 chris Exp $"

# machint (addr, count)
# char *addr; int count;
#
# Convert "count" 4-byte PXL-style integers at address "addr"
# to and from machine integers.  (Note that calling machint
# twice is effectively a no-op.)

	.align	2
	.globl	_machint
_machint:
	.word	0

	movl	4(ap),r1		# r1 = addr
	ashl	$2,8(ap),r2
	addl2	r1,r2			# r2 = &addr[count]
1:	cmpl	r1,r2			# is addr >= end?
	blss	2f
	ret				# return if r1 >= r2
2:	movl	(r1)+,r0		# r0 = *r1++
	movb	r0,-1(r1)		# byte 0 to byte 3
	ashl	$-8,r0,r0		# r0 >>= 8
	movb	r0,-2(r1)		# byte 1 to byte 2
	ashl	$-8,r0,r0		# etc
	movb	r0,-3(r1)
	ashl	$-8,r0,r0
	movb	r0,-4(r1)
	brb	1b			# and repeat
SHAR_EOF
fi # end of overwriting check
if test -f 'pxl.c'
then
	echo shar: will not over-write existing file "'pxl.c'"
else
cat << \SHAR_EOF > 'pxl.c'
#ifndef lint
static char rcsid[] = "$Header: pxl.c,v 1.9 85/10/15 18:19:05 chris Exp $";
#endif

/* Routines for manipulating PXL files---Vax version */

/* The functions DMagFactor, GenPXLFileName, and ReadPXLFile could go in
   separate files, but it's likely that any program that uses any one
   function uses all three. */

#include "pxl.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

extern int errno;

char *malloc (), *sprintf (), *getenv ();
long  lseek ();

/* Convert a magnification factor to floating point.  This is used in
   conjunction with the FONT_SLOP stuff to try to get the file names
   right, and may also be used by DVI reading programs to get slightly
   more accurate values for (mag/1000.0). */
double
DMagFactor (mag)
int mag;
{
    if (mag == 1095)
	return 1.095445;	/* stephalf */
    if (mag == 1315)
	return 1.314534;	/* stepihalf */
    if (mag == 2074)
	return 2.0736;		/* stepiv */
    if (mag == 2488)
	return 2.48832;		/* stepv */
    if (mag == 2986)
	return 2.985984;	/* stepiv */
 /* remaining mags have been ok */
    return (double) mag / 1000.;
}

/* Generate the name of a PXL font file, given the partial name `nm',
   at the magnification `magfactor', with design size `designsize',
   a global mag factor of `globalmag' (default 1000), and a fontname
   path of `path' (default PXLPATH).  Paths are defined as colon-
   separated strings (eg, "/usr/foo:/usr/bar").
   
   Font directories either contain all the fonts directly, or else each
   font is in its own subdirectory.  For example, amti10.* would be
   found in the `amti10' directory; ambx7.* in `ambx7', and so forth.
   The latter method is used iff there is a file in the main directory
   called `SUBDIR'. */
char *
GenPXLFileName (nm, magfactor, designsize, globalmag, path)
char *nm;
int   magfactor, designsize, globalmag;
char *path;
{
    double  dmag;
    register char  *s,
		   *p;
    register int    mag,	/* expected magnification */
                    slop;	/* current slop index */
    char   *slash;		/* path name separator */
    char   *fmt;		/* either oldfmt or newfmt */
    char    pbuf[256];		/* expansion area for path components */

    static char oldfmt[] = "%s%s%s%0.0s.%dpxl";
    static char newfmt[] = "%s%s%s/%s.%dpxl";
				/* the formats for generating names */
				/* arguments are path, /, nm, nm, sz */
    static char rv[256];	/* the generated name (and other uses) */

    if (globalmag == 0)
	globalmag = 1000;
    mag = (int) ((double) magfactor / (double) designsize * 1000.0 + .5);
    dmag = DMagFactor (mag);
    mag = (int) (DMagFactor (globalmag) * 1000.0 * dmag + .5);
    if (mag > 9999)
	mag = 9999;
    else if (mag < 0)
	mag = 0;

 /* For some reason I used to look for slashes in `nm', and suppress path
    expansion if there were any.  This seems awfully bogus, so I've changed
    it to suppress path expansion iff the font name starts with '/'.  Also,
    we no longer choke on font names with percent signs in them. */
    if (*nm == '/')
	slash = s = "";
    else {
	s = path;
	if (s == 0 || *s == 0)
	    s = PXLPATH;
	slash = "/";
    }

 /* Tread the path in s, trying for the file, and testing "nearby" names */
    while (s) {
	p = pbuf;
	while (*s) {
	    if ((*p = *s++) == ':')
		break;
	    p++;
	}
	*p = 0;
	if (*s == 0)
	    s = 0;

     /* choose new format if SUBDIR file exists, old format otherwise */
     /* but always use old format for names starting with / */
	if (*nm == '/')
	    fmt = oldfmt;
	else {
	    (void) sprintf (rv, "%s%sSUBDIR", pbuf, slash);
	    fmt = access (rv, 0) == 0 ? newfmt : oldfmt;
	}

	for (slop = 0; slop < FONT_SLOP; slop++) {
	    (void) sprintf (rv, fmt, pbuf, slash, nm, nm, mag + slop);
	    if (access (rv, 4) == 0)
		return rv;
	    if (slop) {
		(void) sprintf (rv, fmt, pbuf, slash, nm, nm, mag - slop);
		if (access (rv, 4) == 0)
		    return rv;
	    }
	}
    }

 /* Not found - give up and return expected name anyway */
 /* Someday, we may actually generate the PXL (or GF) file here. */
    (void) sprintf (rv, "%s.%dpxl", nm, mag);/* note: no path! */
    return rv;
}

/* Read in a PXL font file, performing all the necessary byte swapping.
   Return a pointer to a struct pxltail.  If 'getrast' is true, get the
   raster too. */

#define TAILSIZE (517 * 4)	/* size of pxl tail info */

struct pxltail *
ReadPXLFile (nm, getrast)
char *nm;
int   getrast;
{
    register char  *p;
    register int    f;
    struct stat stat;
#define px ((struct pxltail *) p)

 /* First open the file, and read the pxltail part */

    if ((f = open (nm, 0)) < 0)
	return 0;
    (void) fstat (f, &stat);
 /* There should be 4n bytes, with an absolute minimum of TAILSIZE + 4
    (+4 for the initial PXLID) */
    if (stat.st_size & 3 || stat.st_size < (TAILSIZE + 4)) {
	errno = EINVAL;
	return 0;
    }
    (void) lseek (f, (long) (-TAILSIZE), 2);
    p = malloc ((unsigned) TAILSIZE);
    if (p == 0)
	return 0;
    if (read (f, p, TAILSIZE) != TAILSIZE) {
	int     saverr = errno;
	free (p);
	errno = saverr;
	return 0;
    }

 /* Next, byte swap, since PXL file byte order is the opposite of VAX byte
    order */
    machint ((int *) p, TAILSIZE / 4);

 /* Finally, check the PXLID part, and if desired, read the character
    rasters */

    if (px -> px_pxlid != PXLID)
	error (0, 0, "Warning: strange PXL id (%d) in \"%s\"",
		px -> px_pxlid, nm);
    if (getrast) {
	int     rastsize = stat.st_size - (TAILSIZE + 4);

	if (ReadRasters (px -> px_info, f, rastsize, nm)) {
	    int     saverr = errno;
	    free (p);
	    errno = saverr;
	    return 0;
	}
    }
    (void) close (f);

    return px;
#undef px
}

/* Round n up to the nearest multiple of r (r must be a power of two) */
#define ROUND(n,r) (((n) + ((r) - 1)) & ~((r) - 1))

/* Read the raster info from a PXL file.  To avoid system call overhead, we
   read the entire thing into core, then break up the glyphs for the chinfo
   array.  NOTE: if malloc fails, we don't try very hard to clean up---most
   programs will die anyway if they fail to find a font.

   The reason for breaking up the characters in the first place is so that
   the storage allocated to any particular glyph may be freed.  The rotation
   code uses this to get rid of bits it no longer needs.  If they are not
   released, it is possible to run out of core when using many fonts. */
static
ReadRasters (ch, fd, sz, nm)
register struct chinfo *ch;
int fd, sz;
char *nm;
{
    register int    i;

    if (i = sz) {
	register char  *p,	/* glyph storage area */
		       *rp;	/* raster pointer */
	register int	rs;	/* raster size, in bytes */

    /* First, read all the glyph bits */
	if ((p = malloc ((unsigned) i)) == 0)
	    return -1;
	(void) lseek (fd, 4L, 0);
	if (read (fd, p, i) != i)
	    return -1;

    /* Next, break them up into the 128 characters */
	p -= 4;			/* to account for the initial PXLID */
	for (i = 128; --i >= 0; ch++) {
	    if (ch -> ch_rastoff) {
		rs = ch -> ch_height * (ROUND (ch -> ch_width, 32) >> 3);
		if ((rp = malloc ((unsigned) rs)) == 0)
		    return -1;
	     /* the << 2 accounts for the fact that ch_rastoff is for 32
		bit things, and we are using 8 bits (32/8 = 4 = 1<<2) */
		bcopy (&p[ch -> ch_rastoff << 2], rp, rs);
		ch -> ch_raster = rp;
	    }
	}

    /* Finally, release the temporary copy */
	free (p + 4);
    }
    else {			/* should be 'totally white' */
	for (i = 128; --i >= 0; ch++)
	    if (ch -> ch_rastoff || ch -> ch_height || ch -> ch_width ||
		    ch -> ch_yoffset || ch -> ch_xoffset)
		error (1, 0, "bad pxl file \"%s\"...help!", nm);
    }

    return 0;
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0