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

extern char *save(char *);
extern struct arrele *createarray(int);
extern struct arrele *concat(struct arrele *,struct arrele *,struct arrele *);
extern struct arrele *pullarray(void);
extern void dstrip (struct usere *);
extern void single (char *);
extern void docom(struct idlist *, int);
extern struct arrele *bind(struct arrele *);

double fonta,fontb,fontc,fontd,fonte,fontf;
double ccpox, ccpoy;
int numputs, newflag=1;
char *ndefstr;
int echo=1;
struct gstate gstack[32];
struct stelem mstack[500];
int allowed=0;
int gpo=0;
struct arrele *ttq,*ttq2;
int bw=0;
int globc;
struct userdict *dictstack[20];
int doffset=0;
struct idlist *idbase=NULL;
char used[230];
static struct etr *et[256];
struct etr *etbase;
int pths,etc;
double dgc=57.2957795;
double ox1,oy1,ox2,oy2;
double etx;
double mcx,mcy,mzx,mzy;
int clsd;
int ety;
int ymin, ymax;
int fflg=0;
int oldang;
int abc;
int exx=1;
int ab=0;
int on=0;
int to;
int escpress = 0;
jmp_buf env;
int flag = 0;
int ind = 0;
int cb = 0;
int rb = 0;
int esc = 0;
int offset = -1;
double cx = 0;
double cy = 0;
int cpath = 0;
int drti = 0;
double cline;
double freq,ang,prc;
double tim = 0.03125;
double tma,tmb,tmc,tmd,tmx,tmy;
int pjoin=0;
double t1[32],t2[32],t3[32];
double sintab[720],costab[720];

char acc[500];

struct gpath *baseg = NULL;
struct gpath *nextg = NULL;
struct gstate *currgs = NULL;

double x,y;

struct arrele *ctm;

struct userdict *fontdir;

struct stelem *current = NULL;

double pullnum(void);
void pushnum(double);
void dooproc(struct arrele *);
void seterror(char *);

char *tenc[] = {
        "space","exclam","quotedbl","numbersign","dollar",
        "percent","ampersand","quoteright","parenleft",
        "parenright","asterisk","plus","comma","hyphen",
        "period","slash","zero","one","two","three","four",
        "five","six","seven","eight","nine","colon",
        "semicolon","less","equal","greater","question",
        "at","A","B","C","D","E","F","G","H","I","J","K",
        "L","M","N","O","P","Q","R","S","T","U","V","W","X",
        "Y","Z","bracketleft","backslash","bracketright",
        "asciicircum","underscore","quoteleft","a","b","c",
        "d","e","f","g","h","i","j","k","l","m","n","o","p",
        "q","r","s","t","u","v","w","x","y","z","braceleft",
        "bar","braceright","asciitilde" };

char *systemdict[] ={
        "=","==","[","]",
        "abs","add","aload","anchorsearch","and","arc","arcn","arcto",
        "array","ashow","astore","atan","awidthshow","banddevice",
        "begin","bind","bitshift","bytesavailable","cachestatus",
        "ceiling","charpath","clear","cleartomark","clip","clippath",
        "closefile","closepath","concat","concatmatrix","copy",
        "copypage","cos","count","countdictstack","countexecstack",
        "counttomark","currentdash","currentdict","currentfile",
        "currentflat","currentfont","currentgray","currenthsbcolor",
        "currentlinecap","currentlinejoin","currentlinewidth",
        "currentmatrix","currentmiterlimit","currentpoint",
        "currentrgbcolor","currentscreen","currenttransfer",
        "curveto","cvi","cvlit","cvn","cvr","cvrs","cvs","cvx",
        "def","defaultmatrix","definefont","dict","dictstack",
        "div","dtransform","dup","echo","end","eoclip","eofill",
        "eq","erasepage","errordict","exch","exec","execstack",
        "executeonly","exit","exp","false","file","fill","findfont",
        "flattenpath","floor","flush","flushfile","fontdirectory",
        "for","forall","framedevice","ge","get","getinterval",
        "grestore","grestoreall","gsave","gt","identmatrix",
        "idiv","idtransform","if","ifelse","image","imagemask",
        "index","initclip","initgraphics","initmatrix",
        "invertmatrix","itransform","known","kshow","le","length",
        "lineto","ln","load","log","loop","lt","makefont","mark",
        "matrix","maxlength","mod","moveto","mul","ne","neg",
        "newpath","noaccess","not","null","nulldevice","or",
        "pathbbox","pathforall","pop","print","prompt","pstack",
        "put","putinterval","quit","rand","rcheck",
        "rcurveto","read","readhexstring","readline","readonly",
        "readstring","renderbands","repeat","resetfile","restore",
        "reversepath","rlineto","rmoveto","roll","rotate","round",
        "rrand","run","save","scale","scalefont","search",
        "setcachedevice","setcachelimit","setcharwidth","setdash",
        "setflat","setfont","setgray","sethsbcolor","setlinecap",
        "setlinejoin","setlinewidth","setmatrix","setmiterlimit",
        "setrgbcolor","setscreen","settransfer","show",
        "showpage","sin","sqrt","srand","stack",
        "standardencoding","start","status","stop","stopped",
        "store","string","stringwidth","stroke","strokepath",
        "sub","systemdict","token","transform","translate","true",
        "truncate","type","userdict","usertime","version",
        "vmstatus","wcheck","where","widthshow","write",
        "writehexstring","writestring","xcheck","xor","xx",(char *)0 };

struct arrele *stenca;

double rad(degrees)
double degrees;
{
        return(degrees/dgc);
}

double deg(radians)
double radians;
{
        return(radians*dgc);
}

char *ftos(number)
double number;
{
        char name[30];
        sprintf((char *)name, "%g", number);
        return((char *)save((char *)name));
}        

void getxy()
{
        y = pullnum();
        x = pullnum();
}

void setgray(val)
double val;
{
        pushnum(val);
        dooproc(currgs->curt);
        val=pullnum();
        if (val<0 || val>1) seterror("undefined");
        if (bw) gcol(0, (int)(val*16-(val==1)));
        else {
                gcol(0, 21*(int)(val*4-(val==1)));
                tint(2, (int)(val*16-(val==1)) % 4); }
}

void setcol()
{
        int c;
        int t=0;
        int d=3;
        int f;
        if (currgs->red == currgs->green && currgs->red == currgs->blue)
                setgray(currgs->red);
        else {
                c=(int)((int)(currgs->red*4)-(int)(currgs->red==1));
                f=(int)(c+(((int)(currgs->green*4)-(currgs->green==1)) << 2) +
                        (((int)(currgs->blue*4)-(currgs->blue==1)) << 4));
                gcol(0, f);
                if (currgs->red==0) d--;
                if (currgs->green==0) d--;
                if (currgs->blue==0) d--;
                if (bw) gcol(0, ((int)(currgs->red*16-(currgs->red==1))+
                                 (int)(currgs->green*16-(currgs->green==1))+
                                 (int)(currgs->blue*16-(currgs->blue==1)))/d);
                else {
                        t=(((int)(currgs->red*16-(currgs->red==1)) & 3)+
                             ((int)(currgs->green*16-(currgs->green==1)) & 3)+
                             ((int)(currgs->blue*16-(currgs->blue==1)) & 3))/d;
                        tint(2, t); }
                }
}

void doclg()
{
        if (bw) gcol(0, 15);
        else {
                gcol(0, 63);
                tint(2,3); }
        rectanglefill(0,0,718,1023);
        setcol();
}

struct usere *searchdic(match)
char *match;
{
        struct idlist *t = idbase;
        while (t != NULL && strcmp(match, t->name) != 0) t=t->next;
        if (t == NULL) return(NULL);
        else {
                int found=0;
                struct usere *g;
                globc=doffset;
                while (globc>=0 && !found) {
                        g=t->invoc;
                        while (g != NULL && g->id != dictstack[globc])
                                g=g->next;
                        if (g != NULL) found=1;
                        else --globc;
                        }
                return(g);
                }
}

void seterror(match)
char *match;
{
        struct usere *tuser;
        tuser=searchdic(match);
        if (tuser != NULL) {
                dstrip(tuser);
                longjmp(env, 1); }
        else {
                printf("%s\n", match);
                longjmp(env, 1); }
}

void undef()
{
        seterror("Not implemented");
}

int hex(ch)
char ch;
{
        if (ch >= 'a' && ch <= 'f') ch=ch-32;
        if (ch >= '0' && ch <= '9') return(ch-48);
        else if (ch >= 'A' && ch <= 'F') return(ch-55);
             else {
               seterror("rangecheck"); return(0); }
}

int tohex(ch)
int ch;
{
        return(48+ch+39*(ch>9));
}

void readctm(temp)
struct arrele *temp;
{
        struct stelem *t=temp->array;
        tma = t[0].u.number;
        tmb = t[1].u.number;
        tmc = t[2].u.number;
        tmd = t[3].u.number;
        tmx = t[4].u.number;
        tmy = t[5].u.number;
}

void pull()
{
        if (offset > 0) {
                --offset;
                current = &mstack[offset];
                }
        else if (offset) seterror("stackunderflow");
             else {
                        --offset;
                        current = NULL;
                  }
}

struct idlist *pullname()
{
        struct idlist *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != NAME) seterror("typecheck");
        temp = current->u.name;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

char *pullspec()
{
        char *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != SPECNAME) seterror("typecheck");
        temp = current->u.spname;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

struct fontdict *pullspdict()
{
        struct fontdict *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != SPECDICT) seterror("typecheck");
        temp = current->u.spdict;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

int pullbool()
{
        int temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != BOOLEAN) seterror("typecheck");
        temp = current->u.bool;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

struct strdef *pullrs()
{
        struct strdef *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != STRING) seterror("typecheck");
        temp = current->u.restr;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

struct userdict *pulldict()
{
        struct userdict *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != DICTIONARY) seterror("typecheck");
        temp = current->u.dict;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

void dpush()
{
        struct userdict *t=pulldict();
        if (doffset == 19) seterror("dictstackoverflow");
        doffset++;
        dictstack[doffset] = t;
}

struct userdict *dcreate(amount)
int amount;
{
        struct userdict *temp;
        temp = (struct userdict *)calloc(1, sizeof(struct userdict));
        temp->maxsize = amount;
        temp->size = 0;
        temp->start = NULL;
        return(temp);
}

void pushst(elem)
struct stelem *elem;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        *current = *elem;
}

void pushnum(val)
double val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = NUMBER;
        current->u.number = val;
}

void pushspec(val)
char *val;
{
        if (offset == MAXSTACK) seterror("stackunderflow");
        offset++;
        current = &mstack[offset];
        current->sort = SPECNAME;
        current->u.spname = val;
}

void pushspdict(val)
struct fontdict *val;
{
        if (offset == MAXSTACK) seterror("stackunderflow");
        offset++;
        current = &mstack[offset];
        current->sort = SPECDICT;
        current->u.spdict = val;
}

void pushname(val)
struct idlist *val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = NAME;
        current->u.name = val;
}

void pushoper(val, count)
struct idlist *val;
int count;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = OPERATOR;
        current->u.oper.k = count;
        current->u.oper.called = val;
}

void pushrs(val)
struct strdef *val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = STRING;
        current->u.restr = val;
}

void pushms(str, l)
char *str;
int l;
{
        struct strdef *new;
        new = (struct strdef *)calloc(1, sizeof(struct strdef));
        new->string = str;
        new->len = l;
        pushrs(new);
}

void pushdict(val)
struct userdict *val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = DICTIONARY;
        current->u.dict = val;
}

void pushbool(val)
int val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = BOOLEAN;
        current->u.bool = val;
}

void pushfile(val)
struct phile *val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = FILETYPE;
        current->u.filo = val;
}

void pushmark()
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = MARK;
}

void pushnull()
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = EMPTY;
}

void pushpmark()
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = PMARK;
}

void pusharray(val)
struct arrele *val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = ARRAY;
        current->u.array = val;
}

void pushproc(val)
struct arrele *val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = PROCEDURE;
        current->u.array = val;
}

void dooproc(start)
struct arrele *start;
{
        int c=0,l;
        struct stelem *t=start->array, *ss;
        l=start->length;
        exx=1;
        while (c<l && exx) {
                ss=&t[c];
                switch(ss->sort) {
                case EMPTY: pushnull();
                            break;
                case NUMBER: pushnum(ss->u.number);
                             break;
                case ARRAY: pusharray(ss->u.array);
                            break;
                case DICTIONARY: pushdict(ss->u.dict);
                                 break;
                case STRING: pushrs(ss->u.restr);
                             break;
                case NAME: pushname(ss->u.name);
                           break;
                case BOOLEAN: pushbool(ss->u.bool);
                              break;
                case PROCEDURE: pushproc(ss->u.array);
                                break;
                case MARK: pushmark();
                           break;
                case FILETYPE: pushfile(ss->u.filo);
                               break;
                case PMARK: break;
                case OPERATOR: docom(ss->u.oper.called,ss->u.oper.k);
                               break;
                case SPECNAME: pushspec(ss->u.spname);
                               break;
                case SPECDICT: pushspdict(ss->u.spdict);
                               break; }
                c++; }
}

void pushgraph()
{
        if (gpo==31) seterror("limitcheck");
        currgs->path = baseg;
        currgs->epath = nextg;
        currgs->ctma = tma;
        currgs->ctmb = tmb;
        currgs->ctmc = tmc;
        currgs->ctmd = tmd;
        currgs->ctmx = tmx;
        currgs->ctmy = tmy;
        currgs->cline = cline;
        currgs->cx = cx;
        currgs->cy = cy;
        gpo++;
        gstack[gpo]=gstack[gpo-1];
        currgs=&gstack[gpo];
}

void setnum(a, val)
struct stelem *a;
double val;
{
        a->sort = NUMBER;
        a->u.number = val;
}

void doaoe(which)
int which;
{
        int ans=0;
        int b;
        int b2;
        switch(current->sort) {
        case BOOLEAN: b=pullbool();
                      b2=pullbool();
                      switch(which) {
                      case 1: if (b && b2) ans=1; break;
                      case 2: if (b || b2) ans=1; break;
                      case 3: if (b ^ b2) ans=1; break; }
                      pushbool(ans);
                      break;
        case NUMBER: b=(int)pullnum();
                     switch(which) {
                     case 1: ans=((int)pullnum()) & b; break;
                     case 2: ans=((int)pullnum()) | b; break;
                     case 3: ans=((int)pullnum()) ^ b; break; }
                     pushnum((double)ans);
                     break;
        default: seterror("typecheck"); break; }
}

void setmat(arry,a,b,c,d,e,f)
struct arrele *arry;
double a,b,c,d,e,f;
{
        struct stelem *ar=arry->array;
        setnum(&ar[0], a);
        setnum(&ar[1], b);
        setnum(&ar[2], c);
        setnum(&ar[3], d);
        setnum(&ar[4], e);
        setnum(&ar[5], f);
}

struct arrele *inverse(mat, dest)
struct arrele *mat;
struct arrele *dest;
{
        double a,b,c,d,e,f,det;
        struct stelem *m=mat->array;
        a = m[0].u.number;
        b = m[1].u.number;
        c = m[2].u.number;
        d = m[3].u.number;
        e = m[4].u.number;
        f = m[5].u.number;
        det = a*d-b*c;
        if (det == 0) seterror("undefinedresult");
        setmat(dest,d/det,-b/det,-c/det,a/det,(c*f-d*e)/det,-(a*f-b*e)/det);
        return(dest);
}

void doinvmat()
{
        struct arrele *mat1;
        struct arrele *mat2;
        mat2 = (struct arrele *)pullarray();
        mat1 = (struct arrele *)pullarray();
        if (mat1->length == 6 && mat2->length == 6)
                pusharray(inverse(mat1, mat2));
        else seterror("typecheck");
}

void pdub(g,mat)
struct gpath *g;
struct arrele *mat;
{
        double tx,ty;
        tx=g->xc;
        ty=g->yc;
        readctm(mat);
        pushnum(tma*tx+tmc*ty+tmx);
        pushnum(tmb*tx+tmd*ty+tmy);
        readctm(ctm);
}

void sttod(from, to)
struct stelem *from;
struct usere *to;
{
        to->sort = from->sort;
        to->u = from->u;
}

struct arrele *whicht(tr)
int tr;
{
        int an;
        struct arrele *temp=ttq;
        switch (tr) {
        case ROTATE: an=(int)(2*pullnum());
                     while (an >= 720) an-=720;
                     while (an < 0) an+=720;
                     setmat(temp,costab[an],sintab[an],
                            -sintab[an],costab[an],0.0,0.0);
                     break;
        case TRANSLATE: getxy();
                        setmat(temp,1.0,0.0,0.0,1.0,x,y);
                        break;
        case SCALE: getxy();
                    setmat(temp,x,0.0,0.0,y,0.0,0.0);
                    break;
        default: break; }
        readctm(inverse(temp, ttq2));
        cx=tma*cx+tmc*cy+tmx;
        cy=tmb*cx+tmd*cy+tmy;
        readctm(ctm);
        return(temp);
}

void changectm(tr)
int tr;
{
        struct arrele *temp;
        switch(current->sort) {
        case ARRAY:  temp=(struct arrele *)pullarray();
                     if (temp->length != 6) seterror("typecheck");
                     else pusharray(concat(whicht(tr),temp,temp));
                     break;
        case NUMBER: concat(whicht(tr), ctm, ctm);
                     break;
        default: seterror("typecheck"); break; }
        readctm(ctm);
}

int cotm()
{
        int of=offset;
        while (of >= 0 && mstack[of].sort != MARK) --of;
        if (of<0) seterror("unmatchedmark");
        return(offset-of);
}

void pushele(val)
struct stelem *val;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        *current = *val;
}

char *save(value)
char *value;
{
        char *c;
        int k = -1;
        c=(char *)calloc(1+strlen(value), sizeof(char));
        do {
                k++;
                c[k]=value[k]; }
        while (value[k]!=0);
        return(c);
}


struct arrele *createarray(n)
int n;
{
        struct arrele *temp;
        temp = (struct arrele *)calloc(1, sizeof(struct arrele));
        temp->length = n;
        if (n>0) temp->array=(struct stelem *)calloc(n, sizeof(struct stelem));
        else temp->array = NULL;
        return(temp);
}

void deletearray(mat)
struct arrele *mat;
{
        if (mat->array != NULL) free(mat->array);
        free(mat);
}

void linejoin()
{
        switch(currgs->ljoin) {
        case 0:
                break;
        case 1:
                circlefill((int)currgs->ax,(int)currgs->ay,(int)cline);
                break;
        case 2:
                break; }
}

void linecap(theta, sx, sy, tx, ty)
int theta;
double sx,sy,tx,ty;
{
        double xx,yy,xz,yz;
        if (currgs->lcap)
                switch (currgs->lcap) {
                case 1:
                        circlefill((int)sx,(int)sy,(int)cline);
                        circlefill((int)tx,(int)ty,(int)cline);
                        break;
                case 2:
                        xx=cline*costab[theta];
                        yy=cline*sintab[theta];
                        xz=cline*costab[180-theta];
                        yz=cline*sintab[180-theta];
                        if (sx>tx || (sx==tx && sy>ty)) {
                        xz = -xz;
                        yz = -yz; }
                        plot(4, (int)(sx-xx), (int)(sy+yy));
                        plot(4, (int)(sx+xx), (int)(sy-yy));
                        plot(85, (int)(sx-xz-xx), (int)(sy-yz+yy));
                        plot(85, (int)(sx-xz+xx), (int)(sy-yz-yy));
                        plot(4, (int)(tx-xx), (int)(ty+yy));
                        plot(4, (int)(tx+xx), (int)(ty-yy));
                        plot(85, (int)(tx+xz-xx), (int)(ty+yz+yy));
                        plot(85, (int)(tx+xz+xx), (int)(ty+yz-yy));
                        break; }
}

void tplot(a,bl,cl)
int a;
double bl,cl;
{
        int theta;
        double tx,ty,zx=currgs->ax,zy=currgs->ay;
        if (a==DRAW) {
                if (cline<1) {
                        plot(4, (int)zx, (int)zy);
                        plot(5, (int)bl, (int)cl);
                        pjoin=1; }
                else {
                     if (bl==zx) {
                        plot(4, (int)(zx-cline), (int)zy);
                        plot(4, (int)(zx+cline), (int)zy);
                        plot(85, (int)(zx-cline), (int)cl);
                        plot(85, (int)(zx+cline), (int)cl);
                        theta=0; }
                     else {
                        theta=(int)(2*(90-deg(atan((cl-zy)/(bl-zx)))));
                        tx=cline*costab[theta];
                        ty=cline*sintab[theta];
                        plot(4, (int)(zx+tx), (int)(zy-ty));
                        plot(4, (int)(zx-tx), (int)(zy+ty));
                        plot(85, (int)(bl+tx), (int)(cl-ty));
                        plot(85, (int)(bl-tx), (int)(cl+ty)); }
                     if (pjoin) linejoin();
                     pjoin=1; 
                     linecap(theta,zx,zy,bl,cl); }
                }
        else if (a==MOVE) pjoin=0;
        currgs->ax=bl;
        currgs->ay=cl;
}

void addvec(xx2, yy2)
double xx2;
int yy2;
{
        int ty, uu=1, yy1;
        double tx, xx1;
        struct etr *new;
        xx1=etx; yy1=ety;
        etx=xx2;
        ety=yy2;
        if (yy1 != yy2) {
                if (yy2 < yy1) {
                        tx=xx2;
                        ty=yy2;
                        xx2=xx1; yy2=yy1;
                        xx1=tx; yy1=ty;
                        uu = -1; }
                if (yy1<ymin) ymin=yy1;
                if (yy2>ymax) ymax=yy2;
                if (yy2>=0 && yy1<=255) {
                        if (yy1<0) {
                                xx1-=yy1*(xx2-xx1)/(yy2-yy1);
                                yy1=0; }
                        if (yy1 != yy2) {
                               new=&etbase[etc];
                               etc++;
                               new->next = et[yy1];
                               et[yy1]=new;
                               new->y2=yy2;
                               new->x1=xx1;
                               new->dx=(xx2-xx1)/(yy2-yy1);
                               new->up=uu; }
                        }
        }
}

void actc(x1, y1, x2, y2, x3, y3, zx, zy)
double x1, y1, x2, y2, x3, y3, zx, zy;
{
        double tt2,tt3,nx,ny,tx,ty;
        double p1,p2,p3,p4,p5,p6;
        int c=1;
        int theta;
        p1 = -x+x1-x2+x3;
        p2 = 3*x-2*x1+x2;
        p3 = -3*x+x1;
        p4 = -y+y1-y2+y3;
        p5 = 3*y-2*y1+y2;
        p6 = -3*y+y1;
        tt2=tim*tim;
        tt3=tt2*tim;
        nx = tt3*p1+tt2*p2+tim*p3+x;
        ny = tt3*p4+tt2*p5+tim*p6+y;
        if (!fflg && nx==zx) {
                plot(4,(int)(zx-cline), (int)zy);
                plot(4,(int)(zx+cline), (int)zy); }
        else if (!fflg) {
                theta=(90-(int)(dgc*atan((ny-zy)/(nx-zx)))) << 1;
                tx=cline*costab[theta];
                ty=cline*sintab[theta];
                plot(4,(int)(zx+tx), (int)(zy-ty));
                plot(4,(int)(zx-tx), (int)(zy+ty)); }
        for (; c < 32; c++) {
                nx = t3[c]*p1+t2[c]*p2+t1[c]*p3+x;
                ny = t3[c]*p4+t2[c]*p5+t1[c]*p6+y;
                if (fflg) addvec(nx/2, (int)ny >> 2);
                else if (nx==zx) {
                            plot(85,(int)(zx-cline), (int)ny);
                            plot(85,(int)(zx+cline), (int)ny); }
                     else {
                            theta=(90-(int)(dgc*atan((ny-zy)/(nx-zx)))) << 1;
                            tx=cline*costab[theta];
                            ty=cline*sintab[theta];
                            plot(85,(int)(nx+tx), (int)(ny-ty));
                            plot(85,(int)(nx-tx), (int)(ny+ty)); }
                zx=nx;
                zy=ny; }
        if (newflag) {
                currgs->ax=zx;
                currgs->ay=zy;
                x=x3;
                y=y3; }
}

void dcur()
{
        double x1,x2,x3,y1,y2,y3;
        x3=baseg->xc; y3=baseg->yc;
        baseg=baseg->next;
        x2=3*baseg->xc; y2=3*baseg->yc;
        baseg=baseg->next;
        x1=3*baseg->xc; y1=3*baseg->yc;
        actc(x1, y1, x2, y2, x3, y3, currgs->ax, currgs->ay);
}

void doelement()
{
        switch (baseg->code) {
        case MOVE: if (fflg && !clsd) {
                        clsd=1;
                        addvec(currgs->sx/2,(int)currgs->sy >> 2); }
                   x=baseg->xc;
                   y=baseg->yc;
                   currgs->sx=x;
                   currgs->sy=y;
                   drti=1;
                   if (fflg) {
                        etx=x/2;
                        ety=(int)y >> 2; }
                   else tplot(MOVE, x, y);
                   break;
        case DRAW: x=baseg->xc;
                   y=baseg->yc;
                   if (fflg) addvec(x/2, (int)y >> 2);
                   else tplot(DRAW, x, y);
                   clsd=0;
                   break;
        case CURVE: dcur();
                    clsd=0;
                    break;
        case CLOSE: if (drti) {
                        clsd=1;
                        x=currgs->sx;
                        y=currgs->sy;
                        if (fflg) addvec(x/2, (int)y >>2);
                        else tplot(DRAW, x, y);
                        break; }
                    break;
        }
}

void pathelem(comm, ex, wy)
char comm;
double ex, wy;
{
        if (baseg == NULL) {
                baseg = (struct gpath *)calloc(1, sizeof(struct gpath));
                nextg = baseg;
                cpath = 1;
        }
        else {
                nextg->next = (struct gpath *)calloc(1, sizeof(struct gpath));
                nextg = nextg->next; }
        if (comm == MOVE) {
                mzx=ex;
                mzy=wy;
                mcx=cx;
                mcy=cy; }
        if (comm == CLOSE) {
                cx=mcx;
                cy=mcy; }
        currgs->ax=ex;
        currgs->ay=wy;
        nextg->code = comm;
        nextg->xc = ex;
        nextg->yc = wy;
}

struct arrele *concat(mat1, mat2, mat3)
struct arrele *mat1;
struct arrele *mat2;
struct arrele *mat3;
{
        double a1,b1,c1,d1,tx1,ty1,a2,b2,c2,d2,tx2,ty2;
        struct stelem *m1=mat1->array, *m2=mat2->array, *m3=mat3->array;
        a1 = m1[0].u.number;
        b1 = m1[1].u.number;
        c1 = m1[2].u.number;
        d1 = m1[3].u.number;
        tx1 = m1[4].u.number;
        ty1 = m1[5].u.number;
        a2 = m2[0].u.number;
        b2 = m2[1].u.number;
        c2 = m2[2].u.number;
        d2 = m2[3].u.number;
        tx2 = m2[4].u.number;
        ty2 = m2[5].u.number;
        m3[5].u.number=tx1*b2+ty1*d2+ty2;
        m3[4].u.number=tx1*a2+ty1*c2+tx2;
        m3[3].u.number=c1*b2+d1*d2;
        m3[2].u.number=c1*a2+d1*c2;
        m3[1].u.number=a1*b2+b1*d2;
        m3[0].u.number=a1*a2+b1*c2;
        return(mat3);
}

void graph(comm, x1, y1)
char comm;
double x1,y1;
{
        if (currgs->nopath)
                if (comm & 3) seterror("nocurrentpoint");
                else currgs->nopath=0;
        cx+=x1;
        cy+=y1;
        pathelem(comm, tma*cx+tmc*cy+tmx, tmb*cx+tmd*cy+tmy);
}

void addtodict(value, which, token)
struct usere *value;
struct userdict *which;
struct idlist *token;
{
        struct usere *t=token->invoc;
        while (t != NULL && t->id != which) t=t->next;
        if (t != NULL) {
                t->sort = value->sort;
                t->u = value->u; }
        else {
                if (which->size == which->maxsize) seterror("dictfull");
                t = (struct usere *)calloc(1, sizeof(struct usere));
                *t = *value;
                value = token->invoc;
                token->invoc = t;
                t->next = value;
                t->id = which;
                t->dnext = which->start;
                t->name = token;
                which->start = t;
                which->size++;
                }
}

void dstrip(value)
struct usere *value;
{
        switch (value->sort) {
        case EMPTY: pushnull(); break;
        case NUMBER: pushnum(value->u.number); break;
        case ARRAY: pusharray(value->u.array); break;
        case DICTIONARY: pushdict(value->u.dict); break;
        case STRING: pushrs(value->u.restr); break;
        case NAME: pushname(value->u.name); break;
        case BOOLEAN: pushbool(value->u.bool); break;
        case PROCEDURE: dooproc(value->u.array); break;
        case MARK: pushmark(); break;
        case FILETYPE: pushfile(value->u.filo); break;
        case PMARK: break;
        case OPERATOR: pushoper(value->u.oper.called, value->u.oper.k); break;
        case SPECNAME: pushspec(value->u.spname); break;
        case SPECDICT: pushspdict(value->u.spdict); break;
        }
}

void pdict(value)
struct usere *value;
{
        if (offset == MAXSTACK) seterror("stackoverflow");
        offset++;
        current = &mstack[offset];
        current->sort = value->sort;
        current->u = value->u;
}

void ptsn(val)
struct strdef *val;
{
        int c=0;
        printf("(");
        while (c < val->len) {
                if (val->string[c] > 31) printf("%c", val->string[c]);
                else printf(".");
                c++; }
        printf(")");
}

void pse2(this)
struct arrele *this;
{
        int c=0,l=this->length;
        struct stelem *t=this->array;
        while (c<l) {
                switch (t[c].sort) {
                case NUMBER: printf("%s",ftos(t[c].u.number));
                             break;
                case BOOLEAN: if (t[c].u.bool) printf("true");
                              else printf("false"); break;
                case DICTIONARY: printf("DICT"); break;
                case MARK: printf("["); break;
                case ARRAY: printf("ARRAY"); break;
                case STRING: ptsn(t[c].u.restr); break;
                case EMPTY: printf("null"); break;
                case NAME: printf("/%s", t[c].u.name->name); break;
                case OPERATOR: printf("%s",t[c].u.oper.called->name); break;
                case PROCEDURE: printf("{");
                                pse2(t[c].u.array);
                                printf("}"); break;
                case PMARK: printf("PROCEDURE MARK"); break;
                case FILETYPE: printf("FILE"); break;
                case SPECNAME: printf("s_/%s", t[c].u.spname); break;
                case SPECDICT: printf("FONT"); break; }
        printf(" ");
        c++;
        }
}

void pse(this)
struct stelem *this;
{
        switch (this->sort) {
        case NUMBER: printf("%s",ftos(this->u.number));
                     break;
        case BOOLEAN: if (this->u.bool) printf("true");
                      else printf("false"); break;
        case DICTIONARY: printf("DICT %d", this->u.dict->size); break;
        case MARK: printf("["); break;
        case EMPTY: printf("null"); break;
        case ARRAY: printf("ARRAY"); break;
        case STRING: ptsn(this->u.restr); break;
        case NAME: printf("/%s", this->u.name->name); break;
        case OPERATOR: printf("%s", this->u.oper.called->name); break;
        case PROCEDURE: printf("{");
                        pse2(this->u.array);
                        printf("}"); break;
        case PMARK: printf("PROCEDURE MARK"); break;
        case FILETYPE: printf("FILE"); break;
        case SPECNAME: printf("s_/%s", this->u.spname); break;
        case SPECDICT: printf("FONT"); break;
        }
}

void pstack()
{
        int of=offset;
        while (of >= 0) {
                pse(&mstack[of]);
                printf("\n");
                --of; }
}

double pullnum()
{
        double temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != NUMBER) seterror("typecheck");
        temp = current->u.number;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

double pullpnum()
{
        double temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort == NUMBER && current->u.number >= 0) {
                temp = current->u.number;
                --offset;
                if (offset < 0) current=NULL;
                else current = &mstack[offset]; }
        else seterror("typecheck");
        return(temp);
}

struct phile *pullfile()
{
        struct phile *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != FILETYPE) seterror("typecheck");
        temp = current->u.filo;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

struct arrele *pullarray()
{
        struct arrele *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != ARRAY) seterror("typecheck");
        temp = current->u.array;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

struct arrele *pullproc()
{
        struct arrele *temp;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != PROCEDURE) seterror("typecheck");
        temp = current->u.array;
        --offset;
        if (offset < 0) current=NULL;
        else current = &mstack[offset];
        return(temp);
}

int pullgraph()
{
        if (!gpo) return(0);
        --gpo;
        currgs=&gstack[gpo];
        baseg = currgs->path;
        if (baseg == NULL) cpath = 0;
        else cpath = 1;
        nextg = currgs->epath;
        cx = currgs->cx;
        cy = currgs->cy;
        ctm->array[0].u.number = currgs->ctma;
        ctm->array[1].u.number = currgs->ctmb;
        ctm->array[2].u.number = currgs->ctmc;
        ctm->array[3].u.number = currgs->ctmd;
        ctm->array[4].u.number = currgs->ctmx;
        ctm->array[5].u.number = currgs->ctmy;
        readctm(ctm);
        tplot(4, currgs->ax, currgs->ay);
        setcol();
        cline=currgs->cline;
        return(1);
}

struct etr *sort(aet)
struct etr *aet;
{
        struct etr *temp=NULL,*old=aet,*atemp,*otemp;
        if (aet != NULL) temp=aet->next;
        while(temp != NULL)
                if (temp->x1 < old->x1) {
                        otemp=NULL;
                        atemp=aet;
                        while (atemp->x1 < temp->x1) {
                                otemp=atemp;
                                atemp=atemp->next; }
                        old->next=temp->next;
                        temp->next=atemp;
                        if (otemp==NULL) aet=temp;
                        else otemp->next=temp;
                        temp=old->next; }
                else {
                        old=temp;
                        temp=temp->next; }
        return(aet);
}

void fillit(nzw)
int nzw;
{
        int c,d,res;
        struct etr *aet=NULL;
        struct etr *temp,*temp2,*old;
        if (ymax>255) ymax=255;
        if (ymin<0) ymin=0;
        for (c=ymin; c<=ymax; c++) {
                d=c << 2;
                temp=aet;
                old=NULL;
                while (temp != NULL)
                        if (temp->y2 == c) {
                                if (temp==aet) aet=temp->next;
                                else old->next=temp->next;
                                temp=temp->next; }
                        else {
                                old=temp;
                                temp->x1+=temp->dx;
                                temp=temp->next; }
                if (aet != NULL && old != NULL) old->next = et[c];
                else aet=et[c];
                aet=sort(aet);
                temp=aet;
                if (nzw) {
                        if (temp != NULL) {
                                res=0;
                                plot(4, (int)(temp->x1) << 1, d);
                                temp2=temp->next;
                                while(temp2 != NULL) {
                                        res+=temp2->up;
                                        temp2=temp2->next; }
                                while (temp->next != NULL) {
                                        temp=temp->next;
                                        plot(5-(res==0), (int)(temp->x1) << 1,
                                                d);
                                        res-=temp->up; }
                                }
                        }
                else
                        while (temp != NULL) {
                                plot(4, (int)(temp->x1) << 1, d);
                                temp=temp->next;
                                plot(5, (int)(temp->x1) << 1, d);
                                temp=temp->next; }
                et[c]=NULL;
                }
}

void startfill(nzw)
int nzw;
{
        struct gpath *tbg;
        fflg=1;
        pjoin=0;
        clsd=1;
        ymin = 256;
        ymax = -1;
        tbg = baseg;
        pths=0;
        etc=0;
        while (tbg != NULL) {
                if (tbg->code == CURVE) pths+=32;
                else pths++;
                tbg=tbg->next; }
        if (pths) etbase=(struct etr *)calloc(pths, sizeof(struct etr));
        while (baseg != NULL) {
                doelement();
                baseg = baseg->next; }
        if (drti && !clsd) addvec(currgs->sx/2, (int)currgs->sy >>2);
        fflg=0;
        currgs->nopath = 1;
        fillit(nzw);
        if (pths) free(etbase);
}

char *left(string, amount)
char *string;
int amount;
{
        char *temp;
        temp = save(string);
        temp[amount] = 0;
        return(temp);
}

char *right(string, amount)
char *string;
int amount;
{
        char *temp;
        temp = save(string);
        temp = (char *)(temp+strlen(string)-amount);
        return(temp);
}

struct arrele *bindit(proc)
struct arrele *proc;
{
        int a=0, c=0, d, l=proc->length, notfound;
        struct stelem *act=proc->array;
        struct usere *tt;
        struct arrele *newp, *at;
        at=createarray(l);
        proc->length = proc->length * -1;
        while (c<l) {
                switch(act[c].sort) {
                case OPERATOR:
                        d=doffset;
                        notfound=1;
                        while (d>=0 && notfound) {
                                tt=act[c].u.oper.called->invoc;
                                while (tt != NULL && tt->id != dictstack[d])
                                        tt=tt->next;
                                if (tt != NULL) notfound=0;
                                else --d; }
                        if (!notfound && tt->sort == PROCEDURE &&
                            tt->u.array->length >= 0) {
                                at->array[c].u.array = bindit(tt->u.array);
                                at->array[c].sort = TPROC;
                                a+=at->array[c].u.array->length; }
                        else {
                                a++;
                                at->array[c] = act[c]; }
                        break;
                case PROCEDURE:
                        if (act[c].u.array->length >= 0) {
                                at->array[c].u.array = bind(act[c].u.array);
                                at->array[c].sort = PROCEDURE; }
                        else at->array[c] = act[c];
                        a++;
                        break;
                default:
                        a++;
                        at->array[c] = act[c];
                        break; }
                c++; }
        newp=createarray(a);
        c=0; d=0;
        while (c<l) {
                if (at->array[c].sort == TPROC) {
                        a=0;
                        while (a < at->array[c].u.array->length) {
                                newp->array[d]=at->array[c].u.array->array[a];
                                a++; d++; }
                        deletearray(at->array[c].u.array); }
                else {
                        newp->array[d] = at->array[c];
                        d++; }
                c++; }
        deletearray(at);
        proc->length = proc->length * -1;
        return(newp);
}

struct arrele *bind(proc)
struct arrele *proc;
{
        struct arrele *t=bindit(proc);
        *proc = *t;
        return(proc);
}

void readfontmat()
{
        struct stelem *f = currgs->font->fontmatrix->array;
        fonta=f[0].u.number;
        fontb=f[1].u.number;
        fontc=f[2].u.number;
        fontd=f[3].u.number;
        fonte=f[4].u.number;
        fontf=f[5].u.number;
}

void addmove(mp)
struct point *mp;
{
        double f,g;
        f=fonta*mp->x+fontc*mp->y+fonte;
        g=fontb*mp->x+fontd*mp->y+fontf;
        ccpox=currgs->ax+tma*f+tmc*g+tmx;
        ccpoy=currgs->ay+tmb*f+tmd*g+tmy;
        etx = ccpox/2; ety = (int)ccpoy >> 2;
}

void addline(mp)
struct point *mp;
{
        double f,g;
        f=fonta*mp->x+fontc*mp->y+fonte;
        g=fontb*mp->x+fontd*mp->y+fontf;
        ccpox=currgs->ax+tma*f+tmc*g+tmx;
        ccpoy=currgs->ay+tmb*f+tmd*g+tmy;
        addvec(ccpox / 2, (int)ccpoy >> 2);
}

void addcurve(mp1, mp2, mp3)
struct point *mp1, *mp2, *mp3;
{
        double a,b,c,d,e,f,g,h;
        x=ccpox;
        y=ccpoy;
        a=fonta*mp1->x+fontc*mp1->y+fonte;
        b=fontb*mp1->x+fontd*mp1->y+fontf;
        c=currgs->ax+tma*a+tmc*b+tmx;
        d=currgs->ay+tmb*a+tmd*b+tmy;

        a=fonta*mp2->x+fontc*mp2->y+fonte;
        b=fontb*mp2->x+fontd*mp2->y+fontf;
        e=currgs->ax+tma*a+tmc*b+tmx;
        f=currgs->ay+tmb*a+tmd*b+tmy;

        a=fonta*mp3->x+fontc*mp3->y+fonte;
        b=fontb*mp3->x+fontd*mp3->y+fontf;
        g=currgs->ax+tma*a+tmc*b+tmx;
        h=currgs->ay+tmb*a+tmd*b+tmy;

        actc(3*c, 3*d, 3*e, 3*f, g, h, ccpox, ccpoy);
        ccpox=g;
        ccpoy=h;
}

void pchar(ch, t)
struct charlist *ch;
int t;
{
        int s, e, p, c=0, k, w;
        int xx,yy;
        struct subpath *ts;
        struct elem *te;
        struct point *tp;
        if (currgs->nopath) seterror("nocurrentpoint");
        fflg=1;
        newflag=0;
        s=ch->length;
        etbase = (struct etr *)calloc(ch->storage, sizeof(struct etr));
        etc=0;
        ymin=256; ymax=-1;
        for (; c<s; c++) {
                ts=&ch->sub[c];
                e=ts->length;
                k=0;
                for (; k<e; k++) {
                        te=&ts->segments[k];
                        p=te->npoints;
                        tp=te->points;
                        if (!k) {
                                addmove(&tp[0]);
                                xx=tp[0].x; yy=tp[0].y; }
/*                        else if (p) addline(&tp[0]); */
                        switch (te->type) {
                        case DRAW:
                                for (w=1; w<p; w++) addline(&tp[w]);
                                break;
                        case CURVE:
                                for (w=1; w<p; w+=3)
                                        addcurve(&tp[w],&tp[w+1],&tp[w+2]);
                                break;
                        default: seterror("System error"); }
                }
                if (ch->storage > 0 && (xx != tp[w-1].x || yy != tp[w-1].y))
                   addline(&tp[0]);
        }
        fillit(0);
        newflag=1;
        fflg=0;
        free(etbase);
        graph(4, fonta*ch->width+fonte, fontb*ch->width+fontf);
}

int insys(match)
char *match;
{
        int n;
        int usf = 1;
        int stp = 11;
        unsigned half = 57;
        int count = 114;
        do {
                n=strcmp(match,systemdict[count]);
                if (n==0) usf=0;
                else {
                        if (n<0) count-=half;
                        else count+=half;
                        half=half >> 1;
                        if (half == 0) half++;
                        stp--; }
        }
        while (usf && stp);
        if (stp) return(count);
        else return(-1);
}

struct idlist *findop(match)
char *match;
{
        struct idlist *find=idbase;
        while (find != NULL && strcmp(match, find->name) != 0) find=find->next;
        if (find == NULL) {
                find = (struct idlist *)calloc(1, sizeof(struct idlist));
                find->name = save(match);
                find->invoc = NULL;
                find->next = idbase;
                idbase = find;
                }
        return(find);
}

void dinp(match)
char *match;
{
        struct arrele *new = NULL;
        int l=0,toff,t;
        struct stelem *nq;
        if (strlen(match))
                switch (match[0]) {
                case '{': pushpmark(); break;
                case '}': toff=offset;
                          while (mstack[toff].sort != PMARK) --toff;
                          l=offset-toff;
                          new=createarray(l);
                          nq=new->array;
                          for (--l; l>=0; --l) {
                                nq[l] = *current;
                                pull(); }
                          --offset;
                          if (offset < 0) current=NULL;
                          else current = &mstack[offset];
                          pushproc(new);
                          break;
                case '/': match++;
                          t=insys(match);
                          if (t >= 0) used[t]=0;
                          pushname(findop(match));
                          break;
                case '[': pushmark();
                          break;
                case ']': if (cb) pushoper(findop("]"), RB);
                          else docom(findop("]"), RB);
                          break;
                case '(': match++;
                          match[strlen(match)-1] = 0;
                          pushms(save(match), strlen(match));
                          break;
                default: if (match[0] >= '=' && match[0] <= 'z') {
                                if (cb) pushoper(findop(match),
                                                 insys(match));
                                else docom(findop(match), insys(match));
                         }
                         else pushnum(atof(match));
                         break; }
        acc[0]=0;
}

void single(line)
char *line;
{
int fr;
char *hy;
char temp[2];
temp[1] = 0;
while (line[0] != 0) {
        temp[0] = line[0];
        line++;
        if (rb>0)
                if (esc) {
                        switch (temp[0]) {
                        case 'n': temp[0] = '\n'; break;
                        case 'r': temp[0] = '\r'; break;
                        case 't': temp[0] = '\t'; break;
                        case 'b': temp[0] = '\b'; break;
                        case 'f': temp[0] = '\f'; break;
                        case '\n': temp[0] = 0; break;
                        }
                        strcat(acc,temp);
                        esc=0; }
                else {
                        switch (temp[0]) {
                        case ')': if (rb == 0) seterror("syntaxerror");
                                  else {
                                        --rb;
                                        if (rb == 0) {
                                                strcat(acc,")");
                                                dinp(acc); }
                                        else strcat(acc,")");
                                  }
                                  break;
                        case '(': rb++;
                                  strcat(acc,"(");
                                  break;
                        case '\\': esc = 1;
                                   break;
                        default: strcat(acc, temp);
                                 break; }
                }
        else if (ab)
                switch (temp[0]) {
                case ' ': break;
                case '\n': break;
                case '>' : if (on) {
                                on=0;
                                acc[abc] = 16*to;
                                abc++; }
                           hy=(char *)calloc(abc, sizeof(char));
                           fr=0;
                           while (fr < abc) {
                                hy[fr] = acc[fr];
                                fr++; }
                           pushms(hy, abc);
                           acc[0]=0;
                           ab=0;
                           break;
                default: if (temp[0]>='a' && temp[0]<='f')
                                temp[0]=temp[0]-32;
                         if (temp[0]>='0' && temp[0]<='9') fr=temp[0]-48;
                         else if (temp[0]>='A' && temp[0]<='F')
                                fr=temp[0]-55;
                              else seterror("syntaxerror");
                         if (on) {
                                to=16*to+fr;
                                acc[abc] = to;
                                abc++; }
                         else to=fr;
                         on = 1-on;
                         break; }
             else
                switch (temp[0]) {
                case '{': dinp(acc);
                          dinp("{");
                          cb++;
                          break;
                case '}': if (cb == 0) seterror("syntaxerror");
                          else {
                                dinp(acc);
                                --cb;
                                dinp("}");
                                }
                          break;
                case '(': dinp(acc);
                          rb=1;
                          strcat(acc,"(");
                          break;
                case ')': seterror("syntaxerror");
                          break;
                case '<': dinp(acc);
                          ab=1;
                          abc=0;
                          break;
                case '\n': dinp(acc);
                           break;
                case ' ': dinp(acc);
                          break;
                case '[': dinp(acc);
                          dinp("[");
                          break;
                case ']': dinp(acc);
                          dinp("]");
                          break;
                case '%': line[0] = 0;
                          dinp(acc);
                          break;
                default: strcat(acc,temp); break; }
        }
}

int numfiles(path)
char *path;
{
        int c=0,d=0;
        reg_set block, retblock;
        struct buftype buffer;
        do {
                block.r[0] = 10;
                block.r[1] = (int)path;
                block.r[2] = (int)&buffer;
                block.r[3] = 1;
                block.r[4] = c;
                block.r[5] = 100;
                block.r[6] = (int)"*";
                retblock = swi(12, &block);
                if (retblock.r[3] && buffer.tp == 1) d++;
                c++;
                }
        while (retblock.r[4] != -1);
        return(d);
}

char *cocat(path, name)
char *path, *name;
{
        char *co;
        int c=0,d=0;
        co = (char *)calloc(strlen(path)+strlen(name)+2, sizeof(char));
        for (; c<strlen(path); c++) co[c]=path[c];
        if (c) {
                co[c] = '.';
                c++; }
        for (; d<strlen(name); d++) co[c+d]=name[d];
        co[c+d] = 0;
        return(save(co));
}

struct idlist *valid_font(name)
char *name;
{
        FILE *fp;
        char inp[256];
        int nof;
        fp = fopen(name, "r");
        if (fp == NULL) return(NULL);
        inp[0]=0;
        nof=(int)fgets(inp, 256, fp);
        if (nof == NULL || strcmp(inp, "~#~#psfont\n") != 0) return(NULL);
        nof=(int)fgets(inp, 256, fp);
        if (nof == NULL || strlen(inp) == 0) return(NULL);
        inp[strlen(inp)-1] = 0;
        return(findop(inp));
}

void whichfonts(path, num)
char *path;
int num;
{
        int c=0;
        reg_set block, retblock;
        struct idlist *tss;
        struct buftype buffer;
        struct usere temp;
        while (num) {
                do {
                        block.r[0] = 10;
                        block.r[1] = (int)path;
                        block.r[2] = (int)&buffer;
                        block.r[3] = 1;
                        block.r[4] = c;
                        block.r[5] = 100;
                        block.r[6] = (int)"*";
                        retblock = swi(12, &block);
                        c++;
                        }
                while (buffer.tp != 1);
                temp.sort = SPECNAME;
                temp.u.spname = cocat(path, buffer.name);
                tss=valid_font(temp.u.spname);
                if (tss != NULL) {
                        printf("%s\n", tss->name);
                        addtodict(&temp, fontdir, tss); }
                --num; }
}

void startup(vers)
char *vers;
{
        int c,numfonts;
        double angle=0.0;
        double t;
        mode(0);
        printf("Postscript Interpreter - Version %s\n\n", vers);
        ttq = createarray(6);
        ttq2 = createarray(6);
        ctm = createarray(6);
        currgs = &gstack[0];
        dictstack[0] = dcreate(MAXDICT);
        printf("Computing tables");
        for (c=0; c<720; c++) {
                sintab[c] = sin(rad(angle));
                costab[c] = cos(rad(angle));
                angle=angle+0.5;
                if (!(c%50)) printf("."); }
        sintab[0] = 0; costab[0] = 1;
        sintab[180] = 1; costab[180] = 0;
        sintab[360] = 0; costab[360] = -1;
        sintab[540] = -1; costab[540] = 0;
        c=0;
        for (t=tim; t<=1; t=t+tim) {
                t1[c]=t;
                t2[c]=t*t;
                t3[c]=t*t*t;
                c++; }
        for (c=0; c<230; c++) used[c]=1;
        stenca=createarray(256);
        ndefstr=save(".notdef");
        for (c=0; c<32; c++) {
            stenca->array[c].sort=SPECNAME;
            stenca->array[c].u.spname=ndefstr; }
        for (; c<127; c++) {
            stenca->array[c].sort=SPECNAME;
            stenca->array[c].u.spname=tenc[c-32]; }
        for (; c<256; c++) {
            stenca->array[c].sort=SPECNAME;
            stenca->array[c].u.spname=ndefstr; }
        if (bw) {
                mode(12);
                colour(15);
                for (c=0; c<16; c++) palette(c,16,c*16,c*16,c*16); }
        else mode(15);
        vdu(28); vdu(45); vdu(31); vdu(79); vdu(0);
        gwindow(0,0,718,1023);
        cls();
        numfonts=numfiles("fonts");
        fontdir=dcreate(numfonts);
        printf("Fonts available...\n\n");
        whichfonts("fonts", numfonts);
        printf("\n");
}
