svgpic: new program to convert pic to svg
This is an experiment. Like tpic it's a copy-and-paste fork of pic. Change-Id: Ia22772bd5881c7904a6d8f8e0b46fde8cea89cbd Reviewed-on: https://plan9port-review.googlesource.com/2920 Reviewed-by: Russ Cox <rsc@swtch.com>
This commit is contained in:
parent
a9530c00e8
commit
3ebbd193dc
19 changed files with 4034 additions and 0 deletions
|
|
@ -23,6 +23,11 @@ pic, tpic \- troff and tex preprocessors for drawing pictures
|
|||
[
|
||||
.I files
|
||||
]
|
||||
.PP
|
||||
.B svgpic
|
||||
[
|
||||
.I files
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Pic
|
||||
is a
|
||||
|
|
@ -306,6 +311,12 @@ The box may be output this way:
|
|||
.IP
|
||||
.L
|
||||
\ecenterline{\ebox\egraph}
|
||||
.PP
|
||||
.I Svgpic
|
||||
accepts
|
||||
.IR pic
|
||||
language and produces a Scalable Vector Graphics (SVG) image
|
||||
suitable for use in HTML documents.
|
||||
.SH EXAMPLES
|
||||
.EX
|
||||
arrow "input" above; box "process"; arrow "output" above
|
||||
|
|
@ -342,3 +353,7 @@ B. W. Kernighan,
|
|||
.I
|
||||
Unix Research System Programmer's Manual,
|
||||
Tenth Edition, Volume 2
|
||||
.SH BUGS
|
||||
.I Svgpic
|
||||
is only lightly tested.
|
||||
It should handle troff commands in text output.
|
||||
|
|
|
|||
224
src/cmd/svgpic/arcgen.c
Normal file
224
src/cmd/svgpic/arcgen.c
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "pic.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
void arc_extreme(double, double, double, double, double, double);
|
||||
int quadrant(double x, double y);
|
||||
|
||||
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, battr;
|
||||
obj *p, *ppos;
|
||||
double fromx, fromy, tox, toy, fillval = 0;
|
||||
Attr *ap;
|
||||
|
||||
tox=toy=0.0; /* Botch? (gcc) */
|
||||
|
||||
prevrad = getfval("arcrad");
|
||||
prevh = getfval("arrowht");
|
||||
prevw = getfval("arrowwid");
|
||||
fromx = curx;
|
||||
fromy = cury;
|
||||
head = to = at = cw = invis = ddtype = battr = 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;
|
||||
case FILL:
|
||||
battr |= FILLBIT;
|
||||
if (ap->a_sub == DEFAULT)
|
||||
fillval = getfval("fillval");
|
||||
else
|
||||
fillval = ap->a_val.f;
|
||||
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 | battr;
|
||||
p->o_fillval = fillval;
|
||||
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)
|
||||
/* start, end, center */
|
||||
{
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
226
src/cmd/svgpic/blockgen.c
Normal file
226
src/cmd/svgpic/blockgen.c
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.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;
|
||||
|
||||
void blockadj(obj *);
|
||||
|
||||
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 */
|
||||
if (xmin > xmax) /* nothing happened */
|
||||
xmin = xmax;
|
||||
if (ymin > ymax)
|
||||
ymin = ymax;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
115
src/cmd/svgpic/boxgen.c
Normal file
115
src/cmd/svgpic/boxgen.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#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 NOEDGE:
|
||||
battr |= NOEDGEBIT;
|
||||
break;
|
||||
case DOT:
|
||||
case DASH:
|
||||
battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
|
||||
if (ap->a_sub == DEFAULT)
|
||||
ddval = getfval("dashwid");
|
||||
else
|
||||
ddval = ap->a_val.f;
|
||||
break;
|
||||
case FILL:
|
||||
battr |= FILLBIT;
|
||||
if (ap->a_sub == DEFAULT)
|
||||
fillval = getfval("fillval");
|
||||
else
|
||||
fillval = ap->a_val.f;
|
||||
break;
|
||||
case TEXTATTR:
|
||||
savetext(ap->a_sub, ap->a_val.p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (with) {
|
||||
switch (with) {
|
||||
case NORTH: ywith = -h / 2; break;
|
||||
case SOUTH: ywith = h / 2; break;
|
||||
case EAST: xwith = -w / 2; break;
|
||||
case WEST: xwith = w / 2; break;
|
||||
case NE: xwith = -w / 2; ywith = -h / 2; break;
|
||||
case SE: xwith = -w / 2; ywith = h / 2; break;
|
||||
case NW: xwith = w / 2; ywith = -h / 2; break;
|
||||
case SW: xwith = w / 2; ywith = h / 2; break;
|
||||
}
|
||||
curx += xwith;
|
||||
cury += ywith;
|
||||
}
|
||||
if (!at) {
|
||||
if (isright(hvmode))
|
||||
curx += w / 2;
|
||||
else if (isleft(hvmode))
|
||||
curx -= w / 2;
|
||||
else if (isup(hvmode))
|
||||
cury += h / 2;
|
||||
else
|
||||
cury -= h / 2;
|
||||
}
|
||||
x0 = curx - w / 2;
|
||||
y0 = cury - h / 2;
|
||||
x1 = curx + w / 2;
|
||||
y1 = cury + h / 2;
|
||||
extreme(x0, y0);
|
||||
extreme(x1, y1);
|
||||
p = makenode(BOX, 2);
|
||||
p->o_val[0] = w;
|
||||
p->o_val[1] = h;
|
||||
p->o_attr = battr;
|
||||
p->o_ddval = ddval;
|
||||
p->o_fillval = fillval;
|
||||
dprintf("B %g %g %g %g at %g %g, h=%g, w=%g\n", x0, y0, x1, y1, curx, cury, h, w);
|
||||
if (isright(hvmode))
|
||||
curx = x1;
|
||||
else if (isleft(hvmode))
|
||||
curx = x0;
|
||||
else if (isup(hvmode))
|
||||
cury = y1;
|
||||
else
|
||||
cury = y0;
|
||||
prevh = h;
|
||||
prevw = w;
|
||||
return(p);
|
||||
}
|
||||
128
src/cmd/svgpic/circgen.c
Normal file
128
src/cmd/svgpic/circgen.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#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;
|
||||
|
||||
r = r2 = 0.0; /* Botch? (gcc) */
|
||||
|
||||
battr = at = 0;
|
||||
with = xwith = ywith = fillval = ddval = 0;
|
||||
t = (type == CIRCLE) ? 0 : 1;
|
||||
if (type == CIRCLE)
|
||||
r = r2 = getfval("circlerad");
|
||||
else if (type == ELLIPSE) {
|
||||
r = getfval("ellipsewid") / 2;
|
||||
r2 = getfval("ellipseht") / 2;
|
||||
}
|
||||
for (i = 0; i < nattr; i++) {
|
||||
ap = &attr[i];
|
||||
switch (ap->a_type) {
|
||||
case TEXTATTR:
|
||||
savetext(ap->a_sub, ap->a_val.p);
|
||||
break;
|
||||
case RADIUS:
|
||||
r = ap->a_val.f;
|
||||
break;
|
||||
case DIAMETER:
|
||||
case WIDTH:
|
||||
r = ap->a_val.f / 2;
|
||||
break;
|
||||
case HEIGHT:
|
||||
r2 = ap->a_val.f / 2;
|
||||
break;
|
||||
case SAME:
|
||||
r = rad[t];
|
||||
r2 = rad2[t];
|
||||
break;
|
||||
case WITH:
|
||||
with = ap->a_val.i;
|
||||
break;
|
||||
case AT:
|
||||
ppos = ap->a_val.o;
|
||||
curx = ppos->o_x;
|
||||
cury = ppos->o_y;
|
||||
at++;
|
||||
break;
|
||||
case INVIS:
|
||||
battr |= INVIS;
|
||||
break;
|
||||
case NOEDGE:
|
||||
battr |= NOEDGEBIT;
|
||||
break;
|
||||
case DOT:
|
||||
case DASH:
|
||||
battr |= ap->a_type==DOT ? DOTBIT : DASHBIT;
|
||||
if (ap->a_sub == DEFAULT)
|
||||
ddval = getfval("dashwid");
|
||||
else
|
||||
ddval = ap->a_val.f;
|
||||
break;
|
||||
case FILL:
|
||||
battr |= FILLBIT;
|
||||
if (ap->a_sub == DEFAULT)
|
||||
fillval = getfval("fillval");
|
||||
else
|
||||
fillval = ap->a_val.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
95
src/cmd/svgpic/for.c
Normal file
95
src/cmd/svgpic/for.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.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 setfval(char *, double);
|
||||
void nextfor(void);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
598
src/cmd/svgpic/input.c
Normal file
598
src/cmd/svgpic/input.c
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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 do_thru(void);
|
||||
int nextchar(void);
|
||||
int getarg(char *);
|
||||
void freedef(char *);
|
||||
int baldelim(int, char *);
|
||||
|
||||
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 ", (int)(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 ", (int) (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", (int) (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)
|
||||
{
|
||||
register 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)
|
||||
{
|
||||
register int c;
|
||||
|
||||
c = 0; /* Botch: gcc */
|
||||
|
||||
loop:
|
||||
switch (srcp->type) {
|
||||
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((unsigned char) *srcp->sp)) {
|
||||
int n = 0;
|
||||
while (isdigit((unsigned char) *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", (int) (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)
|
||||
{
|
||||
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 eprint(void);
|
||||
|
||||
void yyerror(char *s)
|
||||
{
|
||||
extern char *cmdname;
|
||||
int ern = errno; /* cause some libraries clobber it */
|
||||
|
||||
if (synerr)
|
||||
return;
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "%s: %s", cmdname, s);
|
||||
if (ern > 0) {
|
||||
errno = ern;
|
||||
perror("???");
|
||||
}
|
||||
fprintf(stderr, " near %s:%d\n",
|
||||
curfile->fname, curfile->lineno+1);
|
||||
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(char *);
|
||||
|
||||
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, "rc -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);
|
||||
}
|
||||
239
src/cmd/svgpic/linegen.c
Normal file
239
src/cmd/svgpic/linegen.c
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
#include <stdio.h>
|
||||
#include <math.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, battr, with;
|
||||
double ddval, chop1, chop2, x0, y0, x1, y1;
|
||||
double fillval = 0;
|
||||
double theta;
|
||||
double defx, defy, xwith, ywith;
|
||||
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 = battr = with = 0;
|
||||
chop = chop1 = chop2 = 0;
|
||||
ddtype = ddval = xwith = ywith = 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 NOEDGE:
|
||||
battr |= NOEDGEBIT;
|
||||
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;
|
||||
case WITH:
|
||||
with = ap->a_val.i;
|
||||
break;
|
||||
case CHOP:
|
||||
if (ap->a_sub != PLACENAME) {
|
||||
if( chop == 0)
|
||||
chop1 = chop2 = ap->a_val.f;
|
||||
else
|
||||
chop2 = 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 (with) { /* this doesn't work at all */
|
||||
switch (with) {
|
||||
case CENTER:
|
||||
xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break;
|
||||
}
|
||||
for (i = 0; i < ndxy; i++) {
|
||||
dx[i] -= xwith;
|
||||
dy[i] -= ywith;
|
||||
}
|
||||
curx += xwith;
|
||||
cury += ywith;
|
||||
}
|
||||
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 | battr;
|
||||
p->o_fillval = fillval;
|
||||
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);
|
||||
}
|
||||
283
src/cmd/svgpic/main.c
Normal file
283
src/cmd/svgpic/main.c
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pic.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
char *version = "version July 5, 1993";
|
||||
|
||||
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 */
|
||||
char *PEstring; /* "PS" or "PE" picked up by lexer */
|
||||
|
||||
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;
|
||||
|
||||
void fpecatch(int);
|
||||
void getdata(void), setdefaults(void);
|
||||
void setfval(char *, double);
|
||||
int getpid(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
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;
|
||||
fprintf(stderr, "%s\n", version);
|
||||
break;
|
||||
case 'V':
|
||||
fprintf(stderr, "%s\n", version);
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
return anyerr;
|
||||
}
|
||||
|
||||
void fpecatch(int n)
|
||||
{
|
||||
ERROR "floating point exception %d", n 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.7, 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;
|
||||
void reset(void), openpl(char *), closepl(char *), print(void);
|
||||
int yyparse(void);
|
||||
|
||||
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;
|
||||
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(&buf[3]); /* puts out .PS, with ht & wid stuck in */
|
||||
printlf(curfile->lineno+1, NULL);
|
||||
print(); /* assumes \n at end */
|
||||
closepl(PEstring); /* does the .PE/F */
|
||||
free(PEstring);
|
||||
}
|
||||
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;
|
||||
extern void freesymtab(struct symtab *);
|
||||
|
||||
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;
|
||||
PEstring = 0;
|
||||
hvmode = R_DIR;
|
||||
xmin = ymin = 30000;
|
||||
xmax = ymax = -30000;
|
||||
}
|
||||
441
src/cmd/svgpic/misc.c
Normal file
441
src/cmd/svgpic/misc.c
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "pic.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
int whatpos(obj *p, int corner, double *px, double *py);
|
||||
void makeattr(int type, int sub, YYSTYPE val);
|
||||
YYSTYPE getblk(obj *, char *);
|
||||
|
||||
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)
|
||||
{
|
||||
register char *p;
|
||||
|
||||
p = malloc(strlen(s)+1);
|
||||
if (p == NULL)
|
||||
ERROR "out of space in tostring on %s", s FATAL;
|
||||
strcpy(p, s);
|
||||
return(p);
|
||||
}
|
||||
|
||||
obj *makepos(double x, double y) /* make a position cell */
|
||||
{
|
||||
obj *p;
|
||||
|
||||
p = makenode(PLACE, 0);
|
||||
p->o_x = x;
|
||||
p->o_y = y;
|
||||
return(p);
|
||||
}
|
||||
|
||||
obj *makebetween(double f, obj *p1, obj *p2) /* make position between p1 and p2 */
|
||||
{
|
||||
obj *p;
|
||||
|
||||
dprintf("fraction = %.2f\n", f);
|
||||
p = makenode(PLACE, 0);
|
||||
p->o_x = p1->o_x + f * (p2->o_x - p1->o_x);
|
||||
p->o_y = p1->o_y + f * (p2->o_y - p1->o_y);
|
||||
return(p);
|
||||
}
|
||||
|
||||
obj *getpos(obj *p, int corner) /* find position of point */
|
||||
{
|
||||
double x, y;
|
||||
|
||||
whatpos(p, corner, &x, &y);
|
||||
return makepos(x, y);
|
||||
}
|
||||
|
||||
int whatpos(obj *p, int corner, double *px, double *py) /* what is the position (no side effect) */
|
||||
{
|
||||
double x, y, x1, y1;
|
||||
|
||||
x1 = y1 = 0.0; /* Botch? (gcc) */
|
||||
|
||||
dprintf("whatpos %p %d %d\n", (void*)p, p->o_type, corner);
|
||||
x = p->o_x;
|
||||
y = p->o_y;
|
||||
if (p->o_type != PLACE && p->o_type != MOVE) {
|
||||
x1 = p->o_val[0];
|
||||
y1 = p->o_val[1];
|
||||
}
|
||||
switch (p->o_type) {
|
||||
case PLACE:
|
||||
break;
|
||||
case BOX:
|
||||
case BLOCK:
|
||||
case TEXT:
|
||||
switch (corner) {
|
||||
case NORTH: y += y1 / 2; break;
|
||||
case SOUTH: y -= y1 / 2; break;
|
||||
case EAST: x += x1 / 2; break;
|
||||
case WEST: x -= x1 / 2; break;
|
||||
case NE: x += x1 / 2; y += y1 / 2; break;
|
||||
case SW: x -= x1 / 2; y -= y1 / 2; break;
|
||||
case SE: x += x1 / 2; y -= y1 / 2; break;
|
||||
case NW: x -= x1 / 2; y += y1 / 2; break;
|
||||
case START:
|
||||
if (p->o_type == BLOCK)
|
||||
return whatpos(objlist[(int)p->o_val[2]], START, px, py);
|
||||
case END:
|
||||
if (p->o_type == BLOCK)
|
||||
return whatpos(objlist[(int)p->o_val[3]], END, px, py);
|
||||
}
|
||||
break;
|
||||
case ARC:
|
||||
switch (corner) {
|
||||
case START:
|
||||
if (p->o_attr & CW_ARC) {
|
||||
x = p->o_val[2]; y = p->o_val[3];
|
||||
} else {
|
||||
x = x1; y = y1;
|
||||
}
|
||||
break;
|
||||
case END:
|
||||
if (p->o_attr & CW_ARC) {
|
||||
x = x1; y = y1;
|
||||
} else {
|
||||
x = p->o_val[2]; y = p->o_val[3];
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (corner == START || corner == END)
|
||||
break;
|
||||
x1 = y1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y));
|
||||
/* Fall Through! */
|
||||
case CIRCLE:
|
||||
case ELLIPSE:
|
||||
switch (corner) {
|
||||
case NORTH: y += y1; break;
|
||||
case SOUTH: y -= y1; break;
|
||||
case EAST: x += x1; break;
|
||||
case WEST: x -= x1; break;
|
||||
case NE: x += 0.707 * x1; y += 0.707 * y1; break;
|
||||
case SE: x += 0.707 * x1; y -= 0.707 * y1; break;
|
||||
case NW: x -= 0.707 * x1; y += 0.707 * y1; break;
|
||||
case SW: x -= 0.707 * x1; y -= 0.707 * y1; break;
|
||||
}
|
||||
break;
|
||||
case LINE:
|
||||
case SPLINE:
|
||||
case ARROW:
|
||||
switch (corner) {
|
||||
case START: break; /* already in place */
|
||||
case END: x = x1; y = y1; break;
|
||||
default: /* change! */
|
||||
case CENTER: x = (x+x1)/2; y = (y+y1)/2; break;
|
||||
case NORTH: if (y1 > y) { x = x1; y = y1; } break;
|
||||
case SOUTH: if (y1 < y) { x = x1; y = y1; } break;
|
||||
case EAST: if (x1 > x) { x = x1; y = y1; } break;
|
||||
case WEST: if (x1 < x) { x = x1; y = y1; } break;
|
||||
}
|
||||
break;
|
||||
case MOVE:
|
||||
/* really ought to be same as line... */
|
||||
break;
|
||||
}
|
||||
dprintf("whatpos returns %g %g\n", x, y);
|
||||
*px = x;
|
||||
*py = y;
|
||||
return 1;
|
||||
}
|
||||
|
||||
obj *gethere(void) /* make a place for curx,cury */
|
||||
{
|
||||
dprintf("gethere %g %g\n", curx, cury);
|
||||
return(makepos(curx, cury));
|
||||
}
|
||||
|
||||
obj *getlast(int n, int t) /* find n-th previous occurrence of type t */
|
||||
{
|
||||
int i, k;
|
||||
obj *p;
|
||||
|
||||
k = n;
|
||||
for (i = nobj-1; i >= 0; i--) {
|
||||
p = objlist[i];
|
||||
if (p->o_type == BLOCKEND) {
|
||||
i = p->o_val[4];
|
||||
continue;
|
||||
}
|
||||
if (p->o_type != t)
|
||||
continue;
|
||||
if (--k > 0)
|
||||
continue; /* not there yet */
|
||||
dprintf("got a last of x,y= %g,%g\n", p->o_x, p->o_y);
|
||||
return(p);
|
||||
}
|
||||
ERROR "there is no %dth last", n WARNING;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
obj *getfirst(int n, int t) /* find n-th occurrence of type t */
|
||||
{
|
||||
int i, k;
|
||||
obj *p;
|
||||
|
||||
k = n;
|
||||
for (i = 0; i < nobj; i++) {
|
||||
p = objlist[i];
|
||||
if (p->o_type == BLOCK && t != BLOCK) { /* skip whole block */
|
||||
i = p->o_val[5] + 1;
|
||||
continue;
|
||||
}
|
||||
if (p->o_type != t)
|
||||
continue;
|
||||
if (--k > 0)
|
||||
continue; /* not there yet */
|
||||
dprintf("got a first of x,y= %g,%g\n", p->o_x, p->o_y);
|
||||
return(p);
|
||||
}
|
||||
ERROR "there is no %dth ", n WARNING;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
double getblkvar(obj *p, char *s) /* find variable s2 in block p */
|
||||
{
|
||||
YYSTYPE y;
|
||||
|
||||
y = getblk(p, s);
|
||||
return y.f;
|
||||
}
|
||||
|
||||
obj *getblock(obj *p, char *s) /* find variable s in block p */
|
||||
{
|
||||
YYSTYPE y;
|
||||
|
||||
y = getblk(p, s);
|
||||
return y.o;
|
||||
}
|
||||
|
||||
YYSTYPE getblk(obj *p, char *s) /* find union type for s in p */
|
||||
{
|
||||
static YYSTYPE bug;
|
||||
struct symtab *stp;
|
||||
|
||||
if (p->o_type != BLOCK) {
|
||||
ERROR ".%s is not in that block", s WARNING;
|
||||
return(bug);
|
||||
}
|
||||
for (stp = p->o_symtab; stp != NULL; stp = stp->s_next)
|
||||
if (strcmp(s, stp->s_name) == 0) {
|
||||
dprintf("getblk %s found x,y= %g,%g\n",
|
||||
s, (stp->s_val.o)->o_x, (stp->s_val.o)->o_y);
|
||||
return(stp->s_val);
|
||||
}
|
||||
ERROR "there is no .%s in that []", s WARNING;
|
||||
return(bug);
|
||||
}
|
||||
|
||||
obj *fixpos(obj *p, double x, double y)
|
||||
{
|
||||
dprintf("fixpos returns %g %g\n", p->o_x + x, p->o_y + y);
|
||||
return makepos(p->o_x + x, p->o_y + y);
|
||||
}
|
||||
|
||||
obj *addpos(obj *p, obj *q)
|
||||
{
|
||||
dprintf("addpos returns %g %g\n", p->o_x+q->o_x, p->o_y+q->o_y);
|
||||
return makepos(p->o_x+q->o_x, p->o_y+q->o_y);
|
||||
}
|
||||
|
||||
obj *subpos(obj *p, obj *q)
|
||||
{
|
||||
dprintf("subpos returns %g %g\n", p->o_x-q->o_x, p->o_y-q->o_y);
|
||||
return makepos(p->o_x-q->o_x, p->o_y-q->o_y);
|
||||
}
|
||||
|
||||
obj *makenode(int type, int n)
|
||||
{
|
||||
obj *p;
|
||||
|
||||
p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(ofloat));
|
||||
if (p == NULL)
|
||||
ERROR "out of space in makenode" FATAL;
|
||||
p->o_type = type;
|
||||
p->o_count = n;
|
||||
p->o_nobj = nobj;
|
||||
p->o_mode = hvmode;
|
||||
p->o_x = curx;
|
||||
p->o_y = cury;
|
||||
p->o_nt1 = ntext1;
|
||||
p->o_nt2 = ntext;
|
||||
ntext1 = ntext; /* ready for next caller */
|
||||
if (nobj >= nobjlist)
|
||||
objlist = (obj **) grow((char *) objlist, "objlist",
|
||||
nobjlist *= 2, sizeof(obj *));
|
||||
objlist[nobj++] = p;
|
||||
return(p);
|
||||
}
|
||||
|
||||
void extreme(double x, double y) /* record max and min x and y values */
|
||||
{
|
||||
if (x > xmax)
|
||||
xmax = x;
|
||||
if (y > ymax)
|
||||
ymax = y;
|
||||
if (x < xmin)
|
||||
xmin = x;
|
||||
if (y < ymin)
|
||||
ymin = y;
|
||||
}
|
||||
36
src/cmd/svgpic/mkfile
Normal file
36
src/cmd/svgpic/mkfile
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<$PLAN9/src/mkhdr
|
||||
|
||||
TARG=svgpic
|
||||
OFILES=picy.$O\
|
||||
picl.$O\
|
||||
main.$O\
|
||||
print.$O\
|
||||
misc.$O\
|
||||
symtab.$O\
|
||||
blockgen.$O\
|
||||
boxgen.$O\
|
||||
circgen.$O\
|
||||
arcgen.$O\
|
||||
linegen.$O\
|
||||
movegen.$O\
|
||||
textgen.$O\
|
||||
input.$O\
|
||||
for.$O\
|
||||
plsvg.$O\
|
||||
|
||||
HFILES=pic.h\
|
||||
y.tab.h\
|
||||
|
||||
YFILES=picy.y\
|
||||
|
||||
<$PLAN9/src/mkone
|
||||
YFLAGS=-S -d
|
||||
|
||||
picy.c: y.tab.c
|
||||
mv $prereq $target
|
||||
|
||||
picl.c:D: picl.lx
|
||||
$LEX -t $prereq > $target
|
||||
|
||||
clean:V:
|
||||
rm -f *.[$OS] [$OS].out y.tab.? y.debug $TARG picy.c picl.c
|
||||
86
src/cmd/svgpic/movegen.c
Normal file
86
src/cmd/svgpic/movegen.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#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);
|
||||
}
|
||||
222
src/cmd/svgpic/pic.h
Normal file
222
src/cmd/svgpic/pic.h
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
#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 void yyerror(char *);
|
||||
|
||||
extern char errbuf[200];
|
||||
|
||||
#undef sprintf /* Snow Leopard */
|
||||
|
||||
#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 NOEDGEBIT 128 /* no edge on filled object */
|
||||
|
||||
#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 char *PEstring;
|
||||
|
||||
char *tostring(char *);
|
||||
char *grow(char *, char *, int, int);
|
||||
double getfval(char *), getcomp(obj *, int), getblkvar(obj *, char *);
|
||||
YYSTYPE getvar(char *);
|
||||
struct symtab *lookup(char *), *makevar(char *, int, YYSTYPE);
|
||||
char *ifstat(double, char *, char *), *delimstr(char *), *sprintgen(char *);
|
||||
void forloop(char *var, double from, double to, int op, double by, char *_str);
|
||||
int setdir(int), curdir(void);
|
||||
void resetvar(void);
|
||||
void checkscale(char *);
|
||||
void pushsrc(int, char *);
|
||||
void copy(void);
|
||||
void copyuntil(char *);
|
||||
void copyfile(char *);
|
||||
void copydef(struct symtab *);
|
||||
void definition(char *);
|
||||
struct symtab *copythru(char *);
|
||||
int input(void);
|
||||
int unput(int);
|
||||
void extreme(double, double);
|
||||
|
||||
extern double deltx, delty;
|
||||
extern int lineno;
|
||||
extern int synerr;
|
||||
|
||||
extern double xmin, ymin, xmax, ymax;
|
||||
|
||||
obj *leftthing(int), *boxgen(void), *circgen(int), *arcgen(int);
|
||||
obj *linegen(int), *splinegen(void), *movegen(void);
|
||||
obj *textgen(void), *plotgen(void);
|
||||
obj *troffgen(char *), *rightthing(obj *, int), *blockgen(obj *, obj *);
|
||||
obj *makenode(int, int), *makepos(double, double);
|
||||
obj *fixpos(obj *, double, double);
|
||||
obj *addpos(obj *, obj *), *subpos(obj *, obj *);
|
||||
obj *makebetween(double, obj *, obj *);
|
||||
obj *getpos(obj *, int), *gethere(void), *getfirst(int, int);
|
||||
obj *getlast(int, int), *getblock(obj *, char *);
|
||||
void savetext(int, char *);
|
||||
void makeiattr(int, int);
|
||||
void makevattr(char *);
|
||||
void makefattr(int type, int sub, double f);
|
||||
void maketattr(int, char *);
|
||||
void makeoattr(int, obj *);
|
||||
void makeattr(int type, int sub, YYSTYPE val);
|
||||
void printexpr(double);
|
||||
void printpos(obj *);
|
||||
void exprsave(double);
|
||||
void addtattr(int);
|
||||
void printlf(int, char *);
|
||||
|
||||
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;
|
||||
|
||||
extern double errcheck(double, char *);
|
||||
#define Log10(x) errcheck(log10(x), "log")
|
||||
#define Exp(x) errcheck(exp(x), "exp")
|
||||
#define Sqrt(x) errcheck(sqrt(x), "sqrt")
|
||||
273
src/cmd/svgpic/picl.lx
Normal file
273
src/cmd/svgpic/picl.lx
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
%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> lex puts one out for us */
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include "pic.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
extern char *filename;
|
||||
extern struct symtab symtab[];
|
||||
|
||||
void pbstr(char *);
|
||||
void dodef(struct symtab *stp);
|
||||
void undefine(char *s);
|
||||
void shell_init(void), shell_exec(void), shell_text(char *);
|
||||
void endfor(void);
|
||||
|
||||
int yyback(int *, int);
|
||||
int yylook(void);
|
||||
int yywrap(void);
|
||||
|
||||
#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>"{"{WS}*(#.*)?\n+ { return(yylval.i = yytext[0]); }
|
||||
|
||||
<A>^".PS".* { if (curfile == infile) ERROR ".PS found inside .PS/.PE" WARNING; }
|
||||
<A>^".PE".* { if (curfile == infile) {
|
||||
yylval.p = PEstring = tostring(yytext);
|
||||
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>noedge { 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((unsigned char)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>"\\"t { cbuf[clen++]='\t'; }
|
||||
<str>"\\\\" { cbuf[clen++]='\\'; }
|
||||
<str>. { CADD; }
|
||||
|
||||
<A>#.* ;
|
||||
|
||||
<A>. return(yylval.i = yytext[0]);
|
||||
|
||||
%%
|
||||
328
src/cmd/svgpic/picy.y
Normal file
328
src/cmd/svgpic/picy.y
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
%{
|
||||
#include <stdio.h>
|
||||
#include "pic.h"
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
YYSTYPE y;
|
||||
|
||||
extern void yyerror(char *);
|
||||
extern 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 NOEDGE
|
||||
%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); }
|
||||
| CHOP PLACENAME { makeattr(CHOP, PLACENAME, getvar($2)); }
|
||||
| FILL expr { makefattr(FILL, !DEFAULT, $2); }
|
||||
| FILL { makefattr(FILL, DEFAULT, 0.0); }
|
||||
| NOEDGE { makeiattr(NOEDGE, 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 %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; }
|
||||
;
|
||||
328
src/cmd/svgpic/plsvg.c
Normal file
328
src/cmd/svgpic/plsvg.c
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "pic.h"
|
||||
extern int dbg;
|
||||
|
||||
#define abs(n) (n >= 0 ? n : -(n))
|
||||
#define max(x,y) ((x)>(y) ? (x) : (y))
|
||||
|
||||
char *textshift = "\\v'.2m'"; /* move text this far down */
|
||||
|
||||
/* scaling stuff defined by s command as X0,Y0 to X1,Y1 */
|
||||
/* output dimensions set by -l,-w options to 0,0 to hmax, vmax */
|
||||
/* default output is 6x6 inches */
|
||||
|
||||
|
||||
double xscale;
|
||||
double yscale;
|
||||
|
||||
double hpos = 0; /* current horizontal position in output coordinate system */
|
||||
double vpos = 0; /* current vertical position; 0 is top of page */
|
||||
|
||||
double htrue = 0; /* where we really are */
|
||||
double vtrue = 0;
|
||||
|
||||
double X0, Y0; /* left bottom of input */
|
||||
double X1, Y1; /* right top of input */
|
||||
|
||||
double hmax; /* right end of output */
|
||||
double vmax; /* top of output (down is positive) */
|
||||
|
||||
extern double deltx;
|
||||
extern double delty;
|
||||
extern double xmin, ymin, xmax, ymax;
|
||||
|
||||
double xconv(double), yconv(double), xsc(double), ysc(double);
|
||||
void space(double, double, double, double);
|
||||
void hgoto(double), vgoto(double), hmot(double), vmot(double);
|
||||
void move(double, double), movehv(double, double);
|
||||
|
||||
char svgfill[40] = "transparent";
|
||||
char svgstroke[40] = "black";
|
||||
|
||||
void openpl(char *s) /* initialize device; s is residue of .PS invocation line */
|
||||
{
|
||||
double maxw, maxh, ratio = 1;
|
||||
double odeltx = deltx, odelty = delty;
|
||||
|
||||
hpos = vpos = 0;
|
||||
maxw = getfval("maxpswid");
|
||||
maxh = getfval("maxpsht");
|
||||
if (deltx > maxw) { /* shrink horizontal */
|
||||
ratio = maxw / deltx;
|
||||
deltx *= ratio;
|
||||
delty *= ratio;
|
||||
}
|
||||
if (delty > maxh) { /* shrink vertical */
|
||||
ratio = maxh / delty;
|
||||
deltx *= ratio;
|
||||
delty *= ratio;
|
||||
}
|
||||
if (ratio != 1) {
|
||||
fprintf(stderr, "pic: %g X %g picture shrunk to", odeltx, odelty);
|
||||
fprintf(stderr, " %g X %g\n", deltx, delty);
|
||||
}
|
||||
space(xmin, ymin, xmax, ymax);
|
||||
|
||||
printf("<svg height=\"%.3f\" width=\"%.3f\"\n", yconv(ymin)+10, xconv(xmax)+10);
|
||||
printf(" xmlns=\"http://www.w3.org/2000/svg\">\n");
|
||||
printf("<g transform=\"translate(5 5)\">\n");
|
||||
|
||||
/*
|
||||
printf("... %g %g %g %g\n", xmin, ymin, xmax, ymax);
|
||||
printf("... %.3fi %.3fi %.3fi %.3fi\n",
|
||||
xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax));
|
||||
printf(".nr 00 \\n(.u\n");
|
||||
printf(".nf\n");
|
||||
printf(".PS %.3fi %.3fi %s", yconv(ymin), xconv(xmax), s);
|
||||
*/
|
||||
}
|
||||
|
||||
void space(double x0, double y0, double x1, double y1) /* set limits of page */
|
||||
{
|
||||
X0 = x0;
|
||||
Y0 = y0;
|
||||
X1 = x1;
|
||||
Y1 = y1;
|
||||
xscale = deltx == 0.0 ? 1.0 : deltx / (X1-X0);
|
||||
yscale = delty == 0.0 ? 1.0 : delty / (Y1-Y0);
|
||||
|
||||
xscale *= 144;
|
||||
yscale *= 144;
|
||||
}
|
||||
|
||||
double xconv(double x) /* convert x from external to internal form */
|
||||
{
|
||||
return (x-X0) * xscale;
|
||||
}
|
||||
|
||||
double xsc(double x) /* convert x from external to internal form, scaling only */
|
||||
{
|
||||
|
||||
return (x) * xscale;
|
||||
}
|
||||
|
||||
double yconv(double y) /* convert y from external to internal form */
|
||||
{
|
||||
return (Y1-y) * yscale;
|
||||
}
|
||||
|
||||
double ysc(double y) /* convert y from external to internal form, scaling only */
|
||||
{
|
||||
return (y) * yscale;
|
||||
}
|
||||
|
||||
void closepl(char *PEline) /* clean up after finished */
|
||||
{
|
||||
printf("</g>\n");
|
||||
printf("</svg>\n");
|
||||
}
|
||||
|
||||
void move(double x, double y) /* go to position x, y in external coords */
|
||||
{
|
||||
hgoto(xconv(x));
|
||||
vgoto(yconv(y));
|
||||
}
|
||||
|
||||
void movehv(double h, double v) /* go to internal position h, v */
|
||||
{
|
||||
hgoto(h);
|
||||
vgoto(v);
|
||||
}
|
||||
|
||||
void hmot(double n) /* generate n units of horizontal motion */
|
||||
{
|
||||
hpos += n;
|
||||
}
|
||||
|
||||
void vmot(double n) /* generate n units of vertical motion */
|
||||
{
|
||||
vpos += n;
|
||||
}
|
||||
|
||||
void hgoto(double n)
|
||||
{
|
||||
hpos = n;
|
||||
}
|
||||
|
||||
void vgoto(double n)
|
||||
{
|
||||
vpos = n;
|
||||
}
|
||||
|
||||
void hvflush(void) /* get to proper point for output */
|
||||
{
|
||||
/*
|
||||
if (fabs(hpos-htrue) >= 0.0005) {
|
||||
printf("\\h'%.3fi'", hpos - htrue);
|
||||
htrue = hpos;
|
||||
}
|
||||
if (fabs(vpos-vtrue) >= 0.0005) {
|
||||
printf("\\v'%.3fi'", vpos - vtrue);
|
||||
vtrue = vpos;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void printlf(int n, char *f)
|
||||
{
|
||||
}
|
||||
|
||||
void troff(char *s) /* output troff right here */
|
||||
{
|
||||
printf("%s\n", s);
|
||||
}
|
||||
|
||||
void label(char *s, int t, int nh) /* text s of type t nh half-lines up */
|
||||
{
|
||||
char *anchor;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
if (t & ABOVE)
|
||||
nh++;
|
||||
else if (t & BELOW)
|
||||
nh--;
|
||||
t &= ~(ABOVE|BELOW);
|
||||
anchor = 0;
|
||||
if (t & LJUST) {
|
||||
// default
|
||||
} else if (t & RJUST) {
|
||||
anchor = "end";
|
||||
} else { /* CENTER */
|
||||
anchor = "middle";
|
||||
}
|
||||
printf("<text x=\"%.3f\" y=\"%.3f\"", hpos, vpos-(double)(nh-0.4)*(12.0/72)/2*144);
|
||||
if(anchor)
|
||||
printf(" text-anchor=\"%s\"", anchor);
|
||||
printf(">%s</text>\n", s);
|
||||
}
|
||||
|
||||
void line(double x0, double y0, double x1, double y1, int attr, double ddval) /* draw line from x0,y0 to x1,y1 */
|
||||
{
|
||||
printf("<path d=\"M %.3f %.3f L %.3f %.3f\" fill=\"transparent\" stroke=\"black\"", xconv(x0), yconv(y0), xconv(x1), yconv(y1));
|
||||
if(attr & DASHBIT)
|
||||
printf(" stroke-dasharray=\"%.3f, %.3f\"", xsc(ddval), xsc(ddval));
|
||||
else if(attr & DOTBIT)
|
||||
printf(" stroke-dasharray=\"1, %.3f\"", xsc(ddval));
|
||||
printf("/>\n");
|
||||
}
|
||||
|
||||
void arrow(double x0, double y0, double x1, double y1, double w, double h,
|
||||
double ang, int nhead) /* draw arrow (without shaft) */
|
||||
{
|
||||
double alpha, rot, drot, hyp;
|
||||
double 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;
|
||||
dprintf("rot=%g, hyp=%g, alpha=%g\n", rot, hyp, alpha);
|
||||
printf("<path d=\"");
|
||||
for (i = 1; i >= 0; i--) {
|
||||
drot = 2 * rot / (double) (2-1) * (double) i;
|
||||
dx = hyp * cos(alpha + PI - rot + drot);
|
||||
dy = hyp * sin(alpha + PI - rot + drot);
|
||||
dprintf("dx,dy = %g,%g\n", dx, dy);
|
||||
if(i == 1)
|
||||
printf("M %.3f %.3f L %.3f %.3f", xconv(x1+dx), yconv(y1+dy), xconv(x1), yconv(y1));
|
||||
else
|
||||
printf(" L %.3f %.3f", xconv(x1+dx), yconv(y1+dy));
|
||||
}
|
||||
if (nhead > 2)
|
||||
printf(" Z");
|
||||
printf("\"");
|
||||
if(nhead > 3)
|
||||
printf(" fill=\"black\" stroke=\"black\"");
|
||||
else if(nhead == 3)
|
||||
printf(" fill=\"white\" stroke=\"black\"");
|
||||
else
|
||||
printf(" fill=\"transparent\" stroke=\"black\"");
|
||||
printf("/>\n");
|
||||
}
|
||||
|
||||
double lastgray = 0;
|
||||
|
||||
void fillstart(double v, int vis, int fill)
|
||||
{
|
||||
int x;
|
||||
|
||||
if(fill) {
|
||||
x = (int)(v*255.0);
|
||||
sprintf(svgfill, "#%02x%02x%02x", x, x, x);
|
||||
} else
|
||||
strcpy(svgfill, "transparent");
|
||||
if(vis)
|
||||
strcpy(svgstroke, "black");
|
||||
else
|
||||
strcpy(svgstroke, "transparent");
|
||||
}
|
||||
|
||||
void fillend(void)
|
||||
{
|
||||
strcpy(svgfill, "transparent");
|
||||
strcpy(svgstroke, "black");
|
||||
}
|
||||
|
||||
void box(double x0, double y0, double x1, double y1, int attr, double ddval)
|
||||
{
|
||||
printf("<path d=\"M %.3f %.3f V %.3f H %.3f V %.3f Z\" fill=\"transparent\" stroke=\"black\"", xconv(x0), yconv(y0), yconv(y1), xconv(x1), yconv(y0));
|
||||
if(attr & DASHBIT)
|
||||
printf(" stroke-dasharray=\"%.3f, %.3f\"", xsc(ddval), xsc(ddval));
|
||||
else if(attr & DOTBIT)
|
||||
printf(" stroke-dasharray=\"1, %.3f\"", xsc(ddval));
|
||||
printf("/>\n");
|
||||
|
||||
}
|
||||
|
||||
void circle(double x, double y, double r)
|
||||
{
|
||||
printf("<circle cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\" fill=\"%s\" stroke=\"%s\"/>\n", xconv(x), yconv(y), xsc(r), svgfill, svgstroke);
|
||||
}
|
||||
|
||||
void spline(double x, double y, double n, ofloat *p, int attr, double ddval)
|
||||
{
|
||||
int i;
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
printf("<path d=\"M %.3f %.3f", xconv(x), yconv(y));
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
for (i = 0; i < 2 * n; i += 2) {
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
x += p[i];
|
||||
y += p[i+1];
|
||||
if(i == 0)
|
||||
printf(" L %.3f %.3f", xconv((x+x1)/2), yconv((y+y1)/2));
|
||||
else
|
||||
printf(" Q %.3f %.3f %.3f %.3f", xconv(x1), yconv(y1), xconv((x+x1)/2), yconv((y+y1)/2));
|
||||
}
|
||||
printf(" L %.3f %.3f", xconv(x), yconv(y));
|
||||
printf("\" fill=\"%s\" stroke=\"%s\"", svgfill, svgstroke);
|
||||
if(attr & DASHBIT)
|
||||
printf(" stroke-dasharray=\"%.3f, %.3f\"", xsc(ddval), xsc(ddval));
|
||||
else if(attr & DOTBIT)
|
||||
printf(" stroke-dasharray=\"1, %.3f\"", xsc(ddval));
|
||||
printf("/>\n");
|
||||
}
|
||||
|
||||
void ellipse(double x, double y, double r1, double r2)
|
||||
{
|
||||
printf("<ellipse cx=\"%.3f\" cy=\"%.3f\" rx=\"%.3f\" ry=\"%.3f\" fill=\"%s\" stroke=\"%s\"/>\n", xconv(x), yconv(y), xsc(r1), ysc(r2), svgfill, svgstroke);
|
||||
}
|
||||
|
||||
void arc(double x, double y, double x0, double y0, double x1, double y1, double r) /* draw arc with center x,y */
|
||||
{
|
||||
printf("<path d=\"M %.3f %.3f A %.3f %.3f %d %d %d %.3f %.3f\" fill=\"%s\" stroke=\"%s\"/>\n",
|
||||
xconv(x0), yconv(y0),
|
||||
xsc(r), ysc(r), 0, 0, 0, xconv(x1), yconv(y1),
|
||||
svgfill, svgstroke);
|
||||
}
|
||||
182
src/cmd/svgpic/print.c
Normal file
182
src/cmd/svgpic/print.c
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "pic.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
void dotext(obj *);
|
||||
void ellipse(double, double, double, double);
|
||||
void circle(double, double, double);
|
||||
void arc(double, double, double, double, double, double, double);
|
||||
void arrow(double, double, double, double, double, double, double, int);
|
||||
void line(double, double, double, double, int, double);
|
||||
void box(double, double, double, double, int, double);
|
||||
void spline(double x, double y, double n, ofloat *p, int dashed, double ddval);
|
||||
void move(double, double);
|
||||
void troff(char *);
|
||||
void dot(void);
|
||||
void fillstart(double, int, int), fillend(void);
|
||||
|
||||
void print(void)
|
||||
{
|
||||
obj *p;
|
||||
int i, j, k, m;
|
||||
int fill, vis, invis;
|
||||
double x0, y0, x1, y1, ox, oy, dx, dy, ndx, ndy;
|
||||
|
||||
x1 = y1 = 0.0; /* Botch? (gcc) */
|
||||
|
||||
for (i = 0; i < nobj; i++) {
|
||||
p = objlist[i];
|
||||
ox = p->o_x;
|
||||
oy = p->o_y;
|
||||
if (p->o_count >= 1)
|
||||
x1 = p->o_val[0];
|
||||
if (p->o_count >= 2)
|
||||
y1 = p->o_val[1];
|
||||
m = p->o_mode;
|
||||
fill = p->o_attr & FILLBIT;
|
||||
invis = p->o_attr & INVIS;
|
||||
vis = !invis;
|
||||
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 (fill) {
|
||||
move(x0, y0);
|
||||
fillstart(p->o_fillval, vis, fill);
|
||||
}
|
||||
if (p->o_type == BLOCK)
|
||||
; /* nothing at all */
|
||||
else if (invis && !fill)
|
||||
; /* nothing at all */
|
||||
else
|
||||
box(x0, y0, x1, y1, p->o_attr & (DOTBIT|DASHBIT), p->o_ddval);
|
||||
if (fill)
|
||||
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 (fill)
|
||||
fillstart(p->o_fillval, vis, fill);
|
||||
if (vis || fill)
|
||||
circle(ox, oy, x1);
|
||||
if (fill)
|
||||
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 (fill)
|
||||
fillstart(p->o_fillval, vis, fill);
|
||||
if (vis || fill)
|
||||
ellipse(ox, oy, x1, y1);
|
||||
if (fill)
|
||||
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:
|
||||
if (fill) {
|
||||
move(ox, oy);
|
||||
fillstart(p->o_fillval, vis, fill);
|
||||
}
|
||||
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 (invis && !fill)
|
||||
/* probably wrong when it's cw */
|
||||
move(x1, y1);
|
||||
else
|
||||
arc(ox, oy, x1, y1, p->o_val[2], p->o_val[3], p->o_val[6]);
|
||||
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 (fill)
|
||||
fillend();
|
||||
if (p->o_attr & CW_ARC)
|
||||
move(x1, y1); /* because drawn backwards */
|
||||
move(ox, oy);
|
||||
dotext(p);
|
||||
break;
|
||||
case LINE:
|
||||
case ARROW:
|
||||
case SPLINE:
|
||||
if (fill) {
|
||||
move(ox, oy);
|
||||
fillstart(p->o_fillval, vis, fill);
|
||||
}
|
||||
if (vis && 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 (invis && !fill)
|
||||
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];
|
||||
line(dx, dy, ndx, ndy, p->o_attr & (DOTBIT|DASHBIT), p->o_ddval);
|
||||
dx = ndx;
|
||||
dy = ndy;
|
||||
}
|
||||
}
|
||||
if (vis && 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);
|
||||
}
|
||||
if (fill)
|
||||
fillend();
|
||||
move((ox + x1)/2, (oy + y1)/2); /* center */
|
||||
dotext(p);
|
||||
break;
|
||||
case MOVE:
|
||||
move(ox, oy);
|
||||
break;
|
||||
case TEXT:
|
||||
move(ox, oy);
|
||||
if (vis)
|
||||
dotext(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dotext(obj *p) /* print text strings of p in proper vertical spacing */
|
||||
{
|
||||
int i, nhalf;
|
||||
void label(char *, int, int);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
104
src/cmd/svgpic/symtab.c
Normal file
104
src/cmd/svgpic/symtab.c
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.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((int) 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; */
|
||||
}
|
||||
111
src/cmd/svgpic/textgen.c
Normal file
111
src/cmd/svgpic/textgen.c
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#include <stdio.h>
|
||||
#include "pic.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
obj *textgen(void)
|
||||
{
|
||||
int i, sub, nstr, at, with, hset, invis;
|
||||
double xwith, ywith, h, w, x0, y0, x1, y1;
|
||||
obj *p, *ppos;
|
||||
Attr *ap;
|
||||
|
||||
at = with = nstr = hset = invis = 0;
|
||||
h = getfval("textht");
|
||||
w = getfval("textwid");
|
||||
for (i = 0; i < nattr; i++) {
|
||||
ap = &attr[i];
|
||||
switch (ap->a_type) {
|
||||
case HEIGHT:
|
||||
h = ap->a_val.f;
|
||||
hset++;
|
||||
break;
|
||||
case WIDTH:
|
||||
w = ap->a_val.f;
|
||||
break;
|
||||
case WITH:
|
||||
with = ap->a_val.i;
|
||||
break;
|
||||
case INVIS:
|
||||
invis = INVIS;
|
||||
break;
|
||||
case AT:
|
||||
ppos = ap->a_val.o;
|
||||
curx = ppos->o_x;
|
||||
cury = ppos->o_y;
|
||||
at++;
|
||||
break;
|
||||
case TEXTATTR:
|
||||
sub = ap->a_sub;
|
||||
if (ap->a_val.p == NULL) /* an isolated modifier */
|
||||
text[ntext-1].t_type = sub;
|
||||
else {
|
||||
savetext(sub, ap->a_val.p);
|
||||
nstr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hset == 0) /* no explicit ht cmd */
|
||||
h *= nstr;
|
||||
if (with) {
|
||||
xwith = ywith = 0.0;
|
||||
switch (with) {
|
||||
case NORTH: ywith = -h / 2; break;
|
||||
case SOUTH: ywith = h / 2; break;
|
||||
case EAST: xwith = -w / 2; break;
|
||||
case WEST: xwith = w / 2; break;
|
||||
case NE: xwith = -w / 2; ywith = -h / 2; break;
|
||||
case SE: xwith = -w / 2; ywith = h / 2; break;
|
||||
case NW: xwith = w / 2; ywith = -h / 2; break;
|
||||
case SW: xwith = w / 2; ywith = h / 2; break;
|
||||
}
|
||||
curx += xwith;
|
||||
cury += ywith;
|
||||
}
|
||||
if (!at) {
|
||||
if (isright(hvmode))
|
||||
curx += w / 2;
|
||||
else if (isleft(hvmode))
|
||||
curx -= w / 2;
|
||||
else if (isup(hvmode))
|
||||
cury += h / 2;
|
||||
else
|
||||
cury -= h / 2;
|
||||
}
|
||||
x0 = curx - w / 2;
|
||||
y0 = cury - h / 2;
|
||||
x1 = curx + w / 2;
|
||||
y1 = cury + h / 2;
|
||||
extreme(x0, y0);
|
||||
extreme(x1, y1);
|
||||
dprintf("Text h %g w %g at %g,%g\n", h, w, curx, cury);
|
||||
p = makenode(TEXT, 2);
|
||||
p->o_attr = invis;
|
||||
p->o_val[0] = w;
|
||||
p->o_val[1] = h;
|
||||
if (isright(hvmode))
|
||||
curx = x1;
|
||||
else if (isleft(hvmode))
|
||||
curx = x0;
|
||||
else if (isup(hvmode))
|
||||
cury = y1;
|
||||
else
|
||||
cury = y0;
|
||||
return(p);
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue