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

extern void docom(struct idlist *, int);

extern struct fontdict *fontfile(char *);

void doshow(a)
int a;
{
        struct strdef *str;
        int c=0, l;
        char *name;
        struct charlist *base;
        double ax,ay;
        if (currgs->font == NULL) seterror("invalidfont");
        if (currgs->nopath) seterror("nocurrentpoint");
        str = pullrs();
        if (a) {
                getxy();
                ax=x; ay=y; }
        readfontmat();
        l=str->len;
        for (; c<l; c++) {
                name = currgs->font->encoding->array[str->string[c]].u.spname;
                base = currgs->font->charstrings;
                while (base != NULL && base->name != name) base=base->next;
                if (base != NULL) pchar(base, currgs->font->painttype);
                if (a) graph(4, ax, ay);
                }
}

void dokshow()
{
        struct strdef *str;
        int c=0, l;
        char *name;
        struct charlist *base;
        struct arrele *proc;
        if (currgs->font == NULL) seterror("invalidfont");
        if (currgs->nopath) seterror("nocurrentpoint");
        str = pullrs();
        proc = pullproc();
        readfontmat();
        l=str->len;
        for (; c<l; c++) {
                name = currgs->font->encoding->array[str->string[c]].u.spname;
                base = currgs->font->charstrings;
                while (base != NULL && base->name != name) base=base->next;
                if (base != NULL) pchar(base, currgs->font->painttype);
                if (c != (l-1)) {
                        pushnum((double)str->string[c]);
                        pushnum((double)str->string[c+1]);
                        dooproc(proc); }
                }
}

void dowidthshow(a)
int a;
{
        struct strdef *str;
        int c=0, l;
        char *name;
        struct charlist *base;
        int ch;
        double qx,qy,ax,ay;
        if (currgs->font == NULL) seterror("invalidfont");
        if (currgs->nopath) seterror("nocurrentpoint");
        str = pullrs();
        if (a) {
                getxy();
                ax=x; ay=y; }
        ch = (int)pullnum();
        getxy();
        qx=x; qy=y;
        readfontmat();
        l=str->len;
        for (; c<l; c++) {
                name = currgs->font->encoding->array[str->string[c]].u.spname;
                base = currgs->font->charstrings;
                while (base != NULL && base->name != name) base=base->next;
                if (base != NULL) pchar(base, currgs->font->painttype);
                if (a) graph(4, ax, ay);
                if ((int)str->string[c] == ch) graph(4, qx, qy);
                }
}

void dostringwidth()
{
        struct strdef *str;
        int c=0, l;
        char *name;
        struct charlist *base;
        double f, g, ax=0, ay=0;
        if (currgs->font == NULL) seterror("invalidfont");
        str = pullrs();
        readfontmat();
        l=str->len;
        for (; c<l; c++) {
                name = currgs->font->encoding->array[str->string[c]].u.spname;
                base = currgs->font->charstrings;
                while (base != NULL && base->name != name) base=base->next;
                if (base != NULL) {
                        f=fonta*base->width+fonte;
                        g=fontb*base->width+fontf;
                        ax+=tma*f+tmc*g+tmx;
                        ay+=tmb*f+tmd*g+tmy; }
                }
        pushnum(ax);
        pushnum(ay);
}

void dofindfont()
{
        struct usere *find;
        find = pullname()->invoc;
        while (find != NULL && find->id != fontdir) find=find->next;
        if (find == NULL) seterror("invalidfont");
        switch (find->sort) {
        case SPECDICT: break;
        case SPECNAME: find->u.spdict=fontfile(find->u.spname);
                       find->sort = SPECDICT;
                       break;
        default: seterror("typecheck"); }
        pushspdict(find->u.spdict);
}

void domakefont()
{
        int c=0;
        struct arrele *matrix, *temp;
        struct fontdict *font, *new;
        matrix = pullarray();
        if (matrix->length != 6) seterror("typecheck");
        font = pullspdict();
        new=(struct fontdict *)calloc(1, sizeof(struct fontdict));
        *new = *font;
        temp=createarray(6);
        for (; c<6; c++) temp->array[c].sort = NUMBER;
        new->fontmatrix = concat(matrix, font->fontmatrix, temp);
        pushspdict(new);
}

void doscalefont()
{
        double scale;
        struct fontdict *old, *new;
        struct arrele *temp;
        scale=pullnum();
        old=pullspdict();
        new=(struct fontdict *)calloc(1, sizeof(struct fontdict));
        *new = *old;
        temp=createarray(6);
        setmat(temp, scale, 0.0, 0.0, scale, 0.0, 0.0);
        new->fontmatrix = concat(temp, old->fontmatrix, temp);
        pushspdict(new);
}

void doarray()
{
        struct arrele *temp;
        struct stelem *t;
        int c=(int)pullnum();
        temp=createarray(c);
        t=temp->array;
        for (--c; c>=0; --c) t[c].sort = EMPTY;
        pusharray(temp);
}

void stac(ms)
struct stelem *ms;
{
        int c;
        switch(ms->sort) {
        case BOOLEAN: if (ms->u.bool) printf("true");
                      else printf("false");
                      break;
        case NUMBER: printf(ftos(ms->u.number));
                     break;
        case STRING: c=0;
                     while (c < ms->u.restr->len) {
                         putchar(ms->u.restr->string[c]);
                         c++; }
                         break;
        case NAME: printf("/%s", ms->u.name->name);
                   break;
        case SPECNAME: printf("/%s", ms->u.spname);
                       break;
        case OPERATOR: printf(ms->u.oper.called->name);
                       break;
        default: printf("--nostringval--");
                 break; }
        printf("\n");
}

void dostack()
{
        int of=offset;
        while (of >= 0) {
                stac(&mstack[of]);
                --of; }
}

void docvs()
{
        struct strdef *str;
        char *temp;
        int l = -1;
        int c=0;
        struct strdef *t2;
        str=pullrs();
        if (offset < 0) seterror("stackunderflow");
        switch (current->sort) {
        case BOOLEAN: if (pullbool()) temp="true";
                      else temp="false";
                      break;
        case NUMBER: temp=ftos(pullnum());
                     break;
        case STRING: t2=pullrs();
                     temp=t2->string;
                     l=t2->len;
                     break;
        case NAME: temp=pullname()->name;
                   break;
        case OPERATOR: temp=current->u.oper.called->name;
                       pull();
                       break;
        case SPECNAME: temp=pullspec();
                       break;
        default: pull();
                 temp="--nostringval--";
                 break; }
        if (l<0) l=strlen(temp);
        if (l > str->len) seterror("rangecheck");
        while (c<l) {
                str->string[c] = temp[c];
                c++; }
        pushms(str->string, l);
}

void docvn()
{
        int t;
        if (offset < 0) seterror("stackunderflow");
        if (current->sort != STRING) seterror("typecheck");
        current->sort = NAME;
        current->u.name = findop(current->u.restr->string);
        t=insys(current->u.restr->string);
        if (t>=0) used[t]=0;
}

void docvrs()
{
        struct strdef *str;
        int radix,num,start,t;
        int c=0;
        str=pullrs();
        radix=(int)pullnum();
        num=(int)pullnum();
        if (radix<2 || radix>36) seterror("rangecheck");
        start=radix;
        while ((num/start) >0) start=start*radix;
        do {
                start=start/radix;
                t=num/start;
                num=num-t*start;
                if (c > str->len) seterror("rangecheck");
                if (t > 9) str->string[c] = (char)(55+t);
                else str->string[c] = (char)(48+t);
                c++; }
        while (start>1);
        pushms(str->string, c);
}

void dopathforall()
{
        struct gpath *g;
        struct gpath *g1;
        struct gpath *g2;
        struct arrele *mat;
        struct arrele *move;
        struct arrele *line;
        struct arrele *curve;
        struct arrele *close;
        close=pullproc();
        curve=pullproc();
        line=pullproc();
        move=pullproc();
        mat=createarray(6);
        inverse(ctm, mat);
        g=baseg;
        while (g != NULL && exx) {
                switch (g->code) {
                case DRAW: pdub(g,mat);
                           dooproc(line);
                           break;
                case MOVE: pdub(g,mat);
                           dooproc(move);
                           break;
                case CLOSE: dooproc(close);
                            break;
                case CURVE: g1=g;
                            g=g->next;
                            g2=g;
                            g=g->next;
                            pdub(g,mat);
                            pdub(g2,mat);
                            pdub(g1,mat);
                            dooproc(curve);
                            break; }
                g=g->next; }
        exx=1;
        deletearray(mat);
}

void dopathbbox()
{
        double llx,lly,urx,ury;
        struct arrele *mat;
        struct gpath *g;
        if (baseg == NULL) seterror("nocurrentpoint");
        else {
                mat=inverse(ctm, createarray(6));
                g=baseg;
                llx=g->xc;
                lly=g->yc;
                urx=llx;
                ury=lly;
                g=g->next;
                while (g != NULL) {
                        if (g->code != CLOSE) {
                                if ((g->xc) < llx) llx=g->xc;
                                if ((g->xc) > urx) urx=g->xc;
                                if ((g->yc) < lly) lly=g->yc;
                                if ((g->yc) > ury) ury=g->yc; }
                        g=g->next; }
                llx=llx;
                lly=lly;
                urx=urx;
                ury=ury;
                readctm(mat);
                pushnum(tma*llx+tmc*lly+tmx);
                pushnum(tmb*llx+tmd*lly+tmy);
                pushnum(tma*urx+tmc*ury+tmx);
                pushnum(tmb*urx+tmd*ury+tmy);
                readctm(ctm);
                deletearray(mat);
        }
}

void doanch()
{
        int a = 0;
        struct strdef *seek;
        struct strdef *str;
        seek = pullrs();
        str = pullrs();
        while (a < seek->len && seek->string[a] == str->string[a])
                a++;
        if (a==seek->len) {
                pushms(right(str->string, str->len-a), str->len-a);
                pushrs(seek);
                pushbool(1); }
        else {
                pushrs(str);
                pushbool(0); }
}

void dosearch()
{
        struct strdef *seek;
        struct strdef *str;
        int l1;
        int l2;
        int a=0;
        int b=0;
        int nomatch = 1;
        seek = pullrs();
        str = pullrs();
        l1 = str->len;
        l2 = seek->len;
        while (nomatch && a < l1) {
                if (str->string[a] == seek->string[0]) {
                        b=0;
                        while (b<l2 && (b+a)<l1 &&
                                str->string[a+b] == seek->string[b]) b++;
                        if (b==l2) nomatch=0; }
                a++; }
        if (nomatch) {
                pushrs(str);
                pushbool(0); }
        else {
                pushms(right(str->string, 1+l1-(a+l2)), 1+l1-(a+l2));
                pushrs(seek);
                pushms(left(str->string, a-1), a-1);
                pushbool(1); }
}

void dostring()
{
        int n;
        int c=0;
        char *string;
        n = (int)pullnum();
        if (n>MAXSTRING) seterror("limitcheck");
        if (n<0) seterror("rangecheck");
        string = (char *)calloc(1+n, sizeof(char));
        while (c < n) {
                string[c] = NULL;
                c++; }
        pushms(string, n);
        string[n] = 0;
}

void dowhere()
{
        struct usere *t2, *t=pullname()->invoc;
        int c=doffset, found=0;
        while (c>=0 && !found) {
                t2=t;
                while (t2 != NULL && t2->id != dictstack[c]) t2=t2->next;
                if (t2 != NULL) found=1;
                else --c; }
        if (found) {
                pushdict(dictstack[c]);
                pushbool(1); }
        else pushbool(0);
}

void dotype()
{
        char *st, t;
        if (offset < 0) seterror("stackunderflow");
        t=current->sort;
        switch(t) {
        case EMPTY: st="nulltype"; break;
        case NUMBER: st="realtype"; break;
        case ARRAY: st="arraytype"; break;
        case DICTIONARY: st="dicttype"; break;
        case STRING: st="stringtype"; break;
        case NAME: st="nametype"; break;
        case BOOLEAN: st="booleantype"; break;
        case PROCEDURE: st="operatortype"; break;
        case MARK: st="marktype"; break;
        case FILETYPE: st="filetype"; break;
        case PMARK: break;
        case OPERATOR: st="operatortype"; break;
        case SPECNAME: st="spec_nametype"; break;
        case SPECDICT: st="fonttype"; break; }
        current->sort = NAME;
        current->u.name = findop(st);
}

void doml()
{
        struct userdict *temp;
        temp = pulldict();
        pushnum((double)temp->size);
}

void doputint()
{
        struct arrele *a1, *a2;
        struct strdef *s1, *s2;
        struct stelem *h1, *h2;
        int o = 0;
        int i;
        switch(current->sort) {
        case ARRAY: a2 = pullarray();
                    i = (int)pullnum();
                    a1 = pullarray();
                    if ((i+a2->length) > a1->length) seterror("rangecheck");
                    h1 = a1->array;
                    h2 = a2->array;
                    while (o < a2->length) {
                        h1[i] = h2[o];
                        o++;
                        i++; }
                    break;
        case STRING: s2 = pullrs();
                     i = (int)pullnum();
                     s1 = pullrs();
                     if ((i+s2->len) > s1->len) seterror("rangecheck");
                     else
                        while (o < s2->len) {
                                s1->string[i+o] = s2->string[o];
                                o++; }
                     break;
        default: seterror("typecheck"); break; }
}

void dogetint()
{
        int c, i;
        struct arrele *a, *a2;
        struct strdef *s;
        c = (int)pullpnum();
        i = (int)pullpnum();
        if (current == NULL) seterror("stackunderflow");
        switch(current->sort) {
        case ARRAY: a = pullarray();
                    if ((c+i) > a->length) seterror("rangecheck");
                    a2 = (struct arrele *)calloc(1, sizeof(struct arrele));
                    a2->length = c;
                    if (c) a2->array = &a->array[i];
                    else a2->array = NULL;
                    pusharray(a2);
                    break;
        case STRING: s = pullrs();
                     if ((c+i) > s->len) seterror("rangecheck");
                     pushms((char *)(i+s->string), c);
                     break;
        default: seterror("typecheck"); break; }
}

void doput()
{
        int i;
        struct arrele *ta;
        struct stelem temp2, *temp;
        struct usere tempd;
        struct strdef *st2;
        if (offset < 2) seterror("stackunderflow");
        temp2 = mstack[offset];
        temp = &temp2;
        pull();
        switch(current->sort) {
        case NUMBER: i = (int)pullnum();
                     if (i<0) seterror("rangecheck");
                     switch(current->sort) {
                     case ARRAY: ta = pullarray();
                                 if (i >= ta->length) seterror("rangecheck");
                                 pushst(temp);
                                 ta->array[i] = *current;
                                 pull();
                                 break;
                     case STRING: st2=pullrs();
                                  if (temp->sort != NUMBER)
                                          seterror("typecheck");
                                  if (i >= st2->len) seterror("rangecheck");
                                  st2->string[i]=(int)(temp->u.number);
                                  break;
                     default: seterror("typecheck"); break; }
                              break;
        case NAME: {
                   struct idlist *nm;
                   struct userdict *dd;
                   nm = pullname();
                   dd=pulldict();
                   sttod(temp, &tempd);
                   tempd.id=dd;
                   addtodict(&tempd, dd, nm);
                   }
                   break;
        default: seterror("typecheck"); break; }
}

void docm()
{
        struct arrele *temp;
        temp = pullarray();
        if (temp->length == 6) {
                setmat(temp,tma,tmb,tmc,tmd,tmx,tmy);
                pusharray(temp); }
}

void dodm()
{
        struct arrele *temp;
        temp = pullarray();
        if (temp->length == 6) {
                setmat(temp,1.0,0.0,0.0,1.0,0.0,0.0);
                pusharray(temp); }
}

void doconcat()
{
        struct arrele *temp;
        temp = pullarray();
        if (temp->length == 6) {
                concat(temp, ctm, ctm);
                readctm(ctm); }
        else seterror("typecheck");
}

void doconcatm()
{
        struct arrele *temp;
        struct arrele *temp2;
        struct arrele *temp3;
        temp3=pullarray();
        temp2=pullarray();
        temp=pullarray();
        if (temp->length==6 && temp2->length==6 && temp3->length==6)
                pusharray(concat(temp, temp2, temp3));
        else seterror("typecheck");
}

void identmatrix()
{
        if (current->sort != ARRAY) seterror("typecheck");
        else if (current->u.array->length == 6)
                setmat(current->u.array,1.0,0.0,0.0,1.0,0.0,0.0);
             else seterror("rangecheck");
}

void index()
{
        int i=(int)pullpnum();
        if (i>offset) seterror("rangecheck");
        pushst(&mstack[offset-i]);
}

void doaload()
{
        struct arrele *temp=pullarray();
        struct stelem *t;
        int c=0,l;
        l=temp->length;
        t=temp->array;
        while (c<l) {
                if (offset == MAXSTACK) seterror("stackoverflow");
                offset++;
                current=&mstack[offset];
                *current = t[c];
                c++; }
        pusharray(temp);
}

void doknown()
{
        struct userdict *iid;
        struct idlist *nm;
        struct usere *stu;
        nm=pullname();
        iid=pulldict();
        stu=nm->invoc;
        while (stu != NULL && stu->id != iid) stu=stu->next;
        pushbool(stu != NULL);
}

void doget()
{
        struct arrele *temp;
        struct strdef *str;
        int i;
        switch(current->sort) {
        case NUMBER: i=(int)pullnum();
                     if (i<0) seterror("rangecheck");
                     switch(current->sort) {
                     case ARRAY: temp = pullarray();
                                 if (i >= temp->length) seterror("rangecheck");
                                 pushele(&temp->array[i]);
                                 break;
                     case STRING: str = pullrs();
                                  if (i >= str->len) seterror("rangecheck");
                                  pushnum((double)str->string[i]);
                                  break;
                     default: seterror("typecheck"); break; }
                     break;
        case NAME: {
                        struct usere *dr;
                        struct userdict *iid;
                        dr = pullname()->invoc;
                        iid = pulldict();
                        while (dr != NULL && dr->id != iid) dr=dr->next;
                        if (dr == NULL) seterror("undefined");
                        pdict(dr); }
                   break;
        default: seterror("typecheck"); break; }
}

void docopy()
{
        struct arrele *temp, *a1, *a2, *a3;
        struct strdef *st1, *st2;
        struct stelem *h1, *h2;
        int i,c=0;
        if (current == NULL) seterror("stackunderflow");
        switch(current->sort) {
        case NUMBER: temp = createarray((int)pullnum());
                     while (c < temp->length && current != NULL) {
                        temp->array[c] = *current;
                        pull();
                        c++; }
                     if (c != temp->length) {
                             deletearray(temp);
                             seterror("stackunderflow"); }
                     for (i=0; i<2; i++) {
                        c = temp->length - 1;
                        while (c>=0) {
                                pushele(&temp->array[c]);
                                c--; }
                        }
                     deletearray(temp);
                     break;
        case ARRAY: a2 = pullarray();
                    a1 = pullarray();
                    if (a2->length < a1->length) seterror("rangecheck");
                    h1 = a1->array;
                    h2 = a2->array;
                    for (; c < a1->length; c++) h2[c] = h1[c];
                    a3 = (struct arrele *)calloc(1, sizeof(struct arrele));
                    a3->length = a1->length;
                    a3->array = h2;
                    pusharray(a3);
                    break;
        case DICTIONARY: {
                         struct userdict *d1, *d2;
                         struct usere *tempu;
                         d2 = pulldict();
                         d1 = pulldict();
                         if (d2->size != 0 || d2->maxsize < d1->size)
                                 seterror("rangecheck");
                         tempu=d1->start;
                         while (tempu != NULL) {
                                addtodict(tempu, d2, tempu->name);
                                tempu=tempu->dnext; }
                         pushdict(d2);
                         }
                         break;
        case STRING: st2 = pullrs();
                     st1 = pullrs();
                     if (st2->len < st1->len) seterror("rangecheck");
                     i=0;
                     while (i < st1->len) {
                             st2->string[i] = st1->string[i];
                             i++; }
                     pushms(st2->string, st1->len);
                     break;
        default: seterror("typecheck"); break; }
}

void doastore()
{
        struct arrele *temp;
        int c;
        temp = pullarray();
        c = temp->length - 1;
        while (c>=0 && current != NULL) {
                temp->array[c] = *current;
                pull();
                c--; }
        if (c >= 0) seterror("stackunderflow");
        pusharray(temp);
}

void doarry()
{
        int n;
        struct arrele *temp;
        n=cotm();
        temp = createarray(n);
        for (n--; n>=0; n--) {
                temp->array[n] = *current;
                pull(); }
        pull();
        pusharray(temp);
}

void dodup()
{
        if (offset == -1) seterror("stackunderflow");
        mstack[offset+1]=mstack[offset];
        offset++;
        current = &mstack[offset];
}

int doexch()
{
        struct stelem temp=mstack[offset];
        if (offset < 1) return(1);
        mstack[offset]=mstack[offset-1];
        mstack[offset-1]=temp;
        return(0);
}

void dodef()
{
        struct usere sta;
        sta.sort = current->sort;
        sta.u = current->u;
        pull();
        sta.id = dictstack[doffset];
        addtodict(&sta, dictstack[doffset], pullname());
}

void doforall()
{
        struct arrele *temp, *proc;
        struct strdef *str;
        int n, c=0;
        proc = pullproc();
        switch(current->sort) {
        case ARRAY: temp = pullarray();
                    while (c < temp->length) {
                        pushele(&temp->array[c]);
                        dooproc(proc);
                        c++; }
                    break;
        case DICTIONARY: {
                         struct userdict *d;
                         struct usere *tempu;
                         d=pulldict();
                         tempu=d->start;
                         while (tempu != NULL) {
                                pushname(tempu->name);
                                pdict(tempu);
                                dooproc(proc);
                                tempu=tempu->dnext; }
                         }
                         break;
        case SPECDICT: {
                        struct fontdict *f;
                        f=pullspdict();
                        pushspec("FontMatrix"); pusharray(f->fontmatrix);
                        dooproc(proc);
                        pushspec("FontType"); pushnum((double)f->fonttype);
                        dooproc(proc);
                        pushspec("FontBBox"); pusharray(f->fontbbox);
                        dooproc(proc);
                        pushspec("Encoding"); pusharray(f->encoding);
                        dooproc(proc);
                        pushspec("FontName"); pushname(f->fontname);
                        dooproc(proc);
                        pushspec("PainType"); pushnum((double)f->painttype);
                        dooproc(proc);
                        pushspec("UniqueID"); pushnum((double)f->uniqueid);
                        dooproc(proc);
                       }
                        break;
        case STRING: str = pullrs();
                     while (c < str->len && exx) {
                             n = str->string[c];
                             c++;
                             pushnum((double)n);
                             dooproc(proc); }
                     break;
        default: seterror("typecheck"); break; }
        exx=1;
}

void dofor()
{
        double f, t, s;
        struct arrele *temp;
        temp = pullproc();
        getxy();
        f = pullnum();
        t = y;
        s = x;
        if (s > 0)
                for (; f <= t; f=f+s) {
                        pushnum(f);
                        dooproc(temp);
                        if (!exx) f=t+1; }
        else    for (; f >= t; f=f+s) {
                        pushnum(f);
                        dooproc(temp);
                        if (!exx) f=t-1; }
        exx=1;
}

void dorepeat()
{
        int count;
        struct arrele *temp;
        temp = pullproc();
        count = (int)pullnum();
        if (count<0) seterror("rangecheck");
        for (; count > 0; count--) {
                dooproc(temp);
                if (!exx) count=0; }
        exx=1;
}

void doqu(which)
int which;
{
        int ans=0;
        struct strdef *s;
        int v;
        switch(current->sort) {
        case NUMBER: getxy();
                     switch(which) {
                     case 1: if (x >= y) ans = 1; break;
                     case 2: if (x > y) ans = 1; break;
                     case 3: if (x <= y) ans = 1; break;
                     case 4: if (x < y) ans = 1; break; }
                     break;
        case STRING: s=pullrs();
                     v=strcmp(s->string, pullrs()->string);
                     switch(which) {
                     case 1: if (v<=0) ans=1; break;
                     case 2: if (v<0) ans=1; break;
                     case 3: if (v>=0) ans=1; break;
                     case 4: if (v>0) ans=1; break; }
                     break;
        default: seterror("typecheck"); break; }
        if (ans) pushbool(1);
        else pushbool(0);
}

void doequ(eqne)
int eqne;
{
        double a;
        int b,ans=0;
        char *p;
        struct phile *f;
        struct arrele *r;
        struct userdict *d;
        struct strdef *str;
        struct fontdict *h;
        switch(current->sort) {
        case NUMBER: a=pullnum();
                     if (current->sort == NUMBER) {
                        if (a==pullnum()) ans=1; }
                     else pull();
                     break;
        case BOOLEAN: b=pullbool();
                      if (current->sort == BOOLEAN) {
                        if (b == pullbool()) ans=1; }
                      else pull();
                      break;
        case FILETYPE: f=pullfile();
                   if (current->sort == FILETYPE) {
                        if (f == pullfile()) ans=1; }
                   else pull();
                   break;
        case MARK: pull();
                   if (current->sort == MARK) ans=1;
                   pull();
                   break;
        case EMPTY: pull();
                    if (current->sort == EMPTY) ans=1;
                    pull();
                    break;
        case DICTIONARY: d=pulldict();
                         if (current->sort == DICTIONARY) {
                                if (pulldict() == d) ans=1; }
                         else pull();
                         break;
        case SPECDICT: h=pullspdict();
                       if (current->sort == SPECDICT) {
                                if (pullspdict() == h) ans=1; }
                       else pull();
                       break;
        case PROCEDURE: r=pullproc();
                        if (current->sort == PROCEDURE) {
                                if (pullproc() == r) ans=1; }
                        else pull();
                        break;
        case ARRAY: r=pullarray();
                    if (current->sort == ARRAY) {
                        if (pullarray() == r) ans=1; }
                    else pull();
                    break;
        case STRING: str=pullrs();
                     if (current->sort == STRING) {
                        if (strcmp(pullrs()->string, str->string) == 0) ans=1;
                        }
                     else if (current->sort == NAME) {
                             if(strcmp(pullname()->name,str->string)==0) ans=1;
                             }
                          else pull();
                     break;
        case NAME: p=pullname()->name;
                   if (current->sort == STRING) {
                      if (strcmp(pullrs()->string, p) == 0) ans=1; }
                   else if (current->sort == NAME) {
                           if (strcmp(pullname()->name,p) == 0) ans=1; }
                        else pull();
                   break;
        default: break; }
        if (eqne) ans=1-ans;
        if (ans) pushbool(1);
        else pushbool(0);
}

void bezarc(a1,a2,r,a,b,tt,w)
double a1,a2,r,a,b,tt;
int w;
{
        double d,beta,tmp;
        int ai2,gamma,delta;
        if (a1<0) a1+=360;
        if (a2<0) a2+=360;
        if (a1>=360) a1-=360;
        if (a2>=360) a2-=360;
        if (w) ai2=(int)(2*a2);
        else ai2=(int)(2*a1);
        if (ai2==720) ai2=0;
        tmp=tt/180;
        beta=(53.1301023*tmp+deg(atan(1.333333333*tmp)))/2;
        gamma=(int)(2*(a2-beta));
        if (gamma<0) gamma+=720;
        if (gamma>=720) gamma-=720;
        delta=(int)(2*(a1+beta));
        if (delta<0) delta+=720;
        if (delta>=720) delta-=720;
        d=r/costab[(int)(beta*2)];
        graph(CURVE, a+r*costab[ai2]-cx, b+r*sintab[ai2]-cy);
        if (w) {
                graph(CURVE, a+d*costab[gamma]-cx, b+d*sintab[gamma]-cy);
                graph(CURVE, a+d*costab[delta]-cx, b+d*sintab[delta]-cy); }
        else {
                graph(CURVE, a+d*costab[delta]-cx, b+d*sintab[delta]-cy);
                graph(CURVE, a+d*costab[gamma]-cx, b+d*sintab[gamma]-cy); }
}

void doarc()
{
        double r,a1,a2,tt;
        char dd = DRAW;
        int ai1;
        getxy();
        while (x>360) x-=360;
        while (y>360) y-=360;
        while (x<0) x+=360;
        while (y<0) x+=360;
        a1 = x;
        a2 = y;
        ai1 = (int)(2*x);
        if (ai1==720) ai1=0;
        r = pullnum();
        getxy();
        if (currgs->nopath) dd=MOVE;
        graph(dd, x+r*costab[ai1]-cx, y+r*sintab[ai1]-cy);
        tt=a2-a1;
        if (tt<0) tt+= 360;
        if (tt <= 180) bezarc(a1,a2,r,x,y,tt,1);
        else {
                bezarc(a1,a1+180,r,x,y,180,1);
                bezarc(a1+180,a2,r,x,y,tt-180,1); }
}

void doarcn()
{
        double r,a1,a2,tt;
        char dd = DRAW;
        int ai1;
        getxy();
        while (x>360) x-=360;
        while (y>360) y-=360;
        while (x<0) x+=360;
        while (y<0) x+=360;
        a2 = x;
        a1 = y;
        ai1 = (int)(2*x);
        if (ai1==720) ai1=0;
        r = pullnum();
        getxy();
        if (currgs->nopath) dd=MOVE;
        graph(dd, x+r*costab[ai1]-cx, y+r*sintab[ai1]-cy);
        tt=a2-a1;
        if (tt<0) tt+= 360;
        if (tt <= 180) bezarc(a1,a2,r,x,y,tt,0);
        else {
                bezarc(a2-180,a2,r,x,y,180,0);
                bezarc(a1,a2-180,r,x,y,tt-180,0); }
}

void doarcto()
{
}

void curveto(re)
int re;
{
        double tx,ty;
        tx=cx;
        ty=cy;
        getxy();
        x=x+(re+1)*tx;
        y=y+(re+1)*ty;
        graph(CURVE, x-cx, y-cy);
        getxy();
        x=x+(re+1)*tx;
        y=y+(re+1)*ty;
        graph(CURVE, x-cx, y-cy);
        getxy();
        x=x+(re+1)*tx;
        y=y+(re+1)*ty;
        graph(CURVE, x-cx, y-cy);
}

void dostroke()
{
        clsd=1;
        pjoin=0;
        while (baseg != NULL) {
                doelement();
                baseg = baseg->next; }
        currgs->nopath = 1;
}

void doi(w)
int w;
{
        getxy();
        if (w) {
                pushnum(tma*x+tmc*y+tmx);
                pushnum(tmb*x+tmd*y+tmy); }
        else {
                pushnum(tma*x+tmc*y);
                pushnum(tmb*x+tmd*y); }
        readctm(ctm);
}

void dotrans(w)
int w;
{
        struct arrele *mat;
        if (current->sort == ARRAY) {
                mat=pullarray();
                if (mat->length == 6) readctm(mat);
                else seterror("typecheck"); }
        doi(w);
}

void doitrans(w)
int w;
{
        struct arrele *mat;
        struct arrele *tmat;
        tmat=createarray(6);
        if (current->sort == ARRAY) {
                mat=pullarray();
                if (mat->length == 6) readctm(inverse(mat,tmat));
                else seterror("typecheck"); }
        else readctm(inverse(ctm,tmat));
        doi(w);
        deletearray(tmat);
}

void doload()
{
        struct usere *tt;
        struct idlist *key;
        int c=doffset;
        key = pullname();
        while (c>=0) {
              tt=key->invoc;
              while (tt != NULL && tt->id != dictstack[c]) tt=tt->next;
              if (tt != NULL) {
                 pdict(tt);
                 c = -1; }
              --c;
              }
        if (tt == NULL) seterror("undefined");
}

void doroll()
{
        struct stelem temp;
        int n,j,size,e,c=0;
        getxy();
        n=(int)x;
        j=(int)y;
        if (j<0) size=(j*-1) % n;
        else size=j % n;
        if (n<0) seterror("typecheck");
        if ((offset+1)<n) seterror("rangecheck");
        if (j<0) for (; c<size; c++) {
                        temp=mstack[offset-n+1];
                        for(e=offset-n+1; e<offset; e++) mstack[e]=mstack[e+1];
                        mstack[offset]=temp; }
        else for(; c<size; c++) {
                        temp=mstack[offset];
                        for(e=offset; e>(offset-n+1); --e)
                                mstack[e]=mstack[e-1];
                        mstack[offset-n+1]=temp; }
}

void dostore()
{
        struct stelem value;
        struct idlist *key;
        if (offset < 1) seterror("stackunderflow");
        value=mstack[offset];
        pull();
        key=pullname();
        pushname(key);
        dowhere();
        if (current->u.bool) pull();
        else {
                pull();
                pushdict(dictstack[doffset]); }
        pushname(key);
        pushst(&value);
        doput();
}

void dolength()
{
        int i=0;
        switch (current->sort) {
        case ARRAY: i = pullarray()->length;
                    break;
        case DICTIONARY: i=pulldict()->size;
                         break;
        case SPECDICT: i=FONT_DICT_SIZE;
                       break;
        case STRING: i=pullrs()->len;
                     break;
        default: seterror("typecheck"); break; }
        pushnum((double)i);
}

void dofile()
{
        char *s1, *s2;
        struct phile *ff;
        FILE *tt;
        s2=pullrs()->string;
        s1=pullrs()->string;
        if (strlen(s2) != 1) seterror("invalidfileaccess");
        switch(s2[0]) {
        case 'r': tt=fopen(s1, "r"); break;
        case 'w': tt=fopen(s1, "w"); break;
        default: seterror("invalidfileaccess"); break; }
        if (tt==NULL) seterror("undefinedfilename");
        ff=(struct phile *)calloc(1, sizeof(struct phile));
        ff->f=tt;
        if (strcmp(s2,"r")==0) ff->status=READ;
        else ff->status=WRITE;
        pushfile(ff);
}

void doclosef()
{
        struct phile *ff;
        ff=pullfile();
        ff->status=CLOSED;
        fclose(ff->f);
}

void doread()
{
        struct phile *ff;
        int ch;
        ff=pullfile();
        if (ff->status != READ) seterror("invalidaccess");
        if ((ch=getc(ff->f)) != EOF) {
                pushnum((double)ch);
                pushbool(1); }
        else {
                ff->status=CLOSED;
                pushbool(0); }
}

void dowrite()
{
        struct phile *ff;
        int ch;
        ch=((int)pullnum()) % 256;
        ff=pullfile();
        if (ff->status != WRITE) seterror("invalidaccess");
        putc(ch, ff->f);
}

void dowritestring()
{
        struct phile *ff;
        int ch,c=0;
        struct strdef *str;
        str=pullrs();
        ff=pullfile();
        if (ff->status != WRITE) seterror("invalidaccess");
        while (c < str->len) {
                ch=str->string[c];
                putc(ch, ff->f);
                c++; }
}

void dowhs()
{
        struct phile *ff;
        int ch,c=0;
        struct strdef *str;
        str=pullrs();
        ff=pullfile();
        if (ff->status != WRITE) seterror("invalidaccess");
        while (c < str->len) {
                ch=str->string[c];
                putc(tohex(ch >> 4), ff->f);
                putc(tohex(ch & 15), ff->f);
                c++; }
}

void doreadstring()
{
        struct phile *ff;
        int ch,c=0;
        struct strdef *str;
        str=pullrs();
        ff=pullfile();
        if (ff->status != READ) seterror("invalidaccess");
        while (c < str->len && (ch=getc(ff->f)) != EOF) {
                str->string[c]=ch;
                c++; }
        pushrs(str);
        pushbool(c == str->len);
        if (c < str->len) ff->status=CLOSED;
}

void doreadline()
{
        struct phile *ff;
        int ch,c=0;
        struct strdef *str;
        str=pullrs();
        ff=pullfile();
        if (ff->status != READ) seterror("invalidaccess");
        while (c < str->len && (ch=getc(ff->f)) != EOF && ch != '\n') {
                str->string[c]=ch;
                c++; }
        if (ch==EOF || ch=='\n') pushms(str->string, c);
        else seterror("rangecheck");
        if (ch==EOF) ff->status=CLOSED;
        pushbool(ch=='\n');
}

void dorhs()
{
        struct phile *dsc;
        struct strdef *str;
        int c=0;
        int total=0;
        int ch;
        int which=0;
        str=pullrs();
        dsc=pullfile();
        if (dsc->status != READ) seterror("invalidaccess");
        while (c < str->len && (ch=getc(dsc->f)) != EOF)
                switch((char)ch) {
                case ' ': break;
                case '\n': break;
                default: if (which) {
                                total=16*total+hex((char)ch);
                                str->string[c]=total;
                                c++; }
                         else total=hex((char)ch);
                         which=1-which;
                         break; }
        pushms(str->string, c);
        pushbool(c == str->len);
        if (c != str->len) dsc->status=CLOSED;
}

void dgray(byte, off, gd)
int byte, off, gd;
{
        switch(gd) {
        case 1: setgray((byte >> (7-off)) & 1);
                break;
        case 2: setgray(((double)((byte >> (6-off*2)) & 3))/3);
                break;
        case 4: setgray(((double)((byte >> (4-off*4)) & 15))/15);
                break;
        case 8: setgray(((double)byte)/255);
                break; }
}

int npix(byte, nbyte, off, invert)
int byte,nbyte,off,invert;
{
        if (off==7) {
                off = -1;
                byte=nbyte; }
        off++;
        return(!(invert ^ ((byte >> (7-off)) & 1)));
}

int pix(byte, off, invert)
int byte,off,invert;
{
        return(!(invert ^ ((byte >> (7-off)) & 1)));
}

void doimage(image)
int image;
{
        int width,height,k,m,off,byte,nbyte,ebyte,cpis,bs,tr,invert;
        double a,b,c,d,e,f,wx,wy,kx,ky,ex,ey,nx,ny,rx,ry;
        double nex,ney,nkx,nky,r,r2,bx,by,vx,vy;
        int dd=85,alpha,beta,nexf=1,nexf2=1;
        struct strdef *brw;
        struct arrele *mat, *proc, *iom;
        struct stelem *im;
        proc=pullproc();
        mat=pullarray();
        if (image) bs=(int)pullnum();
        else {
                invert=pullbool();
                bs=1; }
        height=(int)pullnum();
        width=(int)pullnum();
        if (bs != 1 && bs != 2 && bs != 4 && bs != 8) seterror("undefined");
        switch(bs) {
        case 1: tr=8; break;
        case 2: tr=4; break;
        case 4: tr=2; break;
        case 8: tr=1; break; }
        iom=createarray(6);
        im=iom->array;
        inverse(mat, iom);
        f = im[5].u.number;
        e = im[4].u.number;
        d = im[3].u.number;
        c = im[2].u.number;
        b = im[1].u.number;
        a = im[0].u.number;
        wx=tma*e+tmc*f+tmx;
        wy=tmb*e+tmd*f+tmy;
        x=a+e;
        y=b+f;
        kx=tma*x+tmc*y+tmx-wx;
        ky=tmb*x+tmd*y+tmy-wy;
        x=c+e;
        y=d+f;
        ex=tma*x+tmc*y+tmx-wx;
        ey=tmb*x+tmd*y+tmy-wy;
        if (image) {
                nex=ex;
                ney=ey; }
        else {
                if (!kx) {
                        alpha=180;
                        r=fabs(ky)-4; }
                else {
                        alpha=(int)(2*deg(atan(ky/kx)));
                        if (alpha<0) alpha = -alpha;
                        r=fabs(kx/costab[alpha])-2-2*sintab[alpha]; }
                if (!ex) {
                        beta=180;
                        r2=fabs(ey)-4; }
                else {
                        beta=(int)(2*deg(atan(ey/ex)));
                        if (beta<0) beta = -beta;
                        r2=fabs(ex/costab[beta])-2-2*sintab[beta]; }
                nkx = r*costab[alpha];
                nky = r*sintab[alpha];
                nex = r2*costab[beta];
                ney = r2*sintab[beta];
                nex = ((ex>0)-(ex<0))*fabs(nex);
                ney = ((ey>0)-(ey<0))*fabs(ney);
                nkx = ((kx>0)-(kx<0))*fabs(nkx);
                nky = ((ky>0)-(ky<0))*fabs(nky); }
        if (height) {
                dooproc(proc);
                brw=pullrs();
                if (brw->len == 0) nexf=0;
                else {
                        nbyte=brw->string[0];
                        ebyte=nbyte; }
                cpis=0; }
        for (k=1; k<=height && nexf; k++) {
                nx=wx+nex;
                ny=wy+ney;
                plot(4, (int)wx, (int)wy);
                plot(4, (int)nx, (int)ny);
                off=tr; m=1; bx=0; by=0;
                while(m<=width && nexf) {
                    if (off==tr) {
                            off=0;
                            cpis++;
                            byte=nbyte;
                            if (cpis == brw->len) {
                                    dooproc(proc);
                                    brw=pullrs();
                                    if (brw->len == 0) nexf=0;
                                    cpis=0; }
                            if (nexf) nbyte=brw->string[cpis];
                            }
                    while (off<tr && m<=width && nexf2) {
                            if (image) {
                                    dgray(byte, off, bs);
                                    plot(dd,(int)(wx+bx+kx),(int)(wy+by+ky));
                                    plot(dd,(int)(nx+bx+kx),(int)(ny+by+ky)); }
                            else if(!(invert ^ ((byte >> (7-off)) & 1))) {
                                    plot(4, (int)(wx+bx), (int)(wy+by));
                                    rx=nkx;
                                    ry=nky;
                                    vx=nx;
                                    vy=ny;
                                    if (m<width && npix(byte,nbyte,off,invert))
                                        {
                                            rx=kx;
                                            ry=ky; }
                                    if (k<height && pix(ebyte,off,invert))
                                        {
                                          vx=wx+ex;
                                          vy=wy+ey; }
                                    plot(4, (int)(vx+bx), (int)(vy+by));
                                    plot(85,(int)(wx+bx+rx),(int)(wy+by+ry));
                                    plot(85,(int)(vx+bx+rx),(int)(vy+by+ry)); }
                            off++;
                            nexf2=nexf;
                            bx+=kx;
                            by+=ky;
                            m++; }
                    }
                ebyte=nbyte;
                wx+=ex;
                wy+=ey;
                }
        setcol();
}

void doloop()
{
        struct arrele *proc;
        proc=pullproc();
        while (exx) dooproc(proc);
        exx=1;
}

void doprint()
{
        struct strdef *temp;
        int c=0;
        temp=pullrs();
        while (c < temp->len) {
                printf("%c", temp->string[c]);
                c++; }
        printf("\n");
}

void doexec()
{
        if (offset == -1) seterror("stackunderflow");
        switch (current->sort) {
        case PROCEDURE: dooproc(pullproc());
                        break;
        default: break; }
}

void docheck(which)
int which;
{
        if (offset == -1) seterror("stackunderflow");
        switch (current->sort) {
        case ARRAY:
        case DICTIONARY:
        case STRING: pull();
                     pushbool(1);
                     break;
        case SPECDICT: pull();
                       pushbool(0);
                       break;
        case FILETYPE: pushbool(pullfile()->status == which);
                       break;
        default: seterror("typecheck"); }
}

void doif()
{
        struct arrele *ta=pullproc();
        if (pullbool()) dooproc(ta);
}

void doifelse()
{
        struct arrele *ta, *ta2;
        ta=pullproc();
        ta2=pullproc();
        if (pullbool()) dooproc(ta2);
        else dooproc(ta);
}

void dodictstack()
{
        struct arrele *nw, *a=pullarray();
        int l=0;
        if (doffset >= a->length) seterror("rangecheck");
        while (l<=doffset) {
                a->array[l].sort = DICTIONARY;
                a->array[l].u.dict = dictstack[l];
                l++; }
        nw = (struct arrele *)calloc(1, sizeof(struct arrele));
        nw->length = l;
        nw->array = a->array;
        pusharray(nw);
}

void dostopped()
{
        struct stelem *temp=current;
        if (current==NULL) seterror("stackunderflow");
        pull();
        exx=1;
        allowed=1;
        switch (temp->sort) {
        case EMPTY: pushnull();
                    break;
        case NUMBER: pushnum(temp->u.number);
                     break;
        case ARRAY: pusharray(temp->u.array);
                    break;
        case DICTIONARY: pushdict(temp->u.dict);
                         break;
        case STRING: pushrs(temp->u.restr);
                     break;
        case NAME: pushname(temp->u.name);
                   break;
        case BOOLEAN: pushbool(temp->u.bool);
                      break;
        case PROCEDURE: dooproc(temp->u.array);
                        break;
        case MARK: pushmark();
                   break;
        case FILETYPE: pushfile(temp->u.filo);
                       break;
        case PMARK: break;
        case OPERATOR: docom(temp->u.oper.called,temp->u.oper.k);
                       break;
        case SPECNAME: pushspec(temp->u.spname);
                       break;
        case SPECDICT: pushspdict(temp->u.spdict);
                       break; }
        pushbool(!exx);
        allowed=0;
}

void dorun(this)
char *this;
{
        char inp[256];
        int nof;
        FILE *fp;
        acc[0]=(char *)0;
        fp = fopen(this, "r");
        if (fp == NULL) seterror("invalidfileaccess");
        do {
                inp[0]=0;
                nof=(int)fgets(inp, 256, fp);
                if (strlen(inp) > 0) {
                        inp[strlen(inp)-1] = 0;
                        printf("%s\n",(char *)inp);
                        single(inp);
                        single("\n"); }
        } while (nof != NULL);
        fclose(fp);
}

void initgraphics()
{
        drti = 0;
        cx = 0;
        cy = 0;
        currgs->red = 0;
        currgs->green = 0;
        currgs->blue = 0;
        cline = 0.5;
        freq=1;
        ang=1;
        prc=1;
        currgs->ax=0;
        currgs->ay=0;
        currgs->curt=NULL;
        currgs->mlim=1;
        currgs->ljoin=0;
        currgs->lcap=0;
        currgs->flat=1;
        plot(4, 0, 0);
        currgs->nopath = 1;
        setmat(ctm,1.0,0.0,0.0,1.0,0.0,0.0);
        readctm(ctm);
        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;
        currgs->font = NULL;
        setcol();
}
