Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "pic.h"
#include "y.tab.h"

int whatpos(obj *p, int corner, double *px, double *py);
void makeattr(int type, int sub, YYSTYPE val);
YYSTYPE getblk(obj *, char *);

setdir(int n)   /* set direction (hvmode) from LEFT, RIGHT, etc. */
{
        switch (n) {
        case UP:        hvmode = U_DIR; break;
        case DOWN:      hvmode = D_DIR; break;
        case LEFT:      hvmode = L_DIR; break;
        case RIGHT:     hvmode = R_DIR; break;
        }
        return(hvmode);
}

curdir(void)    /* convert current dir (hvmode) to RIGHT, LEFT, etc. */
{
        switch (hvmode) {
        case R_DIR:     return RIGHT;
        case L_DIR:     return LEFT;
        case U_DIR:     return UP;
        case D_DIR:     return DOWN;
        }
        ERROR "can't happen curdir" FATAL;
        return 0;
}

double getcomp(obj *p, int t)   /* return component of a position */
{
        switch (t) {
        case DOTX:
                return p->o_x;
        case DOTY:
                return p->o_y;
        case DOTWID:
                switch (p->o_type) {
                case BOX:
                case BLOCK:
                case TEXT:
                        return p->o_val[0];
                case CIRCLE:
                case ELLIPSE:
                        return 2 * p->o_val[0];
                case LINE:
                case ARROW:
                        return p->o_val[0] - p->o_x;
                case PLACE:
                        return 0;
                }
        case DOTHT:
                switch (p->o_type) {
                case BOX:
                case BLOCK:
                case TEXT:
                        return p->o_val[1];
                case CIRCLE:
                case ELLIPSE:
                        return 2 * p->o_val[1];
                case LINE:
                case ARROW:
                        return p->o_val[1] - p->o_y;
                case PLACE:
                        return 0;
                }
        case DOTRAD:
                switch (p->o_type) {
                case CIRCLE:
                case ELLIPSE:
                        return p->o_val[0];
                }
        }
        ERROR "you asked for a weird dimension or position" WARNING;
        return 0;
}

double  exprlist[100];
int     nexpr   = 0;

void exprsave(double f)
{
        exprlist[nexpr++] = f;
}

char *sprintgen(char *fmt)
{
        char buf[1000];

        sprintf(buf, fmt, exprlist[0], exprlist[1], exprlist[2], exprlist[3], exprlist[4]);
        nexpr = 0;
        free(fmt);
        return tostring(buf);
}

void makefattr(int type, int sub, double f)     /* double attr */
{
        YYSTYPE val;
        val.f = f;
        makeattr(type, sub, val);
}

void makeoattr(int type, obj *o)        /* obj* attr */
{
        YYSTYPE val;
        val.o = o;
        makeattr(type, 0, val);
}

void makeiattr(int type, int i) /* int attr */
{
        YYSTYPE val;
        val.i = i;
        makeattr(type, 0, val);
}

void maketattr(int sub, char *p)        /* text attribute: takes two */
{
        YYSTYPE val;
        val.p = p;
        makeattr(TEXTATTR, sub, val);
}

void addtattr(int sub)          /* add text attrib to existing item */
{
        attr[nattr-1].a_sub |= sub;
}

void makevattr(char *p) /* varname attribute */
{
        YYSTYPE val;
        val.p = p;
        makeattr(VARNAME, 0, val);
}

void makeattr(int type, int sub, YYSTYPE val)   /* add attribute type and val */
{
        if (type == 0 && val.i == 0) {  /* clear table for next stat */
                nattr = 0;
                return;
        }
        if (nattr >= nattrlist)
                attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
        dprintf("attr %d:  %d %d %d\n", nattr, type, sub, val.i);
        attr[nattr].a_type = type;
        attr[nattr].a_sub = sub;
        attr[nattr].a_val = val;
        nattr++;
}

void printexpr(double f)        /* print expression for debugging */
{
        printf("%g\n", f);
}

void printpos(obj *p)   /* print position for debugging */
{
        printf("%g, %g\n", p->o_x, p->o_y);
}

char *tostring(char *s)
{
        register char *p;

        p = malloc(strlen(s)+1);
        if (p == NULL)
                ERROR "out of space in tostring on %s", s FATAL;
        strcpy(p, s);
        return(p);
}

obj *makepos(double x, double y)        /* make a position cell */
{
        obj *p;

        p = makenode(PLACE, 0);
        p->o_x = x;
        p->o_y = y;
        return(p);
}

obj *makebetween(double f, obj *p1, obj *p2)    /* make position between p1 and p2 */
{
        obj *p;

        dprintf("fraction = %.2f\n", f);
        p = makenode(PLACE, 0);
        p->o_x = p1->o_x + f * (p2->o_x - p1->o_x);
        p->o_y = p1->o_y + f * (p2->o_y - p1->o_y);
        return(p);
}

obj *getpos(obj *p, int corner) /* find position of point */
{
        double x, y;

        whatpos(p, corner, &x, &y);
        return makepos(x, y);
}

int whatpos(obj *p, int corner, double *px, double *py) /* what is the position (no side effect) */
{
        double x, y, x1, y1;

        if (p == NULL)
                ERROR "null object" FATAL;
        dprintf("whatpos %o %d %d\n", p, p->o_type, corner);
        x = p->o_x;
        y = p->o_y;
        if (p->o_type != PLACE && p->o_type != MOVE) {
                x1 = p->o_val[0];
                y1 = p->o_val[1];
        }
        switch (p->o_type) {
        case PLACE:
                break;
        case BOX:
        case BLOCK:
        case TEXT:
                switch (corner) {
                case NORTH:     y += y1 / 2; break;
                case SOUTH:     y -= y1 / 2; break;
                case EAST:      x += x1 / 2; break;
                case WEST:      x -= x1 / 2; break;
                case NE:        x += x1 / 2; y += y1 / 2; break;
                case SW:        x -= x1 / 2; y -= y1 / 2; break;
                case SE:        x += x1 / 2; y -= y1 / 2; break;
                case NW:        x -= x1 / 2; y += y1 / 2; break;
                case START:
                        if (p->o_type == BLOCK)
                                return whatpos(objlist[(int)p->o_val[2]], START, px, py);
                case END:
                        if (p->o_type == BLOCK)
                                return whatpos(objlist[(int)p->o_val[3]], END, px, py);
                }
                break;
        case ARC:
                switch (corner) {
                case START:
                        if (p->o_attr & CW_ARC) {
                                x = p->o_val[2]; y = p->o_val[3];
                        } else {
                                x = x1; y = y1;
                        }
                        break;
                case END:
                        if (p->o_attr & CW_ARC) {
                                x = x1; y = y1;
                        } else {
                                x = p->o_val[2]; y = p->o_val[3];
                        }
                        break;
                }
                if (corner == START || corner == END)
                        break;
                x1 = y1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y));
                /* Fall Through! */
        case CIRCLE:
        case ELLIPSE:
                switch (corner) {
                case NORTH:     y += y1; break;
                case SOUTH:     y -= y1; break;
                case EAST:      x += x1; break;
                case WEST:      x -= x1; break;
                case NE:        x += 0.707 * x1; y += 0.707 * y1; break;
                case SE:        x += 0.707 * x1; y -= 0.707 * y1; break;
                case NW:        x -= 0.707 * x1; y += 0.707 * y1; break;
                case SW:        x -= 0.707 * x1; y -= 0.707 * y1; break;
                }
                break;
        case LINE:
        case SPLINE:
        case ARROW:
                switch (corner) {
                case START:     break;  /* already in place */
                case END:       x = x1; y = y1; break;
                default: /* change! */
                case CENTER:    x = (x+x1)/2; y = (y+y1)/2; break;
                case NORTH:     if (y1 > y) { x = x1; y = y1; } break;
                case SOUTH:     if (y1 < y) { x = x1; y = y1; } break;
                case EAST:      if (x1 > x) { x = x1; y = y1; } break;
                case WEST:      if (x1 < x) { x = x1; y = y1; } break;
                }
                break;
        case MOVE:
                /* really ought to be same as line... */
                break;
        }
        dprintf("whatpos returns %g %g\n", x, y);
        *px = x;
        *py = y;
        return 1;
}

obj *gethere(void)      /* make a place for curx,cury */
{
        dprintf("gethere %g %g\n", curx, cury);
        return(makepos(curx, cury));
}

obj *getlast(int n, int t)      /* find n-th previous occurrence of type t */
{
        int i, k;
        obj *p;

        k = n;
        for (i = nobj-1; i >= 0; i--) {
                p = objlist[i];
                if (p->o_type == BLOCKEND) {
                        i = p->o_val[4];
                        continue;
                }
                if (p->o_type != t)
                        continue;
                if (--k > 0)
                        continue;       /* not there yet */
                dprintf("got a last of x,y= %g,%g\n", p->o_x, p->o_y);
                return(p);
        }
        ERROR "there is no %dth last", n FATAL;
        return(NULL);
}

obj *getfirst(int n, int t)     /* find n-th occurrence of type t */
{
        int i, k;
        obj *p;

        k = n;
        for (i = 0; i < nobj; i++) {
                p = objlist[i];
                if (p->o_type == BLOCK && t != BLOCK) { /* skip whole block */
                        i = p->o_val[5] + 1;
                        continue;
                }
                if (p->o_type != t)
                        continue;
                if (--k > 0)
                        continue;       /* not there yet */
                dprintf("got a first of x,y= %g,%g\n", p->o_x, p->o_y);
                return(p);
        }
        ERROR "there is no %dth ", n FATAL;
        return(NULL);
}

double getblkvar(obj *p, char *s)       /* find variable s2 in block p */
{
        YYSTYPE y;

        y = getblk(p, s);
        return y.f;
}

obj *getblock(obj *p, char *s)  /* find variable s in block p */
{
        YYSTYPE y;

        y = getblk(p, s);
        return y.o;
}

YYSTYPE getblk(obj *p, char *s) /* find union type for s in p */
{
        static YYSTYPE bug;
        struct symtab *stp;

        if (p->o_type != BLOCK) {
                ERROR ".%s is not in that block", s WARNING;
                return(bug);
        }
        for (stp = p->o_symtab; stp != NULL; stp = stp->s_next)
                if (strcmp(s, stp->s_name) == 0) {
                        dprintf("getblk %s found x,y= %g,%g\n",
                                s, (stp->s_val.o)->o_x, (stp->s_val.o)->o_y);
                        return(stp->s_val);
                }
        ERROR "there is no .%s in that []", s WARNING;
        return(bug);
}

obj *fixpos(obj *p, double x, double y)
{
        dprintf("fixpos returns %g %g\n", p->o_x + x, p->o_y + y);
        return makepos(p->o_x + x, p->o_y + y);
}

obj *addpos(obj *p, obj *q)
{
        dprintf("addpos returns %g %g\n", p->o_x+q->o_x, p->o_y+q->o_y);
        return makepos(p->o_x+q->o_x, p->o_y+q->o_y);
}

obj *subpos(obj *p, obj *q)
{
        dprintf("subpos returns %g %g\n", p->o_x-q->o_x, p->o_y-q->o_y);
        return makepos(p->o_x-q->o_x, p->o_y-q->o_y);
}

obj *makenode(int type, int n)
{
        obj *p;

        p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(ofloat));
        if (p == NULL)
                ERROR "out of space in makenode" FATAL;
        p->o_type = type;
        p->o_count = n;
        p->o_nobj = nobj;
        p->o_mode = hvmode;
        p->o_x = curx;
        p->o_y = cury;
        p->o_nt1 = ntext1;
        p->o_nt2 = ntext;
        ntext1 = ntext; /* ready for next caller */
        if (nobj >= nobjlist)
                objlist = (obj **) grow((char *) objlist, "objlist",
                        nobjlist *= 2, sizeof(obj *));
        objlist[nobj++] = p;
        return(p);
}

void extreme(double x, double y)        /* record max and min x and y values */
{
        if (x > xmax)
                xmax = x;
        if (y > ymax)
                ymax = y;
        if (x < xmin)
                xmin = x;
        if (y < ymin)
                ymin = y;
}