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 ---