static void getdata(void) { char *p, buf[1000], buf1[100]; int ln; curfile->lineno = 0; printlf(1, curfile->fname); while (fgets(buf, sizeof buf, curfile->fin) != NULL) { curfile->lineno++; if (*buf == '.' && *(buf+1) == 'P' && *(buf+2) == 'S') { for (p = &buf[3]; *p == ' '; p++) ; if (*p++ == '<') { Infile svfile; svfile = *curfile; sscanf(p, "%s", buf1); if ((curfile->fin=fopen(buf1, "r")) == NULL) ERROR "can't open %s", buf1 FATAL; curfile->fname = tostring(buf1); getdata(); fclose(curfile->fin); free(curfile->fname); *curfile = svfile; printlf(curfile->lineno, curfile->fname); continue; } reset(); yyparse(); anyerr += synerr; /* yylval.i now contains 'E' or 'F' from .PE or .PF */ deltx = (xmax - xmin) / getfval("scale"); delty = (ymax - ymin) / getfval("scale"); if (buf[3] == ' ') { /* next things are wid & ht */ if (sscanf(&buf[4],"%lf %lf", &deltx, &delty) < 2) delty = deltx * (ymax-ymin) / (xmax-xmin); #if 0 /* else { * double xfac, yfac; */ * xfac = deltx / (xmax-xmin); * yfac = delty / (ymax-ymin); * if (xfac <= yfac) * delty = xfac * (ymax-ymin); * else * deltx = yfac * (xmax-xmin); *} */ #endif } dprintf("deltx = %g, delty = %g\n", deltx, delty); if (codegen && !synerr) { openpl(&buf[3]); /* puts out .PS, with ht & wid stuck in */ printlf(curfile->lineno+1, NULL); print(); /* assumes \n at end */ closepl(yylval.i); /* does the .PE/F */ } printlf(curfile->lineno+1, NULL); fflush(stdout); } else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
void openpl(char *s) /* initialize device; s is residue of .PS invocation line */ { double maxw, maxh, ratio = 1; double odeltx = deltx, odelty = delty; hpos = vpos = 0; maxw = getfval("maxpswid"); maxh = getfval("maxpsht"); if (deltx > maxw) { /* shrink horizontal */ ratio = maxw / deltx; deltx *= ratio; delty *= ratio; } if (delty > maxh) { /* shrink vertical */ ratio = maxh / delty; deltx *= ratio; delty *= ratio; } if (ratio != 1) { fprintf(stderr, "pic: %g X %g picture shrunk to", odeltx, odelty); fprintf(stderr, " %g X %g\n", deltx, delty); } space(xmin, ymin, xmax, ymax); printf(".\\\" %g %g %g %g\n", xmin, ymin, xmax, ymax); printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax)); printf(".nr 00 \\n(.u\n"); printf(".nf\n"); printf(".PS %.3fi %.3fi %s", yconv(ymin), xconv(xmax), s); /* assumes \n comes as part of s */ }
Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ { Awkfloat i, j = 0; double v; Cell *x, *y, *z; x = execute(a[0]); i = getfval(x); tempfree(x); if (n != UMINUS) { y = execute(a[1]); j = getfval(y); tempfree(y); } z = gettemp(); switch (n) { case ADD: i += j; break; case MINUS: i -= j; break; case MULT: i *= j; break; case DIVIDE: if (j == 0) ERROR "division by zero" FATAL; i /= j; break; case MOD: if (j == 0) ERROR "division by zero in mod" FATAL; modf(i/j, &v); i = i - j * v; break; case UMINUS: i = -i; break; case POWER: if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ i = ipow(i, (int) j); else i = errcheck(pow(i, j), "pow"); break; default: /* can't happen */ ERROR "illegal arithmetic operator %d", n FATAL; } setfval(z, i); return(z); }
Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */ { int k, m, n; char *s; int temp; Cell *x, *y, *z = 0; x = execute(a[0]); y = execute(a[1]); if (a[2] != 0) z = execute(a[2]); s = getsval(x); k = strlen(s) + 1; if (k <= 1) { tempfree(x); tempfree(y); if (a[2] != 0) { tempfree(z); } x = gettemp(); setsval(x, ""); return(x); } m = (int) getfval(y); if (m <= 0) m = 1; else if (m > k) m = k; tempfree(y); if (a[2] != 0) { n = (int) getfval(z); tempfree(z); } else n = k - 1; if (n < 0) n = 0; else if (n > k - m) n = k - m; dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); y = gettemp(); temp = s[n+m-1]; /* with thanks to John Linderman */ s[n+m-1] = '\0'; setsval(y, s + m - 1); s[n+m-1] = temp; tempfree(x); return(y); }
void checktextcolor (obj *p) { if (p->o_nt2 > p->o_nt1) { if (p->o_text == -1) p->o_text = getfval("textcolor"); p->o_text = checkcolor((double)p->o_text); } }
Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ { Cell *y; switch (n) { case EXIT: if (a[0] != NULL) { y = execute(a[0]); errorflag = getfval(y); tempfree(y); } longjmp(env, 1); case RETURN: if (a[0] != NULL) { y = execute(a[0]); if ((y->tval & (STR|NUM)) == (STR|NUM)) { setsval(fp->retval, getsval(y)); fp->retval->fval = getfval(y); fp->retval->tval |= NUM; } else if (y->tval & STR) setsval(fp->retval, getsval(y)); else if (y->tval & NUM) setfval(fp->retval, getfval(y)); else /* can't happen */ ERROR "bad type variable %d", y->tval FATAL; tempfree(y); } return(jret); case NEXT: return(jnext); case NEXTFILE: nextfile(); return(jnextfile); case BREAK: return(jbreak); case CONTINUE: return(jcont); default: /* can't happen */ ERROR "illegal jump type %d", n FATAL; } return 0; /* not reached */ }
void openpl(char *s) /* initialize device */ /* char *s; / * residue of .PS invocation line */ { double maxw, maxh, ratio = 1; double odeltx = deltx, odelty = delty; hpos = vpos = 0; maxw = getfval("maxpswid"); maxh = getfval("maxpsht"); /* if (deltx > getfval("maxpswid") || delty > getfval("maxpsht")) { / * 8.5x11 inches max * / * fprintf(stderr, "pic: %g X %g picture shrunk to", deltx, delty); * maxdelt = max(deltx, delty); * deltx *= 7/maxdelt; / * screwed up anyway; * / * delty *= 7/maxdelt; / * make it 7x7 so someone can see it * / * fprintf(stderr, " %g X %g\n", deltx, delty); * } */ if (deltx > maxw) { /* shrink horizontal */ ratio = maxw / deltx; deltx *= ratio; delty *= ratio; } if (delty > maxh) { /* shrink vertical */ ratio = maxh / delty; deltx *= ratio; delty *= ratio; } if (ratio != 1) { fprintf(stderr, "pic: %g X %g picture shrunk to", odeltx, odelty); fprintf(stderr, " %g X %g\n", deltx, delty); } space(xmin, ymin, xmax, ymax); printf("... %g %g %g %g\n", xmin, ymin, xmax, ymax); printf("... %.3fi %.3fi %.3fi %.3fi\n", xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax)); printf(".nr 00 \\n(.u\n"); printf(".nf\n"); printf(".PS %.3fi %.3fi %s", yconv(ymin), xconv(xmax), s); /* assumes \n comes as part of s */ }
void nextfor(void) /* do one iteration of a for loop */ { /* BUG: this should depend on op and direction */ if (getfval(forp->var) > SLOP * forp->to) { /* loop is done */ free(forp->str); if (--forp < forstk) ERROR "forstk popped too far" FATAL; } else { /* another iteration */ pushsrc(String, "\nEndfor\n"); pushsrc(String, forp->str); } }
void checkscale(char *s) /* if s is "scale", adjust default variables */ { int i; double scale; if (strcmp(s, "scale") == 0) { scale = getfval("scale"); for (i = 1; defaults[i].name != NULL; i++) if (defaults[i].scalable) setfval(defaults[i].name, defaults[i].val * scale); } }
Cell *indirect(Node **a, int n) /* $( a[0] ) */ { Cell *x; int m; char *s; x = execute(a[0]); m = getfval(x); if (m == 0 && !isnumber(s = getsval(x))) /* suspicion! */ ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL; /* can x->nval ever be null??? */ /* ERROR "illegal field $(%s)", s FATAL; */ tempfree(x); x = fieldadr(m); x->ctype = OCELL; x->csub = CFLD; return(x); }
Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */ { Cell *x, *z; int k; Awkfloat xf; x = execute(a[0]); xf = getfval(x); k = (n == PREINCR || n == POSTINCR) ? 1 : -1; if (n == PREINCR || n == PREDECR) { setfval(x, xf + k); return(x); } z = gettemp(); setfval(z, xf); setfval(x, xf + k); tempfree(x); return(z); }
void primattrs(obj *p, struct objattr *obat) /* note: ht, wid, rad and layer are set elsewhere */ /* because of nonuniformities in their design */ /* (this could be further rationalized!) */ { int n; float x; p->o_attr |= obat->a_flags; p->o_text = obat->a_tcolor; checktextcolor(p); if (obat->a_flags & FILLED) { if (obat->a_pcolor == -1.) obat->a_pcolor = getfval ("fillcolor"); p->o_fill = checkcolor((double)obat->a_pcolor); } if (obat->a_flags & EDGED) { if (obat->a_weight == -1.) obat->a_weight = getfval ("lineweight"); if (obat->a_weight >= 0.) p->o_weight = obat->a_weight; if (obat->a_lcolor == -1.) obat->a_lcolor = getfval ("linecolor"); p->o_color = checkcolor((double)obat->a_lcolor); if ((n = (int)getfval("linecap")) >= 0) p->o_attr |= (1 + n%3)*LINECAP; if ((n = (int)getfval("linejoin")) >= 0) p->o_attr |= (1 + n%3)*JOIN; if (n == 0) { /* mitre join */ x = getfval("miterlimit"); if (x >= 1) { for (n = 1; n < 8; n++) if (miters[n] == 0 || miters[n] == x) break; if (n == 8) for (n = 1; n < 7; ++n) miters[n] = miters[n+1]; miters[n] = x; p->o_attr |= n * MITER; } } } else p->o_weight = 0; if (obat->a_dashpat.a != NULL && obat->a_dashpat.a[1] == -1) /* dots */ if ((obat->a_dashpat.a[1] = p->o_weight) == 0) obat->a_dashpat.a[1] = 1/(pgscale*2); p->o_ddpat = obat->a_dashpat; }
Cell *indirect(Node **a, int n) /* $( a[0] ) */ { Awkfloat val; Cell *x; int m; char *s; x = execute(a[0]); val = getfval(x); /* freebsd: defend against super large field numbers */ if ((Awkfloat)INT_MAX < val) FATAL("trying to access out of range field %s", x->nval); m = (int) val; if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */ FATAL("illegal field $(%s), name \"%s\"", s, x->nval); /* BUG: can x->nval ever be null??? */ tempfree(x); x = fieldadr(m); x->ctype = OCELL; /* BUG? why are these needed? */ x->csub = CFLD; return(x); }
char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ { char *t; int fldno; Awkfloat f; dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); if (isfld(vp)) { donerec = 0; /* mark $0 invalid */ fldno = atoi(vp->nval); if (fldno > *NF) newfld(fldno); dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); } else if (isrec(vp)) { donefld = 0; /* mark $1... invalid */ donerec = 1; } t = tostring(s); /* in case it's self-assign */ if (freeable(vp)) xfree(vp->sval); vp->tval &= ~NUM; vp->tval |= STR; vp->tval &= ~DONTFREE; dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) ); vp->sval = t; if (&vp->fval == NF) { donerec = 0; /* mark $0 invalid */ f = getfval(vp); setlastfld(f); dprintf( ("setting NF to %g\n", f) ); } return(vp->sval); }
Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ { static Cell newcopycell = { OCELL, CCOPY, 0, (char *) "", 0.0, NUM|STR|DONTFREE }; int i, ncall, ndef; Node *x; Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn; char *s; fcn = execute(a[0]); /* the function itself */ s = fcn->nval; if (!isfunc(fcn)) ERROR "calling undefined function %s", s FATAL; if (frame == NULL) { fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); if (frame == NULL) ERROR "out of space for stack frames calling %s", s FATAL; } for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ ncall++; ndef = (int) fcn->fval; /* args in defn */ dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) ); if (ncall > ndef) ERROR "function %s called with %d args, uses only %d", s, ncall, ndef WARNING; if (ncall + ndef > NARGS) ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL; for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) ); y = execute(x); oargs[i] = y; dprintf( ("args[%d]: %s %f <%s>, t=%o\n", i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) ); if (isfunc(y)) ERROR "can't use function %s as argument in %s", y->nval, s FATAL; if (isarr(y)) args[i] = y; /* arrays by ref */ else args[i] = copycell(y); tempfree(y); } for ( ; i < ndef; i++) { /* add null args for ones not provided */ args[i] = gettemp(); *args[i] = newcopycell; } fp++; /* now ok to up frame */ if (fp >= frame + nframe) { int dfp = fp - frame; /* old index */ frame = (struct Frame *) realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); if (frame == NULL) ERROR "out of space for stack frames in %s", s FATAL; fp = frame + dfp; } fp->fcncell = fcn; fp->args = args; fp->nargs = ndef; /* number defined with (excess are locals) */ fp->retval = gettemp(); dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) ); y = execute((Node *)(fcn->sval)); /* execute body */ dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) ); for (i = 0; i < ndef; i++) { Cell *t = fp->args[i]; if (isarr(t)) { if (t->csub == CCOPY) { if (i >= ncall) { freesymtab(t); t->csub = CTEMP; } else { oargs[i]->tval = t->tval; oargs[i]->tval &= ~(STR|NUM|DONTFREE); oargs[i]->sval = t->sval; tempfree(t); } } } else if (t != y) { /* kludge to prevent freeing twice */ t->csub = CTEMP; tempfree(t); } } tempfree(fcn); if (isexit(y) || isnext(y) || isnextfile(y)) return y; tempfree(y); /* this can free twice! */ z = fp->retval; /* return value */ dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); fp--; return(z); }
void miscattrs(Attr *ap, struct objattr *obat) { float *fp; int n; switch (ap->a_type) { case FONT: reset_font((double)ap->a_val.f); break; case SIZE: reset_size(ap->a_sub, (double)ap->a_val.f); break; case SPACE: reset_space(ap->a_sub, (double)ap->a_val.f); break; case TEXTATTR: if (ap->a_val.p != NULL) savetext(ap->a_sub, ap->a_val.p); else /* These type values should be propagated back to other strings */ /* Maybe by calling reset_type, to be added to textgen.c */ text[ntext-1].t_type = ap->a_sub; /* ??? can this ever happen */ /* except after a previous */ /* text in the same object? */ break; case NOEDGE: obat->a_flags &= ~EDGED; break; case LAYER: obat->a_layer = ap->a_val.f; break; case LWEIGHT: obat->a_weight = ap->a_val.f; break; case LCOLOR: obat->a_lcolor = ap->a_val.f; break; case PCOLOR: obat->a_flags |= FILLED; if (ap->a_sub != DEFAULT) obat->a_pcolor = ap->a_val.f; break; case TCOLOR: obat->a_tcolor = ap->a_val.f; break; case DOT: case DASH: n = ap->a_type == DOT ? 3 : 2; if ((fp = (float *)malloc(n * sizeof(float))) == NULL) { yyerror("out of space in miscattrs"); break; } *fp = --n; fp[n] = (ap->a_sub == DEFAULT ? getfval("dashwid") : ap->a_val.f); if (n == 2) fp[1] = -1; /* fill in later, from weight */ ap->a_val.a = fp; /* and fall through to the general case */ case DASHPAT: obat->a_flags |= DOTDASH; obat->a_dashpat.a = ap->a_val.a; break; case HEIGHT: obat->a_ht = ap->a_val.f; break; case WIDTH: obat->a_wid = ap->a_val.f; break; case RADIUS: obat->a_rad = ap->a_val.f; break; case DIAMETER: obat->a_rad = ap->a_val.f / 2; break; } }
double setattr(obj *p, int type, double val) { int cw_switch; double x, y; obj *q; if (p->o_type == BLOCK) { for (q = p->o_next; q != p->o_val[N_VAL].o; q = q->o_next) setattr (q, type, val); } else if (p->o_type <= TEXT) switch (type) { case TCOLOR: if (val >= 0.0 || checkcolor(val) >= 0.0) p->o_text = val; break; case LCOLOR: if (val >= 0.0 || checkcolor(val) >= 0.0) p->o_color = val; break; case PCOLOR: if (val < 0.0 || checkcolor(val) < 0.0) p->o_attr &= ~FILLED; else { p->o_fill = val; /* ignored for TEXT? */ p->o_attr |= FILLED; } break; case LAYER: if (val < -128) val = -128; else if (val > 127) val = 127; p->o_layer = (short)val; if (val > getfval("maxlayer")) setfval ("maxlayer", val); break; case LWEIGHT: p->o_weight = val; break; case NOEDGE: if (val != 0.0) p->o_attr &= ~EDGED; else p->o_attr |= EDGED; break; case CCW: case CW: if (p->o_type == ARC) { cw_switch = (p->o_attr & CW_ARC); if (type == CW) cw_switch = !cw_switch; if (cw_switch) { x = p->o_val[N_VAL+2].f; y = p->o_val[N_VAL+3].f; p->o_val[N_VAL+2] = p->o_val[N_VAL+4]; p->o_val[N_VAL+3] = p->o_val[N_VAL+5]; /* exchange from & to */ p->o_val[N_VAL+4].f = x; p->o_val[N_VAL+5].f = y; p->o_attr ^= (p->o_attr & CW_ARC); } } break; case DIAMETER: val /= 2; case RADIUS: switch (p->o_type) { case ARROW: case LINE: case BOX: case ARC: case SECTOR: p->o_val[N_VAL].f = val; break; case CIRCLE: case ELLIPSE: p->o_wid = val * 2; break; } break; case WIDTH: p->o_wid = val; break; case HEIGHT: p->o_ht = val; break; default: yyerror ("can't happen setattr"); } return val; }
obj *linegen(int type) { static double prevdx = HT; static double prevdy = 0; static double prevw = HT10; static double prevh = HT5; int i, j, some, head, ddtype, invis, chop; double ddval, chop1, chop2, x0, y0, x1, y1; double sin(), cos(), atan2(), theta; double defx, defy; obj *p, *ppos; static int xtab[] = { 1, 0, -1, 0 }; /* R=0, U=1, L=2, D=3 */ static int ytab[] = { 0, 1, 0, -1 }; double dx[500], dy[500]; int ndxy; double nx, ny; Attr *ap; nx = curx; ny = cury; defx = getfval("linewid"); defy = getfval("lineht"); prevh = getfval("arrowht"); prevw = getfval("arrowwid"); dx[0] = dy[0] = ndxy = some = head = invis = 0; chop = chop1 = chop2 = 0; ddtype = ddval = 0; for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; case HEAD: head += ap->a_val.i; break; case INVIS: invis = INVIS; break; case CHOP: if (chop++ == 0) chop1 = chop2 = ap->a_val.f; else chop2 = ap->a_val.f; break; case DOT: case DASH: ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT; if (ap->a_sub == DEFAULT) ddval = getfval("dashwid"); else ddval = ap->a_val.f; break; case SAME: dx[ndxy] = prevdx; dy[ndxy] = prevdy; some++; break; case LEFT: dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; some++; hvmode = L_DIR; break; case RIGHT: dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; some++; hvmode = R_DIR; break; case UP: dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; some++; hvmode = U_DIR; break; case DOWN: dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; some++; hvmode = D_DIR; break; case HEIGHT: /* length of arrowhead */ prevh = ap->a_val.f; break; case WIDTH: /* width of arrowhead */ prevw = ap->a_val.f; break; case TO: if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; dx[ndxy] = dy[ndxy] = some = 0; } ppos = attr[i].a_val.o; dx[ndxy] = ppos->o_x - nx; dy[ndxy] = ppos->o_y - ny; some++; break; case BY: if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; dx[ndxy] = dy[ndxy] = some = 0; } ppos = ap->a_val.o; dx[ndxy] = ppos->o_x; dy[ndxy] = ppos->o_y; some++; break; case THEN: /* turn off any previous accumulation */ if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; dx[ndxy] = dy[ndxy] = some = 0; } break; case FROM: case AT: ppos = ap->a_val.o; nx = curx = ppos->o_x; ny = cury = ppos->o_y; break; } } if (some) { nx += dx[ndxy]; ny += dy[ndxy]; ndxy++; defx = dx[ndxy-1]; defy = dy[ndxy-1]; } else { defx *= xtab[hvmode]; defy *= ytab[hvmode]; dx[ndxy] = defx; dy[ndxy] = defy; ndxy++; nx += defx; ny += defy; } prevdx = defx; prevdy = defy; if (chop) { if (chop == 1 && chop1 == 0) /* just said "chop", so use default */ chop1 = chop2 = getfval("circlerad"); theta = atan2(dy[0], dx[0]); x0 = chop1 * cos(theta); y0 = chop1 * sin(theta); curx += x0; cury += y0; dx[0] -= x0; dy[0] -= y0; theta = atan2(dy[ndxy-1], dx[ndxy-1]); x1 = chop2 * cos(theta); y1 = chop2 * sin(theta); nx -= x1; ny -= y1; dx[ndxy-1] -= x1; dy[ndxy-1] -= y1; dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n", x0, y0, x1, y1, curx, cury, nx, ny); } p = makenode(type, 5 + 2 * ndxy); curx = p->o_val[0] = nx; cury = p->o_val[1] = ny; if (head || type == ARROW) { p->o_nhead = getfval("arrowhead"); p->o_val[2] = prevw; p->o_val[3] = prevh; if (head == 0) head = HEAD2; /* default arrow head */ } p->o_attr = head | invis | ddtype; p->o_val[4] = ndxy; nx = p->o_x; ny = p->o_y; for (i = 0, j = 5; i < ndxy; i++, j += 2) { p->o_val[j] = dx[i]; p->o_val[j+1] = dy[i]; if (type == LINE || type == ARROW) extreme(nx += dx[i], ny += dy[i]); else if (type == SPLINE && i < ndxy-1) { /* to compute approx extreme of spline at p, * compute midway between p-1 and p+1, * then go 3/4 from there to p */ double ex, ey, xi, yi, xi1, yi1; xi = nx + dx[i]; yi = ny + dy[i]; /* p */ xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1]; /* p+1 */ ex = (nx+xi1)/2; ey = (ny+yi1)/2; /* midway */ ex += 0.75*(xi-ex); ey += 0.75*(yi-ey); extreme(ex, ey); nx = xi; ny = yi; } } p->o_ddval = ddval; if (dbg) { printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy); for (i = 0, j = 5; i < ndxy; i++, j += 2) printf("%g %g\n", p->o_val[j], p->o_val[j+1]); } extreme(p->o_x, p->o_y); extreme(curx, cury); return(p); }
obj * arcgen(int type) /* handles circular and (eventually) elliptical arcs */ { static double prevwid = HT10; static double prevht = HT5; static double prevrad = HT2; static int dtox[2][4] = { { 1, -1, -1, 1 }, { 1, 1, -1, -1 } }; static int dtoy[2][4] = { { 1, 1, -1, -1 }, { -1, 1, 1, -1 } }; static int dctrx[2][4] = { { 0, -1, 0, 1 }, { 0, 1, 0, -1 } }; static int dctry[2][4] = { { 1, 0, -1, 0 }, { -1, 0, 1, 0 } }; static int nexthv[2][4] = { { U_DIR, L_DIR, D_DIR, R_DIR }, { D_DIR, R_DIR, U_DIR, L_DIR } }; struct objattr obat; double dx2, dy2, phi, r, d, fromx, fromy, tox, toy; int i, head, to, at, cw; obj *p, *ppos; Attr *ap; obat.a_ht = getfval("arrowht"); obat.a_wid = getfval("arrowwid"); obat.a_rad = getfval("arcrad"); obat.a_layer = (int)getfval("curlayer"); obat.a_flags = EDGED; obat.a_weight = obat.a_lcolor = obat.a_pcolor = obat.a_tcolor = -1; obat.a_dashpat.a = (float *)0; set_text(); fromx = curx; fromy = cury; head = to = at = cw = 0; for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { default: miscattrs(ap, &obat); break; case HEAD: head += ap->a_val.i; break; case CW: cw = 1; break; case FROM: /* start point of arc */ ppos = ap->a_val.o; fromx = Xformx(ppos, 1, ppos->o_x, ppos->o_y); fromy = Xformy(ppos, 0, ppos->o_x, ppos->o_y); break; case TO: /* end point of arc */ ppos = ap->a_val.o; tox = Xformx(ppos, 1, ppos->o_x, ppos->o_y); toy = Xformy(ppos, 0, ppos->o_x, ppos->o_y); to++; break; case AT: /* center of arc */ ppos = ap->a_val.o; curx = Xformx(ppos, 1, ppos->o_x, ppos->o_y); cury = Xformy(ppos, 0, ppos->o_x, ppos->o_y); at = 1; break; case UP: hvmode = U_DIR; break; case DOWN: hvmode = D_DIR; break; case RIGHT: hvmode = R_DIR; break; case LEFT: hvmode = L_DIR; break; case SAME: obat.a_ht = prevht; obat.a_wid = prevwid; obat.a_rad = prevrad; break; } } if (!at && !to) { /* the defaults are mostly OK */ curx = fromx + obat.a_rad * dctrx[cw][hvmode]; cury = fromy + obat.a_rad * dctry[cw][hvmode]; tox = fromx + obat.a_rad * dtox[cw][hvmode]; toy = fromy + obat.a_rad * dtoy[cw][hvmode]; hvmode = nexthv[cw][hvmode]; } else if (to) { /* then compute center */ dx2 = (tox - fromx) / 2; dy2 = (toy - fromy) / 2; phi = atan2(dy2, dx2) + (cw ? -M_PI_2 : M_PI_2); /* If from, to, at (and possibly radius) are all supplied, * the arc is overdetermined. Recompute the radius (as * well as at (i.e., curx and cury)) in that case. */ if (at) { double alpha; obat.a_rad = sqrt((curx - fromx) * (curx - fromx) + (cury - fromy) * (cury - fromy)); alpha = atan2(toy - cury, tox - curx) - atan2(fromy - cury, fromx - curx); if (alpha < 0.) alpha += 2 * M_PI; if ((!cw && alpha > M_PI) || (cw && alpha < M_PI)) phi += M_PI; } else if (obat.a_rad <= 0.0) obat.a_rad = sqrt(dx2*dx2+dy2*dy2); for (r=obat.a_rad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2) ; /* this kludge gets around too-small radii */ obat.a_rad = r; d = sqrt(d); curx = fromx + dx2 + d * cos(phi); cury = fromy + dy2 + d * sin(phi); } else if (at && !to) { /* do we have all the cases??? */ tox = fromx + obat.a_rad * dtox[cw][hvmode]; toy = fromy + obat.a_rad * dtoy[cw][hvmode]; hvmode = nexthv[cw][hvmode]; } p = makenode(type, N_VAL + 10, obat.a_layer); prevrad = p->o_val[N_VAL+0].f = p->o_val[N_VAL+1].f = obat.a_rad; prevwid = p->o_val[N_VAL+8].f = obat.a_wid; prevht = p->o_val[N_VAL+9].f = obat.a_ht; if (cw) { /* interchange roles of from-to and heads */ double temp; temp = fromx; curx = fromx = tox; tox = temp; temp = fromy; cury = fromy = toy; toy = temp; if (head == HEAD1) head = HEAD2; else if (head == HEAD2) head = HEAD1; p->o_attr |= CW_ARC; } else { curx = tox; cury = toy; } p->o_val[N_VAL+2].f = fromx; p->o_val[N_VAL+3].f = fromy; p->o_val[N_VAL+4].f = tox; p->o_val[N_VAL+5].f = toy; if (head) p->o_attr |= head | arrowfill(); primattrs(p, &obat); text_bounds(p); arc_extreme(p); return(p); }
obj *circgen(type) { static float rad[2] = { HT2, WID2 }; static float rad2[2] = { HT2, HT2 }; static float x0, y0, x1, y1, x2, y2; int i, at, t, invis, ddtype, with; float xwith, ywith; float r, r2, ddval; obj *p, *ppos; Attr *ap; at = invis = ddtype = 0; with = xwith = ywith = 0; t = (type == CIRCLE) ? 0 : 1; if (type == CIRCLE) r = r2 = getfval("circlerad"); else if (type == ELLIPSE) { r = getfval("ellipsewid") / 2; r2 = getfval("ellipseht") / 2; } for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; case RADIUS: r = ap->a_val.f; break; case DIAMETER: case WIDTH: r = ap->a_val.f / 2; break; case HEIGHT: r2 = ap->a_val.f / 2; break; case SAME: r = rad[t]; r2 = rad2[t]; break; case WITH: with = ap->a_val.i; break; case AT: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at++; break; case INVIS: invis = INVIS; break; case DOT: case DASH: ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT; if (ap->a_sub == DEFAULT) ddval = getfval("dashwid"); else ddval = ap->a_val.f; break; } } if (type == CIRCLE) r2 = r; /* probably superfluous */ if (with) { switch (with) { case NORTH: ywith = -r2; break; case SOUTH: ywith = r2; break; case EAST: xwith = -r; break; case WEST: xwith = r; break; case NE: xwith = -r * 0.707; ywith = -r2 * 0.707; break; case SE: xwith = -r * 0.707; ywith = r2 * 0.707; break; case NW: xwith = r * 0.707; ywith = -r2 * 0.707; break; case SW: xwith = r * 0.707; ywith = r2 * 0.707; break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; } p = makenode(type, 2); p->o_val[0] = rad[t] = r; p->o_val[1] = rad2[t] = r2; if (r <= 0 || r2 <= 0) { yyerror("%s has invalid radius %g\n", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2); } p->o_attr = invis | ddtype; extreme(curx+r, cury+r2); extreme(curx-r, cury-r2); if (type == CIRCLE) dprintf("C %g %g %g\n", curx, cury, r); if (type == ELLIPSE) dprintf("E %g %g %g %g\n", curx, cury, r, r2); if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; return(p); }
obj *arcgen(type) /* handles circular and (eventually) elliptical arcs */ { static float prevw = HT10; static float prevh = HT5; static float prevrad = HT2; static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 }; static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 }; static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 }; static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 }; static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR, R_DIR, U_DIR, L_DIR }; float dx2, dy2, ht, phi, r, d, ddval; int i, head, to, at, cw, invis, ddtype; obj *p, *ppos; float fromx, fromy, tox, toy; Attr *ap; prevrad = getfval("arcrad"); prevh = getfval("arrowht"); prevw = getfval("arrowwid"); fromx = curx; fromy = cury; head = to = at = cw = invis = ddtype = 0; for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; case HEAD: head += ap->a_val.i; break; case INVIS: invis = INVIS; break; case DOT: case DASH: ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT; if (ap->a_sub == DEFAULT) ddval = getfval("dashwid"); else ddval = ap->a_val.f; break; case HEIGHT: /* length of arrowhead */ prevh = ap->a_val.f; break; case WIDTH: /* width of arrowhead */ prevw = ap->a_val.f; break; case RADIUS: prevrad = ap->a_val.f; break; case DIAMETER: prevrad = ap->a_val.f / 2; break; case CW: cw = 1; break; case FROM: /* start point of arc */ ppos = ap->a_val.o; fromx = ppos->o_x; fromy = ppos->o_y; break; case TO: /* end point of arc */ ppos = ap->a_val.o; tox = ppos->o_x; toy = ppos->o_y; to++; break; case AT: /* center of arc */ ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at = 1; break; case UP: hvmode = U_DIR; break; case DOWN: hvmode = D_DIR; break; case RIGHT: hvmode = R_DIR; break; case LEFT: hvmode = L_DIR; break; } } if (!at && !to) { /* the defaults are mostly OK */ curx = fromx + prevrad * dctrx[cw][hvmode]; cury = fromy + prevrad * dctry[cw][hvmode]; tox = fromx + prevrad * dtox[cw][hvmode]; toy = fromy + prevrad * dtoy[cw][hvmode]; hvmode = nexthv[cw][hvmode]; } else if (!at) { dx2 = (tox - fromx) / 2; dy2 = (toy - fromy) / 2; phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2); if (prevrad <= 0.0) prevrad = dx2*dx2+dy2*dy2; for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2) ; /* this kludge gets around too-small radii */ prevrad = r; ht = sqrt(d); curx = fromx + dx2 + ht * cos(phi); cury = fromy + dy2 + ht * sin(phi); dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n", dx2, dy2, phi, r, ht); } else if (at && !to) { /* do we have all the cases??? */ tox = fromx + prevrad * dtox[cw][hvmode]; toy = fromy + prevrad * dtoy[cw][hvmode]; hvmode = nexthv[cw][hvmode]; } if (cw) { /* interchange roles of from-to and heads */ float temp; temp = fromx; fromx = tox; tox = temp; temp = fromy; fromy = toy; toy = temp; if (head == HEAD1) head = HEAD2; else if (head == HEAD2) head = HEAD1; } p = makenode(type, 7); arc_extreme(fromx, fromy, tox, toy, curx, cury); p->o_val[0] = fromx; p->o_val[1] = fromy; p->o_val[2] = tox; p->o_val[3] = toy; if (cw) { curx = fromx; cury = fromy; } else { curx = tox; cury = toy; } p->o_val[4] = prevw; p->o_val[5] = prevh; p->o_val[6] = prevrad; p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype; if (head) p->o_nhead = getfval("arrowhead"); dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n", prevrad, p->o_x, p->o_y, p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]); return(p); }
obj *textgen(void) { int i, sub, nstr, at, with, hset, invis; double xwith, ywith, h, w, x0, y0, x1, y1; obj *p, *ppos; Attr *ap; at = with = nstr = hset = invis = 0; h = getfval("textht"); w = getfval("textwid"); for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case HEIGHT: h = ap->a_val.f; hset++; break; case WIDTH: w = ap->a_val.f; break; case WITH: with = ap->a_val.i; break; case INVIS: invis = INVIS; break; case AT: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at++; break; case TEXTATTR: sub = ap->a_sub; if (ap->a_val.p == NULL) /* an isolated modifier */ text[ntext-1].t_type = sub; else { savetext(sub, ap->a_val.p); nstr++; } break; } } if (hset == 0) /* no explicit ht cmd */ h *= nstr; if (with) { xwith = ywith = 0.0; switch (with) { case NORTH: ywith = -h / 2; break; case SOUTH: ywith = h / 2; break; case EAST: xwith = -w / 2; break; case WEST: xwith = w / 2; break; case NE: xwith = -w / 2; ywith = -h / 2; break; case SE: xwith = -w / 2; ywith = h / 2; break; case NW: xwith = w / 2; ywith = -h / 2; break; case SW: xwith = w / 2; ywith = h / 2; break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += w / 2; else if (isleft(hvmode)) curx -= w / 2; else if (isup(hvmode)) cury += h / 2; else cury -= h / 2; } x0 = curx - w / 2; y0 = cury - h / 2; x1 = curx + w / 2; y1 = cury + h / 2; extreme(x0, y0); extreme(x1, y1); dprintf("Text h %g w %g at %g,%g\n", h, w, curx, cury); p = makenode(TEXT, 2); p->o_attr = invis; p->o_val[0] = w; p->o_val[1] = h; if (isright(hvmode)) curx = x1; else if (isleft(hvmode)) curx = x0; else if (isup(hvmode)) cury = y1; else cury = y0; return(p); }
int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */ { char *fmt; char *p, *t; const char *os; Cell *x; int flag = 0, n; int fmtwd; /* format width */ int fmtsz = recsize; char *buf = *pbuf; int bufsize = *pbufsize; os = s; p = buf; if ((fmt = (char *) malloc(fmtsz)) == NULL) FATAL("out of memory in format()"); while (*s) { adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1"); if (*s != '%') { *p++ = *s++; continue; } if (*(s+1) == '%') { *p++ = '%'; s += 2; continue; } /* have to be real careful in case this is a huge number, eg, %100000d */ fmtwd = atoi(s+1); if (fmtwd < 0) fmtwd = -fmtwd; adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2"); for (t = fmt; (*t++ = *s) != '\0'; s++) { if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3")) FATAL("format item %.30s... ran format() out of memory", os); if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L') break; /* the ansi panoply */ if (*s == '*') { x = execute(a); a = a->nnext; sprintf(t-1, "%d", fmtwd=(int) getfval(x)); if (fmtwd < 0) fmtwd = -fmtwd; adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); t = fmt + strlen(fmt); tempfree(x); } } *t = '\0'; if (fmtwd < 0) fmtwd = -fmtwd; adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4"); switch (*s) { case 'f': case 'e': case 'g': case 'E': case 'G': flag = 'f'; break; case 'd': case 'i': flag = 'd'; if(*(s-1) == 'l') break; *(t-1) = 'l'; *t = 'd'; *++t = '\0'; break; case 'o': case 'x': case 'X': case 'u': flag = *(s-1) == 'l' ? 'd' : 'u'; break; case 's': flag = 's'; break; case 'c': flag = 'c'; break; default: WARNING("weird printf conversion %s", fmt); flag = '?'; break; } if (a == NULL) FATAL("not enough args in printf(%s)", os); x = execute(a); a = a->nnext; n = MAXNUMSIZE; if (fmtwd > n) n = fmtwd; adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5"); switch (flag) { case '?': sprintf(p, "%s", fmt); /* unknown, so dump it too */ t = getsval(x); n = strlen(t); if (fmtwd > n) n = fmtwd; adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6"); p += strlen(p); sprintf(p, "%s", t); break; case 'f': sprintf(p, fmt, getfval(x)); break; case 'd': sprintf(p, fmt, (long) getfval(x)); break; case 'u': sprintf(p, fmt, (int) getfval(x)); break; case 's': t = getsval(x); n = strlen(t); if (fmtwd > n) n = fmtwd; if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7")) FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t); sprintf(p, fmt, t); break; case 'c': if (isnum(x)) { if (getfval(x)) sprintf(p, fmt, (int) getfval(x)); else { *p++ = '\0'; /* explicit null byte */ *p = '\0'; /* next output will start here */ } } else sprintf(p, fmt, getsval(x)[0]); break; default: FATAL("can't happen: bad conversion %c in format()", flag); } tempfree(x); p += strlen(p); s++; } *p = '\0'; free(fmt); for ( ; a; a = a->nnext) /* evaluate any remaining args */ execute(a); *pbuf = buf; *pbufsize = bufsize; return p - buf; }
Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ { Cell *x, *y; Awkfloat u; int t; Awkfloat tmp; char *p, *buf; Node *nextarg; FILE *fp; void flush_all(void); t = ptoi(a[0]); x = execute(a[1]); nextarg = a[1]->nnext; switch (t) { case FLENGTH: if (isarr(x)) u = ((Array *) x->sval)->nelem; /* GROT. should be function*/ else u = strlen(getsval(x)); break; case FLOG: u = errcheck(log(getfval(x)), "log"); break; case FINT: modf(getfval(x), &u); break; case FEXP: u = errcheck(exp(getfval(x)), "exp"); break; case FSQRT: u = errcheck(sqrt(getfval(x)), "sqrt"); break; case FSIN: u = sin(getfval(x)); break; case FCOS: u = cos(getfval(x)); break; case FATAN: if (nextarg == 0) { WARNING("atan2 requires two arguments; returning 1.0"); u = 1.0; } else { y = execute(a[1]->nnext); u = atan2(getfval(x), getfval(y)); tempfree(y); nextarg = nextarg->nnext; } break; case FSYSTEM: fflush(stdout); /* in case something is buffered already */ u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ break; case FRAND: /* in principle, rand() returns something in 0..RAND_MAX */ u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; break; case FSRAND: if (isrec(x)) /* no argument provided */ u = time((time_t *)0); else u = getfval(x); tmp = u; srand((unsigned int) u); u = srand_seed; srand_seed = tmp; break; case FTOUPPER: case FTOLOWER: buf = tostring(getsval(x)); if (t == FTOUPPER) { for (p = buf; *p; p++) if (islower((uschar) *p)) *p = toupper((uschar)*p); } else { for (p = buf; *p; p++) if (isupper((uschar) *p)) *p = tolower((uschar)*p); } tempfree(x); x = gettemp(); setsval(x, buf); free(buf); return x; case FFLUSH: if (isrec(x) || strlen(getsval(x)) == 0) { flush_all(); /* fflush() or fflush("") -> all */ u = 0; } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL) u = EOF; else u = fflush(fp); break; default: /* can't happen */ FATAL("illegal function type %d", t); break; } tempfree(x); x = gettemp(); setfval(x, u); if (nextarg != 0) { WARNING("warning: function has too many arguments"); for ( ; nextarg; nextarg = nextarg->nnext) execute(nextarg); } return(x); }
obj* movegen(void) { static double prevdx, prevdy; int i, some; double defx, defy, dx, dy; obj *p; obj *ppos; static int xtab[] = { 1, 0, -1, 0 }; /* R=0, U=1, L=2, D=3 */ static int ytab[] = { 0, 1, 0, -1 }; Attr *ap; defx = getfval("movewid"); defy = getfval("moveht"); dx = dy = some = 0; for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; case SAME: dx = prevdx; dy = prevdy; some++; break; case LEFT: dx -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; some++; hvmode = L_DIR; break; case RIGHT: dx += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f; some++; hvmode = R_DIR; break; case UP: dy += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; some++; hvmode = U_DIR; break; case DOWN: dy -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f; some++; hvmode = D_DIR; break; case TO: ppos = ap->a_val.o; dx = ppos->o_x - curx; dy = ppos->o_y - cury; some++; break; case BY: ppos = ap->a_val.o; dx = ppos->o_x; dy = ppos->o_y; some++; break; case FROM: case AT: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; break; } } if (some) { defx = dx; defy = dy; } else { defx *= xtab[hvmode]; defy *= ytab[hvmode]; } prevdx = defx; prevdy = defy; extreme(curx, cury); curx += defx; cury += defy; extreme(curx, cury); p = makenode(MOVE, 0); dprintf("M %g %g\n", curx, cury); return(p); }
Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ { /* this is subtle; don't muck with it. */ Cell *x, *y; Awkfloat xf, yf; double v; y = execute(a[1]); x = execute(a[0]); if (n == ASSIGN) { /* ordinary assignment */ if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */ ; /* leave alone unless it's a field */ else if ((y->tval & (STR|NUM)) == (STR|NUM)) { setsval(x, getsval(y)); x->fval = getfval(y); x->tval |= NUM; } else if (y->tval & STR) setsval(x, getsval(y)); else if (y->tval & NUM) setfval(x, getfval(y)); else funnyvar(y, "read value of"); tempfree(y); return(x); } xf = getfval(x); yf = getfval(y); switch (n) { case ADDEQ: xf += yf; break; case SUBEQ: xf -= yf; break; case MULTEQ: xf *= yf; break; case DIVEQ: if (yf == 0) ERROR "division by zero in /=" FATAL; xf /= yf; break; case MODEQ: if (yf == 0) ERROR "division by zero in %%=" FATAL; modf(xf/yf, &v); xf = xf - yf * v; break; case POWEQ: if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */ xf = ipow(xf, (int) yf); else xf = errcheck(pow(xf, yf), "pow"); break; default: ERROR "illegal assignment operator %d", n FATAL; break; } tempfree(y); setfval(x, xf); return(x); }
Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ { register Cell *x, *y; Awkfloat u; register int t; uchar *p, buf[RECSIZE]; Node *nextarg; FILE *fp; t = (int) a[0]; x = execute(a[1]); nextarg = a[1]->nnext; switch (t) { case FLENGTH: u = strlen(getsval(x)); break; case FLOG: u = errcheck(log(getfval(x)), "log"); break; case FINT: modf(getfval(x), &u); break; case FEXP: u = errcheck(exp(getfval(x)), "exp"); break; case FSQRT: u = errcheck(sqrt(getfval(x)), "sqrt"); break; case FSIN: u = sin(getfval(x)); break; case FCOS: u = cos(getfval(x)); break; case FATAN: if (nextarg == 0) { ERROR "atan2 requires two arguments; returning 1.0" WARNING; u = 1.0; } else { y = execute(a[1]->nnext); u = atan2(getfval(x), getfval(y)); tempfree(y); nextarg = nextarg->nnext; } break; case FSYSTEM: fflush(stdout); /* in case something is buffered already */ u = (Awkfloat) system((char *)getsval(x)) / 256; /* 256 is unix-dep */ break; case FRAND: /* in principle, rand() returns something in 0..RAND_MAX */ u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; break; case FSRAND: if (x->tval & REC) /* no argument provided */ u = time((long *)0); else u = getfval(x); srand((int) u); u = (int) u; break; case FTOUPPER: case FTOLOWER: strcpy(buf, getsval(x)); if (t == FTOUPPER) { for (p = buf; *p; p++) if (islower(*p)) *p = toupper(*p); } else { for (p = buf; *p; p++) if (isupper(*p)) *p = tolower(*p); } tempfree(x); x = gettemp(); setsval(x, buf); return x; case FFLUSH: if ((fp = openfile(GT, getsval(x))) == NULL) u = EOF; else u = fflush(fp); break; default: /* can't happen */ ERROR "illegal function type %d", t FATAL; break; } tempfree(x); x = gettemp(); setfval(x, u); if (nextarg != 0) { ERROR "warning: function has too many arguments" WARNING; for ( ; nextarg; nextarg = nextarg->nnext) execute(nextarg); } return(x); }
obj * circgen(int type) { static double rad[2] = { HT2, WID2 }; static double rad2[2] = { HT2, HT2 }; struct objattr obat; double xwith, ywith, r, r2; int i, at, t, with; obj *p, *ppos; Attr *ap; obat.a_layer = (int)getfval("curlayer"); obat.a_flags = EDGED; obat.a_weight = obat.a_lcolor = obat.a_pcolor = obat.a_tcolor = -1; obat.a_dashpat.a = (float *)0; at = with = xwith = ywith = 0; if ((t = (type == CIRCLE) ? 0 : 1)) { r = getfval("ellipsewid") / 2; r2 = getfval("ellipseht") / 2; } else r = r2 = getfval("circlerad"); set_text(); for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { default: miscattrs(ap, &obat); break; case RADIUS: r = ap->a_val.f; break; case DIAMETER: case WIDTH: r = ap->a_val.f / 2; break; case HEIGHT: r2 = ap->a_val.f / 2; break; case SAME: r = rad[t]; r2 = rad2[t]; break; case WITH: with = ap->a_val.i; break; case AT: ppos = ap->a_val.o; curx = Xformx(ppos, 1, ppos->o_x, ppos->o_y); cury = Xformy(ppos, 0, ppos->o_x, ppos->o_y); at++; break; } } if (type == CIRCLE) r2 = r; /* probably superfluous */ if (with) { if (pic_compat) /* map NE to 2nd, etc. */ with = with == NE ? 2 : with == NW ? 4 : with == SW ? 6 : with == SE ? 8 : with; switch (with) { case NORTH: ywith = -r2; break; case SOUTH: ywith = r2; break; case EAST: xwith = -r; break; case WEST: xwith = r; break; case NE: xwith = -r; ywith = -r2; break; case SE: xwith = -r; ywith = r2; break; case NW: xwith = r; ywith = -r2; break; case SW: xwith = r; ywith = r2; break; case CENTER: case START: case END: break; default: xwith = -r * xdelta[with % 8]; ywith = -r2 * ydelta[with % 8]; if (with % 2 == 0) { xwith *= M_SQRT1_2; ywith *= M_SQRT1_2; } break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; } if (r <= 0 || r2 <= 0) yyerror("%s has invalid radius %g", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2); p = makenode(type, N_VAL, obat.a_layer); p->o_wid = 2 * (rad[t] = r); p->o_ht = 2 * (rad2[t] = r2); primattrs(p, &obat); text_bounds(p); if (isright(hvmode)) curx += r; else if (isleft(hvmode)) curx -= r; else if (isup(hvmode)) cury += r2; else cury -= r2; r += p->o_weight/2; r2 += p->o_weight/2; track_bounds (p->o_x - r, p->o_y - r2, p->o_x + r, p->o_y + r2); return(p); }
obj *boxgen(void) { static double prevh = HT; static double prevw = WID; /* golden mean, sort of */ int i, at, battr, with; double ddval, fillval, xwith, ywith; double h, w, x0, y0, x1, y1; obj *p, *ppos; Attr *ap; h = getfval("boxht"); w = getfval("boxwid"); at = battr = with = 0; ddval = fillval = xwith = ywith = 0; for (i = 0; i < nattr; i++) { ap = &attr[i]; switch (ap->a_type) { case HEIGHT: h = ap->a_val.f; break; case WIDTH: w = ap->a_val.f; break; case SAME: h = prevh; w = prevw; break; case WITH: with = ap->a_val.i; /* corner */ break; case AT: ppos = ap->a_val.o; curx = ppos->o_x; cury = ppos->o_y; at++; break; case INVIS: battr |= INVIS; break; case NOEDGE: battr |= NOEDGEBIT; break; case DOT: case DASH: battr |= ap->a_type==DOT ? DOTBIT : DASHBIT; if (ap->a_sub == DEFAULT) ddval = getfval("dashwid"); else ddval = ap->a_val.f; break; case FILL: battr |= FILLBIT; if (ap->a_sub == DEFAULT) fillval = getfval("fillval"); else fillval = ap->a_val.f; break; case TEXTATTR: savetext(ap->a_sub, ap->a_val.p); break; } } if (with) { switch (with) { case NORTH: ywith = -h / 2; break; case SOUTH: ywith = h / 2; break; case EAST: xwith = -w / 2; break; case WEST: xwith = w / 2; break; case NE: xwith = -w / 2; ywith = -h / 2; break; case SE: xwith = -w / 2; ywith = h / 2; break; case NW: xwith = w / 2; ywith = -h / 2; break; case SW: xwith = w / 2; ywith = h / 2; break; } curx += xwith; cury += ywith; } if (!at) { if (isright(hvmode)) curx += w / 2; else if (isleft(hvmode)) curx -= w / 2; else if (isup(hvmode)) cury += h / 2; else cury -= h / 2; } x0 = curx - w / 2; y0 = cury - h / 2; x1 = curx + w / 2; y1 = cury + h / 2; extreme(x0, y0); extreme(x1, y1); p = makenode(BOX, 2); p->o_val[0] = w; p->o_val[1] = h; p->o_attr = battr; p->o_ddval = ddval; p->o_fillval = fillval; dprintf("B %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w); if (isright(hvmode)) curx = x1; else if (isleft(hvmode)) curx = x0; else if (isup(hvmode)) cury = y1; else cury = y0; prevh = h; prevw = w; return(p); }
int format(char *buf, int bufsize, char *s, Node *a) /* printf-like conversions */ { char fmt[RECSIZE]; char *p, *t, *os; Cell *x; int flag = 0, n; os = s; p = buf; while (*s) { if (p - buf >= bufsize) return -1; if (*s != '%') { *p++ = *s++; continue; } if (*(s+1) == '%') { *p++ = '%'; s += 2; continue; } for (t=fmt; (*t++ = *s) != '\0'; s++) { if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L') break; /* the ansi panoply */ if (*s == '*') { x = execute(a); a = a->nnext; sprintf((char *)t-1, "%d", (int) getfval(x)); t = fmt + strlen(fmt); tempfree(x); } } *t = '\0'; if (t >= fmt + sizeof(fmt)) ERROR "format item %.30s... too long", os FATAL; switch (*s) { case 'f': case 'e': case 'g': case 'E': case 'G': flag = 1; break; case 'd': case 'i': flag = 2; if(*(s-1) == 'l') break; *(t-1) = 'l'; *t = 'd'; *++t = '\0'; break; case 'o': case 'x': case 'X': case 'u': flag = *(s-1) == 'l' ? 2 : 3; break; case 's': flag = 4; break; case 'c': flag = 5; break; default: ERROR "weird printf conversion %s", fmt WARNING; flag = 0; break; } if (a == NULL) ERROR "not enough args in printf(%s)", os FATAL; x = execute(a); a = a->nnext; switch (flag) { case 0: sprintf((char *)p, "%s", fmt); /* unknown, so dump it too */ p += strlen(p); sprintf((char *)p, "%s", getsval(x)); break; case 1: sprintf((char *)p, (char *)fmt, getfval(x)); break; case 2: sprintf((char *)p, (char *)fmt, (long) getfval(x)); break; case 3: sprintf((char *)p, (char *)fmt, (int) getfval(x)); break; case 4: t = getsval(x); n = strlen(t); if (n >= bufsize) ERROR "huge string (%d chars) in printf %.30s...", n, t FATAL; sprintf((char *)p, (char *)fmt, t); break; case 5: isnum(x) ? sprintf((char *)p, (char *)fmt, (int) getfval(x)) : sprintf((char *)p, (char *)fmt, getsval(x)[0]); break; } tempfree(x); p += strlen(p); s++; } *p = '\0'; for ( ; a; a = a->nnext) /* evaluate any remaining args */ execute(a); return 0; }