[comp.sources.mac] PseudoPS

CER@STAR.STANFORD.EDU (Craig Rasmussen) (10/18/87)

[Info-Mac Archives: <INFO-MAC>UTILITY-PSEUDOPS05-PART[1-3].HQX]

[Moderator's Note:  The binary for this program has been posted to
 comp.binaries.mac.]

---
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	PseudoPS.doc
#	PseudoPS.h
#	PseudoPS.c
#	ParsePS.c
#	stack.c
#	PostScript.demo
sed 's/^X//' << 'SHAR_EOF' > PseudoPS.doc
XPseudoPS is a very small PostScript interpreter.  This version reads PostScript
Xfrom a text file and displays the graphics to the Macintosh screen.  Logically,
Xthere is really only one command (besides Quit).  By using the Open command
Xfrom the File menu, one can select the the PostScript file to be displayed.  As
Xa test you might want to open the file PostScript.demo. 
X
XThe PostScript subset includes: moveto, rmoveto, lineto, rlineto, arc,
Xtranslate, scale, setlinewidth, setgray, newpath, closepath, fill, stroke,
Xscalefont, and show.  If an unknown command is encountered an %offending
Xcommand message is printed to the file "PS.errors".  However, the program
Xcontinues so things can get messed up in a hurry -- if for instance, paths are
Xnot explicitly closed or if an unknown command leaves the stack in a unknown
Xstate.  A minor irritation is that if a file has already been displayed and
Xit's window has been closed, the files window must first be selected (from the
Xwindow menu) before it can be displayed again. 
X
XThe goal of this project was to make a "movie" on the Macintosh and not to make
Xan accurate rendition of PostScript.  It was kind of fun programming for the
XMac, though, wished I could do it more often.  Even though this program will
Xhandle only a small subset of the PostScript language, it has been useful to me
Xand I hope that you may find it useful as well.  Oh yes, please freely
Xdistribute and improve it.  If you do improve it, please mail the changes back
Xto me and I'll try to maintain the archived version. 
X
X/*
X *  PseudoPS -- a small PostScript interpreter (1987)
X *
X *  Written by		Craig E Rasmussen
X *			Center for Atmospheric and Space Science
X *			Utah State University
X *			Logan, Utah 84322-4405
X *			(801) 750-2967
X *
X *	email		- cer@star.stanford.edu
X *		        - theory::craig on the SPAN network
X *
X *  with the use of SimpleTools.c  (c) Erik Kilk 1986
X * 
X *  Link with LightSpeedC modules
X *	  -	MacTraps
X *	  -	math
X *	  -	stdio
X *	  -	strings
X *	  -	unix
X */
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > PseudoPS.h
X#define STRINGLENGTH 255
X#define WXTOP 3			/* 20  */
X#define WYTOP 40		/* 50  */
X#define WXBOT 508		/* 490 */
X#define WYBOT 338		/* 325 */
X
Xextern FILE *fpErr;
Xextern char PStext[STRINGLENGTH];
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > PseudoPS.c
X/*
X *  PseudoPS -- a small PostScript interpreter (1987)
X *
X *  Written by		Craig E Rasmussen
X *					Center for Atmospheric and Space Science
X *					Utah State University
X *					Logan, Utah 84322-4405
X *					(801) 750-2967
X *
X *	email		-	cer@star.stanford.edu
X *				-	theory::craig on the SPAN network
X *
X *  with the use of SimpleTools.c (c) Erik Kilk 1986
X * 
X *  This program may be freely distributed and modified as long as this
X *  header remains in place.
X *
X *  Link with LightSpeedC modules
X *	  -	MacTraps
X *	  -	math
X *	  -	stdio
X *	  -	strings
X *	  -	unix
X */
X 
X#include <Quickdraw.h>
X#include "simple.h"		/* SimpleTools header file	*/
X#include "PseudoPS.h"
X
XFILE *fpPS, *fpErr;
Xchar PStext[STRINGLENGTH];
Xint PSopen = FALSE;
X
Xinwindow (x, y)			/* executed when click in our window */
Xint x, y;
X{
X  Point m;
X	while ( StillDown() ) {	/* while the Button is pressed */
X		GetMouse (&m);		/* waste time */
X	}
X
X}
X
Xnop()
X{
X}
X
Xno_edit ()			/* turn off edit menu (on activation) */
X{
X  menu ("Edit", "", itemdisable);
X}
X
Xyes_edit ()			/* turn on edit menu (on deactivation) */
X{
X  menu ("Edit", "", itemenable);
X}
X
XaboutPs()			/* About message */
X{
X	char messageStr[255];
X	strcpy(messageStr,"PseudoPS -- by Craig E Rasmussen (1987)\r");
X	strcat(messageStr,"A very small PostScript interpreter.\r");
X	strcat(messageStr,"Please freely distribute and improve.\r");
X	if (message(messageStr)) {
X		strcpy(messageStr,"Programmed with the aid of SimpleTools\r");
X		strcat(messageStr,"(c) Erik Kilk 1986");
X		message(messageStr);
X	}
X}
X
XOpenPSfile()			/* to be executed File-open menu is selected */
X{
X	char PSfile[255], *PtoCstr();
X	int i, n, c;
X	
X	if (PSopen == TRUE) {
X		SysBeep(10);
X		message("a file is already open");
X		return;
X	}
X	if (getfile("TEXT", PSfile)) {
X		if ((fpPS = fopen(PtoCstr(PSfile), "r")) != NULL) {
X			PSopen = TRUE;
X			window (PSfile, WXTOP, WYTOP, WXBOT, WYBOT
X				, no_edit, yes_edit, nop, inwindow);
X			menu ("File", "Open.../O", itemdisable);
X			SetTransforms(WXTOP, WYTOP, WXBOT, WYBOT);
X		}
X		else SysBeep(10);
X	}
X	else SysBeep(10);
X}
X
X
Xsetup ()			/* Setup the menus and windows */
X{
X	menu (applestring, "About PsuedoPS...", aboutPs);
X	menu (applestring, "About PsuedoPS...", itemenable);
X	menu ("File", "Open.../O", OpenPSfile);
X	simplequits ();
X	
X	if ((fpErr = fopen("PS.errors", "w")) == NULL) {
X		SysBeep(0);
X		exit();
X	}
X}
X
Xmain ()
X{
X	
X	simpletools ("About PsuedoPS...");		/* Initialize SimpleTools	*/
X	setup ();
X	
X	while (1) {
X		simpleevents ();					/* Handle all events		*/
X		PostScript();
X	}
X}
X
X
XPostScript()
X{
X	char s[STRINGLENGTH];
X	int status;
X	float atof();
X
X	if (!PSopen) return;	
X	if ((status = getPS(s, STRINGLENGTH))) {
X		if (status == -1)
X			fprintf(fpErr, "PostScript buffer overflow\n");
X		else if (status == -2) {
X			fprintf(fpErr, "unterminated PostScript string\n");
X			strcpy(PStext, s);
X		}
X		else if (status == 2) strcpy(PStext, s);
X		else if (IsInteger(s)) push( (float)atoi(s) );
X		else if (IsFloat(s)) push(atof(s));
X		else ParsePS(s);
X	}
X}
X
X
X/*
X *  Copy PostScript token to s if present, return(1); else return(0) if
X *  no token present or return(-1) if buffer overflow.
X */
X 
XgetPS(s, max)
Xchar *s;
Xint max;
X{
X	char *sPtr;
X	int count = 0, c;
X
X	sPtr = s;
X	while (WhiteSpace(c = getc(fpPS)));		/* remove leading blanks */
X
X	if (c == '(') return(getPSstr(s, max));	/* get PostScript string */
X	
X	while (!WhiteSpace(c)) {				/* copy character to s */
X		if (c != EOF) {
X			if (++count < max) *sPtr++ = c;	/* copy c if space available */
X			else {							/* buffer overflow */
X				*sPtr = '\0';
X				return(-1);
X			}
X		}
X		else {								/* end of file reached */
X			fclose(fpPS);
X			PSopen = FALSE;
X			menu ("File", "Open.../O", itemenable);
X			if (count > 0) {				/* token present */
X				*sPtr = '\0';
X				return(1);
X			}
X			else return(0);					/* no token present */
X		}
X		c = getc(fpPS);
X	}
X	*sPtr = '\0';
X	return(1);								/* token present */
X}
X
X
X/*
X *  Copy PostScript string to s if present, return(2); else return(0) if
X *  no string not properly terminated or return(-1) if buffer overflow.
X *  Character '(' already found in input stream.
X */
X 
XgetPSstr(s, max)
Xchar *s;
Xint max;
X{
X	char *sPtr;
X	int count = 0, excess = 0, c;
X
X	sPtr = s;
X	c = getc(fpPS);
X	
X	while (c != ')'  ||  excess > 0) {		/* copy character to s */
X		if (c != EOF) {
X			if (++count < max) {			/* copy c if space available */
X				*sPtr++ = c;
X				if (c == '(') ++excess;		/* increase unbalanced ( count */
X				else if (c == ')') --excess;
X			}
X			else {							/* buffer overflow */
X				*sPtr = '\0';
X				return(-1);
X			}
X		}
X		else {								/* end of file reached */
X			fclose(fpPS);
X			PSopen = FALSE;
X			menu ("File", "Open.../O", itemenable);
X			if (count > 0) {				/* string present */
X				*sPtr = '\0';				/* but not terminated by ')' */
X				return(-2);
X			}
X			else return(0);					/* no string present */
X		}
X		c = getc(fpPS);
X	}
X	*sPtr = '\0';
X	return(2);								/* string present */
X}
X
X
XIsFloat(s)
Xchar *s;
X{
X	char c;
X
X	while (WhiteSpace(*s)) s++;
X	if (*s == '-' || *s == '+') s++;	
X	while (c = *s++)
X		if (c < '0' || c > '9') {
X			if (c == '.') break;
X			else return (0);
X		}
X	if (c != '.') return(0);					/* no decimal point */
X	while (c = *s++) if (c < '0'  ||  c > '9') return (0); /* decimal part */
X	return (1);
X} 
X
X
XIsInteger(s)
Xchar *s;
X{
X	char c;
X
X	while (WhiteSpace(*s)) s++;
X	if (*s == '-' || *s == '+') s++;	
X	while (c = *s++) if (c < '0'  ||  c > '9') return (0);
X	return (1);
X} 
X
XWhiteSpace(c)
X{
X	switch (c) {
X		case ' ':
X		case '\n':
X		case '\t':
X		case '\v':
X		case '\f':
X		case '\r':
X			return (1);
X		default:
X			return (0);
X	}
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ParsePS.c
X/*
X *  PseudoPS -- a small PostScript interpreter (1987)
X *
X *  Written by		Craig E Rasmussen
X *					Center for Atmospheric and Space Science
X *					Utah State University
X *					Logan, Utah 84322-4405
X *					(801) 750-2967
X *
X *	email		-	cer@star.stanford.edu
X *				-	theory::craig on the SPAN network
X */
X
X#include <Quickdraw.h>
X#include <stdio.h>
X#include "PseudoPS.h"
X
X#define DTR .01745329252
X
Xfloat xShift, yShift, xScale, yScale, rotate, cosTH, sinTH;
Xint HandleAllocated = FALSE, RegionOpen = FALSE;
XRgnHandle region;
X
X
XParsePS(s)
Xchar *s;
X{
X	Rect rect;
X	float x1, x2, x3, x4, x5, left, top, right, bottom;
X	int pop();
X	char outstring[80];
X
X	switch (*s) {
X		case 'a':
X			if (strcmp(s,"arc") == 0) {
X				if (pop(&x5) != 0) StackError();
X				if (pop(&x4) != 0) StackError();
X				if (pop(&x3) != 0) StackError();
X				if (pop(&x2) != 0) StackError();
X				if (pop(&x1) != 0) StackError();
X				left   = x1 - x3;
X				top    = x2 + x3;
X				right  = x1 + x3;
X				bottom = x2 - x3;
X				transform(&left, &top);
X				transform(&right, &bottom);
X				SetRect(&rect,(int)left,(int)top,(int)right,(int)bottom);
X				FrameArc(&rect, (int)(90.-x4), (int)(x4-x5));
X			}
X			else PSerror(s);
X			break;
X		case 'c':
X			if (strcmp(s,"closepath") == 0) {
X				if (!HandleAllocated) PSerror("closepath (no RegionHandle)");
X				else if (!RegionOpen) PSerror("closepath (no current path)");
X				else {
X					CloseRgn(region);
X					RegionOpen = FALSE;
X				}
X			}
X			else PSerror(s);
X			break;
X		case 'f':
X			if (strcmp(s,"fill") == 0) {
X				if (!HandleAllocated) PSerror("fill (no RegionHandle)");
X				else {
X					PaintRgn(region);
X					DisposeRgn(region);
X					HandleAllocated = FALSE;
X				}
X			}
X			else PSerror(s);
X			break;
X		case 'l':
X			if (strcmp(s,"lineto") == 0) {
X				if (pop(&x2) != 0) StackError();
X				if (pop(&x1) != 0) StackError();
X				transform(&x1, &x2);
X				LineTo((int)x1, (int)x2);
X			}
X			else PSerror(s);
X			break;
X		case 'm':
X			if (strcmp(s,"moveto") == 0) {
X				if (pop(&x2) != 0) StackError();
X				if (pop(&x1) != 0) StackError();
X				transform(&x1, &x2);
X				MoveTo((int)x1, (int)x2);
X			}
X			else PSerror(s);
X			break;
X		case 'n':
X			if (strcmp(s,"newpath") == 0) {
X				if (HandleAllocated) {
X					if (RegionOpen) {
X						PSerror("newpath (region already open)");
X						CloseRgn(region);
X					}
X					PSerror("newpath (RegionHandle already created)");
X					DisposeRgn(region);
X				}
X				region = NewRgn();
X				OpenRgn();
X				HandleAllocated = TRUE;
X				RegionOpen = TRUE;
X			}
X			else PSerror(s);
X			break;
X		case 'r':
X			if (strcmp(s,"rlineto") == 0) {
X				if (pop(&x2) != 0) StackError();
X				if (pop(&x1) != 0) StackError();
X				scale(&x1, &x2);
X				Line((int)x1, (int)x2);
X			}
X			else if (strcmp(s,"rmoveto") == 0) {
X				if (pop(&x2) != 0) StackError();
X				if (pop(&x1) != 0) StackError();
X				scale(&x1, &x2);
X				Move((int)x1, (int)x2);
X			}
X			else if (strcmp(s,"rotate") == 0) {
X				if (pop(&x1) != 0) StackError();
X				rotate = x1;
X				cosTH = 0.0;  /*cos(rotate*DTR);*/
X				sinTH = 1.0;  /*sin(rotate*DTR);*/
X			}
X			else PSerror(s);
X			break;
X		case 's':
X			if (strcmp(s,"scale") == 0) {
X				if (pop(&x2) != 0) StackError();
X				if (pop(&x1) != 0) StackError();
X				xScale *= x1;
X				yScale *= x2;
X			}
X			else if (strcmp(s,"scalefont") == 0) {
X				if (pop(&x1) != 0) StackError();
X				TextSize((int)x1);
X			}
X			else if (strcmp(s,"setgray") == 0) {
X				if (pop(&x1) != 0) StackError();
X				if (x1 > .875) PenPat(white);
X				else if (x1 > .625) PenPat(ltGray);
X				else if (x1 > .375) PenPat(gray);
X				else if (x1 > .125) PenPat(dkGray);
X				else PenPat(black);
X			}
X			else if (strcmp(s,"setlinewidth") == 0) {
X				if (pop(&x1) != 0) StackError();
X				PenSize((int)x1, (int)x1);
X			}
X			else if (strcmp(s,"show") == 0) {
X				CtoPstr(PStext);
X				DrawString(PStext);
X			}
X			else if (strcmp(s,"showpage") == 0) break;		/* nop */
X			else if (strcmp(s,"stroke") == 0) {
X				if (!HandleAllocated) PSerror("stroke (no RegionHandle)");
X				else {
X					FrameRgn(region);
X					DisposeRgn(region);
X					HandleAllocated = FALSE;
X				}
X			}
X			else PSerror(s);
X			break;
X		case 't':
X			if (strcmp(s,"translate") == 0) {
X				if (pop(&x2) != 0) StackError();
X				if (pop(&x1) != 0) StackError();
X				xShift += x1;
X				yShift += x2;
X			}
X			else PSerror(s);
X			break;
X		default:
X			PSerror(s);
X	}
X}
X
XPSerror(s)
Xchar *s;
X{
X/*	SerialPutS("\n%offending command -> ");
X	SerialPutS(s);
X	SerialPutChar('\n');  */
X	fprintf(fpErr, "%%offending command -> %s\n", s);
X}
X
X
XStackError()
X{
X/*	SerialPutS("\n%stack error\n");  */
X	fprintf(fpErr, "\n%%stack error\n");
X}
X
X
Xtransform(x, y)
Xfloat *x, *y;
X{
X	*x += xShift;
X	*y += yShift;	
X	scale(x, y);
X}
X
X
Xscale1D(r)
Xfloat *r;
X{
X	*r *= sqrt(xScale*xScale + yScale*yScale);
X}
X
X
XTransformAngle(t)
Xfloat *t;
X{
X	*t += rotate;
X}
X
X
Xscale(x, y)
Xfloat *x, *y;
X{
X	*x *=  xScale;
X	*y *= -yScale;					/* change increasing y to upwards */
X}
X
XSetTransforms(wXtop, wYtop, wXbot, wYbot)
Xint wXtop, wYtop, wXbot, wYbot;
X{
X	xShift = 0.0; yShift = 0.0; xScale = 1.0; yScale = 1.0;
X	rotate = 0.0; cosTH = 1.0; sinTH = 0.0;
X	SetOrigin(0, wYtop - wYbot);
X	PenPat(black);
X	PenSize(1,1);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > stack.c
X#define	STKSIZE	10
X
Xfloat stack[STKSIZE], *StkPtr = stack;
X
Xpush(x)
Xfloat x;
X{
X	if (StkPtr >= stack + STKSIZE) return(-1);	/* stack overflow */
X	*(++StkPtr) = x;
X	return(0);
X}
X
Xpop(x)
Xfloat *x;
X{		
X	if (StkPtr < stack) return(-1);		/* stack underflow */
X	*x = *StkPtr--;
X	return(0);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > PostScript.demo
X.5 setgray
X200 100 moveto
Xnewpath
X100 0 rlineto
X0 100 rlineto
X-100 0 rlineto
Xclosepath
Xfill
Xshowpage
SHAR_EOF
exit
---