| #include <stdio.h> |
| #include <string.h> |
| #include <math.h> |
| #include "pic.h" |
| #include "y.tab.h" |
| |
| int |
| 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); |
| } |
| |
| int |
| 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) |
| { |
| 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; |
| |
| dprintf("whatpos %p %d %d\n", p, p->o_type, corner); |
| x = p->o_x; |
| y = p->o_y; |
| x1 = 0; |
| y1 = 0; |
| if (p->o_type != PLACE) { |
| 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 WARNING; |
| 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 WARNING; |
| 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; |
| } |