This commit is contained in:
rsc 2006-04-14 00:04:03 +00:00
parent 434d1b41b6
commit b6d98463b4
22 changed files with 5419 additions and 0 deletions

24
src/cmd/tpic/Changes Normal file
View file

@ -0,0 +1,24 @@
30 Nov 1988 ehg
Copied from /n/bowell/usr/src/cmd/pic.
16 Jan 1989 ehg
Updates from /n/coma/usr/bwk/pic.
Brian picked up printlf() and I moved space() in openpl() in pixel and 4014,
so no changes were needed in the source imported from bowell and bwk.
bwk's print.c calls arc(), which is translated in pl$DEV.c into a call to
devarc() whose code is in lib$DEV/arc.c.
I didn't understand howard's dotline change and it conflicted
with using pure bwk code, so I commented it out in pltex.c.
8 Sep 1989 hwt
Updates from /n/bowell/usr/src/cmd/pic
Some changes in linegen.c (bigger buffers), misc.c, picl.l, picy.y, symtab.c
I removed the \t-><tab> transformation in picl.l (bwk agreed it was bogus).
Put the dotline change back in (to get smaller output files, and avoid
problems where lines were bunching together).
11 Sep 1989 hwt
Went back to troff dotline (the postscript one doesn't act the same
as troff when scale!=1).
Changed default pen size from 8 to 9 (to give same thickness lines
as default pic), and made dots change size with pen size.

214
src/cmd/tpic/arcgen.c Normal file
View file

@ -0,0 +1,214 @@
#include <stdio.h>
#include <math.h>
#include "pic.h"
#include "y.tab.h"
obj*
arcgen(int type) /* handles circular and (eventually) elliptical arcs */
{
static double prevw = HT10;
static double prevh = 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 };
double dx2, dy2, ht, phi, r, d;
int i, head, to, at, cw, invis, ddtype;
obj *p, *ppos;
double fromx, fromy, tox, toy;
Attr *ap;
tox = 0;
toy = 0;
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 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 */
double 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);
}
/***************************************************************************
bounding box of a circular arc Eric Grosse 24 May 84
Conceptually, this routine generates a list consisting of the start,
end, and whichever north, east, south, and west points lie on the arc.
The bounding box is then the range of this list.
list = {start,end}
j = quadrant(start)
k = quadrant(end)
if( j==k && long way 'round ) append north,west,south,east
else
while( j != k )
append center+radius*[j-th of north,west,south,east unit vectors]
j += 1 (mod 4)
return( bounding box of list )
The following code implements this, with simple optimizations.
***********************************************************************/
void
arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc)
{
/* assumes center isn't too far out */
double r, xmin, ymin, xmax, ymax;
int j, k;
x0 -= xc; y0 -= yc; /* move to center */
x1 -= xc; y1 -= yc;
xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
r = sqrt(x0*x0 + y0*y0);
if (r > 0.0) {
j = quadrant(x0,y0);
k = quadrant(x1,y1);
if (j == k && y1*x0 < x1*y0) {
/* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
if( xmax < r) xmax = r; if( ymax < r) ymax = r;
} else {
while (j != k) {
switch (j) {
case 1: if( ymax < r) ymax = r; break; /* north */
case 2: if( xmin > -r) xmin = -r; break; /* west */
case 3: if( ymin > -r) ymin = -r; break; /* south */
case 4: if( xmax < r) xmax = r; break; /* east */
}
j = j%4 + 1;
}
}
}
xmin += xc; ymin += yc;
xmax += xc; ymax += yc;
extreme(xmin, ymin);
extreme(xmax, ymax);
}
int
quadrant(double x, double y)
{
if ( x>=0.0 && y> 0.0) return(1);
else if( x< 0.0 && y>=0.0) return(2);
else if( x<=0.0 && y< 0.0) return(3);
else if( x> 0.0 && y<=0.0) return(4);
else return 0; /* shut up lint */
}

223
src/cmd/tpic/blockgen.c Normal file
View file

@ -0,0 +1,223 @@
#include <stdio.h>
#include "pic.h"
#include "y.tab.h"
#define NBRACK 20 /* depth of [...] */
#define NBRACE 20 /* depth of {...} */
struct pushstack stack[NBRACK];
int nstack = 0;
struct pushstack bracestack[NBRACE];
int nbstack = 0;
obj*
leftthing(int c) /* called for {... or [... */
/* really ought to be separate functions */
{
obj *p;
if (c == '[') {
if (nstack >= NBRACK)
ERROR "[...] nested too deep" FATAL;
stack[nstack].p_x = curx;
stack[nstack].p_y = cury;
stack[nstack].p_hvmode = hvmode;
curx = cury = 0;
stack[nstack].p_xmin = xmin;
stack[nstack].p_xmax = xmax;
stack[nstack].p_ymin = ymin;
stack[nstack].p_ymax = ymax;
nstack++;
xmin = ymin = 30000;
xmax = ymax = -30000;
p = makenode(BLOCK, 7);
p->o_val[4] = nobj; /* 1st item within [...] */
if (p->o_nobj != nobj-1)
fprintf(stderr, "nobjs wrong%d %d\n", p->o_nobj, nobj);
} else {
if (nbstack >= NBRACK)
ERROR "{...} nested too deep" FATAL;
bracestack[nbstack].p_x = curx;
bracestack[nbstack].p_y = cury;
bracestack[nbstack].p_hvmode = hvmode;
nbstack++;
p = NULL;
}
return(p);
}
obj*
rightthing(obj *p, int c) /* called for ... ] or ... } */
{
obj *q;
if (c == '}') {
nbstack--;
curx = bracestack[nbstack].p_x;
cury = bracestack[nbstack].p_y;
hvmode = bracestack[nbstack].p_hvmode;
q = makenode(MOVE, 0);
dprintf("M %g %g\n", curx, cury);
} else {
nstack--;
curx = stack[nstack].p_x;
cury = stack[nstack].p_y;
hvmode = stack[nstack].p_hvmode;
q = makenode(BLOCKEND, 7);
q->o_val[4] = p->o_nobj + 1; /* back pointer */
p->o_val[5] = q->o_nobj - 1; /* forward pointer */
p->o_val[0] = xmin; p->o_val[1] = ymin;
p->o_val[2] = xmax; p->o_val[3] = ymax;
p->o_symtab = q->o_symtab = stack[nstack+1].p_symtab;
xmin = stack[nstack].p_xmin;
ymin = stack[nstack].p_ymin;
xmax = stack[nstack].p_xmax;
ymax = stack[nstack].p_ymax;
}
return(q);
}
obj*
blockgen(obj *p, obj *q) /* handles [...] */
{
int i, invis, at, with;
double ddval, h, w, xwith, ywith;
double x0, y0, x1, y1, cx, cy;
obj *ppos;
Attr *ap;
invis = at = 0;
with = xwith = ywith = 0;
ddval = 0;
w = p->o_val[2] - p->o_val[0];
h = p->o_val[3] - p->o_val[1];
cx = (p->o_val[2] + p->o_val[0]) / 2; /* geom ctr of [] wrt local orogin */
cy = (p->o_val[3] + p->o_val[1]) / 2;
dprintf("cx,cy=%g,%g\n", cx, cy);
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 WITH:
with = ap->a_val.i; /* corner */
break;
case PLACE: /* actually with position ... */
ppos = ap->a_val.o;
xwith = cx - ppos->o_x;
ywith = cy - ppos->o_y;
with = PLACE;
break;
case AT:
case FROM:
ppos = ap->a_val.o;
curx = ppos->o_x;
cury = ppos->o_y;
at++;
break;
case INVIS:
invis = INVIS;
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->o_x = curx;
p->o_y = cury;
p->o_nt1 = ntext1;
p->o_nt2 = ntext;
ntext1 = ntext;
p->o_val[0] = w;
p->o_val[1] = h;
p->o_val[2] = cx;
p->o_val[3] = cy;
p->o_val[5] = q->o_nobj - 1; /* last item in [...] */
p->o_ddval = ddval;
p->o_attr = invis;
dprintf("[] %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;
for (i = 0; i <= 5; i++)
q->o_val[i] = p->o_val[i];
stack[nstack+1].p_symtab = NULL; /* so won't be found again */
blockadj(p); /* fix up coords for enclosed blocks */
return(p);
}
void
blockadj(obj *p) /* adjust coords in block starting at p */
{
double dx, dy;
int n, lev;
dx = p->o_x - p->o_val[2];
dy = p->o_y - p->o_val[3];
n = p->o_nobj + 1;
dprintf("into blockadj: dx,dy=%g,%g\n", dx, dy);
for (lev = 1; lev > 0; n++) {
p = objlist[n];
if (p->o_type == BLOCK)
lev++;
else if (p->o_type == BLOCKEND)
lev--;
dprintf("blockadj: type=%d o_x,y=%g,%g;", p->o_type, p->o_x, p->o_y);
p->o_x += dx;
p->o_y += dy;
dprintf(" becomes %g,%g\n", p->o_x, p->o_y);
switch (p->o_type) { /* other absolute coords */
case LINE:
case ARROW:
case SPLINE:
p->o_val[0] += dx;
p->o_val[1] += dy;
break;
case ARC:
p->o_val[0] += dx;
p->o_val[1] += dy;
p->o_val[2] += dx;
p->o_val[3] += dy;
break;
}
}
}

113
src/cmd/tpic/boxgen.c Normal file
View file

@ -0,0 +1,113 @@
#include <stdio.h>
#include "pic.h"
#include "y.tab.h"
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 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);
}

127
src/cmd/tpic/circgen.c Normal file
View file

@ -0,0 +1,127 @@
#include <stdio.h>
#include "pic.h"
#include "y.tab.h"
obj*
circgen(int type)
{
static double rad[2] = { HT2, WID2 };
static double rad2[2] = { HT2, HT2 };
int i, at, t, with, battr;
double xwith, ywith;
double r, r2, ddval, fillval;
obj *p, *ppos;
Attr *ap;
battr = at = 0;
with = xwith = ywith = fillval = 0;
t = (type == CIRCLE) ? 0 : 1;
r = 0;
r2 = 0;
ddval = 0;
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:
battr |= INVIS;
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;
}
}
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) {
ERROR "%s has invalid radius %g\n", (type==CIRCLE) ? "circle" : "ellipse", r<r2 ? r : r2 WARNING;
}
p->o_attr = battr;
p->o_ddval = ddval;
p->o_fillval = fillval;
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);
}

94
src/cmd/tpic/for.c Normal file
View file

@ -0,0 +1,94 @@
#include <stdio.h>
#include "pic.h"
#include "y.tab.h"
#define SLOP 1.001
typedef struct {
char *var; /* index variable */
double to; /* limit */
double by;
int op; /* operator */
char *str; /* string to push back */
} For;
For forstk[10]; /* stack of for loops */
For *forp = forstk; /* pointer to current top */
void
forloop(char *var, double from, double to, int op, double by, char *str) /* set up a for loop */
{
dprintf("# for %s from %g to %g by %c %g \n",
var, from, to, op, by);
if (++forp >= forstk+10)
ERROR "for loop nested too deep" FATAL;
forp->var = var;
forp->to = to;
forp->op = op;
forp->by = by;
forp->str = str;
setfval(var, from);
nextfor();
unput('\n');
}
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
endfor(void) /* end one iteration of for loop */
{
struct symtab *p = lookup(forp->var);
switch (forp->op) {
case '+':
case ' ':
p->s_val.f += forp->by;
break;
case '-':
p->s_val.f -= forp->by;
break;
case '*':
p->s_val.f *= forp->by;
break;
case '/':
p->s_val.f /= forp->by;
break;
}
nextfor();
}
char*
ifstat(double expr, char *thenpart, char *elsepart)
{
dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : "");
if (expr) {
unput('\n');
pushsrc(Free, thenpart);
pushsrc(String, thenpart);
unput('\n');
if (elsepart)
free(elsepart);
return thenpart; /* to be freed later */
} else {
free(thenpart);
if (elsepart) {
unput('\n');
pushsrc(Free, elsepart);
pushsrc(String, elsepart);
unput('\n');
}
return elsepart;
}
}

608
src/cmd/tpic/input.c Normal file
View file

@ -0,0 +1,608 @@
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "pic.h"
#include "y.tab.h"
Infile infile[10];
Infile *curfile = infile;
#define MAXSRC 50
Src src[MAXSRC]; /* input source stack */
Src *srcp = src;
void
pushsrc(int type, char *ptr) /* new input source */
{
if (++srcp >= src + MAXSRC)
ERROR "inputs nested too deep" FATAL;
srcp->type = type;
srcp->sp = ptr;
if (dbg > 1) {
printf("\n%3d ", srcp - src);
switch (srcp->type) {
case File:
printf("push file %s\n", ((Infile *)ptr)->fname);
break;
case Macro:
printf("push macro <%s>\n", ptr);
break;
case Char:
printf("push char <%c>\n", *ptr);
break;
case Thru:
printf("push thru\n");
break;
case String:
printf("push string <%s>\n", ptr);
break;
case Free:
printf("push free <%s>\n", ptr);
break;
default:
ERROR "pushed bad type %d", srcp->type FATAL;
}
}
}
void
popsrc(void) /* restore an old one */
{
if (srcp <= src)
ERROR "too many inputs popped" FATAL;
if (dbg > 1) {
printf("%3d ", srcp - src);
switch (srcp->type) {
case File:
printf("pop file\n");
break;
case Macro:
printf("pop macro\n");
break;
case Char:
printf("pop char <%c>\n", *srcp->sp);
break;
case Thru:
printf("pop thru\n");
break;
case String:
printf("pop string\n");
break;
case Free:
printf("pop free\n");
break;
default:
ERROR "pop weird input %d", srcp->type FATAL;
}
}
srcp--;
}
void
definition(char *s) /* collect definition for s and install */
/* definitions picked up lexically */
{
char *p;
struct symtab *stp;
p = delimstr("definition");
stp = lookup(s);
if (stp != NULL) { /* it's there before */
if (stp->s_type != DEFNAME) {
ERROR "%s used as variable and definition", s WARNING;
return;
}
free(stp->s_val.p);
stp->s_val.p = p;
} else {
YYSTYPE u;
u.p = p;
makevar(tostring(s), DEFNAME, u);
}
dprintf("installing %s as `%s'\n", s, p);
}
char*
delimstr(char *s) /* get body of X ... X */
/* message if too big */
{
int c, delim, rdelim, n, deep;
static char *buf = NULL;
static int nbuf = 0;
char *p;
if (buf == NULL)
buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
;
rdelim = baldelim(delim, "{}"); /* could be "(){}[]`'" */
deep = 1;
for (p = buf; ; ) {
c = input();
if (c == rdelim)
if (--deep == 0)
break;
if (c == delim)
deep++;
if (p >= buf + nbuf) {
n = p - buf;
buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
p = buf + n;
}
if (c == EOF)
ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
*p++ = c;
}
*p = '\0';
dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
return tostring(buf);
}
int
baldelim(int c, char *s) /* replace c by balancing entry in s */
{
for ( ; *s; s += 2)
if (*s == c)
return s[1];
return c;
}
void
undefine(char *s) /* undefine macro */
{
while (*s != ' ' && *s != '\t') /* skip "undef..." */
s++;
while (*s == ' ' || *s == '\t')
s++;
freedef(s);
}
Arg args[10]; /* argument frames */
Arg *argfp = args; /* frame pointer */
int argcnt; /* number of arguments seen so far */
void
dodef(struct symtab *stp) /* collect args and switch input to defn */
{
int i, len;
char *p;
Arg *ap;
ap = argfp+1;
if (ap >= args+10)
ERROR "arguments too deep" FATAL;
argcnt = 0;
if (input() != '(')
ERROR "disaster in dodef" FATAL;
if (ap->argval == 0)
ap->argval = malloc(1000);
for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
ap->argstk[argcnt++] = p;
if (input() == ')')
break;
}
for (i = argcnt; i < MAXARGS; i++)
ap->argstk[i] = "";
if (dbg)
for (i = 0; i < argcnt; i++)
printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
argfp = ap;
pushsrc(Macro, stp->s_val.p);
}
int
getarg(char *p) /* pick up single argument, store in p, return length */
{
int n, c, npar;
n = npar = 0;
for ( ;; ) {
c = input();
if (c == EOF)
ERROR "end of file in getarg" FATAL;
if (npar == 0 && (c == ',' || c == ')'))
break;
if (c == '"') /* copy quoted stuff intact */
do {
*p++ = c;
n++;
} while ((c = input()) != '"' && c != EOF);
else if (c == '(')
npar++;
else if (c == ')')
npar--;
n++;
*p++ = c;
}
*p = 0;
unput(c);
return(n + 1);
}
#define PBSIZE 2000
char pbuf[PBSIZE]; /* pushback buffer */
char *pb = pbuf-1; /* next pushed back character */
char ebuf[200]; /* collect input here for error reporting */
char *ep = ebuf;
int begin = 0;
extern int thru;
extern struct symtab *thrudef;
extern char *untilstr;
int
input(void)
{
int c;
if (thru && begin) {
do_thru();
begin = 0;
}
c = nextchar();
if (dbg > 1)
printf(" <%c>", c);
if (ep >= ebuf + sizeof ebuf)
ep = ebuf;
return *ep++ = c;
}
int
nextchar(void)
{
int c;
loop:
switch (srcp->type) {
default:
c = -1;
break;
case Free: /* free string */
free(srcp->sp);
popsrc();
goto loop;
case Thru: /* end of pushed back line */
begin = 1;
popsrc();
c = '\n';
break;
case Char:
if (pb >= pbuf) {
c = *pb--;
popsrc();
break;
} else { /* can't happen? */
popsrc();
goto loop;
}
case String:
c = *srcp->sp++;
if (c == '\0') {
popsrc();
goto loop;
} else {
if (*srcp->sp == '\0') /* empty, so pop */
popsrc();
break;
}
case Macro:
c = *srcp->sp++;
if (c == '\0') {
if (--argfp < args)
ERROR "argfp underflow" FATAL;
popsrc();
goto loop;
} else if (c == '$' && isdigit(*srcp->sp)) {
int n = 0;
while (isdigit(*srcp->sp))
n = 10 * n + *srcp->sp++ - '0';
if (n > 0 && n <= MAXARGS)
pushsrc(String, argfp->argstk[n-1]);
goto loop;
}
break;
case File:
c = getc(curfile->fin);
if (c == EOF) {
if (curfile == infile)
ERROR "end of file inside .PS/.PE" FATAL;
if (curfile->fin != stdin) {
fclose(curfile->fin);
free(curfile->fname); /* assumes allocated */
}
curfile--;
printlf(curfile->lineno, curfile->fname);
popsrc();
thru = 0; /* chicken out */
thrudef = 0;
if (untilstr) {
free(untilstr);
untilstr = 0;
}
goto loop;
}
if (c == '\n')
curfile->lineno++;
break;
}
return c;
}
void
do_thru(void) /* read one line, make into a macro expansion */
{
int c, i;
char *p;
Arg *ap;
ap = argfp+1;
if (ap >= args+10)
ERROR "arguments too deep" FATAL;
if (ap->argval == NULL)
ap->argval = malloc(1000);
p = ap->argval;
argcnt = 0;
c = nextchar();
if (thru == 0) { /* end of file was seen, so thru is done */
unput(c);
return;
}
for ( ; c != '\n' && c != EOF; ) {
if (c == ' ' || c == '\t') {
c = nextchar();
continue;
}
ap->argstk[argcnt++] = p;
if (c == '"') {
do {
*p++ = c;
if ((c = nextchar()) == '\\') {
*p++ = c;
*p++ = nextchar();
c = nextchar();
}
} while (c != '"' && c != '\n' && c != EOF);
*p++ = '"';
if (c == '"')
c = nextchar();
} else {
do {
*p++ = c;
} while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
if (c == ',')
c = nextchar();
}
*p++ = '\0';
}
if (c == EOF)
ERROR "unexpected end of file in do_thru" FATAL;
if (argcnt == 0) { /* ignore blank line */
pushsrc(Thru, (char *) 0);
return;
}
for (i = argcnt; i < MAXARGS; i++)
ap->argstk[i] = "";
if (dbg)
for (i = 0; i < argcnt; i++)
printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
if (strcmp(ap->argstk[0], ".PE") == 0) {
thru = 0;
thrudef = 0;
pushsrc(String, "\n.PE\n");
return;
}
if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
thru = 0;
thrudef = 0;
free(untilstr);
untilstr = 0;
return;
}
pushsrc(Thru, (char *) 0);
dprintf("do_thru pushing back <%s>\n", thrudef->s_val.p);
argfp = ap;
pushsrc(Macro, thrudef->s_val.p);
}
int
unput(int c)
{
if (++pb >= pbuf + sizeof pbuf)
ERROR "pushback overflow" FATAL;
if (--ep < ebuf)
ep = ebuf + sizeof(ebuf) - 1;
*pb = c;
pushsrc(Char, pb);
return c;
}
void
pbstr(char *s)
{
pushsrc(String, s);
}
double
errcheck(double x, char *s)
{
extern int errno;
if (errno == EDOM) {
errno = 0;
ERROR "%s argument out of domain", s WARNING;
} else if (errno == ERANGE) {
errno = 0;
ERROR "%s result out of range", s WARNING;
}
return x;
}
char errbuf[200];
void
yyerror(char *s)
{
extern char *cmdname;
if (synerr)
return;
fflush(stdout);
fprintf(stderr, "%s: %s", cmdname, s);
if (errno > 0)
fprintf(stderr, " (%s)", strerror(errno));
fprintf(stderr, " near line %d, file %s\n",
curfile->lineno, curfile->fname);
eprint();
synerr = 1;
errno = 0;
}
void
eprint(void) /* try to print context around error */
{
char *p, *q;
p = ep - 1;
if (p > ebuf && *p == '\n')
p--;
for ( ; p >= ebuf && *p != '\n'; p--)
;
while (*p == '\n')
p++;
fprintf(stderr, " context is\n\t");
for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
;
while (p < q)
putc(*p++, stderr);
fprintf(stderr, " >>> ");
while (p < ep)
putc(*p++, stderr);
fprintf(stderr, " <<< ");
while (pb >= pbuf)
putc(*pb--, stderr);
fgets(ebuf, sizeof ebuf, curfile->fin);
fprintf(stderr, "%s", ebuf);
pbstr("\n.PE\n"); /* safety first */
ep = ebuf;
}
void yywrap(void) {;}
char *newfile = 0; /* filename for file copy */
char *untilstr = 0; /* string that terminates a thru */
int thru = 0; /* 1 if copying thru macro */
struct symtab *thrudef = 0; /* macro being used */
void
copyfile(char *s) /* remember file to start reading from */
{
newfile = s;
}
void
copydef(struct symtab *p) /* remember macro symtab ptr */
{
thrudef = p;
}
struct symtab*
copythru(char *s) /* collect the macro name or body for thru */
{
struct symtab *p;
char *q, *addnewline();
p = lookup(s);
if (p != NULL) {
if (p->s_type == DEFNAME) {
p->s_val.p = addnewline(p->s_val.p);
return p;
} else
ERROR "%s used as define and name", s FATAL;
}
/* have to collect the definition */
pbstr(s); /* first char is the delimiter */
q = delimstr("thru body");
s = "nameless";
p = lookup(s);
if (p != NULL) {
if (p->s_val.p)
free(p->s_val.p);
p->s_val.p = q;
} else {
YYSTYPE u;
u.p = q;
p = makevar(tostring(s), DEFNAME, u);
}
p->s_val.p = addnewline(p->s_val.p);
dprintf("installing %s as `%s'\n", s, p->s_val.p);
return p;
}
char*
addnewline(char *p) /* add newline to end of p */
{
int n;
n = strlen(p);
if (p[n-1] != '\n') {
p = realloc(p, n+2);
p[n] = '\n';
p[n+1] = '\0';
}
return p;
}
void
copyuntil(char *s) /* string that terminates a thru */
{
untilstr = s;
}
void
copy(void) /* begin input from file, etc. */
{
FILE *fin;
if (newfile) {
if ((fin = fopen(newfile, "r")) == NULL)
ERROR "can't open file %s", newfile FATAL;
curfile++;
curfile->fin = fin;
curfile->fname = newfile;
curfile->lineno = 0;
printlf(1, curfile->fname);
pushsrc(File, curfile->fname);
newfile = 0;
}
if (thrudef) {
thru = 1;
begin = 1; /* wrong place */
}
}
char shellbuf[1000], *shellp;
void
shell_init(void) /* set up to interpret a shell command */
{
sprintf(shellbuf, "sh -c '");
shellp = shellbuf + strlen(shellbuf);
}
void
shell_text(char *s) /* add string to command being collected */
{
while (*shellp++ = *s++)
;
shellp--;
}
void
shell_exec(void) /* do it */
{
*shellp++ = '\'';
*shellp = '\0';
system(shellbuf);
}

210
src/cmd/tpic/linegen.c Normal file
View file

@ -0,0 +1,210 @@
#include <stdio.h>
#include "pic.h"
#include "y.tab.h"
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);
}

277
src/cmd/tpic/main.c Normal file
View file

@ -0,0 +1,277 @@
#include <stdio.h>
#include <signal.h>
#include "pic.h"
#include "y.tab.h"
obj **objlist = 0; /* store the elements here */
int nobjlist = 0; /* size of objlist array */
int nobj = 0;
Attr *attr; /* attributes stored here as collected */
int nattrlist = 0;
int nattr = 0; /* number of entries in attr_list */
Text *text = 0; /* text strings stored here as collected */
int ntextlist = 0; /* size of text[] array */
int ntext = 0;
int ntext1 = 0; /* record ntext here on entry to each figure */
double curx = 0;
double cury = 0;
int hvmode = R_DIR; /* R => join left to right, D => top to bottom, etc. */
int codegen = 0; /* 1=>output for this picture; 0=>no output */
int PEseen = 0; /* 1=> PE seen during parsing */
double deltx = 6; /* max x value in output, for scaling */
double delty = 6; /* max y value in output, for scaling */
int dbg = 0;
int lineno = 0;
char *filename = "-";
int synerr = 0;
int anyerr = 0; /* becomes 1 if synerr ever 1 */
char *cmdname;
double xmin = 30000; /* min values found in actual data */
double ymin = 30000;
double xmax = -30000; /* max */
double ymax = -30000;
int
main(int argc, char **argv)
{
char buf[20];
extern void fpecatch(int);
signal(SIGFPE, fpecatch);
cmdname = argv[0];
while (argc > 1 && *argv[1] == '-') {
switch (argv[1][1]) {
case 'd':
dbg = atoi(&argv[1][2]);
if (dbg == 0)
dbg = 1;
break;
}
argc--;
argv++;
}
setdefaults();
objlist = (obj **) grow((char *)objlist, "objlist", nobjlist += 1000, sizeof(obj *));
text = (Text *) grow((char *)text, "text", ntextlist += 1000, sizeof(Text));
attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
sprintf(buf, "/%d/", getpid());
pushsrc(String, buf);
definition("pid");
curfile = infile;
pushsrc(File, curfile->fname);
if (argc <= 1) {
curfile->fin = stdin;
curfile->fname = tostring("-");
getdata();
} else
while (argc-- > 1) {
if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
fprintf(stderr, "%s: can't open %s\n", cmdname, *argv);
exit(1);
}
curfile->fname = tostring(*argv);
getdata();
fclose(curfile->fin);
free(curfile->fname);
}
exit(anyerr);
return 0;
}
void
fpecatch(int arg)
{
ERROR "floating point exception" FATAL;
}
char *
grow(char *ptr, char *name, int num, int size) /* make array bigger */
{
char *p;
if (ptr == NULL)
p = malloc(num * size);
else
p = realloc(ptr, num * size);
if (p == NULL)
ERROR "can't grow %s to %d", name, num * size FATAL;
return p;
}
static struct {
char *name;
double val;
short scalable; /* 1 => adjust when "scale" changes */
} defaults[] ={
"scale", SCALE, 1,
"lineht", HT, 1,
"linewid", HT, 1,
"moveht", HT, 1,
"movewid", HT, 1,
"dashwid", HT10, 1,
"boxht", HT, 1,
"boxwid", WID, 1,
"circlerad", HT2, 1,
"arcrad", HT2, 1,
"ellipseht", HT, 1,
"ellipsewid", WID, 1,
"arrowht", HT5, 1,
"arrowwid", HT10, 1,
"arrowhead", 2, 0, /* arrowhead style */
"textht", 0.0, 1, /* 6 lines/inch is also a useful value */
"textwid", 0.0, 1,
"maxpsht", MAXHT, 0,
"maxpswid", MAXWID, 0,
"fillval", 0.3, 0, /* gray value for filling boxes */
NULL, 0, 0
};
void
setdefaults(void) /* set default sizes for variables like boxht */
{
int i;
YYSTYPE v;
for (i = 0; defaults[i].name != NULL; i++) {
v.f = defaults[i].val;
makevar(tostring(defaults[i].name), VARNAME, v);
}
}
void
resetvar(void) /* reset variables listed */
{
int i, j;
if (nattr == 0) { /* none listed, so do all */
setdefaults();
return;
}
for (i = 0; i < nattr; i++) {
for (j = 0; defaults[j].name != NULL; j++)
if (strcmp(defaults[j].name, attr[i].a_val.p) == 0) {
setfval(defaults[j].name, defaults[j].val);
free(attr[i].a_val.p);
break;
}
}
}
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);
}
}
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);
/* else {
/* double xfac, yfac; */
/* xfac = deltx / (xmax-xmin);
/* yfac = delty / (ymax-ymin);
/* if (xfac <= yfac)
/* delty = xfac * (ymax-ymin);
/* else
/* deltx = yfac * (xmax-xmin);
/*}
*/
}
dprintf("deltx = %g, delty = %g\n", deltx, delty);
if (codegen && !synerr) {
openpl(); /* puts out .PS, with ht & wid stuck in */
printlf(curfile->lineno+1, NULL);
print(); /* assumes \n at end */
closepl(); /* does the .PE/F */
}
printlf(curfile->lineno+1, NULL);
fflush(stdout);
} else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
free(curfile->fname);
printlf(curfile->lineno = ln, curfile->fname = tostring(buf1));
} else
printlf(curfile->lineno = ln, NULL);
} else
fputs(buf, stdout);
}
}
void
reset(void)
{
obj *op;
int i;
extern int nstack;
for (i = 0; i < nobj; i++) {
op = objlist[i];
if (op->o_type == BLOCK)
freesymtab(op->o_symtab);
free((char *)objlist[i]);
}
nobj = 0;
nattr = 0;
for (i = 0; i < ntext; i++)
if (text[i].t_val)
free(text[i].t_val);
ntext = ntext1 = 0;
codegen = synerr = 0;
nstack = 0;
curx = cury = 0;
PEseen = 0;
hvmode = R_DIR;
xmin = ymin = 30000;
xmax = ymax = -30000;
}

463
src/cmd/tpic/misc.c Normal file
View file

@ -0,0 +1,463 @@
#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, getblk();
y = getblk(p, s);
return y.f;
}
obj*
getblock(obj *p, char *s) /* find variable s in block p */
{
YYSTYPE y, getblk();
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;
}

39
src/cmd/tpic/mkfile Normal file
View file

@ -0,0 +1,39 @@
<$PLAN9/src/mkhdr
TARG=tpic
YFILES=picy.y
OFILES=\
arcgen.$O\
blockgen.$O\
boxgen.$O\
circgen.$O\
for.$O\
input.$O\
linegen.$O\
main.$O\
misc.$O\
movegen.$O\
picl.$O\
picy.$O\
pltex.$O\
print.$O\
symtab.$O\
tex.$O\
textgen.$O\
HFILES=pic.h y.tab.h tex.h
<$PLAN9/src/mkone
YFLAGS=-d -S
picy.c: y.tab.c
mv y.tab.c picy.c
picl.$O: picl.l
9 lex picl.l
$CC $CFLAGS lex.yy.c
rm lex.yy.c
mv lex.yy.$O picl.$O

87
src/cmd/tpic/movegen.c Normal file
View file

@ -0,0 +1,87 @@
#include <stdio.h>
#include "pic.h"
#include "y.tab.h"
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);
}

285
src/cmd/tpic/pic.h Normal file
View file

@ -0,0 +1,285 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef PI
#define PI 3.1415926535897932384626433832795028841971693993751
#endif
#define MAXWID 8.5 /* default limits max picture to 8.5 x 11; */
#define MAXHT 11 /* change to taste without peril */
#define dprintf if(dbg)printf
extern char errbuf[200];
#define ERROR sprintf(errbuf,
#define FATAL ), yyerror(errbuf), exit(1)
#define WARNING ), yyerror(errbuf)
#define DEFAULT 0
#define HEAD1 1
#define HEAD2 2
#define HEAD12 (HEAD1+HEAD2)
#define INVIS 4
#define CW_ARC 8 /* clockwise arc */
#define DOTBIT 16 /* line styles */
#define DASHBIT 32
#define FILLBIT 64 /* gray-fill on boxes, etc. */
#define CENTER 01 /* text attributes */
#define LJUST 02
#define RJUST 04
#define ABOVE 010
#define BELOW 020
#define SPREAD 040
#define SCALE 1.0 /* default scale: units/inch */
#define WID 0.75 /* default width for boxes and ellipses */
#define WID2 0.375
#define HT 0.5 /* default height and line length */
#define HT2 (HT/2)
#define HT5 (HT/5)
#define HT10 (HT/10)
/* these have to be like so, so that we can write */
/* things like R & V, etc. */
#define H 0
#define V 1
#define R_DIR 0
#define U_DIR 1
#define L_DIR 2
#define D_DIR 3
#define ishor(n) (((n) & V) == 0)
#define isvert(n) (((n) & V) != 0)
#define isright(n) ((n) == R_DIR)
#define isleft(n) ((n) == L_DIR)
#define isdown(n) ((n) == D_DIR)
#define isup(n) ((n) == U_DIR)
typedef float ofloat; /* for o_val[] in obj; could be double */
typedef struct obj { /* stores various things in variable length */
int o_type;
int o_count; /* number of things */
int o_nobj; /* index in objlist */
int o_mode; /* hor or vert */
float o_x; /* coord of "center" */
float o_y;
int o_nt1; /* 1st index in text[] for this object */
int o_nt2; /* 2nd; difference is #text strings */
int o_attr; /* HEAD, CW, INVIS, etc., go here */
int o_size; /* linesize */
int o_nhead; /* arrowhead style */
struct symtab *o_symtab; /* symtab for [...] */
float o_ddval; /* value of dot/dash expression */
float o_fillval; /* gray scale value */
ofloat o_val[1]; /* actually this will be > 1 in general */
/* type is not always FLOAT!!!! */
} obj;
typedef union { /* the yacc stack type */
int i;
char *p;
obj *o;
double f;
struct symtab *st;
} YYSTYPE;
extern YYSTYPE yylval, yyval;
struct symtab {
char *s_name;
int s_type;
YYSTYPE s_val;
struct symtab *s_next;
};
typedef struct { /* attribute of an object */
int a_type;
int a_sub;
YYSTYPE a_val;
} Attr;
typedef struct {
int t_type; /* CENTER, LJUST, etc. */
char t_op; /* optional sign for size changes */
char t_size; /* size, abs or rel */
char *t_val;
} Text;
#define String 01
#define Macro 02
#define File 04
#define Char 010
#define Thru 020
#define Free 040
typedef struct { /* input source */
int type; /* Macro, String, File */
char *sp; /* if String or Macro */
} Src;
extern Src src[], *srcp; /* input source stack */
typedef struct {
FILE *fin;
char *fname;
int lineno;
} Infile;
extern Infile infile[], *curfile;
#define MAXARGS 20
typedef struct { /* argument stack */
char *argstk[MAXARGS]; /* pointers to args */
char *argval; /* points to space containing args */
} Arg;
extern int dbg;
extern obj **objlist;
extern int nobj, nobjlist;
extern Attr *attr;
extern int nattr, nattrlist;
extern Text *text;
extern int ntextlist;
extern int ntext;
extern int ntext1;
extern double curx, cury;
extern int hvmode;
extern int codegen;
extern int PEseen;
extern double deltx, delty;
extern int lineno;
extern int synerr;
extern double xmin, ymin, xmax, ymax;
struct pushstack {
double p_x;
double p_y;
int p_hvmode;
double p_xmin;
double p_ymin;
double p_xmax;
double p_ymax;
struct symtab *p_symtab;
};
extern struct pushstack stack[];
extern int nstack;
extern int cw;
#define Log10(x) errcheck(log10(x), "log")
#define Exp(x) errcheck(exp(x), "exp")
#define Sqrt(x) errcheck(sqrt(x), "sqrt")
char* addnewline(char *p) /* add newline to end of p */;
obj* addpos(obj *p, obj *q);
void addtattr(int sub) /* add text attrib to existing item */;
void arc(double xc, double yc, double x0, double y0, double x1, double y1) /* draw arc with center xc,yc */;
void arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc);
obj* arcgen(int type) /* handles circular and (eventually) elliptical arcs */;
void arrow(double x0, double y0, double x1, double y1, double w, double h, double ang, int nhead) /* draw arrow (without shaft) */ /* head wid w, len h, rotated ang */ /* and drawn with nhead lines */;
int baldelim(int c, char *s) /* replace c by balancing entry in s */;
void blockadj(obj *p) /* adjust coords in block starting at p */;
obj* blockgen(obj *p, obj *q) /* handles [...] */;
obj* boxgen(void);
void checkscale(char *s) /* if s is "scale", adjust default variables */;
obj* circgen(int type);
void copy(void) /* begin input from file, etc. */;
void copydef(struct symtab *p) /* remember macro symtab ptr */;
void copyfile(char *s) /* remember file to start reading from */;
struct symtab* copythru(char *s) /* collect the macro name or body for thru */;
void copyuntil(char *s) /* string that terminates a thru */;
int curdir(void) /* convert current dir (hvmode) to RIGHT, LEFT, etc. */;
void definition(char *s) /* collect definition for s and install */ /* definitions picked up lexically */;
char* delimstr(char *s) /* get body of X ... X */ /* message if too big */;
void do_thru(void) /* read one line, make into a macro expansion */;
void dodef(struct symtab *stp) /* collect args and switch input to defn */;
void dot(void);
void dotbox(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted or dashed box */;
void dotext(obj *p) /* print text strings of p in proper vertical spacing */;
void dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval);
void dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted line */;
void ellipse(double x, double y, double r1, double r2);
void endfor(void) /* end one iteration of for loop */;
void eprint(void) /* try to print context around error */;
double errcheck(double x, char *s);
void exprsave(double f);
void extreme(double x, double y) /* record max and min x and y values */;
void fillend(void);
void fillstart(double v) /* only choose black, light grey (.75), or white, for now */;
obj* fixpos(obj *p, double x, double y);
void forloop(char *, double, double, int, double, char *) /* set up a for loop */;
void fpecatch(int arg);
void freedef(char *s) /* free definition for string s */;
void freesymtab(struct symtab *p) /* free space used by symtab at p */;
int getarg(char *p) /* pick up single argument, store in p, return length */;
YYSTYPE getblk(obj *p, char *s) /* find union type for s in p */;
double getblkvar(obj *p, char *s) /* find variable s2 in block p */;
obj* getblock(obj *p, char *s) /* find variable s in block p */;
double getcomp(obj *p, int t) /* return component of a position */;
void getdata(void);
obj* getfirst(int n, int t) /* find n-th occurrence of type t */;
double getfval(char *s) /* return float value of variable s */;
obj* gethere(void) /* make a place for curx,cury */;
obj* getlast(int n, int t) /* find n-th previous occurrence of type t */;
obj* getpos(obj *p, int corner) /* find position of point */;
YYSTYPE getvar(char *s) /* return value of variable s (usually pointer) */;
char * grow(char *ptr, char *name, int num, int size) /* make array bigger */;
char* ifstat(double expr, char *thenpart, char *elsepart);
int input(void);
void label(char *s, int t, int nh) /* text s of type t nh half-lines up */;
obj* leftthing(int c) /* called for {... or [... */ /* really ought to be separate functions */;
obj* linegen(int type);
struct symtab* lookup(char *s) /* find s in symtab */;
int main(int argc, char **argv);
void makeattr(int type, int sub, YYSTYPE val) /* add attribute type and val */;
obj* makebetween(double f, obj *p1, obj* p2) /* make position between p1 and p2 */;
void makefattr(int type, int sub, double f) /* double attr */;
void makeiattr(int type, int i) /* int attr */;
obj* makenode(int type, int n);
void makeoattr(int type, obj *o) /* obj* attr */;
obj* makepos(double x, double y) /* make a position cell */;
void maketattr(int sub, char *p) /* text attribute: takes two */;
struct symtab* makevar(char *s, int t, YYSTYPE v) /* make variable named s in table */ /* assumes s is static or from tostring */;
void makevattr(char *p) /* varname attribute */;
obj* movegen(void);
int nextchar(void);
void nextfor(void) /* do one iteration of a for loop */;
void pbstr(char *s);
void popsrc(void) /* restore an old one */;
void print(void);
void printexpr(double f) /* print expression for debugging */;
void printlf(int line, char *name);
void printpos(obj *p) /* print position for debugging */;
void pushsrc(int type, char *ptr) /* new input source */;
int quadrant(double x, double y);
void reset(void);
void resetvar(void) /* reset variables listed */;
obj* rightthing(obj *p, int c) /* called for ... ] or ... } */;
void savetext(int t, char *s) /* record text elements for current object */;
void setdefaults(void) /* set default sizes for variables like boxht */;
int setdir(int n) /* set direction (hvmode) from LEFT, RIGHT, etc. */;
void setfval(char *s, double f) /* set variable s to f */;
void shell_exec(void) /* do it */;
void shell_init(void) /* set up to interpret a shell command */;
void shell_text(char *s) /* add string to command being collected */;
void space(double x0, double y0, double x1, double y1) /* set limits of page */;
void spline(double x, double y, double/*sic*/ n, float *p, int dashed, double ddval);
char* sprintgen(char *fmt);
obj* subpos(obj *p, obj *q);
obj* textgen(void);
char* tostring(char *s);
void troff(char *s);
obj* troffgen(char *s) /* save away a string of troff commands */;
void undefine(char *s) /* undefine macro */;
int unput(int c);
int whatpos(obj *p, int corner, double *px, double *py) /* what is the position (no side effect) */;
void yyerror(char *s);
int yyparse(void);
#include "tex.h"

261
src/cmd/tpic/picl.l Normal file
View file

@ -0,0 +1,261 @@
%Start A str def sc br thru sh
%e 1700
%k 120
%a 1800
%o 1500
%p 5000
%n 700
%{
#undef input
#undef unput
#include <stdio.h>
#include <ctype.h>
#include "pic.h"
#include "y.tab.h"
extern double atof();
extern char *filename;
extern struct symtab symtab[];
extern struct symtab*copythru();
#define CADD cbuf[clen++]=yytext[0]; if(clen>=CBUFLEN-1) {ERROR "string too long" WARNING; BEGIN A;}
#define CBUFLEN 500
char cbuf[CBUFLEN];
int c, clen, cflag, delim;
int ifsw = 0; /* 1 if if statement in progress */
%}
A [a-zA-Z_]
B [a-zA-Z0-9_]
D [0-9]
WS [ \t]
%%
switch (yybgin-yysvec-1) { /* witchcraft */
case 0:
BEGIN A;
break;
case sc:
BEGIN A;
return('}');
case br:
BEGIN A;
return(']');
}
<A>{WS} ;
<A>"\\"\n ;
<A>\n { return(ST); }
<A>";" { return(ST); }
<A>"}" { BEGIN sc; return(ST); }
<A>"]" { BEGIN br; return(ST); }
<A>^".PS".* { if (curfile == infile) ERROR ".PS found inside .PS/.PE" WARNING; }
<A>^"."P[EF].* { if (curfile == infile) {
yylval.i = yytext[2];
PEseen = 1;
return(EOF);
}
}
<A>^".".* { yylval.p = tostring(yytext); return(TROFF); }
<A>print return(yylval.i = PRINT);
<A>box return(yylval.i = BOX);
<A>circle return(yylval.i = CIRCLE);
<A>arc return(yylval.i = ARC);
<A>ellipse return(yylval.i = ELLIPSE);
<A>arrow return(yylval.i = ARROW);
<A>spline return(yylval.i = SPLINE);
<A>line return(yylval.i = LINE);
<A>move return(yylval.i = MOVE);
<A>"[]" return(yylval.i = BLOCK);
<A>reset return(RESET);
<A>sprintf return(SPRINTF);
<A>same return(SAME);
<A>between return(BETWEEN);
<A>and return(AND);
<A>of ;
<A>the ;
<A>way ;
<A>"."(e|east) { yylval.i = EAST; return(CORNER); }
<A>"."(r|right) { yylval.i = EAST; return(CORNER); }
<A>"."(w|west) { yylval.i = WEST; return(CORNER); }
<A>"."(l|left) { yylval.i = WEST; return(CORNER); }
<A>"."(n|north) { yylval.i = NORTH; return(CORNER); }
<A>"."(t|top) { yylval.i = NORTH; return(CORNER); }
<A>"."(s|south) { yylval.i = SOUTH; return(CORNER); }
<A>"."(b|bot|bottom) { yylval.i = SOUTH; return(CORNER); }
<A>"."(c|center) { yylval.i = CENTER; return(CORNER); }
<A>".start" { yylval.i = START; return(CORNER); }
<A>".end" { yylval.i = END; return(CORNER); }
<A>".ne" { yylval.i = NE; return(CORNER); }
<A>".se" { yylval.i = SE; return(CORNER); }
<A>".nw" { yylval.i = NW; return(CORNER); }
<A>".sw" { yylval.i = SW; return(CORNER); }
<A>top" "+of { yylval.i = NORTH; return(CORNER); }
<A>north" "+of { yylval.i = NORTH; return(CORNER); }
<A>bottom" "+of { yylval.i = SOUTH; return(CORNER); }
<A>south" "+of { yylval.i = SOUTH; return(CORNER); }
<A>left" "+of { yylval.i = WEST; return(CORNER); }
<A>west" "+of { yylval.i = WEST; return(CORNER); }
<A>right" "+of { yylval.i = EAST; return(CORNER); }
<A>east" "+of { yylval.i = EAST; return(CORNER); }
<A>center" "+of { yylval.i = CENTER; return(CORNER); }
<A>start" "+of { yylval.i = START; return(CORNER); }
<A>end" "+of { yylval.i = END; return(CORNER); }
<A>height|ht { yylval.i = HEIGHT; return(ATTR); }
<A>width|wid { yylval.i = WIDTH; return(ATTR); }
<A>radius|rad { yylval.i = RADIUS; return(ATTR); }
<A>diameter|diam { yylval.i = DIAMETER; return(ATTR); }
<A>size { yylval.i = SIZE; return(ATTR); }
<A>left { yylval.i = LEFT; return(DIR); }
<A>right { yylval.i = RIGHT; return(DIR); }
<A>up { yylval.i = UP; return(DIR); }
<A>down { yylval.i = DOWN; return(DIR); }
<A>cw { yylval.i = CW; return(ATTR); }
<A>clockwise { yylval.i = CW; return(ATTR); }
<A>ccw { yylval.i = CCW; return(ATTR); }
<A>invis(ible)? { yylval.i = INVIS; return(ATTR); }
<A>fill { yylval.i = FILL; return ATTR; }
<A>solid ;
<A>dot(ted)? return(yylval.i = DOT);
<A>dash(ed)? return(yylval.i = DASH);
<A>chop return(yylval.i = CHOP);
<A>spread { yylval.i = SPREAD; return TEXTATTR; }
<A>ljust { yylval.i = LJUST; return TEXTATTR; }
<A>rjust { yylval.i = RJUST; return TEXTATTR; }
<A>above { yylval.i = ABOVE; return TEXTATTR; }
<A>below { yylval.i = BELOW; return TEXTATTR; }
<A>center { yylval.i = CENTER; return TEXTATTR; }
<A>"<-" { yylval.i = HEAD1; return(HEAD); }
<A>"->" { yylval.i = HEAD2; return(HEAD); }
<A>"<->" { yylval.i = HEAD12; return(HEAD); }
<A>".x" return(yylval.i = DOTX);
<A>".y" return(yylval.i = DOTY);
<A>"."(ht|height) return(yylval.i = DOTHT);
<A>"."(wid|width) return(yylval.i = DOTWID);
<A>"."(rad|radius) return(yylval.i = DOTRAD);
<A>from return(yylval.i = FROM);
<A>to return(yylval.i = TO);
<A>at return(yylval.i = AT);
<A>by return(yylval.i = BY);
<A>with return(yylval.i = WITH);
<A>last return(yylval.i = LAST);
<A>log return(LOG);
<A>exp return(EXP);
<A>sin return(SIN);
<A>cos return(COS);
<A>atan2 return(ATAN2);
<A>sqrt return(SQRT);
<A>rand return(RAND);
<A>max return(MAX);
<A>min return(MIN);
<A>int return(INT);
<A>"==" return(EQ);
<A>">=" return(GE);
<A>"<=" return(LE);
<A>"!=" return(NEQ);
<A>">" return(GT);
<A>"<" return(LT);
<A>"&&" return(ANDAND);
<A>"||" return(OROR);
<A>"!" return(NOT);
<A>Here return(yylval.i = HERE);
<A>for return(FOR);
<A>^Endfor\n { endfor(); }
<A>do { yylval.p = delimstr("loop body"); return(DOSTR); }
<A>copy|include return(COPY);
<A>(thru|through){WS}+ { BEGIN thru; return(THRU); }
<thru>{A}{B}*|. { yylval.st = copythru(yytext); BEGIN A; return(DEFNAME); }
<A>until return(UNTIL);
<A>if { ifsw = 1; return(IF); }
<A>then { if (!ifsw) { yylval.i = THEN; return(ATTR); }
yylval.p = delimstr("then part"); ifsw = 0;
return(THENSTR); }
<A>else { yylval.p = delimstr("else part"); return(ELSESTR); }
<A>sh{WS}+ { BEGIN sh;
if ((delim = input()) == '{') delim = '}'; /* no nested {} */
shell_init(); }
<sh>{A}{B}* { struct symtab *p;
if (yytext[0] == delim) {
shell_exec();
BEGIN A;
} else {
p = lookup(yytext);
if (p != NULL && p->s_type == DEFNAME) {
c = input();
unput(c);
if (c == '(')
dodef(p);
else
pbstr(p->s_val.p);
} else
shell_text(yytext);
}
}
<sh>.|\n { if (yytext[0] == delim) {
shell_exec();
BEGIN A;
} else
shell_text(yytext);
}
<A>define{WS}+ { BEGIN def; }
<def>{A}{B}* { definition(yytext); BEGIN A; }
<A>undef(ine)?{WS}+{A}{B}* { undefine(yytext); }
<A>first { yylval.i = 1; return(NTH); }
<A>{D}+(th|nd|rd|st) { yylval.i = atoi(yytext); return(NTH); }
<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
yylval.f = atof(yytext); return(NUMBER); }
<A>{A}{B}* { struct symtab *p;
p = lookup(yytext);
if (p != NULL && p->s_type == DEFNAME) {
c = input();
unput(c);
if (c == '(') /* it's name(...) */
dodef(p);
else { /* no argument list */
pbstr(p->s_val.p);
dprintf("pushing back `%s'\n", p->s_val.p);
}
} else if (islower(yytext[0])) {
yylval.p = tostring(yytext);
return(VARNAME);
} else {
yylval.p = tostring(yytext);
return(PLACENAME);
}
}
<A>\" { BEGIN str; clen=0; }
<str>\" { cbuf[clen]=0; yylval.p = tostring(cbuf); BEGIN A; return(TEXT); }
<str>\n { cbuf[clen]=0; ERROR "missing quote in string \"%s\"", cbuf WARNING;
BEGIN A; return(ST); }
<str>"\\\"" { cbuf[clen++]='"'; }
<str>"\\\\" { cbuf[clen++]='\\'; }
<str>. { CADD; }
<A>#.* ;
<A>. return(yylval.i = yytext[0]);
%%

1239
src/cmd/tpic/picy.c Normal file

File diff suppressed because it is too large Load diff

320
src/cmd/tpic/picy.y Normal file
View file

@ -0,0 +1,320 @@
%{
#include <stdio.h>
#include "pic.h"
#include <math.h>
YYSTYPE y;
int yylex(void);
%}
%token <i> BOX 1 /* DON'T CHANGE THESE! */
%token <i> LINE 2
%token <i> ARROW 3
%token <i> CIRCLE 4
%token <i> ELLIPSE 5
%token <i> ARC 6
%token <i> SPLINE 7
%token <i> BLOCK 8
%token <p> TEXT 9
%token <p> TROFF 10
%token <i> MOVE 11
%token <i> BLOCKEND 12
%token <i> PLACE 13
%token <i> PRINT RESET THRU UNTIL
%token <o> FOR IF COPY
%token <p> THENSTR ELSESTR DOSTR PLACENAME VARNAME SPRINTF
%token <st> DEFNAME
%token <i> ATTR TEXTATTR
%token <i> LEFT RIGHT UP DOWN FROM TO AT BY WITH HEAD CW CCW THEN
%token <i> HEIGHT WIDTH RADIUS DIAMETER LENGTH SIZE
%token <i> CORNER HERE LAST NTH SAME BETWEEN AND
%token <i> EAST WEST NORTH SOUTH NE NW SE SW START END
%token <i> DOTX DOTY DOTHT DOTWID DOTRAD
%token <f> NUMBER
%token <f> LOG EXP SIN COS ATAN2 SQRT RAND MIN MAX INT
%token <i> DIR
%token <i> DOT DASH CHOP FILL
%token <o> ST /* statement terminator */
%right <f> '='
%left <f> OROR
%left <f> ANDAND
%nonassoc <f> GT LT LE GE EQ NEQ
%left <f> '+' '-'
%left <f> '*' '/' '%'
%right <f> UMINUS NOT
%right <f> '^'
%type <f> expr if_expr asgn
%type <p> name text
%type <i> optop exprlist
%type <o> if for copy
/* this is a lie: picture and position are really the whole union */
%type <o> leftbrace picture piclist position lbracket
%type <o> prim place blockname
%type <i> textlist textattr /* not a sensible value */
%type <i> last type
%%
top:
piclist
| /* empty */
| error { ERROR "syntax error" WARNING; }
;
piclist:
picture
| piclist picture
;
picture:
prim ST { codegen = 1; makeiattr(0, 0); }
| leftbrace piclist '}' { rightthing($1, '}'); $$ = $2; }
| PLACENAME ':' picture { y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
| PLACENAME ':' ST picture { y.o=$4; makevar($1,PLACENAME,y); $$ = $4; }
| PLACENAME ':' position ST { y.o=$3; makevar($1,PLACENAME,y); $$ = $3; }
| asgn ST { y.f = $1; $$ = y.o; $$ = makenode(PLACE, 0); }
| DIR { setdir($1); $$ = makenode(PLACE, 0); }
| PRINT expr ST { printexpr($2); $$ = makenode(PLACE, 0); }
| PRINT position ST { printpos($2); $$ = makenode(PLACE, 0); }
| PRINT text ST { printf("%s\n", $2); free($2); $$ = makenode(PLACE, 0); }
| RESET varlist ST { resetvar(); makeiattr(0, 0); $$ = makenode(PLACE, 0); }
| copy
| for
| if
| ST
;
varlist:
/* empty */
| VARNAME { makevattr($1); }
| varlist VARNAME { makevattr($2); }
| varlist ',' VARNAME { makevattr($3); }
;
asgn:
VARNAME '=' expr { $$=y.f=$3; makevar($1,VARNAME,y); checkscale($1); }
;
copy:
COPY copylist { copy(); }
;
copylist:
copyattr
| copylist copyattr
;
copyattr:
text { copyfile($1); }
| THRU DEFNAME { copydef($2); }
| UNTIL text { copyuntil($2); }
;
for:
FOR name FROM expr TO expr BY optop expr DOSTR
{ forloop($2, $4, $6, $8, $9, $10); }
| FOR name FROM expr TO expr DOSTR
{ forloop($2, $4, $6, '+', 1.0, $7); }
| FOR name '=' expr TO expr BY optop expr DOSTR
{ forloop($2, $4, $6, $8, $9, $10); }
| FOR name '=' expr TO expr DOSTR
{ forloop($2, $4, $6, '+', 1.0, $7); }
;
if:
IF if_expr THENSTR ELSESTR { ifstat($2, $3, $4); }
| IF if_expr THENSTR { ifstat($2, $3, (char *) 0); }
;
if_expr:
expr
| text EQ text { $$ = strcmp($1,$3) == 0; free($1); free($3); }
| text NEQ text { $$ = strcmp($1,$3) != 0; free($1); free($3); }
;
name:
VARNAME { y.f = 0; makevar($1, VARNAME, y); }
;
optop:
'+' { $$ = '+'; }
| '-' { $$ = '-'; }
| '*' { $$ = '*'; }
| '/' { $$ = '/'; }
| /* empty */ { $$ = ' '; }
;
leftbrace:
'{' { $$ = leftthing('{'); }
;
prim:
BOX attrlist { $$ = boxgen(); }
| CIRCLE attrlist { $$ = circgen($1); }
| ELLIPSE attrlist { $$ = circgen($1); }
| ARC attrlist { $$ = arcgen($1); }
| LINE attrlist { $$ = linegen($1); }
| ARROW attrlist { $$ = linegen($1); }
| SPLINE attrlist { $$ = linegen($1); }
| MOVE attrlist { $$ = movegen(); }
| textlist attrlist { $$ = textgen(); }
| TROFF { $$ = troffgen($1); }
| lbracket piclist ']' { $<o>$=rightthing($1,']'); } attrlist
{ $$ = blockgen($1, $<o>4); }
;
lbracket:
'[' { $$ = leftthing('['); }
;
attrlist:
attrlist attr
| /* empty */
;
attr:
ATTR expr { makefattr($1, !DEFAULT, $2); }
| ATTR { makefattr($1, DEFAULT, 0.0); }
| expr { makefattr(curdir(), !DEFAULT, $1); }
| DIR expr { makefattr($1, !DEFAULT, $2); }
| DIR { makefattr($1, DEFAULT, 0.0); }
| FROM position { makeoattr($1, $2); }
| TO position { makeoattr($1, $2); }
| AT position { makeoattr($1, $2); }
| BY position { makeoattr($1, $2); }
| WITH CORNER { makeiattr(WITH, $2); }
| WITH '.' PLACENAME { makeoattr(PLACE, getblock(getlast(1,BLOCK), $3)); }
| WITH '.' PLACENAME CORNER
{ makeoattr(PLACE, getpos(getblock(getlast(1,BLOCK), $3), $4)); }
| WITH position { makeoattr(PLACE, $2); }
| SAME { makeiattr(SAME, $1); }
| TEXTATTR { maketattr($1, (char *) 0); }
| HEAD { makeiattr(HEAD, $1); }
| DOT expr { makefattr(DOT, !DEFAULT, $2); }
| DOT { makefattr(DOT, DEFAULT, 0.0); }
| DASH expr { makefattr(DASH, !DEFAULT, $2); }
| DASH { makefattr(DASH, DEFAULT, 0.0); }
| CHOP expr { makefattr(CHOP, !DEFAULT, $2); }
| CHOP { makefattr(CHOP, DEFAULT, 0.0); }
| FILL expr { makefattr(FILL, !DEFAULT, $2); }
| FILL { makefattr(FILL, DEFAULT, 0.0); }
| textlist
;
textlist:
textattr
| textlist textattr
;
textattr:
text { maketattr(CENTER, $1); }
| text TEXTATTR { maketattr($2, $1); }
| textattr TEXTATTR { addtattr($2); }
;
text:
TEXT
| SPRINTF '(' text ')' { $$ = sprintgen($3); }
| SPRINTF '(' text ',' exprlist ')' { $$ = sprintgen($3); }
;
exprlist:
expr { exprsave($1); $$ = 0; }
| exprlist ',' expr { exprsave($3); }
;
position: /* absolute, not relative */
place
| '(' position ')' { $$ = $2; }
| expr ',' expr { $$ = makepos($1, $3); }
| position '+' expr ',' expr { $$ = fixpos($1, $3, $5); }
| position '-' expr ',' expr { $$ = fixpos($1, -$3, -$5); }
| position '+' '(' expr ',' expr ')' { $$ = fixpos($1, $4, $6); }
| position '-' '(' expr ',' expr ')' { $$ = fixpos($1, -$4, -$6); }
| position '+' place { $$ = addpos($1, $3); }
| position '-' place { $$ = subpos($1, $3); }
| '(' place ',' place ')' { $$ = makepos(getcomp($2,DOTX), getcomp($4,DOTY)); }
| expr LT position ',' position GT { $$ = makebetween($1, $3, $5); }
| expr BETWEEN position AND position { $$ = makebetween($1, $3, $5); }
;
place:
PLACENAME { y = getvar($1); $$ = y.o; }
| PLACENAME CORNER { y = getvar($1); $$ = getpos(y.o, $2); }
| CORNER PLACENAME { y = getvar($2); $$ = getpos(y.o, $1); }
| HERE { $$ = gethere(); }
| last type { $$ = getlast($1, $2); }
| last type CORNER { $$ = getpos(getlast($1, $2), $3); }
| CORNER last type { $$ = getpos(getlast($2, $3), $1); }
| NTH type { $$ = getfirst($1, $2); }
| NTH type CORNER { $$ = getpos(getfirst($1, $2), $3); }
| CORNER NTH type { $$ = getpos(getfirst($2, $3), $1); }
| blockname
| blockname CORNER { $$ = getpos($1, $2); }
| CORNER blockname { $$ = getpos($2, $1); }
;
blockname:
last BLOCK '.' PLACENAME { $$ = getblock(getlast($1,$2), $4); }
| NTH BLOCK '.' PLACENAME { $$ = getblock(getfirst($1,$2), $4); }
| PLACENAME '.' PLACENAME { y = getvar($1); $$ = getblock(y.o, $3); }
;
last:
last LAST { $$ = $1 + 1; }
| NTH LAST { $$ = $1; }
| LAST { $$ = 1; }
;
type:
BOX
| CIRCLE
| ELLIPSE
| ARC
| LINE
| ARROW
| SPLINE
| BLOCK
;
expr:
NUMBER
| VARNAME { $$ = getfval($1); }
| asgn
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { if ($3 == 0.0) {
ERROR "division by 0" WARNING; $3 = 1; }
$$ = $1 / $3; }
| expr '%' expr { if ((long)$3 == 0) {
ERROR "mod division by 0" WARNING; $3 = 1; }
$$ = (long)$1 % (long)$3; }
| '-' expr %prec UMINUS { $$ = -$2; }
| '(' expr ')' { $$ = $2; }
| place DOTX { $$ = getcomp($1, $2); }
| place DOTY { $$ = getcomp($1, $2); }
| place DOTHT { $$ = getcomp($1, $2); }
| place DOTWID { $$ = getcomp($1, $2); }
| place DOTRAD { $$ = getcomp($1, $2); }
| PLACENAME '.' VARNAME { y = getvar($1); $$ = getblkvar(y.o, $3); }
| last BLOCK '.' VARNAME { $$ = getblkvar(getlast($1,$2), $4); }
| NTH BLOCK '.' VARNAME { $$ = getblkvar(getfirst($1,$2), $4); }
| expr GT expr { $$ = $1 > $3; }
| expr LT expr { $$ = $1 < $3; }
| expr LE expr { $$ = $1 <= $3; }
| expr GE expr { $$ = $1 >= $3; }
| expr EQ expr { $$ = $1 == $3; }
| expr NEQ expr { $$ = $1 != $3; }
| expr ANDAND expr { $$ = $1 && $3; }
| expr OROR expr { $$ = $1 || $3; }
| NOT expr { $$ = !($2); }
| LOG '(' expr ')' { $$ = Log10($3); }
| EXP '(' expr ')' { $$ = Exp($3 * log(10.0)); }
| expr '^' expr { $$ = pow($1, $3); }
| SIN '(' expr ')' { $$ = sin($3); }
| COS '(' expr ')' { $$ = cos($3); }
| ATAN2 '(' expr ',' expr ')' { $$ = atan2($3, $5); }
| SQRT '(' expr ')' { $$ = Sqrt($3); }
| RAND '(' ')' { $$ = (float)rand() / 32767.0; /* might be 2^31-1 */ }
| MAX '(' expr ',' expr ')' { $$ = $3 >= $5 ? $3 : $5; }
| MIN '(' expr ',' expr ')' { $$ = $3 <= $5 ? $3 : $5; }
| INT '(' expr ')' { $$ = (long) $3; }
;

149
src/cmd/tpic/pltex.c Normal file
View file

@ -0,0 +1,149 @@
/* replacement for pltroff.c to produce a TeX file that makes a box */
#include <stdio.h>
#include <math.h>
#include "pic.h"
double rangex, rangey; /* probably already available inside pic somewhere */
extern int dbg;
int frameno;
/*-----------copied from old version----------*/
void
arrow(double x0, double y0, double x1, double y1, double w, double h, double ang, int nhead) /* draw arrow (without shaft) */
/* head wid w, len h, rotated ang */
/* and drawn with nhead lines */
{
double alpha, rot, drot, hyp;
float dx, dy;
int i;
rot = atan2(w / 2, h);
hyp = sqrt(w/2 * w/2 + h * h);
alpha = atan2(y1-y0, x1-x0) + ang;
if (nhead < 2)
nhead = 2;
for (i = nhead-1; i >= 0; i--) {
drot = 2 * rot / (double) (nhead-1) * (double) i;
dx = hyp * cos(alpha + PI - rot + drot);
dy = hyp * sin(alpha + PI - rot + drot);
line(x1+dx, y1+dy, x1, y1);
}
}
/*-----------new code----------*/
void
printlf(int line, char *name)
{
}
void
fillstart(double v) /* only choose black, light grey (.75), or white, for now */
{
if (v<.05)
fprintf(TEXFILE, " \\special{bk}%%\n");
else if (v>.95)
fprintf(TEXFILE, " \\special{wh}%%\n");
else
fprintf(TEXFILE, " \\special{sh}%%\n");
}
void
fillend(void)
{
}
void
troff(char *s)
{
int size;
if (strncmp(s, ".ps", 3) == 0) {
if (sscanf(&s[3], " %d ", &size) > 0) {
fprintf(TEXFILE, " \\special{pn %d}%%\n", size);
e1->pdiam = size;
} else fprintf(stderr, "Malformed .ps command: %s\n", s);
}
}
void
space(double x0, double y0, double x1, double y1) /* set limits of page */
{
e0->sidex = e1->sidex = deltx*1000;
e0->sidey = e1->sidey = e0->bottom = e1->bottom = delty*1000;
range(x0, y0, x1, y1);
}
void
dot(void)
{
/* use .005" radius at nominal 9pt pen size */
disc(e1->copyx,e1->copyy,(e1->pdiam/9.0)*(4.3/e1->scalex));
}
void
label(char *s, int t, int nh) /* text s of type t nh half-lines up */
{
double nem;
if (t & ABOVE)
nh++;
else if (t & BELOW)
nh--;
nem = .2 - nh*.6;
fprintf(TEXFILE," \\rlap{\\kern %6.3fin\\lower%6.3fin\\hbox{\\lower%5.2fem\\hbox to 0pt{",
INCHES(DTRX(e1->copyx)), INCHES(DTRY(e1->copyy)), nem);
fprintf(TEXFILE,t&LJUST?"%s\\hss":(t&RJUST?"\\hss %s":"\\hss %s\\hss"),s);
fprintf(TEXFILE,"}}}%%\n");
}
void
spline(double x, double y, double/*sic*/ n, float *p, int dashed, double ddval)
{
int k, j;
fprintf(TEXFILE," \\special{pa %d %d}%%\n",TRX(x),TRY(y));
for(k=0, j=0; k<n; k++, j+=2){
x += p[j];
y += p[j+1];
fprintf(TEXFILE," \\special{pa %d %d}%%\n",TRX(x),TRY(y));
}
fprintf(TEXFILE," \\special{sp}%%\n");
}
void
ellipse(double x, double y, double r1, double r2)
{
fprintf(TEXFILE, " \\special{ar %d %d %d %d 0.0 6.2832}%%\n",
TRX(x), TRY(y), SCX(r1), -SCY(r2));
}
void
arc(double xc, double yc, double x0, double y0, double x1, double y1) /* draw arc with center xc,yc */
{
devarc(x0, y0, x1, y1, xc, yc, 1 ); /* radius=1 means counterclockwise */
}
/* If NOEXPANDDASH is defined, use this instead of the normal dotline
* in print(). This dotline relies on vec() noticing that e1->pen
* is not SOLIDPEN, and putting out a call to a different postscript
* routine.
*/
#ifdef NOEXPANDDASH
void
dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval)
{
if (ddval != 0)
e1->dashlen = ddval;
e1->pen = (ddtype&DOTBIT)? DOTPEN : DASHPEN;
move(x0, y0);
vec(x1, y1);
e1->pen = SOLIDPEN;
e1->dashlen = e0->dashlen;
}
#endif

210
src/cmd/tpic/print.c Normal file
View file

@ -0,0 +1,210 @@
#include <stdio.h>
#include <math.h>
#include "pic.h"
#include "y.tab.h"
void
print(void)
{
obj *p;
int i, j, k, m;
double x0, y0, x1, y1, ox, oy, dx, dy, ndx, ndy;
for (i = 0; i < nobj; i++) {
p = objlist[i];
ox = p->o_x;
oy = p->o_y;
x1 = 0;
if (p->o_count >= 1)
x1 = p->o_val[0];
y1 = 0;
if (p->o_count >= 2)
y1 = p->o_val[1];
m = p->o_mode;
switch (p->o_type) {
case TROFF:
troff(text[p->o_nt1].t_val);
break;
case BOX:
case BLOCK:
x0 = ox - x1 / 2;
y0 = oy - y1 / 2;
x1 = ox + x1 / 2;
y1 = oy + y1 / 2;
if (p->o_attr & FILLBIT) {
move(x0, y0);
fillstart(p->o_fillval);
}
if (p->o_attr & INVIS || p->o_type == BLOCK)
; /* nothing at all */
else if (p->o_attr & (DOTBIT|DASHBIT))
dotbox(x0, y0, x1, y1, p->o_attr, p->o_ddval);
else
box(x0, y0, x1, y1);
if (p->o_attr & FILLBIT)
fillend();
move(ox, oy);
dotext(p); /* if there are any text strings */
if (ishor(m))
move(isright(m) ? x1 : x0, oy); /* right side */
else
move(ox, isdown(m) ? y0 : y1); /* bottom */
break;
case BLOCKEND:
break;
case CIRCLE:
if (p->o_attr & FILLBIT)
fillstart(p->o_fillval);
if ((p->o_attr & INVIS) == 0)
circle(ox, oy, x1);
if (p->o_attr & FILLBIT)
fillend();
move(ox, oy);
dotext(p);
if (ishor(m))
move(ox + isright(m) ? x1 : -x1, oy);
else
move(ox, oy + isup(m) ? x1 : -x1);
break;
case ELLIPSE:
if (p->o_attr & FILLBIT)
fillstart(p->o_fillval);
if ((p->o_attr & INVIS) == 0)
ellipse(ox, oy, x1, y1);
if (p->o_attr & FILLBIT)
fillend();
move(ox, oy);
dotext(p);
if (ishor(m))
move(ox + isright(m) ? x1 : -x1, oy);
else
move(ox, oy - isdown(m) ? y1 : -y1);
break;
case ARC:
move(ox, oy);
dotext(p);
if (p->o_attr & HEAD1)
arrow(x1 - (y1 - oy), y1 + (x1 - ox),
x1, y1, p->o_val[4], p->o_val[5], p->o_val[5]/p->o_val[6]/2, p->o_nhead);
if (p->o_attr & INVIS)
/* probably wrong when it's cw */
move(x1, y1);
else
arc(ox, oy, x1, y1, p->o_val[2], p->o_val[3]);
if (p->o_attr & HEAD2)
arrow(p->o_val[2] + p->o_val[3] - oy, p->o_val[3] - (p->o_val[2] - ox),
p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5], -p->o_val[5]/p->o_val[6]/2, p->o_nhead);
if (p->o_attr & CW_ARC)
move(x1, y1); /* because drawn backwards */
break;
case LINE:
case ARROW:
case SPLINE:
move((ox + x1)/2, (oy + y1)/2); /* center */
dotext(p);
if (p->o_attr & HEAD1)
arrow(ox + p->o_val[5], oy + p->o_val[6], ox, oy, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
if (p->o_attr & INVIS)
move(x1, y1);
else if (p->o_type == SPLINE)
spline(ox, oy, p->o_val[4], &p->o_val[5], p->o_attr & (DOTBIT|DASHBIT), p->o_ddval);
else {
dx = ox;
dy = oy;
for (k=0, j=5; k < p->o_val[4]; k++, j += 2) {
ndx = dx + p->o_val[j];
ndy = dy + p->o_val[j+1];
if (p->o_attr & (DOTBIT|DASHBIT))
dotline(dx, dy, ndx, ndy, p->o_attr, p->o_ddval);
else
line(dx, dy, ndx, ndy);
dx = ndx;
dy = ndy;
}
}
if (p->o_attr & HEAD2) {
dx = ox;
dy = oy;
for (k = 0, j = 5; k < p->o_val[4] - 1; k++, j += 2) {
dx += p->o_val[j];
dy += p->o_val[j+1];
}
arrow(dx, dy, x1, y1, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
}
break;
case MOVE:
case TEXT:
move(ox, oy);
dotext(p);
break;
}
}
}
#ifndef NOEXPANDDASH
void
dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted line */
{
static double prevval = 0.05; /* 20 per inch by default */
int i, numdots;
double a, b, dx, dy;
if (ddval == 0)
ddval = prevval;
prevval = ddval;
/* don't save dot/dash value */
dx = x1 - x0;
dy = y1 - y0;
if (ddtype & DOTBIT) {
numdots = sqrt(dx*dx + dy*dy) / prevval + 0.5;
if (numdots > 0)
for (i = 0; i <= numdots; i++) {
a = (double) i / (double) numdots;
move(x0 + (a * dx), y0 + (a * dy));
dot();
}
} else if (ddtype & DASHBIT) {
double d, dashsize, spacesize;
d = sqrt(dx*dx + dy*dy);
if (d <= 2 * prevval) {
line(x0, y0, x1, y1);
return;
}
numdots = d / (2 * prevval) + 1; /* ceiling */
dashsize = prevval;
spacesize = (d - numdots * dashsize) / (numdots - 1);
b = 0;
for (i = 0; i < numdots-1; i++) {
a = i * (dashsize + spacesize) / d;
b = a + dashsize / d;
line(x0 + (a*dx), y0 + (a*dy), x0 + (b*dx), y0 + (b*dy));
a = b;
b = a + spacesize / d;
move(x0 + (a*dx), y0 + (a*dy));
}
line(x0 + (b * dx), y0 + (b * dy), x1, y1);
}
prevval = 0.05;
}
#endif
void
dotbox(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted or dashed box */
{
dotline(x0, y0, x1, y0, ddtype, ddval);
dotline(x1, y0, x1, y1, ddtype, ddval);
dotline(x1, y1, x0, y1, ddtype, ddval);
dotline(x0, y1, x0, y0, ddtype, ddval);
}
void
dotext(obj *p) /* print text strings of p in proper vertical spacing */
{
int i, nhalf;
nhalf = p->o_nt2 - p->o_nt1 - 1;
for (i = p->o_nt1; i < p->o_nt2; i++) {
label(text[i].t_val, text[i].t_type, nhalf);
nhalf -= 2;
}
}

109
src/cmd/tpic/symtab.c Normal file
View file

@ -0,0 +1,109 @@
#include <stdio.h>
#include <ctype.h>
#include "pic.h"
#include "y.tab.h"
YYSTYPE
getvar(char *s) /* return value of variable s (usually pointer) */
{
struct symtab *p;
static YYSTYPE bug;
p = lookup(s);
if (p == NULL) {
if (islower(s[0]))
ERROR "no such variable as %s", s WARNING;
else
ERROR "no such place as %s", s WARNING;
return(bug);
}
return(p->s_val);
}
double
getfval(char *s) /* return float value of variable s */
{
YYSTYPE y;
y = getvar(s);
return y.f;
}
void
setfval(char *s, double f) /* set variable s to f */
{
struct symtab *p;
if ((p = lookup(s)) != NULL)
p->s_val.f = f;
}
struct symtab*
makevar(char *s, int t, YYSTYPE v) /* make variable named s in table */
/* assumes s is static or from tostring */
{
struct symtab *p;
for (p = stack[nstack].p_symtab; p != NULL; p = p->s_next)
if (strcmp(s, p->s_name) == 0)
break;
if (p == NULL) { /* it's a new one */
p = (struct symtab *) malloc(sizeof(struct symtab));
if (p == NULL)
ERROR "out of symtab space with %s", s FATAL;
p->s_next = stack[nstack].p_symtab;
stack[nstack].p_symtab = p; /* stick it at front */
}
p->s_name = s;
p->s_type = t;
p->s_val = v;
return(p);
}
struct symtab*
lookup(char *s) /* find s in symtab */
{
int i;
struct symtab *p;
for (i = nstack; i >= 0; i--) /* look in each active symtab */
for (p = stack[i].p_symtab; p != NULL; p = p->s_next)
if (strcmp(s, p->s_name) == 0)
return(p);
return(NULL);
}
void
freesymtab(struct symtab *p) /* free space used by symtab at p */
{
struct symtab *q;
for ( ; p != NULL; p = q) {
q = p->s_next;
free(p->s_name); /* assumes done with tostring */
free((char *)p);
}
}
void
freedef(char *s) /* free definition for string s */
{
struct symtab *p, *q, *op;
for (p = op = q = stack[nstack].p_symtab; p != NULL; p = p->s_next) {
if (strcmp(s, p->s_name) == 0) { /* got it */
if (p->s_type != DEFNAME)
break;
if (p == op) /* 1st elem */
stack[nstack].p_symtab = p->s_next;
else
q->s_next = p->s_next;
free(p->s_name);
free(p->s_val.p);
free((char *)p);
return;
}
q = p;
}
/* ERROR "%s is not defined at this point", s WARNING; */
}

203
src/cmd/tpic/tex.c Normal file
View file

@ -0,0 +1,203 @@
#include <math.h>
#include <stdio.h>
#include "tex.h"
void
devarc(double x1, double y1, double x2, double y2, double xc, double yc, int r)
{
double t, start, stop;
int rad;
/* tpic arcs go clockwise, and angles are measured clockwise */
start = atan2(y2-yc, x2-xc);
stop = atan2(y1-yc, x1-xc);
if (r<0) {
t = start; start = stop; stop = t;
}
rad = SCX(sqrt((x1-xc)*(x1-xc)+(y1-yc)*(y1-yc)));
fprintf(TEXFILE, " \\special{ar %d %d %d %d %6.3f %6.3f}%%\n",
TRX(xc), TRY(yc), rad, rad, -start, -stop);
}
void
box(double x0, double y0, double x1, double y1)
{
fprintf(TEXFILE," \\special{pa %d %d}",TRX(x0),TRY(y0));
fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x1),TRY(y0));
fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x1),TRY(y1));
fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x0),TRY(y1));
fprintf(TEXFILE,"\\special{pa %d %d}",TRX(x0),TRY(y0));
switch(e1->pen){
case DASHPEN:
fprintf(TEXFILE,"\\special{da %6.3f}%%\n", e1->dashlen); break;
case DOTPEN:
fprintf(TEXFILE,"\\special{dt %6.3f}%%\n", e1->dashlen); break;
case SOLIDPEN:
default:
fprintf(TEXFILE,"\\special{fp}%%\n"); break;
}
}
void
circle(double xc, double yc, double r)
{
int rad = SCX(r);
fprintf(TEXFILE, " \\special{ar %d %d %d %d 0.0 6.2832}%%\n",
TRX(xc), TRY(yc), rad, rad);
}
void
closepl(void)
{
fprintf(TEXFILE, " \\kern %6.3fin\n }\\vss}%%\n", INCHES(e1->sidex));
fprintf(TEXFILE, " \\kern %6.3fin\n}\n", INCHES(e1->sidey));
}
void
disc(double xc, double yc, double r)
{
fprintf(TEXFILE, " \\special{bk}%%\n");
circle(xc, yc, r);
}
void
erase(void)
{
}
void
fill(int num[], double *ff[])
{
double *xp, *yp, **fp, x0, y0;
int i, *n;
n = num;
fp = ff;
while((i = *n++)){
xp = *fp++;
yp = xp+1;
x0 = *xp;
y0 = *yp;
move(x0, y0);
while(--i){
xp += 2;
yp += 2;
vec(*xp, *yp);
}
if (*(xp-2) != x0 || *(yp-2) != y0)
vec(x0, y0);
}
}
void
frame(double xs, double ys, double xf, double yf)
{
double osidex, osidey;
osidex = e1->sidex;
osidey = e1->sidey;
e1->left = xs * (e0->left + e0->sidex);
e1->bottom = ys* (e0->bottom + e0->sidey);
e1->sidex = (xf-xs) * e0->sidex;
e1->sidey = (yf-ys) * e0->sidey;
e1->scalex *= (e1->sidex / osidex);
e1->scaley *= (e1->sidey / osidey);
}
void
line(double x0, double y0, double x1, double y1)
{
move(x0, y0);
vec(x1, y1);
}
void
move(double xx, double yy)
{
e1->copyx = xx;
e1->copyy = yy;
}
extern double xmin, ymin, xmax, ymax;
/* tpic TeX coord system uses millinches, printer's points for pensize */
/* positive y downward, origin at upper left */
#define pHEIGHT 5000.
#define pWIDTH 5000.
#define pPENSIZE 9
#define pPSIZE 10
#define pDLEN .05
struct penvir E[2] = {
{0.,pHEIGHT,0.,0.,1.,-1.,pWIDTH,pHEIGHT,0.,0.,0,pPSIZE,SOLIDPEN,pPENSIZE,pDLEN},
{0.,pHEIGHT,0.,0.,1.,-1.,pWIDTH,pHEIGHT,0.,0.,0,pPSIZE,SOLIDPEN,pPENSIZE,pDLEN}
};
struct penvir *e0 = E, *e1 = &E[1];
FILE *TEXFILE;
void
openpl(void)
{
TEXFILE = stdout;
space(xmin, ymin, xmax, ymax);
fprintf(TEXFILE,"\\catcode`@=11\n");
fprintf(TEXFILE, "\\expandafter\\ifx\\csname graph\\endcsname\\relax");
fprintf(TEXFILE, " \\alloc@4\\box\\chardef\\insc@unt\\graph\\fi\n");
fprintf(TEXFILE, "\\catcode`@=12\n");
fprintf(TEXFILE, "\\setbox\\graph=\\vtop{%%\n");
fprintf(TEXFILE, " \\baselineskip=0pt \\lineskip=0pt ");
fprintf(TEXFILE, "\\lineskiplimit=0pt\n");
fprintf(TEXFILE, " \\vbox to0pt{\\hbox{%%\n");
fprintf(TEXFILE, " \\special{pn %d}%%\n", e1->pdiam);
}
void
range(double x0, double y0, double x1, double y1)
{
e1->xmin = x0;
e1->ymin = y0;
if (x1-x0 < .0000001*e1->sidex)
x1=x0+.0000001;
if (y1-y0 < .0000001*e1->sidey)
y1=y0+.0000001;
e1->scalex = e0->scalex*e1->sidex / (x1 - x0);
e1->scaley = e0->scaley*e1->sidey / (y1 - y0);
}
void
rmove(double xx, double yy)
{
e1->copyx += xx;
e1->copyy += yy;
}
void
rvec(double xx, double yy)
{
vec(xx+e1->copyx, yy+e1->copyy);
}
void
sbox(double x0, double y0, double x1, double y1)
{
fprintf(TEXFILE," \\special{bk}%%\n");
box(x0, y0, x1, y1);
}
void
vec(double xx, double yy)
{
fprintf(TEXFILE," \\special{pa %d %d}",TRX(e1->copyx),TRY(e1->copyy));
e1->copyx = xx;
e1->copyy = yy;
fprintf(TEXFILE,"\\special{pa %d %d}",TRX(xx),TRY(yy));
switch(e1->pen){
case DASHPEN:
fprintf(TEXFILE,"\\special{da %6.3f}%%\n", e1->dashlen); break;
case DOTPEN:
fprintf(TEXFILE,"\\special{dt %6.3f}%%\n", e1->dashlen); break;
case SOLIDPEN:
default:
fprintf(TEXFILE,"\\special{fp}%%\n"); break;
}
}

50
src/cmd/tpic/tex.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef BUFSIZE
#include <stdio.h>
#endif
#define SCX(A) (int)((A)*e1->scalex+0.5)
#define SCY(A) (int)((A)*e1->scaley+0.5)
#define TRX(A) (int)(((A) - e1->xmin)*e1->scalex + e1->left)
#define TRY(A) (int)(((A) - e1->ymin)*e1->scaley + e1->bottom)
#define DTRX(A) (((A) - e1->xmin)*e1->scalex + e1->left)
#define DTRY(A) (((A) - e1->ymin)*e1->scaley + e1->bottom)
#define INCHES(A) ((A)/1000.)
extern struct penvir {
double left, bottom;
double xmin, ymin;
double scalex, scaley;
double sidex, sidey;
double copyx, copyy;
char *font;
int psize;
int pen;
int pdiam;
double dashlen;
} *e0, *e1, *e2, *esave;
enum {
SOLIDPEN, DASHPEN, DOTPEN
};
extern FILE *TEXFILE;
#define round texround
extern int round();
void box(double x0, double y0, double x1, double y1) ;
void circle(double xc, double yc, double r);
void closepl(void);
void devarc(double x1, double y1, double x2, double y2, double xc, double yc, int r);
void disc(double xc, double yc, double r);
void erase(void);
void fill(int num[], double *ff[]);
void frame(double xs, double ys, double xf, double yf);
void line(double x0, double y0, double x1, double y1) ;
void move(double xx, double yy) ;
void openpl(void);
void pen(char *s) ;
void poly(int num[], double *ff[]);
void range(double x0, double y0, double x1, double y1) ;
void rmove(double xx, double yy) ;
void rvec(double xx, double yy) ;
void sbox(double x0, double y0, double x1, double y1) ;
void vec(double xx, double yy) ;
void space(double x0, double y0, double x1, double y1);

114
src/cmd/tpic/textgen.c Normal file
View file

@ -0,0 +1,114 @@
#include <stdio.h>
#include "pic.h"
#include "y.tab.h"
obj*
textgen(void)
{
int i, sub, nstr, at, with, hset;
double xwith, ywith, h, w, x0, y0, x1, y1;
obj *p, *ppos;
static double prevh = 0;
static double prevw = 0;
Attr *ap;
at = with = nstr = hset = 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 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_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;
prevh = h;
prevw = w;
return(p);
}
obj*
troffgen(char *s) /* save away a string of troff commands */
{
savetext(CENTER, s); /* use the existing text mechanism */
return makenode(TROFF, 0);
}
void
savetext(int t, char *s) /* record text elements for current object */
{
if (ntext >= ntextlist)
text = (Text *) grow((char *) text, "text", ntextlist += 200, sizeof(Text));
text[ntext].t_type = t;
text[ntext].t_val = s;
dprintf("saving %d text %s at %d\n", t, s, ntext);
ntext++;
}