/*
 *   Postscript Interpreter
 *   1.0
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <setjmp.h>
#include <Arthur.h>
#include "defs.h"
#include "vars.h"
#include "doos.h"

#define VERSION "1.0"

void docom(match, count)
struct idlist *match;
int count;
{
        int notfound = 1;
        if (count>=0 && used[count]) goto round;
        {
        struct usere *tt;
        int c = doffset;
        while (c>=0 && notfound) {
              tt=match->invoc;
              while (tt != NULL && tt->id != dictstack[c]) tt=tt->next;
              if (tt != NULL) {
                      notfound=0;
                      dstrip(tt); }
              else --c; }
        }
    round:
        if (notfound)
                switch(count) {
/* = */         case 0: if (current == NULL) seterror("stackunderflow");
                        stac(current);
                        pull();
                        break;
/* == */        case 1: if (current == NULL) seterror("stackunderflow");
                        pse(current);
                        printf("\n");
                        pull();
                        break;
/* [ */         case 2: pushmark(); break;
/* ] */         case RB: doarry(); break;
/* abs */       case 4: pushnum(fabs(pullnum())); break;
/* add */       case 5: getxy(); pushnum(x+y); break;
/* aload */     case 6: doaload(); break;
/* anchors */   case 7: doanch(); break;
/* and */       case 8: doaoe(1); break;
/* arc */       case 9: doarc(); break;
/* arcn */      case 10: doarcn(); break;
/* arcto */     case 11: doarcto(); break;
/* array */     case 12: doarray(); break;
/* ashow */     case 13: doshow(1); break;
/* astore */    case 14: doastore(); break;
/* atan */      case 15: getxy();
                         if (x==0 && y==0) seterror("undefinedresult");
                         else if (y==0) pushnum((double)(90+180*(x<0)));
                              else pushnum(deg(atan(x/y))+180*(x<0)+
                                        180*(x<0 && y>=0)+180*(y<0 && x>=0));
                         break;
/* awdthshow */ case 16: dowidthshow(1); break;
/* bnddevice */ case 17: undef();
/* begin */     case 18: dpush(); break;
/* bind */      case 19: pushproc(bind(pullproc())); break;
/* bitshift */  case 20: getxy(); if (y < 0) x = (double)((int)x >> (int)y);
                         else x = (double)((int)x << (int)y);
                         pushnum(x);
                         break;
/* bytesavlb */ case 21: undef();
/* cachstat */  case 22: undef();
/* ceiling */   case 23: pushnum((double)ceil(pullnum())); break;
/* charpath */  case 24: undef();
/* clear */     case 25: offset = -1; current=NULL; break;
/* cleartmrk */ case 26: while ((offset+1) && current->sort != MARK) pull();
                         if (offset+1) pull();
                         else seterror("unmatchedmark");
                         break;
/* clip */      case 27: undef();
/* clippath */  case 28: undef();
/* closefile */ case 29: doclosef(); break;
/* closepath */ case 30: pathelem(CLOSE, mzx, mzy);
                         break;
/* concat */    case 31: doconcat(); break;
/* concatm */   case 32: doconcatm(); break;
/* copy */      case 33: docopy(); break;
/* copypage */  case 34: undef();
/* cos */       case 35: pushnum(cos(rad(pullnum()))); break;
/* count */     case 36: pushnum((double)(offset+1)); break;
/* countdstk */ case 37: pushnum((double)(1+doffset));
                         break;
/* countexst */ case 38: undef();
/* counttmrk */ case 39: pushnum((double)cotm()); break;
/* currdash */  case 40: undef();
/* currdict */  case 41: pushdict(dictstack[doffset]); break;
/* currfile */  case 42: undef();
/* currflat */  case 43: pushnum((double)currgs->flat); break;
/* currfont */  case 44: pushspdict(currgs->font); break;
/* currgray */  case 45: pushnum((currgs->red+2*currgs->green+currgs->blue)/4);
                         break;
/* currhsb */   case 46: undef();
/* currlcap */  case 47: pushnum((double)currgs->lcap); break;
/* currlnjn */  case 48: pushnum((double)currgs->ljoin); break;
/* currlw */    case 49: pushnum((double)(cline*2)); break;
/* currmat */   case 50: docm(); break;
/* currmilm */  case 51: pushnum((double)currgs->mlim); break;
/* currpoint */ case 52: pushnum(cx); pushnum(cy); break;
/* currrgb */   case 53: pushnum(currgs->red);
                         pushnum(currgs->green);
                         pushnum(currgs->blue);
                         break;
/* currscr */   case 54: pushnum((double)freq); pushnum((double)ang);
                         pushnum((double)prc); break;
/* currtran */  case 55: pushproc(currgs->curt); break;
/* curveto */   case 56: curveto(-1); break;
/* cvi */       case 57: switch(current->sort) {
                         case NUMBER: pushnum((double)((int)pullnum()));
                                      break;
                         case STRING: pushnum((double)((int)atof(pullrs()->string)));
                                      break;
                         default: seterror("typecheck"); break; } break;
/* cvlit */     case 58: undef();
/* cvn */       case 59: docvn(); break;
/* cvr */       case 60: switch(current->sort) {
                         case NUMBER: break;
                         case STRING: pushnum(atof(pullrs()->string)); break;
                         default: seterror("typecheck"); break; } break;
/* cvrs */      case 61: docvrs(); break;
/* cvs */       case 62: docvs(); break;
/* cvx */       case 63: undef();
/* def */       case 64: dodef(); break;
/* defmat */    case 65: dodm(); break;
/* deffont */   case 66: undef();
/* dict */      case 67: x=pullnum(); pushdict(dcreate((int)x)); break;
/* dictstack */ case 68: dodictstack(); break;
/* div */       case 69: getxy(); if (y==0) seterror("undefinedresult");
                                  else pushnum(x/y);
                         break;
/* dtrans */    case 70: dotrans(0); break;
/* dup */       case 71: dodup(); break;
/* echo */      case 72: echo=pullbool(); break;
/* end */       case 73: if (doffset) doffset--;
                         else seterror("dictstackunderflow");
                         break;
/* eoclip */    case 74: undef();
/* eofill */    case 75: startfill(0); break;
/* eq */        case 76: doequ(0); break;
/* erasepage */ case 77: doclg(); break;
/* errordict */ case 78: undef();
/* exch */      case 79: if (doexch()) seterror("stackunderflow"); break;
/* exec */      case 80: doexec(); break;
/* execstack */ case 81: undef();
/* execonly */  case 82: undef();
/* exit */      case 83: exx=0; break;
/* exp */       case 84: getxy(); pushnum(pow(x,y)); break;
/* false */     case 85: pushbool(0); break;
/* file */      case 86: dofile(); break;
/* fill */      case 87: startfill(1); break;
/* findfont */  case 88: dofindfont(); break;
/* flatpath */  case 89: undef();
/* floor */     case 90: pushnum((double)floor(pullnum())); break;
/* flush */     case 91: undef();
/* flushfile */ case 92: undef();
/* fontdir */   case 93: pushdict(fontdir); break;
/* for */       case 94: dofor(); break;
/* forall */    case 95: doforall(); break;
/* framdev */   case 96: undef();
/* ge */        case 97: doqu(1); break;
/* get */       case 98: doget(); break;
/* getint */    case 99: dogetint(); break;
/* grestore */  case 100: pullgraph(); break;
/* grestall */  case 101: undef();
/* gsave */     case 102: pushgraph(); break;
/* gt */        case 103: doqu(2); break;
/* idmatrix */  case 104: identmatrix(); break;
/* idiv */      case 105: getxy(); pushnum((double)((int)x / (int)y));
                          break;
/* idtrans */   case 106: doitrans(0); break;
/* if */        case 107: doif();
                          break;
/* ifelse */    case 108: doifelse();
                          break;
/* image */     case 109: doimage(1); break;
/* imagemask */ case 110: doimage(0); break;
/* index */     case 111: index(); break;
/* initclip */  case 112: undef();
/* initgraph */ case 113: initgraphics(); break;
/* initmat */   case 114: setmat(ctm,1.0,0.0,0.0,1.0,0.0,0.0);
                          readctm(ctm); break;
/* invmat */    case 115: doinvmat(); break;
/* itrans */    case 116: doitrans(1); break;
/* known */     case 117: doknown(); break;
/* kshow */     case 118: dokshow(); break;
/* le */        case 119: doqu(3); break;
/* length */    case 120: dolength(); break;
/* lineto */    case 121: getxy(); graph(5, x-cx, y-cy); break;
/* ln */        case 122: pushnum(log(pullnum())); break;
/* load */      case 123: doload(); break;
/* log */       case 124: pushnum(log(pullnum())/LNTEN); break;
/* loop */      case 125: doloop(); break;
/* lt */        case 126: doqu(4); break;
/* makefont */  case 127: domakefont(); break;
/* mark */      case 128: pushmark(); break;
/* matrix */    case 129: pusharray(createarray(6));
                          identmatrix(); break;
/* maxlength */ case 130: doml(); break;
/* mod */       case 131: getxy(); pushnum((double)((int)x % (int)y));
                          break;
/* moveto */    case 132: getxy(); graph(4, x-cx, y-cy); break;
/* mul */       case 133: getxy(); pushnum(x*y); break;
/* ne */        case 134: doequ(1); break;
/* neg */       case 135: pushnum(-1*pullnum()); break;
/* newpath */   case 136: currgs->nopath=1; baseg=NULL; cpath=0; break;
/* noaccess */  case 137: undef();
/* not */       case 138: if (pullbool()) pushbool(0);
                          else pushbool(1); break;
/* null */      case 139: pushnull(); break;
/* nulldev */   case 140: undef();
/* or */        case 141: doaoe(2); break;
/* pathbbox */  case 142: dopathbbox(); break;
/* pathfora */  case 143: dopathforall(); break;
/* pop */       case 144: pull(); break;
/* print */     case 145: doprint(); break;
/* prompt */    case 146: longjmp(env, 1); break;
/* pstack */    case 147: pstack(); break;
/* put */       case 148: doput(); break;
/* putint */    case 149: doputint(); break;
/* quit */      case 150: exit(0); break;
/* rand */      case 151: pushnum((double)(rand())); break;
/* rcheck */    case 152: docheck(READ); break;
/* rcurveto */  case 153: curveto(0); break;
/* read */      case 154: doread(); break;
/* rdhxstr */   case 155: dorhs(); break;
/* readline */  case 156: doreadline(); break;
/* readonly */  case 157: undef();
/* readstr */   case 158: doreadstring(); break;
/* rendbands */ case 159: undef();
/* repeat */    case 160: dorepeat(); break;
/* resetfile */ case 161: undef();
/* restore */   case 162: undef();
/* revpath */   case 163: undef();
/* rlineto */   case 164: getxy(); graph(5, x, y); break;
/* rmoveto */   case 165: getxy(); graph(4, x, y); break;
/* roll */      case 166: doroll(); break;
/* rotate */    case 167: changectm(ROTATE); break;
/* round */     case 168: x=pullnum();
                          if (x>=0) pushnum((double)((int)(x+0.5)));
                          else pushnum((double)(-(int)(0.4-x)));
                          break;
/* rrand */     case 169: undef();
/* run */       case 170: dorun(pullrs()->string); break;
/* save */      case 171: undef();
/* scale */     case 172: changectm(SCALE); break;
/* scalefont */ case 173: doscalefont(); break;
/* search */    case 174: dosearch(); break;
/* setcachdv */ case 175: undef();
/* setcachlm */ case 176: undef();
/* setcharwd */ case 177: undef();
/* setdash */   case 178: undef();
/* setflat */   case 179: x=pullnum(); if (x<0) seterror("typecheck");
                          else currgs->flat=x;
                          break;
/* setfont */   case 180: currgs->font=pullspdict(); break;
/* setgray */   case 181: {
                          double cgray;
                          cgray = pullnum();
                          if (cgray<0 || cgray>1) seterror("undefined");
                          currgs->red=cgray;
                          currgs->green=cgray;
                          currgs->blue=cgray;
                          setcol(); }
                          break;
/* sethsb */    case 182: undef();
/* setlinecp */ case 183: x=pullnum();
                          if (x==0 || x==1 || x==2) currgs->lcap=(int)x;
                          else seterror("typecheck");
                          break;
/* setlinejn */ case 184: x=pullnum();
                          if (x==0 || x==1 || x==2) currgs->ljoin=(int)x;
                          else seterror("typecheck");
                          break;
/* setlw */     case 185: cline = pullnum()/2; break;
/* setmat */    case 186: ctm=pullarray(); readctm(ctm); break;
/* setmitlim */ case 187: x=pullnum();
                          if (x<1) seterror("rangecheck");
                          else currgs->mlim=x;
                          break;
/* setrgb */    case 188: currgs->blue = pullnum();
                          currgs->green = pullnum();
                          currgs->red = pullnum();
                          if (currgs->blue<0 || currgs->blue>1 ||
                              currgs->green<0 || currgs->green>1 ||
                              currgs->red<0 || currgs->red>1)
                                seterror("undefined");
                          setcol();
                          break;
/* setscreen */ case 189: getxy();
                          prc=y;
                          ang=x;
                          x=pullnum();
                          freq=x;
                          break;
/* settran */   case 190: currgs->curt=pullproc(); break;
/* show */      case 191: doshow(0); break;
/* showpage */  case 192: doclg(); initgraphics(); break;
/* sin */       case 193: pushnum(sin(rad(pullnum()))); break;
/* sqrt */      case 194: pushnum(sqrt(pullpnum())); break;
/* srand */     case 195: srand((int)(pullnum())); break;
/* stack */     case 196: dostack(); break;
/* standenc */  case 197: pusharray(stenca); break;
/* start */     case 198: undef();
/* status */    case 199: pushbool(pullfile()->status != CLOSED); break;
/* stop */      case 200: if (allowed) exx=0;
                          else {
                               printf("Interpreter stopped\n");
                               exit(1); }
                          break;
/* stopped */   case 201: dostopped(); break;
/* store */     case 202: dostore(); break;
/* string */    case 203: dostring(); break;
/* strwidth */  case 204: dostringwidth(); break;
/* stroke */    case 205: dostroke(); break;
/* strokepth */ case 206: undef();
/* sub */       case 207: getxy(); pushnum(x-y); break;
/* systdict */  case 208: undef();
/* token */     case 209: undef();
/* transform */ case 210: dotrans(1); break;
/* translate */ case 211: changectm(TRANSLATE); break;
/* true */      case 212: pushbool(1); break;
/* truncate */  case 213: pushnum((double)((int)pullnum())); break;
/* type */      case 214: dotype(); break;
/* userdict */  case 215: pushdict(dictstack[0]); break;
/* usertime */  case 216: pushnum((double)(clock()*10)); break;
/* version */   case 217: pushms(VERSION, 3); break;
/* vmstatus */  case 218: undef();
/* wcheck */    case 219: docheck(WRITE); break;
/* where */     case 220: dowhere(); break;
/* widthshow */ case 221: dowidthshow(0); break;
/* write */     case 222: dowrite(); break;
/* wrhxstr */   case 223: dowhs(); break;
/* writestr */  case 224: dowritestring(); break;
/* xcheck */    case 225: undef();
/* xor */       case 226: doaoe(3); break;
                default: printf("%s ", match->name);
                         seterror("undefined"); }
}

void pids()
{
  printf("Postscript Interpreter - Version %s\n\n", VERSION);
  printf("Commands not implemented...\n\n");
  printf("banddevice      bytesavailable  cachestatus     charpath\n");
  printf("clip            clippath        copypage        countexecstack\n");
  printf("currentdash     currentfile     cvlit           cvx\n");
  printf("definefont      eoclip          errordict       execstack\n");
  printf("flattenpath     flush           flushfile       framedevice\n");
  printf("grestoreall     initclip        noaccess        nulldevice\n");
  printf("readonly        renderbands     resetfile       reversepath\n");
  printf("rrand           save            setcachedevice  setcachelimit\n");
  printf("setcharwidth    setdash         start           strokepath\n");
  printf("systemdict      token           vmstatus        xcheck\n");
  exit(0);
}

int main(argc, argv)
int argc;
char *argv[];
{
        char inp[256];
        int notdone=1;
        if (argc > 1 && strcmp(argv[1], "-bw")==0) bw=1;
        if (argc > 1 && strcmp(argv[1], "-id")==0) pids();
        if (argc > 1 && strcmp(argv[1], "-help")==0) {
                printf("Postscript Interpreter - Version %s\n\n", VERSION);
                printf("Options:        -bw     Set gray scale option. (Default is colour)\n");
                printf("                -id     List commands not implemented\n");
                printf("                -help   Print this\n");
                exit(0); }
        startup(VERSION);
        initgraphics();
        doclg();
        if (setjmp(env)) {
                escpress=0;
                cb=0;
                rb=0;
                acc[0]=0; }
        if (notdone && argc > 1) {
                notdone=0;
                if (!bw || argc==3) dorun(argv[1+(argc>2)]); }
        while(1) {
                if (current != NULL) {
                        pse(current);
                        printf("  "); }
                printf("PS>");
                if (!echo) putchar((char)21);
                gets(inp);
                if (!echo) putchar((char)6);
                escpress=0;
                single(inp);
                single("\n");
        }
}                              
