summaryrefslogtreecommitdiff
path: root/grap
diff options
context:
space:
mode:
Diffstat (limited to 'grap')
-rw-r--r--grap/Makefile.mk41
-rw-r--r--grap/coord.c83
-rw-r--r--grap/for.c101
-rw-r--r--grap/frame.c83
-rw-r--r--grap/grap.1430
-rw-r--r--grap/grap.defines26
-rw-r--r--grap/grap.h257
-rw-r--r--grap/grap.y410
-rw-r--r--grap/grapl.l246
-rw-r--r--grap/input.c628
-rw-r--r--grap/label.c140
-rw-r--r--grap/main.c187
-rw-r--r--grap/misc.c308
-rw-r--r--grap/plot.c144
-rw-r--r--grap/print.c247
-rw-r--r--grap/ticks.c508
-rw-r--r--grap/version.c30
17 files changed, 3869 insertions, 0 deletions
diff --git a/grap/Makefile.mk b/grap/Makefile.mk
new file mode 100644
index 0000000000000..8fa3f470c883f
--- /dev/null
+++ b/grap/Makefile.mk
@@ -0,0 +1,41 @@
+OBJ = coord.o for.o frame.o grap.o grapl.o input.o label.o main.o misc.o \
+ plot.o print.o ticks.o version.o
+
+FLAGS = -DLIBDIR='"$(LIBDIR)"' $(DEFINES) -I../include
+
+YFLAGS = -d
+
+.c.o:
+ $(CC) $(CFLAGS) $(WARN) $(FLAGS) $(CPPFLAGS) -c $<
+
+all: grap.c grapl.c grap
+
+grap: $(OBJ)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) $(LIBS) -lm -o grap
+
+y.tab.h: grap.c
+
+install:
+ $(INSTALL) -c grap $(ROOT)$(BINDIR)/grap
+ $(STRIP) $(ROOT)$(BINDIR)/grap
+ test -d $(ROOT)$(LIBDIR) || mkdir -p $(ROOT)$(LIBDIR)
+ $(INSTALL) -c -m 644 grap.defines $(ROOT)$(LIBDIR)/grap.defines
+ $(INSTALL) -c -m 644 grap.1 $(ROOT)$(MANDIR)/man1/grap.1
+
+clean:
+ rm -f $(OBJ) grapl.c grap.c y.tab.h grap core log *~
+
+mrproper: clean
+
+coord.o: coord.c grap.h y.tab.h
+for.o: for.c grap.h y.tab.h
+frame.o: frame.c grap.h y.tab.h
+grap.o: grap.c grap.h
+grapl.o: grapl.c grap.h y.tab.h
+input.o: input.c grap.h y.tab.h
+label.o: label.c grap.h y.tab.h
+main.o: main.c grap.h y.tab.h
+misc.o: misc.c grap.h y.tab.h
+plot.o: plot.c grap.h y.tab.h
+print.o: print.c grap.h y.tab.h
+ticks.o: ticks.c grap.h y.tab.h
diff --git a/grap/coord.c b/grap/coord.c
new file mode 100644
index 0000000000000..491c41e9a4c85
--- /dev/null
+++ b/grap/coord.c
@@ -0,0 +1,83 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)coord.c 1.3 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "grap.h"
+#include "y.tab.h"
+
+char *dflt_coord = "gg";
+char *curr_coord = "gg";
+int ncoord = 0; /* number of explicit coord's given */
+
+Point xcoord;
+Point ycoord;
+int xcflag = 0; /* 1 if xcoord set */
+int ycflag = 0;
+int logcoord = 0;
+
+void coord_x(Point pt) /* remember x coord */
+{
+ xcoord = pt;
+ xcflag = 1;
+ margin = 0; /* no extra space around picture if explicit coords */
+}
+
+void coord_y(Point pt)
+{
+ ycoord = pt;
+ ycflag = 1;
+ margin = 0; /* no extra space if explicit coords */
+}
+
+void coordlog(int n) /* remember log scaling */
+{
+ logcoord = n;
+}
+
+void coord(Obj *p) /* set coord range */
+{
+ static char buf[10];
+
+ ncoord++;
+ if (ncoord > 1 && strcmp(p->name, dflt_coord) == 0) {
+ /* resetting default coordinate by implication */
+ snprintf(buf, sizeof(buf), "gg%d", ncoord);
+ dflt_coord = buf;
+ p = lookup(dflt_coord, 1);
+ }
+ if (xcflag) {
+ p->coord |= XFLAG;
+ p->pt.x = min(xcoord.x,xcoord.y); /* "xcoord" is xmin, xmax */
+ p->pt1.x = max(xcoord.x,xcoord.y);
+ if ((logcoord&XFLAG) && p->pt.x <= 0.0)
+ FATAL("can't have log of x coord %g,%g", p->pt.x, p->pt1.x);
+ xcflag = 0;
+ }
+ if (ycflag) {
+ p->coord |= YFLAG;
+ p->pt.y = min(ycoord.x,ycoord.y); /* "ycoord" is ymin, ymax */
+ p->pt1.y = max(ycoord.x,ycoord.y);
+ if ((logcoord&YFLAG) && p->pt.y <= 0.0)
+ FATAL("can't have log of y coord %g,%g", p->pt.y, p->pt1.y);
+ ycflag = 0;
+ }
+ p->log = logcoord;
+ logcoord = 0;
+ auto_x = 0;
+}
+
+void resetcoord(Obj *p) /* reset current coordinate */
+{
+ curr_coord = p->name;
+}
diff --git a/grap/for.c b/grap/for.c
new file mode 100644
index 0000000000000..c3e8a4a6918e6
--- /dev/null
+++ b/grap/for.c
@@ -0,0 +1,101 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)for.c 1.3 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <stdlib.h>
+#include "grap.h"
+#include "y.tab.h"
+
+typedef struct {
+ Obj *var; /* index variable */
+ double to; /* limit */
+ double by;
+ int op; /* operator */
+ char *str; /* string to push back */
+} For;
+
+#define MAXFOR 10
+
+For forstk[MAXFOR]; /* stack of for loops */
+For *forp = forstk; /* pointer to current top */
+
+void forloop(Obj *var, double from, double to, int op, double by, char *str) /* set up a for loop */
+{
+ fprintf(tfd, "# for %s from %g to %g by %c %g \n",
+ var->name, from, to, op, by);
+ if (++forp >= forstk+MAXFOR)
+ FATAL("for loop nested too deep");
+ forp->var = var;
+ forp->to = to;
+ forp->op = op;
+ forp->by = by;
+ forp->str = str;
+ setvar(var, from);
+ nextfor();
+ unput('\n');
+}
+
+void nextfor(void) /* do one iteration of a for loop */
+{
+ /* BUG: this should depend on op and direction */
+ if (forp->var->fval > SLOP * forp->to) { /* loop is done */
+ free(forp->str);
+ if (--forp < forstk)
+ FATAL("forstk popped too far");
+ } else { /* another iteration */
+ pushsrc(String, "\nEndfor\n");
+ pushsrc(String, forp->str);
+ }
+}
+
+void endfor(void) /* end one iteration of for loop */
+{
+ switch (forp->op) {
+ case '+':
+ case ' ':
+ forp->var->fval += forp->by;
+ break;
+ case '-':
+ forp->var->fval -= forp->by;
+ break;
+ case '*':
+ forp->var->fval *= forp->by;
+ break;
+ case '/':
+ forp->var->fval /= 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;
+ }
+}
diff --git a/grap/frame.c b/grap/frame.c
new file mode 100644
index 0000000000000..e01b2835efe2a
--- /dev/null
+++ b/grap/frame.c
@@ -0,0 +1,83 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)frame.c 1.3 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <stdlib.h>
+#include "grap.h"
+#include "y.tab.h"
+
+double frame_ht; /* default frame height */
+double frame_wid; /* and width */
+
+int nsides = 0; /* how many sides given on this frame */
+char *sides[] = {
+ "\tline from Frame.nw to Frame.ne",
+ "\tline from Frame.sw to Frame.se",
+ "\tline from Frame.sw to Frame.nw",
+ "\tline from Frame.se to Frame.ne"
+};
+char *newsides[4] = { 0, 0, 0, 0 }; /* filled in later */
+
+void frame(void) /* pump out frame definition, reset for next */
+{
+ int i;
+
+ fprintf(tfd, "\tframeht = %g\n", frame_ht);
+ fprintf(tfd, "\tframewid = %g\n", frame_wid);
+ fprintf(tfd, "Frame:\tbox ht frameht wid framewid with .sw at 0,0 ");
+ if (nsides == 0)
+ fprintf(tfd, "\n");
+ else {
+ fprintf(tfd, "invis\n");
+ for (i = 0; i < 4; i++) {
+ if (newsides[i]) {
+ fprintf(tfd, "%s\n", newsides[i]);
+ free(newsides[i]);
+ newsides[i] = 0;
+ } else
+ fprintf(tfd, "%s\n", sides[i]);
+ }
+ nsides = 0;
+ }
+}
+
+void frameht(double f) /* set height of frame */
+{
+ frame_ht = f;
+}
+
+void framewid(double f) /* set width of frame */
+{
+ frame_wid = f;
+}
+
+void frameside(int type, Attr *desc) /* create and remember sides */
+{
+ int n = 0;
+ char buf[100];
+
+ nsides++;
+ switch (type) {
+ case 0: /* no side specified; kludge up all */
+ frameside(TOP, desc);
+ frameside(BOT, desc);
+ frameside(LEFT, desc);
+ frameside(RIGHT, desc);
+ return;
+ case TOP: n = 0; break;
+ case BOT: n = 1; break;
+ case LEFT: n = 2; break;
+ case RIGHT: n = 3; break;
+ }
+ snprintf(buf, sizeof(buf), "%s %s", sides[n], desc_str(desc));
+ newsides[n] = tostring(buf);
+}
diff --git a/grap/grap.1 b/grap/grap.1
new file mode 100644
index 0000000000000..a3a96a5cb2b66
--- /dev/null
+++ b/grap/grap.1
@@ -0,0 +1,430 @@
+.\"
+.\" Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+.\"
+.\" Derived from Plan 9 v4 /opt/unix/plan9v4/sys/man/1/grap
+.\"
+.\" Copyright (C) 2003, Lucent Technologies Inc. and others.
+.\" All Rights Reserved.
+.\"
+.\" Distributed under the terms of the Lucent Public License Version 1.02.
+.\"
+.\" Sccsid @(#)grap.1 1.5 (gritter) 2/2/07
+.TH GRAP 1 "2/2/07" "Heirloom Documentation Tools" "User Commands"
+.SH NAME
+grap \- pic preprocessor for drawing graphs
+.SH SYNOPSIS
+\fBgrap\fR [\fB\-SU\fR] [\fIfile\fR]
+.SH DESCRIPTION
+.I Grap
+is a
+.IR pic (1)
+preprocessor for drawing graphs on a typesetter.
+Graphs are surrounded by the
+.I troff
+`commands'
+.B \&.G1
+and
+.BR \&.G2 .
+Data are scaled and plotted,
+with tick marks supplied automatically.
+Commands exist to modify the frame,
+add labels, override the default ticks,
+change the plotting style,
+define coordinate ranges and transformations,
+and include data from files.
+In addition,
+.I grap
+provides the same loops, conditionals, and macro processing that
+.I pic
+does.
+.PP
+.BI frame
+.B ht
+.I e
+.B wid
+.I e
+.B top
+.B dotted
+.IR ... :
+Set the frame around the graph to specified
+.B ht
+and
+.BR wid ;
+default is 2 by 3 (inches).
+The line
+.I styles
+.RB ( dotted ,
+.BR dashed ,
+.BR invis ,
+.BR solid
+(default))
+of the
+.I sides
+.RB ( top ,
+.BR bot ,
+.BR left ,
+.BR right )
+of the frame can be set
+independently.
+.PP
+.B label
+.I side
+.B \&"a label"
+.B \&"as a set of strings"
+.IR adjust :
+Place label on specified side; default side is bottom.
+.I adjust
+is
+.B up
+(or
+.B down
+.B left
+.BR right )
+.I expr
+to shift default position;
+.B width
+.I expr
+sets the width explicitly.
+.PP
+.BI ticks
+.I side
+.B in
+.B at
+.IR "optname expr, expr, ..." :
+Put ticks on
+.I side
+at
+.I "expr, ...,
+and label with
+.I \&"expr"\f1.
+If any
+.I expr
+is followed by "...", label tick with "...",
+and turn off all automatic labels.
+If "..." contains
+.BR %f 's,
+they will be interpreted as
+.B printf
+formatting instructions for the tick value.
+Ticks point
+.B in
+or
+.B out
+(default out).
+Tick iterator: instead of
+.B at
+.IR \&... ,
+use
+.BI from
+.I expr
+.B to
+.I expr
+.B by
+.I "op expr
+where
+.I op
+is optionally
+.B +\-*/
+for additive or multiplicative steps.
+.B by
+can be omitted, to give steps of size 1.
+If no ticks are requested, they are supplied automatically;
+suppress this with
+.B ticks
+.BR off .
+Automatic ticks normally
+leave a margin of 7% on each side; set this to anything by
+.B margin
+.B =
+.IR expr .
+.PP
+.B grid
+.I "side linedesc"
+.B at
+.IR "optname expr, expr, ..." :
+Draw grids perpendicular to
+.I side
+in style
+.I linedesc
+at
+.I "expr, ....\&
+Iterators and labels work as with ticks.
+.PP
+.B coord
+.I optname
+.B x
+.I "min, max"
+.B y
+.I "min, max"
+.B "log x
+.BR " log y" :
+Set range of coords and optional log scaling on either or both.
+This overrides computation of data range.
+Default value of
+.I optname
+is current coordinate system
+(each
+.B coord
+defines a new coordinate system).
+.PP
+.B plot
+.I \&"str"
+.B at
+.IR point ;
+.B
+.I \&"str"
+.B at
+.IR point :
+Put
+.I str
+at
+.IR point .
+Text position can be qualified with
+.BR rjust ,
+.BR ljust ,
+.BR above ,
+.BR below
+after "...".
+.PP
+.B line
+.B from
+.I point
+.B to
+.IR "point linedesc" :
+Draw line from here to there.
+.B arrow
+works in place of
+.BR line .
+.PP
+.B next
+.I optname
+.B at
+.IR "point linedesc" :
+Continue plot of data in
+.I optname to
+.IR point ;
+default is current.
+.PP
+.BI draw
+.IR "optname linedesc ..." :
+Set mode for
+.BR next :
+use this style from now on,
+and plot "..." at each point (if given).
+.PP
+.BI new
+.IR "optname linedesc ..." :
+Set mode for
+.BR next ,
+but disconnect from previous.
+.PP
+A list of numbers
+.I "x y1 y2 y3 ...
+is treated as
+.B plot
+.B bullet
+.B at
+.IR x,y1 ;
+.B plot
+.B bullet
+.B at
+.IR x,y2 ;
+etc., or as
+.B next
+.B at
+.I x,y1
+etc., if
+.B draw
+is specified.
+Abscissae of 1,2,3,... are provided if there is only one input number per line.
+.PP
+A
+point
+.I "optname expr, expr
+maps the point to the named coordinate system.
+A
+.I linedesc
+is one of
+.B dot
+.B dash
+.B invis
+.B solid
+optionally followed by an expression.
+.PP
+.BI define
+.I name
+.BI { whatever } \f1:
+Define a macro.
+There are macros already defined for standard plotting
+symbols like
+.BR bullet ,
+.BR circle ,
+.BR star ,
+.BR plus ,
+etc., in
+.BR /sys/lib/grap.defines ,
+which is included if it exists.
+.PP
+.I var
+.B =
+.IR expr :
+Evaluate an expression.
+Operators are
+.B=
+.B +
+.B \-
+.B *
+and
+.BR / .
+Functions are
+.B log
+and
+.B exp
+(both base 10),
+.BR sin ,
+.BR cos ,
+.BR sqrt ;
+.B rand
+returns random number on [0,1);
+.BI max( e , e )\f1,
+.BI min( e , e )\f1,
+.BI int( e )\f1.
+.PP
+.B print
+.IR expr ;
+.B print
+\fR"\f2...\fR"\f1:
+As a debugging aid, print
+.I expr
+or
+.I string
+on the standard error.
+.PP
+.B copy
+\fR"\fIfile name\fR"\fR:
+Include this file right here.
+.PP
+.B copy
+.B thru
+.IR macro :
+Pass rest of input (until
+.BR \&.G2 )
+through
+.IR macro ,
+treating each field (non-blank, or "...") as an argument.
+.I macro
+can be the name of a macro previously defined,
+or the body of one in place, like
+.BR "/plot $1 at $2,$3/" .
+.PP
+.B copy
+.B thru
+.I macro
+.B until
+\fR"\fIstring\fR"\fR:
+Stop copy when input is
+.I string
+(left-justified).
+.PP
+.BI pic
+.IR "remainder of line" :
+Copy to output with leading blanks removed.
+.PP
+.BI graph
+.IR "Name pic-position" :
+Start a new frame, place it at specified position,
+e.g.,
+.B graph
+.B Thing2
+.BR "with .sw at Thing1.se + (0.1,0)" .
+.I Name
+must be capitalized to keep
+.I pic
+happy.
+.PP
+.BI \&. "anything at beginning of
+.IR line :
+Copied verbatim.
+.PP
+.B sh
+.BI % anything
+.BR % :
+Pass everything between the
+.BR % 's
+to the shell;
+as with macros,
+.B %
+may be any character and
+.I anything
+may include newlines.
+The
+.B \-S
+option disables execution of the shell command;
+the
+.B \-U
+option reverts the effect of a previous
+.IR \-S .
+.PP
+.B #
+.IR anything :
+A comment, which is discarded.
+.PP
+Order is mostly irrelevant; no category is mandatory.
+Any arguments on the
+.B \&.G1
+line are placed on the generated
+.B \&.PS
+line for
+.IR pic .
+.\".SH EXAMPLES
+.\".EX
+.\".ps -1
+.\".vs -1
+.\"\&.G1
+.\"frame ht 1 top invis right invis
+.\"coord x 0, 10 y 1, 3 log y
+.\"ticks left in at 1 "bottommost tick", 2,3 "top tick"
+.\"ticks bot in from 0 to 10 by 2
+.\"label bot "silly graph"
+.\"label left "left side label" "here"
+.\"grid left dashed at 2.5
+.\"copy thru / circle at $1,$2 /
+.\"1 1
+.\"2 1.5
+.\"3 2
+.\"4 1.5
+.\"10 3
+.\"\&.G2
+.\".G1
+.\"frame ht 1 top invis right invis
+.\"coord x 0, 10 y 1, 3 log y
+.\"ticks left in at 1 "bottommost tick", 2,3 "top tick"
+.\"ticks bot in from 0 to 10 by 2
+.\"label bot "silly graph"
+.\"label left "left side label" "here"
+.\"grid left dashed at 2.5
+.\"copy thru / circle at $1,$2 /
+.\"1 1
+.\"2 1.5
+.\"3 2
+.\"4 1.5
+.\"10 3
+.\".G2
+.\".ps
+.\".vs
+.\".EE
+.SH FILES
+.TP
+.B /usr/ucblib/grap.defines
+definitions of standard plotting characters, e.g., bullet
+.\".SH SOURCE
+.\".B /sys/src/cmd/grap
+.SH "SEE ALSO"
+.IR pic (1),
+.IR troff (1)
+.br
+J. L. Bentley and B. W. Kernighan,
+``GRAP\(emA Language for Typesetting Graphs'',
+.I
+Unix Research System Programmer's Manual,
+Tenth Edition, Volume 2.
diff --git a/grap/grap.defines b/grap/grap.defines
new file mode 100644
index 0000000000000..ac13602695831
--- /dev/null
+++ b/grap/grap.defines
@@ -0,0 +1,26 @@
+#
+# Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+#
+# Derived from Plan 9 v4 /sys/lib/grap.defines
+#
+# Copyright (C) 2003, Lucent Technologies Inc. and others.
+# All Rights Reserved.
+#
+# Distributed under the terms of the Lucent Public License Version 1.02.
+#
+
+# Sccsid @(#)grap.defines 1.2 (gritter) 10/18/05
+
+# These definitions are right for the 202,
+# but might need fiddling elsewhere
+
+define bullet % "\s-5\(bu\s0" %
+define plus % "\s-3\(pl\s0" %
+define box % "\s-4\(bx\s0" %
+define star % "\(**" %
+define dot % "\v'-.2m'\s+4.\s0\v'.2m'" %
+define times % "\s-3\(mu\s0" %
+define htick % "\-" %
+define vtick % "\(or" %
+define square % "\s-3\(sq\s0" %
+define delta % "\s-3\(*D\s0" %
diff --git a/grap/grap.h b/grap/grap.h
new file mode 100644
index 0000000000000..cbba8eb38d0f0
--- /dev/null
+++ b/grap/grap.h
@@ -0,0 +1,257 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)grap.h 1.5 (gritter) 12/5/05 */
+extern void FATAL(const char *, ...);
+extern void WARNING(const char *, ...);
+
+#include "global.h"
+
+#define dprintf if(dbg)printf
+
+#define String 01
+#define Macro 02
+#define File 04
+#define Char 010
+#define Thru 020
+#define Free 040
+
+#define MARGIN 0.07 /* default margin around data */
+#define SLOP 1.001 /* slop for limits of for loops */
+#define FRAMEWID 3 /* default width for boxes and ellipses */
+#define FRAMEHT 2 /* default height and line length */
+#define TICKLEN 0.1
+
+#define MAXNUM 200
+
+#define XFLAG 01
+#define YFLAG 02
+
+#define INTICK 01
+#define OUTICK 02
+
+#define BOT 01
+#define TOP 02
+#define RIGHT 04
+#define LEFT 010
+
+#define RJUST 01
+#define LJUST 02
+#define ABOVE 04
+#define BELOW 010
+
+typedef struct infile {
+ FILE *fin;
+ char *fname;
+ int lineno;
+} Infile;
+
+typedef struct { /* input source */
+ int type; /* Macro, String, File */
+ char *sp; /* if String or Macro */
+} Src;
+
+extern Src src[], *srcp; /* input source stack */
+
+#define MAXARGS 100
+typedef struct { /* argument stack */
+ char *argstk[MAXARGS]; /* pointers to args */
+ char *argval; /* points to space containing args */
+} Arg;
+
+extern Infile infile[10];
+extern Infile *curfile;
+
+typedef struct {
+ struct obj *obj;
+ double x, y;
+} Point;
+
+typedef struct attr { /* e.g., DASH 1.1 or "..." rjust size *.5 */
+ int type;
+ double fval;
+ char *sval;
+ int just; /* justification, for STRING type */
+ int op; /* optional operator, ditto */
+ struct attr *next;
+} Attr;
+
+typedef struct obj { /* a name and its properties */
+ char *name;
+ char *val; /* body of define, etc. */
+ double fval; /* if a numeric variable */
+ Point pt; /* usually for max and min */
+ Point pt1;
+ int type; /* NAME, DEFNAME, ... */
+ int first; /* 1 after 1st item seen */
+ int coord; /* 1 if coord system specified for this name */
+ int log; /* x, y, or z (= x+y) */
+ Attr *attr; /* DASH, etc., for now */
+ struct obj *next;
+} Obj;
+
+#define YYSTYPE YYSTYPE
+typedef union { /* the yacc stack type */
+ int i;
+ char *p;
+ double f;
+ Point pt;
+ Obj *op;
+ Attr *ap;
+} YYSTYPE;
+
+extern YYSTYPE yylval;
+
+extern int dbg;
+
+extern int ntext;
+extern double num[MAXNUM];
+extern int nnum;
+extern int ntick, tside;
+
+extern char *tostring(char *);
+extern char *grow(char *, char *, int, int);
+
+extern int lineno;
+extern int synerr;
+extern int codegen;
+extern char tempfile[];
+extern FILE *tfd;
+extern int Sflag;
+
+extern Point ptmin, ptmax;
+
+extern char *dflt_coord;
+extern char *curr_coord;
+extern int ncoord;
+extern int auto_x;
+extern double margin;
+extern int autoticks;
+extern int pointsize, ps_set;
+
+
+#define logit(x) (x) = log10(x)
+#define Log10(x) errcheck(log10(x), "log")
+#define Exp(x) errcheck(exp(x), "exp")
+#define Sqrt(x) errcheck(sqrt(x), "sqrt")
+
+#define min(x,y) (((x) <= (y)) ? (x) : (y))
+#define max(x,y) (((x) >= (y)) ? (x) : (y))
+
+extern void yyerror(char *);
+extern void coord_x(Point);
+extern void coord_y(Point);
+extern void coordlog(int);
+extern void coord(Obj *);
+extern void resetcoord(Obj *);
+extern void savenum(int, double);
+extern void setjust(int);
+extern void setsize(int, double);
+extern void range(Point);
+extern void halfrange(Obj *, int, double);
+extern Obj *lookup(char *, int);
+extern double getvar(Obj *);
+extern double setvar(Obj *, double);
+extern Point makepoint(Obj *, double, double);
+extern Attr *makefattr(int, double);
+extern Attr *makesattr(char *);
+extern Attr *makeattr(int, double, char *, int, int);
+extern Attr *addattr(Attr *, Attr *);
+extern void freeattr(Attr *);
+extern char *slprint(Attr *);
+extern char *juststr(int);
+extern char *sprntf(char *, Attr *);
+extern void forloop(Obj *, double, double, int, double, char *);
+extern void nextfor(void);
+extern void endfor(void);
+extern char *ifstat(double, char *, char *);
+extern void frame(void);
+extern void frameht(double);
+extern void framewid(double);
+extern void frameside(int, Attr *);
+extern void pushsrc(int, char *);
+extern void popsrc(void);
+extern void definition(char *);
+extern char *delimstr(char *);
+extern int baldelim(int, char *);
+extern void dodef(Obj *);
+extern int getarg(char *);
+#ifdef FLEX_SCANNER
+extern int xxinput(void);
+extern int xxunput(int);
+#else /* !FLEX_SCANNER */
+#define input xxinput
+#define unput xxunput
+extern int input(void);
+extern int unput(int);
+#endif /* !FLEX_SCANNER */
+extern int nextchar(void);
+extern void do_thru(void);
+extern void pbstr(char *);
+extern double errcheck(double, char *);
+extern void yyerror(char *);
+extern void eprint(void);
+extern int yywrap(void);
+extern void copyfile(char *);
+extern void copydef(Obj *);
+extern Obj *copythru(char *);
+extern char *addnewline(char *);
+extern void copyuntil(char *);
+extern void copy(void);
+extern void shell_init(void);
+extern void shell_text(char *);
+extern void shell_exec(void);
+extern void labelwid(double);
+extern void labelmove(int, double);
+extern void label(int, Attr *);
+extern void lab_adjust(void);
+extern char *sizeit(Attr *);
+extern void line(int, Point, Point, Attr *);
+extern void circle(double, Point);
+extern char *xyname(Point);
+extern void pic(char *);
+extern void numlist(void);
+extern void plot(Attr *, Point);
+extern void plotnum(double, char *, Point);
+extern void drawdesc(int, Obj *, Attr *, char *);
+extern void next(Obj *, Point, Attr *);
+extern void print(void);
+extern void endstat(void);
+extern void graph(char *);
+extern void setup(void);
+extern void do_first(void);
+extern void reset(void);
+extern void opentemp(void);
+extern void savetick(double, char *);
+extern void dflt_tick(double);
+extern void tickside(int);
+extern void tickoff(int);
+extern void gridtickoff(void);
+extern void setlist(void);
+extern void tickdir(int, double, int);
+extern void ticks(void);
+extern double modfloor(double, double);
+extern double modceil(double, double);
+extern void do_autoticks(Obj *);
+extern void logtick(double, double, double);
+extern Obj *setauto(void);
+extern void autoside(Obj *, int);
+extern void autolog(Obj *, int);
+extern void iterator(double, double, int, double, char *);
+extern void ticklist(Obj *, int);
+extern void print_ticks(int, int, Obj *, char *, char *);
+extern void maketick(int, char *, int, int, double, char *, char *, char *);
+extern void griddesc(Attr *);
+extern void gridlist(Obj *);
+extern char *desc_str(Attr *);
+extern int sidelog(int, int);
+
+extern Obj *objlist;
diff --git a/grap/grap.y b/grap/grap.y
new file mode 100644
index 0000000000000..4c6fc9d4395e6
--- /dev/null
+++ b/grap/grap.y
@@ -0,0 +1,410 @@
+%{
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)grap.y 1.3 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "grap.h"
+
+#ifndef RAND_MAX
+#define RAND_MAX 32767 /* if your rand() returns bigger, change this too */
+#endif
+
+extern int yylex(void);
+extern int yyparse(void);
+
+%}
+
+%token <i> FRAME TICKS GRID LABEL COORD
+%token <i> LINE ARROW CIRCLE DRAW NEW PLOT NEXT
+%token <p> PIC
+%token <i> COPY THRU UNTIL
+%token <i> FOR FROM TO BY AT WITH
+%token <i> IF
+%token <p> GRAPH THEN ELSE DOSTR
+%token <i> DOT DASH INVIS SOLID
+%token <i> TEXT JUST SIZE
+%token <i> LOG EXP SIN COS ATAN2 SQRT RAND MAX MIN INT PRINT SPRINTF
+%token <i> X Y SIDE IN OUT OFF UP DOWN ACROSS
+%token <i> HEIGHT WIDTH RADIUS
+%token <f> NUMBER
+%token <op> NAME VARNAME DEFNAME
+%token <p> STRING
+%token <i> ST '(' ')' ','
+
+%right <f> '='
+%left <f> OR
+%left <f> AND
+%nonassoc <f> GT LT LE GE EQ NE
+%left <f> '+' '-'
+%left <f> '*' '/' '%'
+%right <f> UMINUS NOT
+%right <f> '^'
+
+%type <f> expr optexpr if_expr number assign
+%type <i> optop
+%type <p> optstring if
+%type <op> optname iterator name
+%type <pt> point
+%type <i> side optside numlist comma linetype drawtype
+%type <ap> linedesc optdesc stringlist string stringattr sattrlist exprlist
+%type <i> frameitem framelist coordlog
+%type <f> string_expr
+
+%%
+
+top:
+ graphseq { if (codegen && !synerr) graph((char *) 0); }
+ | /* empty */ { codegen = 0; }
+ | error { codegen = 0; WARNING("syntax error"); }
+ ;
+
+graphseq:
+ statlist
+ | graph statlist
+ | graphseq graph statlist
+ ;
+graph:
+ GRAPH { graph($1); endstat(); }
+ ;
+
+statlist:
+ ST
+ | stat ST { endstat(); }
+ | statlist stat ST { endstat(); }
+ ;
+
+stat:
+ FRAME framelist { codegen = 1; }
+ | ticks { codegen = 1; }
+ | grid { codegen = 1; }
+ | label { codegen = 1; }
+ | coord
+ | plot { codegen = 1; }
+ | line { codegen = 1; }
+ | circle { codegen = 1; }
+ | draw
+ | next { codegen = 1; }
+ | PIC { codegen = 1; pic($1); }
+ | for
+ | if
+ | copy
+ | numlist { codegen = 1; numlist(); }
+ | assign
+ | PRINT expr { fprintf(stderr, "\t%g\n", $2); }
+ | PRINT string { fprintf(stderr, "\t%s\n", $2->sval); freeattr($2); }
+ | /* empty */
+ ;
+
+numlist:
+ number { savenum(0, $1); $$ = 1; }
+ | numlist number { savenum($1, $2); $$ = $1+1; }
+ | numlist comma number { savenum($1, $3); $$ = $1+1; }
+ ;
+number:
+ NUMBER
+ | '-' NUMBER %prec UMINUS { $$ = -$2; }
+ | '+' NUMBER %prec UMINUS { $$ = $2; }
+ ;
+
+label:
+ LABEL optside stringlist lablist { label($2, $3); }
+ ;
+lablist:
+ labattr
+ | lablist labattr
+ | /* empty */
+ ;
+labattr:
+ UP expr { labelmove($1, $2); }
+ | DOWN expr { labelmove($1, $2); }
+ | SIDE expr { labelmove($1, $2); /* LEFT or RIGHT only */ }
+ | WIDTH expr { labelwid($2); }
+ ;
+
+framelist:
+ framelist frameitem
+ | /* empty */ { $$ = 0; }
+ ;
+frameitem:
+ HEIGHT expr { frameht($2); }
+ | WIDTH expr { framewid($2); }
+ | side linedesc { frameside($1, $2); }
+ | linedesc { frameside(0, $1); }
+ ;
+side:
+ SIDE
+ ;
+optside:
+ side
+ | /* empty */ { $$ = 0; }
+ ;
+
+linedesc:
+ linetype optexpr { $$ = makeattr($1, $2, (char *) 0, 0, 0); }
+ ;
+linetype:
+ DOT | DASH | SOLID | INVIS
+ ;
+optdesc:
+ linedesc
+ | /* empty */ { $$ = makeattr(0, 0.0, (char *) 0, 0, 0); }
+ ;
+
+ticks:
+ TICKS tickdesc { ticks(); }
+ ;
+tickdesc:
+ tickattr
+ | tickdesc tickattr
+ ;
+tickattr:
+ side { tickside($1); }
+ | IN expr { tickdir(IN, $2, 1); }
+ | OUT expr { tickdir(OUT, $2, 1); }
+ | IN { tickdir(IN, 0.0, 0); }
+ | OUT { tickdir(OUT, 0.0, 0); }
+ | AT optname ticklist { setlist(); ticklist($2, AT); }
+ | iterator { setlist(); ticklist($1, AT); }
+ | side OFF { tickoff($1); }
+ | OFF { tickoff(LEFT|RIGHT|TOP|BOT); }
+ | labattr
+ ;
+ticklist:
+ tickpoint
+ | ticklist comma tickpoint
+ ;
+tickpoint:
+ expr { savetick($1, (char *) 0); }
+ | expr string { savetick($1, $2->sval); }
+ ;
+iterator:
+ FROM optname expr TO optname expr BY optop expr optstring
+ { iterator($3, $6, $8, $9, $10); $$ = $2; }
+ | FROM optname expr TO optname expr optstring
+ { iterator($3, $6, '+', 1.0, $7); $$ = $2; }
+ ;
+optop:
+ '+' { $$ = '+'; }
+ | '-' { $$ = '-'; }
+ | '*' { $$ = '*'; }
+ | '/' { $$ = '/'; }
+ | /* empty */ { $$ = ' '; }
+ ;
+optstring:
+ string { $$ = $1->sval; }
+ | /* empty */ { $$ = (char *) 0; }
+ ;
+
+grid:
+ GRID griddesc { ticks(); }
+ ;
+griddesc:
+ gridattr
+ | griddesc gridattr
+ ;
+gridattr:
+ side { tickside($1); }
+ | X { tickside(BOT); }
+ | Y { tickside(LEFT); }
+ | linedesc { griddesc($1); }
+ | AT optname ticklist { setlist(); gridlist($2); }
+ | iterator { setlist(); gridlist($1); }
+ | TICKS OFF { gridtickoff(); }
+ | OFF { gridtickoff(); }
+ | labattr
+ ;
+
+line:
+ LINE FROM point TO point optdesc { line($1, $3, $5, $6); }
+ | LINE optdesc FROM point TO point { line($1, $4, $6, $2); }
+ ;
+circle:
+ CIRCLE RADIUS expr AT point { circle($3, $5); }
+ | CIRCLE AT point RADIUS expr { circle($5, $3); }
+ | CIRCLE AT point { circle(0.0, $3); }
+ ;
+
+stringlist:
+ string
+ | stringlist string { $$ = addattr($1, $2); }
+ ;
+string:
+ STRING sattrlist { $$ = makesattr($1); }
+ | SPRINTF '(' STRING ')' sattrlist
+ { $$ = makesattr(sprntf($3, (Attr*) 0)); }
+ | SPRINTF '(' STRING ',' exprlist ')' sattrlist
+ { $$ = makesattr(sprntf($3, $5)); }
+ ;
+exprlist:
+ expr { $$ = makefattr(NUMBER, $1); }
+ | exprlist ',' expr { $$ = addattr($1, makefattr(NUMBER, $3)); }
+ ;
+sattrlist:
+ stringattr
+ | sattrlist stringattr
+ | /* empty */ { $$ = (Attr *) 0; }
+ ;
+stringattr:
+ JUST { setjust($1); }
+ | SIZE optop expr { setsize($2, $3); }
+ ;
+
+coord:
+ COORD optname coordlist { coord($2); }
+ | COORD optname { resetcoord($2); }
+ ;
+coordlist:
+ coorditem
+ | coordlist coorditem
+ ;
+coorditem:
+ coordlog { coordlog($1); }
+ | X point { coord_x($2); }
+ | Y point { coord_y($2); }
+ | X optname expr TO expr { coord_x(makepoint($2, $3, $5)); }
+ | Y optname expr TO expr { coord_y(makepoint($2, $3, $5)); }
+ | X FROM optname expr TO expr { coord_x(makepoint($3, $4, $6)); }
+ | Y FROM optname expr TO expr { coord_y(makepoint($3, $4, $6)); }
+ ;
+coordlog:
+ LOG X { $$ = XFLAG; }
+ | LOG Y { $$ = YFLAG; }
+ | LOG X LOG Y { $$ = XFLAG|YFLAG; }
+ | LOG Y LOG X { $$ = XFLAG|YFLAG; }
+ | LOG LOG { $$ = XFLAG|YFLAG; }
+ ;
+
+plot:
+ stringlist AT point { plot($1, $3); }
+ | PLOT stringlist AT point { plot($2, $4); }
+ | PLOT expr optstring AT point { plotnum($2, $3, $5); }
+ ;
+
+draw:
+ drawtype optname linedesc { drawdesc($1, $2, $3, (char *) 0); }
+ | drawtype optname optdesc string { drawdesc($1, $2, $3, $4->sval); }
+ | drawtype optname string optdesc { drawdesc($1, $2, $4, $3->sval); }
+ ;
+drawtype:
+ DRAW
+ | NEW
+ ;
+
+next:
+ NEXT optname AT point optdesc { next($2, $4, $5); }
+
+copy:
+ COPY copylist { copy(); }
+ ;
+copylist:
+ copyattr
+ | copylist copyattr
+ ;
+copyattr:
+ string { copyfile($1->sval); }
+ | THRU DEFNAME { copydef($2); }
+ | UNTIL string { copyuntil($2->sval); }
+ ;
+
+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 THEN ELSE { $$ = ifstat($2, $3, $4); }
+ | IF if_expr THEN { $$ = ifstat($2, $3, (char *) 0); }
+ ;
+if_expr:
+ expr
+ | string_expr
+ | if_expr AND string_expr { $$ = $1 && $3; }
+ | if_expr OR string_expr { $$ = $1 || $3; }
+ ;
+string_expr:
+ STRING EQ STRING { $$ = strcmp($1,$3) == 0; free($1); free($3); }
+ | STRING NE STRING { $$ = strcmp($1,$3) != 0; free($1); free($3); }
+ ;
+
+point:
+ optname expr comma expr { $$ = makepoint($1, $2, $4); }
+ | optname '(' expr comma expr ')' { $$ = makepoint($1, $3, $5); }
+ ;
+comma:
+ ',' { $$ = ','; }
+ ;
+
+optname:
+ NAME { $$ = $1; }
+ | /* empty */ { $$ = lookup(curr_coord, 1); }
+ ;
+
+expr:
+ NUMBER
+ | assign
+ | '(' string_expr ')' { $$ = $2; }
+ | VARNAME { $$ = getvar($1); }
+ | expr '+' expr { $$ = $1 + $3; }
+ | expr '-' expr { $$ = $1 - $3; }
+ | expr '*' expr { $$ = $1 * $3; }
+ | expr '/' expr { if ($3 == 0.0) {
+ WARNING("division by 0"); $3 = 1; }
+ $$ = $1 / $3; }
+ | expr '%' expr { if ((long)$3 == 0) {
+ WARNING("mod division by 0"); $3 = 1; }
+ $$ = (long)$1 % (long)$3; }
+ | '-' expr %prec UMINUS { $$ = -$2; }
+ | '+' expr %prec UMINUS { $$ = $2; }
+ | '(' 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 '(' ')' { $$ = (double)random() / (double)RAND_MAX; }
+ | MAX '(' expr ',' expr ')' { $$ = $3 >= $5 ? $3 : $5; }
+ | MIN '(' expr ',' expr ')' { $$ = $3 <= $5 ? $3 : $5; }
+ | INT '(' expr ')' { $$ = (long) $3; }
+ | 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 NE expr { $$ = $1 != $3; }
+ | expr AND expr { $$ = $1 && $3; }
+ | expr OR expr { $$ = $1 || $3; }
+ | NOT expr { $$ = !($2); }
+ ;
+assign:
+ name '=' expr { $$ = setvar($1, $3); }
+ ;
+
+name:
+ NAME
+ | VARNAME
+ ;
+
+optexpr:
+ expr
+ | /* empty */ { $$ = 0.0; }
+ ;
diff --git a/grap/grapl.l b/grap/grapl.l
new file mode 100644
index 0000000000000..763537270e89a
--- /dev/null
+++ b/grap/grapl.l
@@ -0,0 +1,246 @@
+%{
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)grapl.l 1.4 (gritter) 11/22/05 */
+%}
+%Start A str def thru sh
+
+%{
+#ifndef FLEX_SCANNER
+#undef input
+#undef unput
+#endif /* !FLEX_SCANNER */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "grap.h"
+#include "y.tab.h"
+
+#ifdef FLEX_SCANNER
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max_size) { \
+ int c = xxinput(); \
+ result = (c == EOF || c == 0) ? YY_NULL : (buf[0] = c, 1); \
+}
+#define witchcraft YY_START
+#else /* !FLEX_SCANNER */
+#define witchcraft yybgin-yysvec-1
+#endif /* !FLEX_SCANNER */
+
+int yyback(int *, int);
+int yylook(void);
+int yywrap(void);
+void shell_init(void), shell_exec(void), shell_text(char *);
+
+#define CADD cbuf[clen++] = yytext[0]; \
+ if (clen >= CBUFLEN-1) { \
+ WARNING("string too long", cbuf); BEGIN A; }
+#define CBUFLEN 1500
+char cbuf[CBUFLEN];
+int clen, cflag;
+int c, delim, shcnt;
+%}
+
+A [a-zA-Z_]
+B [a-zA-Z0-9_]
+D [0-9]
+WS [ \t]
+
+%%
+ if (witchcraft == 0) {
+ BEGIN A;
+ }
+
+<A>{WS} ;
+<A>"\\"\n ;
+<A>\n return(ST);
+<A>";" return(ST);
+
+<A>line return(yylval.i = LINE);
+<A>arrow { yylval.i = ARROW; return(LINE); }
+<A>circle return(yylval.i = CIRCLE);
+<A>frame return(FRAME);
+<A>tick(s)? return(TICKS);
+<A>grid(line)?(s)? return(GRID);
+<A>coord(s)? return(COORD);
+<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>print return(PRINT);
+<A>sprintf return(SPRINTF);
+<A>pic{WS}.* { yylval.p = tostring(yytext+3); return(PIC); }
+<A>graph{WS}.* { yylval.p = tostring(yytext+5); return(GRAPH); }
+
+<A>for return(FOR);
+<A>^Endfor\n { endfor(); }
+<A>do { yylval.p = delimstr("loop body"); BEGIN A; return(DOSTR); }
+
+<A>copy|include { return(COPY); }
+<A>thru|through { BEGIN thru; return(THRU); }
+<thru>{WS}+ ;
+<thru>{A}{B}*|. { yylval.op = copythru(yytext); BEGIN A; return(DEFNAME); }
+<A>until return(UNTIL);
+
+<A>if return(IF);
+<A>then { yylval.p = delimstr("then part"); BEGIN A; return(THEN); }
+<A>else { yylval.p = delimstr("else part"); BEGIN A; return(ELSE); }
+
+<A>next return(NEXT);
+<A>draw return(yylval.i = DRAW);
+<A>new return(yylval.i = NEW);
+<A>plot return(yylval.i = PLOT);
+<A>label(s)? return(LABEL);
+<A>x return(X);
+<A>y return(Y);
+
+<A>top { yylval.i = TOP; return SIDE; }
+<A>bot(tom)? { yylval.i = BOT; return SIDE; }
+<A>left { yylval.i = LEFT; return SIDE; }
+<A>right { yylval.i = RIGHT; return SIDE; }
+<A>up return(yylval.i = UP);
+<A>down return(yylval.i = DOWN);
+<A>across return(yylval.i = ACROSS);
+<A>height|ht return(yylval.i = HEIGHT);
+<A>wid(th)? return(yylval.i = WIDTH);
+<A>rad(ius)? return(yylval.i = RADIUS);
+<A>invis return(yylval.i = INVIS);
+<A>dot(ted) return(yylval.i = DOT);
+<A>dash(ed) return(yylval.i = DASH);
+<A>solid return(yylval.i = SOLID);
+
+<A>ljust { yylval.i = LJUST; return JUST; }
+<A>rjust { yylval.i = RJUST; return JUST; }
+<A>above { yylval.i = ABOVE; return JUST; }
+<A>below { yylval.i = BELOW; return JUST; }
+<A>size return(yylval.i = SIZE);
+
+<A>from return(yylval.i = FROM);
+<A>to return(yylval.i = TO);
+<A>by|step return(yylval.i = BY);
+<A>at return(yylval.i = AT);
+<A>with return(yylval.i = WITH);
+<A>in return(yylval.i = IN);
+<A>out return(yylval.i = OUT);
+<A>off return(yylval.i = OFF);
+
+<A>sh{WS}+ { BEGIN sh;
+ if ((delim = input()) == '{') {
+ shcnt = 1;
+ delim = '}';
+ }
+ shell_init();
+ }
+<sh>{A}{B}* {
+ int c;
+ Obj *p;
+ if (yytext[0] == delim) {
+ shell_exec();
+ BEGIN A;
+ } else {
+ p = lookup(yytext, 0);
+ if (p != NULL && p->type == DEFNAME) {
+ c = input();
+ xxunput(c);
+ if (c == '(')
+ dodef(p);
+ else
+ pbstr(p->val);
+ } else
+ shell_text(yytext);
+ }
+ }
+<sh>"{" { shcnt++; shell_text(yytext); }
+<sh>"}" { if (delim != '}' || --shcnt > 0)
+ shell_text(yytext);
+ else {
+ shell_exec();
+ BEGIN A;
+ }
+ }
+<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>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
+ yylval.f = atof(yytext); return(NUMBER); }
+
+<A>^"."[^0-9].* { if (yytext[1] == 'G' && yytext[2] == '2') {
+ yylval.i = yytext[2];
+ return(EOF);
+ } else {
+ yylval.p = tostring(yytext);
+ return(PIC);
+ }
+ }
+
+<A>{A}{B}* {
+ int c;
+ Obj *p;
+ p = lookup(yytext, 1);
+ if (p->type == DEFNAME) {
+ c = input();
+ xxunput(c);
+ if (c == '(') /* it's name(...) */
+ dodef(p);
+ else /* no argument list */
+ pbstr(p->val);
+ } else {
+ yylval.op = p;
+ return p->type; /* NAME or VARNAME */
+ }
+ }
+
+<A>"==" return(EQ);
+<A>">=" return(GE);
+<A>"<=" return(LE);
+<A>"!=" return(NE);
+<A>">" return(GT);
+<A>"<" return(LT);
+<A>"&&" return(AND);
+<A>"||" return(OR);
+<A>"!" return(NOT);
+
+<A>\" { BEGIN str; clen = 0; }
+
+<A>#.* ;
+
+<A>. { yylval.i = yytext[0]; return(yytext[0]); }
+
+<str>\" { BEGIN A; cbuf[clen] = 0;
+ yylval.p = tostring(cbuf); return(STRING); }
+<str>\n { WARNING("newline in string"); BEGIN A; return(ST); }
+<str>"\\\"" { cbuf[clen++] = '\\'; cbuf[clen++] = '"'; }
+<str>"\\\\" { cbuf[clen++] = '\\'; cbuf[clen++] = '\\'; }
+<str>. { CADD; }
+
+%%
+
+#ifdef FLEX_SCANNER
+void xxcruft(void)
+{
+ unput(0);
+}
+#endif /* FLEX_SCANNER */
diff --git a/grap/input.c b/grap/input.c
new file mode 100644
index 0000000000000..33451da2cb440
--- /dev/null
+++ b/grap/input.c
@@ -0,0 +1,628 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)input.c 1.7 (gritter) 12/25/06 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include "grap.h"
+#include "y.tab.h"
+
+#if defined (__GLIBC__) && defined (_IO_getc_unlocked)
+#undef getc
+#define getc(f) _IO_getc_unlocked(f)
+#endif
+
+Infile infile[10];
+Infile *curfile = infile;
+
+#define MAXSRC 50
+Src src[MAXSRC]; /* input source stack */
+Src *srcp = src;
+
+void pushsrc(int type, char *ptr) /* new input source */
+{
+ if (++srcp >= src + MAXSRC)
+ FATAL("inputs nested too deep");
+ srcp->type = type;
+ srcp->sp = ptr;
+ if (dbg) {
+ 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:
+ FATAL("pushed bad type %d", srcp->type);
+ }
+ }
+}
+
+void popsrc(void) /* restore an old one */
+{
+ if (srcp <= src)
+ FATAL("too many inputs popped");
+ if (dbg) {
+ 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:
+ FATAL("pop weird input %d", srcp->type);
+ }
+ }
+ srcp--;
+}
+
+void definition(char *s) /* collect definition for s and install */
+ /* definitions picked up lexically */
+{
+ char *p;
+ Obj *stp;
+
+ p = delimstr("definition");
+ stp = lookup(s, 0);
+ if (stp != NULL) { /* it's there before */
+ if (stp->type != DEFNAME) {
+ WARNING("%s used as variable and definition", s);
+ return;
+ }
+ free(stp->val);
+ } else {
+ stp = lookup(s, 1);
+ stp->type = DEFNAME;
+ }
+ stp->val = p;
+ 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)
+ FATAL("end of file in %s %c %.20s... %c", s, delim, buf, delim);
+ *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;
+}
+
+Arg args[10]; /* argument frames */
+Arg *argfp = args; /* frame pointer */
+int argcnt; /* number of arguments seen so far */
+
+void dodef(Obj *stp) /* collect args and switch input to defn */
+{
+ int i, len;
+ char *p;
+ Arg *ap;
+
+ ap = argfp+1;
+ if (ap >= args+10)
+ FATAL("arguments too deep");
+ argcnt = 0;
+ if (input() != '(')
+ FATAL("disaster in dodef");
+ 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->val);
+}
+
+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)
+ FATAL("end of file in getarg!");
+ 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 Obj *thrudef;
+extern char *untilstr;
+
+int input(void)
+{
+ register int c;
+
+ if (thru && begin) {
+ do_thru();
+ begin = 0;
+ }
+ c = nextchar();
+ dprintf(" <%c>", c);
+ if (ep >= ebuf + sizeof ebuf)
+ ep = ebuf;
+ return (*ep++ = c) & 0377;
+}
+
+int nextchar(void)
+{
+ register int c = 0;
+
+ 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)
+ FATAL("argfp underflow");
+ popsrc();
+ goto loop;
+ } else if (c == '$' && isdigit((int)*srcp->sp)) { /* $3 */
+ int n = 0;
+ while (isdigit((int)*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)
+ FATAL("end of file inside .G1/.G2");
+ if (curfile->fin != stdin) {
+ fclose(curfile->fin);
+ free(curfile->fname); /* assumes allocated */
+ }
+ curfile--;
+ printf(".lf %d %s\n", 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)
+ FATAL("arguments too deep");
+ 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;
+ }
+ if (argcnt >= MAXARGS)
+ FATAL("too many fields on input line");
+ 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)
+ FATAL("unexpected end of file in do_thru");
+ 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], ".G2") == 0) {
+ thru = 0;
+ thrudef = 0;
+ pushsrc(String, "\n.G2\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->val);
+ argfp = ap;
+ pushsrc(Macro, thrudef->val);
+}
+
+int unput(int c)
+{
+ if (++pb >= pbuf + sizeof pbuf)
+ FATAL("pushback overflow");
+ 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;
+ WARNING("%s argument out of domain", s);
+ } else if (errno == ERANGE) {
+ errno = 0;
+ WARNING("%s result out of range", s);
+ }
+ return x;
+}
+
+char errbuf[200];
+
+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--)
+ ;
+ for (; p < q; p++)
+ if (isprint((int)*p))
+ putc(*p, stderr);
+ fprintf(stderr, " >>> ");
+ for (; p < q; p++)
+ if (isprint((int)*p))
+ putc(*p, stderr);
+ fprintf(stderr, " <<< ");
+ while (pb >= pbuf)
+ putc(*pb--, stderr);
+ fgets(ebuf, sizeof ebuf, curfile->fin);
+ fprintf(stderr, "%s", ebuf);
+ pbstr("\n.G2\n"); /* safety first */
+ ep = ebuf;
+}
+
+int yywrap(void) {return 1;}
+
+char *newfile = 0; /* filename for file copy */
+char *untilstr = 0; /* string that terminates a thru */
+int thru = 0; /* 1 if copying thru macro */
+Obj *thrudef = 0; /* macro being used */
+
+void copyfile(char *s) /* remember file to start reading from */
+{
+ newfile = s;
+}
+
+void copydef(Obj *p) /* remember macro Obj */
+{
+ thrudef = p;
+}
+
+Obj *copythru(char *s) /* collect the macro name or body for thru */
+{
+ Obj *p;
+ char *q;
+
+ p = lookup(s, 0);
+ if (p != NULL) {
+ if (p->type == DEFNAME) {
+ p->val = addnewline(p->val);
+ return p;
+ } else
+ FATAL("%s used as define and name", s);
+ }
+ /* have to collect the definition */
+ pbstr(s); /* first char is the delimiter */
+ q = delimstr("thru body");
+ p = lookup("nameless", 1);
+ if (p != NULL)
+ if (p->val)
+ free(p->val);
+ p->type = DEFNAME;
+ p->val = q;
+ p->val = addnewline(p->val);
+ dprintf("installing nameless as `%s'\n", p->val);
+ 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)
+ FATAL("can't open file %s", newfile);
+ curfile++;
+ curfile->fin = fin;
+ curfile->fname = tostring(newfile);
+ curfile->lineno = 0;
+ printf(".lf 1 %s\n", 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 */
+{
+ fprintf(tfd, "# shell cmd...\n");
+ shellp = shellbuf;
+}
+
+void shell_text(char *s) /* add string to command being collected */
+{
+ /* fprintf(tfd, "#add <%s> to <%s>\n", s, shellbuf); */
+ while (*s) {
+ if (shellp+5 >= &shellbuf[sizeof shellbuf])
+ FATAL("shell command too long");
+ if (*s == '\'') { /* protect interior quotes */
+ *shellp++ = '\'';
+ *shellp++ = '\\';
+ *shellp++ = '\'';
+ }
+ *shellp++ = *s++;
+ }
+}
+
+void shell_exec(void) /* do it */
+{
+ /* fprintf(tfd, "# run <%s>\n", shellbuf); */
+ *shellp = '\0';
+ if (Sflag)
+ WARNING("-S inhibited execution of shell command");
+ else
+ system(shellbuf);
+}
+
+#define LSIZE 128
+
+char *fgetline(char **line, size_t *linesize, size_t *llen, FILE *fp)
+{
+ int c;
+ size_t n = 0;
+
+ if (*line == NULL || *linesize < LSIZE + n + 1)
+ *line = realloc(*line, *linesize = LSIZE + n + 1);
+ for (;;) {
+ if (n >= *linesize - LSIZE / 2)
+ *line = realloc(*line, *linesize += LSIZE);
+ c = getc(fp);
+ if (c != EOF) {
+ (*line)[n++] = c;
+ (*line)[n] = '\0';
+ if (c == '\n')
+ break;
+ } else {
+ if (n > 0)
+ break;
+ else
+ return NULL;
+ }
+ }
+ if (llen)
+ *llen = n;
+ return *line;
+}
diff --git a/grap/label.c b/grap/label.c
new file mode 100644
index 0000000000000..a633597ba14ae
--- /dev/null
+++ b/grap/label.c
@@ -0,0 +1,140 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)label.c 1.2 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <string.h>
+#include "grap.h"
+#include "y.tab.h"
+
+int pointsize = 10; /* assumed pointsize to start */
+int ps_set = 0; /* someone has set pointsize explicitly */
+
+double textht = 1.0/6.0; /* 6 lines/inch */
+double textwid = 1; /* width of text box for vertical */
+
+double lab_up = 0.0; /* extra motion for label */
+double lab_rt = 0.0; /* extra motion for label */
+double lab_wid = 0.0; /* override default width computation */
+
+void labelwid(double amt)
+{
+ lab_wid = amt + .00001;
+}
+
+void labelmove(int dir, double amt) /* record direction & motion of position corr */
+{
+ switch (dir) {
+ case UP: lab_up += amt; break;
+ case DOWN: lab_up -= amt; break;
+ case LEFT: lab_rt -= amt; break;
+ case RIGHT: lab_rt += amt; break;
+ }
+}
+
+void label(int label_side, Attr *stringlist) /* stick label on label_side */
+{
+ int m;
+ Attr *ap;
+
+ fprintf(tfd, "\ttextht = %g\n", textht);
+ if (lab_wid != 0.0) {
+ fprintf(tfd, "\ttextwid = %g\n", lab_wid);
+ lab_wid = 0;
+ } else if (label_side == LEFT || label_side == RIGHT) {
+ textwid = 0;
+ for (ap = stringlist; ap != NULL; ap = ap->next)
+ if ((m = strlen(ap->sval)) > textwid)
+ textwid = m;
+ textwid /= 15; /* estimate width at 15 chars/inch */
+ fprintf(tfd, "\ttextwid = %g\n", textwid);
+ }
+ fprintf(tfd, "Label:\t%s", slprint(stringlist));
+ freeattr(stringlist);
+ switch (label_side) {
+ case BOT:
+ case 0:
+ fprintf(tfd, " with .n at Frame.s - (0,2 * textht)");
+ break;
+ case LEFT:
+ fprintf(tfd, " wid textwid with .e at Frame.w - (0.2,0)");
+ break;
+ case RIGHT:
+ fprintf(tfd, " wid textwid with .w at Frame.e + (0.2,0)");
+ break;
+ case TOP:
+ fprintf(tfd, " with .s at Frame.n + (0,2 * textht)");
+ break;
+ }
+ lab_adjust();
+ fprintf(tfd, "\n");
+ label_side = BOT;
+}
+
+void lab_adjust(void) /* add a string to adjust labels, ticks, etc. */
+{
+ if (lab_up != 0.0 || lab_rt != 0.0)
+ fprintf(tfd, " + (%g,%g)", lab_rt, lab_up);
+}
+
+char *sizeit(Attr *ap) /* add \s..\s to ap->sval */
+{
+ int n;
+ static char buf[1000];
+
+ if (!ap->op) { /* no explicit size command */
+ if (ps_set) {
+ snprintf(buf, sizeof(buf), "\\s%d%s\\s0", pointsize,
+ ap->sval);
+ return buf;
+ } else
+ return ap->sval;
+ } else if (!ps_set) { /* explicit size but no global size */
+ n = (int) ap->fval;
+ switch (ap->op) {
+ case ' ': /* absolute size */
+ snprintf(buf, sizeof(buf), "\\s%d%s\\s0", n, ap->sval);
+ break;
+ case '+': /* better be only one digit! */
+ snprintf(buf, sizeof(buf), "\\s+%d%s\\s-%d", n,
+ ap->sval, n);
+ break;
+ case '-':
+ snprintf(buf, sizeof(buf), "\\s-%d%s\\s+%d", n,
+ ap->sval, n);
+ break;
+ case '*':
+ case '/':
+ return ap->sval; /* ignore for now */
+ }
+ return buf;
+ } else {
+ /* explicit size and a global background size */
+ n = (int) ap->fval;
+ switch (ap->op) {
+ case ' ': /* absolute size */
+ snprintf(buf, sizeof(buf), "\\s%d%s\\s0", n, ap->sval);
+ break;
+ case '+':
+ snprintf(buf, sizeof(buf), "\\s%d%s\\s0", pointsize+n,
+ ap->sval);
+ break;
+ case '-':
+ snprintf(buf, sizeof(buf), "\\s%d%s\\s0", pointsize-n,
+ ap->sval);
+ break;
+ case '*':
+ case '/':
+ return ap->sval; /* ignore for now */
+ }
+ return buf;
+ }
+}
diff --git a/grap/main.c b/grap/main.c
new file mode 100644
index 0000000000000..ac35127bf3f5a
--- /dev/null
+++ b/grap/main.c
@@ -0,0 +1,187 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)main.c 1.5 (gritter) 12/5/05 */
+#include <stdio.h>
+#include <signal.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "grap.h"
+#include "y.tab.h"
+
+int dbg = 0;
+
+#define GRAPDEFINES LIBDIR "/grap.defines"
+char *lib_defines = GRAPDEFINES;
+
+int lib = 1; /* 1 to include lib_defines */
+FILE *tfd = NULL;
+char tempfile[] = "/var/tmp/grapXXXXXX";
+int Sflag;
+
+int synerr = 0;
+int codegen = 0; /* 1=>output for this picture; 0=>no output */
+char *cmdname;
+
+Obj *objlist = NULL; /* all names stored here */
+
+#define BIG 1e30
+Point ptmin = { NULL, -BIG, -BIG };
+Point ptmax = { NULL, BIG, BIG };
+
+extern const char version[];
+
+extern int yyparse(void);
+extern void setdefaults(void);
+extern void getdata(void);
+
+int
+main(int argc, char *argv[])
+{
+ extern void onintr(int), fpecatch(int);
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, onintr);
+ signal(SIGFPE, fpecatch);
+ cmdname = argv[0];
+ close(mkstemp(tempfile));
+ while (argc > 1 && *argv[1] == '-') {
+ switch (argv[1][1]) {
+ case 'd':
+ dbg = 1;
+ tfd = stdout;
+ n_strcpy(tempfile, "grap.temp", sizeof(tempfile));
+ unlink(tempfile);
+ fprintf(stderr, "%s\n", version);
+ break;
+ case 'l': /* turn off /usr/lib inclusion */
+ lib = 0;
+ break;
+ case 'S':
+ Sflag = 1;
+ break;
+ case 'U':
+ Sflag = 0;
+ break;
+ }
+ argc--;
+ argv++;
+ }
+ setdefaults();
+ curfile = infile;
+ if (argc <= 1) {
+ curfile->fin = stdin;
+ curfile->fname = tostring("-");
+ pushsrc(File, curfile->fname);
+ getdata();
+ } else
+ while (argc-- > 1) {
+ if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
+ fprintf(stderr, "grap: can't open %s\n", *argv);
+ onintr(0);
+ }
+ curfile->fname = tostring(*argv);
+ pushsrc(File, curfile->fname);
+ getdata();
+ fclose(curfile->fin);
+ free(curfile->fname);
+ }
+ if (!dbg)
+ unlink(tempfile);
+ exit(0);
+}
+
+/*ARGSUSED*/
+void onintr(int n)
+{
+ if (!dbg)
+ unlink(tempfile);
+ exit(1);
+}
+
+void fpecatch(int n)
+{
+ WARNING("floating point exception");
+ onintr(n);
+}
+
+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)
+ FATAL("can't grow %s to %d", name, num * size);
+ return p;
+}
+
+static struct {
+ char *name;
+ double val;
+} defaults[] ={
+ { "frameht" , FRAMEHT },
+ { "framewid", FRAMEWID },
+ { "ticklen" , TICKLEN },
+ { "slop" , SLOP },
+ { NULL , 0 }
+};
+
+void setdefaults(void) /* set default sizes for variables */
+{
+ int i;
+ Obj *p;
+
+ for (i = 0; defaults[i].name != NULL; i++) {
+ p = lookup(defaults[i].name, 1);
+ setvar(p, defaults[i].val);
+ }
+}
+
+void getdata(void) /* read input */
+{
+ register FILE *fin;
+ char *buf = NULL, *buf1 = NULL;
+ size_t size = 0;
+ int ln;
+ char *fgetline(char **, size_t *, size_t *, FILE *);
+
+ fin = curfile->fin;
+ curfile->lineno = 0;
+ printf(".lf 1 %s\n", curfile->fname);
+ while (fgetline(&buf, &size, NULL, fin) != NULL) {
+ curfile->lineno++;
+ if (*buf == '.' && *(buf+1) == 'G' && *(buf+2) == '1') {
+ setup();
+ fprintf(stdout, ".PS%s", &buf[3]); /* maps .G1 [w] to .PS w */
+ printf("scale = 1\n"); /* defends against cip users */
+ printf(".lf %d\n", curfile->lineno+1);
+ yyparse();
+ fprintf(stdout, ".PE\n");
+ printf(".lf %d\n", curfile->lineno+1);
+ fflush(stdout);
+ } else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
+ buf1 = realloc(buf1, size);
+ if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
+ free(curfile->fname);
+ printf(".lf %d %s\n", curfile->lineno = ln, curfile->fname = tostring(buf1));
+ } else
+ printf(".lf %d\n", curfile->lineno = ln);
+ } else
+ fputs(buf, stdout);
+ }
+ free(buf);
+ free(buf1);
+}
diff --git a/grap/misc.c b/grap/misc.c
new file mode 100644
index 0000000000000..fa0360403b81e
--- /dev/null
+++ b/grap/misc.c
@@ -0,0 +1,308 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)misc.c 1.3 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "grap.h"
+#include "y.tab.h"
+
+int nnum = 0; /* number of saved numbers */
+double num[MAXNUM];
+
+int just; /* current justification mode (RJUST, etc.) */
+int sizeop; /* current optional operator for size change */
+double sizexpr; /* current size change expression */
+
+void savenum(int n, double f) /* save f in num[n] */
+{
+ num[n] = f;
+ nnum = n+1;
+ if (nnum >= MAXNUM)
+ WARNING("too many numbers");
+}
+
+void setjust(int j)
+{
+ just |= j;
+}
+
+void setsize(int op, double expr)
+{
+ sizeop = op;
+ sizexpr = expr;
+}
+
+char *tostring(char *s)
+{
+ register char *p;
+ size_t l;
+
+ l = strlen(s)+1;
+ p = malloc(l);
+ if (p == NULL)
+ FATAL("out of space in tostring on %s", s);
+ n_strcpy(p, s, l);
+ return(p);
+}
+
+void range(Point pt) /* update the range for point pt */
+{
+ Obj *p = pt.obj;
+
+ if (!(p->coord & XFLAG)) {
+ if (pt.x > p->pt1.x)
+ p->pt1.x = pt.x;
+ if (pt.x < p->pt.x)
+ p->pt.x = pt.x;
+ }
+ if (!(p->coord & YFLAG)) {
+ if (pt.y > p->pt1.y)
+ p->pt1.y = pt.y;
+ if (pt.y < p->pt.y)
+ p->pt.y = pt.y;
+ }
+}
+
+void halfrange(Obj *p, int side, double val) /* record max and min for one direction */
+{
+ if (!(p->coord&XFLAG) && (side == LEFT || side == RIGHT)) {
+ if (val < p->pt.y)
+ p->pt.y = val;
+ if (val > p->pt1.y)
+ p->pt1.y = val;
+ } else if (!(p->coord&YFLAG) && (side == TOP || side == BOT)) {
+ if (val < p->pt.x)
+ p->pt.x = val;
+ if (val > p->pt1.x)
+ p->pt1.x = val;
+ }
+}
+
+
+Obj *lookup(char *s, int inst) /* find s in objlist, install if inst */
+{
+ Obj *p;
+ int found = 0;
+
+ for (p = objlist; p; p = p->next){
+ if (strcmp(s, p->name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (p == NULL && inst != 0) {
+ p = (Obj *) calloc(1, sizeof(Obj));
+ if (p == NULL)
+ FATAL("out of space in lookup");
+ p->name = tostring(s);
+ p->type = NAME;
+ p->pt = ptmax;
+ p->pt1 = ptmin;
+ p->fval = 0.0;
+ p->next = objlist;
+ objlist = p;
+ }
+ dprintf("lookup(%s,%d) = %d\n", s, inst, found);
+ return p;
+}
+
+double getvar(Obj *p) /* return value of variable */
+{
+ return p->fval;
+}
+
+double setvar(Obj *p, double f) /* set value of variable to f */
+{
+ if (strcmp(p->name, "pointsize") == 0) { /* kludge */
+ pointsize = f;
+ ps_set = 1;
+ }
+ p->type = VARNAME;
+ return p->fval = f;
+}
+
+Point makepoint(Obj *s, double x, double y) /* make a Point */
+{
+ Point p;
+
+ dprintf("makepoint: %s, %g,%g\n", s->name, x, y);
+ p.obj = s;
+ p.x = x;
+ p.y = y;
+ return p;
+}
+
+Attr *makefattr(int type, double fval) /* set double in attribute */
+{
+ return makeattr(type, fval, (char *) 0, 0, 0);
+}
+
+Attr *makesattr(char *s) /* make an Attr cell containing s */
+{
+ Attr *ap = makeattr(STRING, sizexpr, s, just, sizeop);
+ just = sizeop = 0;
+ sizexpr = 0.0;
+ return ap;
+}
+
+Attr *makeattr(int type, double fval, char *sval, int just, int op)
+{
+ Attr *a;
+
+ a = (Attr *) malloc(sizeof(Attr));
+ if (a == NULL)
+ FATAL("out of space in makeattr");
+ a->type = type;
+ a->fval = fval;
+ a->sval = sval;
+ a->just = just;
+ a->op = op;
+ a->next = NULL;
+ return a;
+}
+
+Attr *addattr(Attr *a1, Attr *ap) /* add attr ap to end of list a1 */
+{
+ Attr *p;
+
+ if (a1 == 0)
+ return ap;
+ if (ap == 0)
+ return a1;
+ for (p = a1; p->next; p = p->next)
+ ;
+ p->next = ap;
+ return a1;
+}
+
+void freeattr(Attr *ap) /* free an attribute list */
+{
+ Attr *p;
+
+ while (ap) {
+ p = ap->next; /* save next */
+ if (ap->sval)
+ free(ap->sval);
+ free((char *) ap);
+ ap = p;
+ }
+}
+
+char *slprint(Attr *stringlist) /* print strings from stringlist */
+{
+ int ntext, n, last_op, last_just;
+ double last_fval;
+ static char buf[1000];
+ Attr *ap;
+
+ buf[0] = '\0';
+ last_op = last_just = 0;
+ last_fval = 0.0;
+ for (ntext = 0, ap = stringlist; ap != NULL; ap = ap->next)
+ ntext++;
+ snprintf(buf, sizeof(buf), "box invis wid 0 ht %d*textht", ntext);
+ n = strlen(buf);
+ for (ap = stringlist; ap != NULL; ap = ap->next) {
+ if (ap->op == 0) { /* propagate last value */
+ ap->op = last_op;
+ ap->fval = last_fval;
+ } else {
+ last_op = ap->op;
+ last_fval = ap->fval;
+ }
+ snprintf(buf+n, sizeof(buf) - n, " \"%s\"",
+ ps_set || ap->op ? sizeit(ap) : ap->sval);
+ if (ap->just)
+ last_just = ap->just;
+ if (last_just)
+ n_strcat(buf+n, juststr(last_just), sizeof(buf) - n);
+ n = strlen(buf);
+ }
+ return buf; /* watch it: static */
+}
+
+char *juststr(int j) /* convert RJUST, etc., into string */
+{
+ static char buf[50];
+
+ buf[0] = '\0';
+ if (j & RJUST)
+ n_strcat(buf, " rjust", sizeof(buf));
+ if (j & LJUST)
+ n_strcat(buf, " ljust", sizeof(buf));
+ if (j & ABOVE)
+ n_strcat(buf, " above", sizeof(buf));
+ if (j & BELOW)
+ n_strcat(buf, " below", sizeof(buf));
+ return buf; /* watch it: static */
+}
+
+char *sprntf(char *s, Attr *ap) /* sprintf(s, attrlist ap) */
+{
+ char buf[500];
+ int n;
+ Attr *p;
+
+ for (n = 0, p = ap; p; p = p->next)
+ n++;
+ switch (n) {
+ case 0:
+ return s;
+ case 1:
+ snprintf(buf, sizeof(buf), s, ap->fval);
+ break;
+ case 2:
+ snprintf(buf, sizeof(buf), s, ap->fval, ap->next->fval);
+ break;
+ case 3:
+ snprintf(buf, sizeof(buf), s, ap->fval, ap->next->fval,
+ ap->next->next->fval);
+ break;
+ case 5:
+ WARNING("too many expressions in sprintf");
+ case 4:
+ snprintf(buf, sizeof(buf), s, ap->fval, ap->next->fval,
+ ap->next->next->fval, ap->next->next->next->fval);
+ break;
+ }
+ free(s);
+ return tostring(buf);
+}
+
+static void
+verror(const char *fmt, va_list ap)
+{
+ char errbuf[4096];
+
+ vsnprintf(errbuf, sizeof errbuf, fmt, ap);
+ yyerror(errbuf);
+}
+
+void FATAL(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verror(fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void WARNING(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ verror(fmt, ap);
+ va_end(ap);
+}
diff --git a/grap/plot.c b/grap/plot.c
new file mode 100644
index 0000000000000..48f7340de3a33
--- /dev/null
+++ b/grap/plot.c
@@ -0,0 +1,144 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)plot.c 1.3 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "grap.h"
+#include "y.tab.h"
+
+void line(int type, Point p1, Point p2, Attr *desc) /* draw a line segment */
+{
+ fprintf(tfd, "%s %s from %s",
+ type==LINE ? "line" : "arrow", desc_str(desc), xyname(p1));
+ fprintf(tfd, " to %s", xyname(p2)); /* 'cause xyname is botched */
+ fprintf(tfd, "\n");
+ range(p1);
+ range(p2);
+}
+
+void circle(double r, Point pt) /* draw a circle */
+{
+ if (r > 0.0)
+ fprintf(tfd, "circle rad %g at %s\n", r, xyname(pt));
+ else
+ fprintf(tfd, "\"\\s-3\\(ob\\s0\" at %s\n", xyname(pt));
+ range(pt);
+}
+
+char *xyname(Point pt) /* generate xy name macro for point p */
+{
+ static char buf[200];
+ Obj *p;
+
+ p = pt.obj;
+ if (p->log & XFLAG) {
+ if (pt.x <= 0.0)
+ FATAL("can't take log of x coord %g", pt.x);
+ logit(pt.x);
+ }
+ if (p->log & YFLAG) {
+ if (pt.y <= 0.0)
+ FATAL("can't take log of y coord %g", pt.y);
+ logit(pt.y);
+ }
+ snprintf(buf, sizeof(buf), "xy_%s(%g,%g)", p->name, pt.x, pt.y);
+ return buf; /* WATCH IT: static */
+}
+
+void pic(char *s) /* fire out pic stuff directly */
+{
+ while (*s == ' ')
+ s++;
+ fprintf(tfd, "%s\n", s);
+}
+
+int auto_x = 0; /* counts abscissa if none provided */
+
+void numlist(void) /* print numbers in default way */
+{
+ Obj *p;
+ Point pt;
+ int i;
+ static char *spot = "\\(bu";
+ Attr *ap;
+
+ p = pt.obj = lookup(curr_coord, 1);
+ if (nnum == 1) {
+ nnum = 2;
+ num[1] = num[0];
+ num[0] = ++auto_x;
+ }
+ pt.x = num[0];
+ if (p->attr && p->attr->sval)
+ spot = p->attr->sval;
+ for (i = 1; i < nnum; i++) {
+ pt.y = num[i];
+ if (p->attr == 0 || p->attr->type == 0) {
+ ap = makesattr(tostring(spot));
+ plot(ap, pt);
+ } else
+ next(p, pt, p->attr);
+ }
+ nnum = 0;
+}
+
+void plot(Attr *sl, Point pt) /* put stringlist sl at point pt */
+{
+ fprintf(tfd, "%s at %s\n", slprint(sl), xyname(pt));
+ range(pt);
+ freeattr(sl);
+}
+
+void plotnum(double f, char *fmt, Point pt) /* plot value f at point */
+{
+ char buf[100];
+
+ if (fmt) {
+ snprintf(buf, sizeof(buf), fmt, f);
+ free(fmt);
+ } else if (f >= 0.0)
+ snprintf(buf, sizeof(buf), "%g", f);
+ else
+ snprintf(buf, sizeof(buf), "\\-%g", -f);
+ fprintf(tfd, "\"%s\" at %s\n", buf, xyname(pt));
+ range(pt);
+}
+
+void drawdesc(int type, Obj *p, Attr *desc, char *s) /* set line description for p */
+{
+ p->attr = desc;
+ p->attr->sval = s;
+ if (type == NEW) {
+ p->first = 0; /* so it really looks new */
+ auto_x = 0;
+ }
+}
+
+void next(Obj *p, Point pt, Attr *desc) /* add component to a path */
+{
+ char *s;
+
+ if (p->first == 0) {
+ p->first++;
+ fprintf(tfd, "L%s: %s\n", p->name, xyname(pt));
+ } else {
+ fprintf(tfd, "line %s from L%s to %s; L%s: Here\n",
+ desc_str(desc->type ? desc : p->attr),
+ p->name, xyname(pt), p->name);
+ }
+ if (p->attr && (s=p->attr->sval)) {
+ /* BUG: should fix size here */
+ fprintf(tfd, "\"%s\" at %s\n", s, xyname(pt));
+ }
+ range(pt);
+}
diff --git a/grap/print.c b/grap/print.c
new file mode 100644
index 0000000000000..d8df0d11e8337
--- /dev/null
+++ b/grap/print.c
@@ -0,0 +1,247 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)print.c 1.3 (gritter) 10/18/05 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include "grap.h"
+#include "y.tab.h"
+
+double margin = MARGIN; /* extra space around edges */
+extern double frame_ht, frame_wid, ticklen;
+extern int just, sizeop, tick_dir;
+extern double sizexpr, lab_up, lab_rt;
+
+char graphname[50] = "Graph";
+char graphpos[200] = "";
+
+void print(void) /* arrange final output */
+{
+ FILE *fd;
+ Obj *p, *dfp;
+ int c;
+ double dx, dy, xfac, yfac;
+
+ if (tfd != NULL) {
+ fclose(tfd); /* end the temp file */
+ tfd = stdout;
+ }
+
+ if ((p=lookup("margin",0)) != NULL)
+ margin = p->fval;
+ if (frame_ht < 0) /* wasn't set explicitly, so use default */
+ frame_ht = getvar(lookup("frameht", 0));
+ if (frame_wid < 0)
+ frame_wid = getvar(lookup("framewid", 0));
+ dfp = NULL;
+ for (p = objlist; p; p = p->next) {
+ dprintf("print: name = <%s>, type = %d\n", p->name, p->type);
+ if (p->type == NAME) {
+ Point pt, pt1;
+ pt = p->pt;
+ pt1 = p->pt1;
+ fprintf(tfd, "\t# %s %g .. %g, %g .. %g\n",
+ p->name, pt.x, pt1.x, pt.y, pt1.y);
+ if (p->log & XFLAG) {
+ if (pt.x <= 0.0)
+ FATAL("can't take log of x coord %g", pt.x);
+ logit(pt.x);
+ logit(pt1.x);
+ }
+ if (p->log & YFLAG) {
+ if (pt.y <= 0.0)
+ FATAL("can't take log of y coord %g", pt.y);
+ logit(pt.y);
+ logit(pt1.y);
+ }
+ if (!(p->coord & XFLAG)) {
+ dx = pt1.x - pt.x;
+ pt.x -= margin * dx;
+ pt1.x += margin * dx;
+ }
+ if (!(p->coord & YFLAG)) {
+ dy = pt1.y - pt.y;
+ pt.y -= margin * dy;
+ pt1.y += margin * dy;
+ }
+ if (autoticks && strcmp(p->name, dflt_coord) == 0) {
+ p->pt = pt;
+ p->pt1 = pt1;
+ if (p->log & XFLAG) {
+ p->pt.x = pow(10.0, pt.x);
+ p->pt1.x = pow(10.0, pt1.x);
+ }
+ if (p->log & YFLAG) {
+ p->pt.y = pow(10.0, pt.y);
+ p->pt1.y = pow(10.0, pt1.y);
+ }
+ dfp = setauto();
+ }
+ dx = pt1.x - pt.x;
+ dy = pt1.y - pt.y;
+ xfac = dx > 0 ? frame_wid/dx : frame_wid/2;
+ yfac = dy > 0 ? frame_ht/dy : frame_ht/2;
+
+ fprintf(tfd, "define xy_%s @ ", p->name);
+ if (dx > 0)
+ fprintf(tfd, "\t(($1)-(%g))*%g", pt.x, xfac);
+ else
+ fprintf(tfd, "\t%g", xfac);
+ if (dy > 0)
+ fprintf(tfd, ", (($2)-(%g))*%g @\n", pt.y, yfac);
+ else
+ fprintf(tfd, ", %g @\n", yfac);
+ fprintf(tfd, "define x_%s @ ", p->name);
+ if (dx > 0)
+ fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.x, xfac);
+ else
+ fprintf(tfd, "\t%g @\n", xfac);
+ fprintf(tfd, "define y_%s @ ", p->name);
+ if (dy > 0)
+ fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.y, yfac);
+ else
+ fprintf(tfd, "\t%g @\n", yfac);
+ }
+ }
+ if (codegen)
+ frame();
+ if (codegen && autoticks && dfp)
+ do_autoticks(dfp);
+
+ if ((fd = fopen(tempfile, "r")) != NULL) {
+ while ((c = getc(fd)) != EOF)
+ putc(c, tfd);
+ fclose(fd);
+ }
+ tfd = NULL;
+}
+
+void endstat(void) /* clean up after each statement */
+{
+
+ just = sizeop = 0;
+ lab_up = lab_rt = 0.0;
+ sizexpr = 0.0;
+ nnum = 0;
+ ntick = 0;
+ tside = 0;
+ tick_dir = OUT;
+ ticklen = TICKLEN;
+}
+
+void graph(char *s) /* graph statement */
+{
+ char *p, *os;
+ int c;
+
+ if (codegen) {
+ fprintf(stdout, "%s: [\n", graphname);
+ print(); /* pump out previous graph */
+ fprintf(stdout, "\n] %s\n", graphpos);
+ reset();
+ }
+ if (s) {
+ dprintf("into graph with <%s>\n", s);
+ opentemp();
+ os = s;
+ while ((c = *s) == ' ' || c == '\t')
+ s++;
+ if (c == '\0')
+ WARNING("no name on graph statement");
+ if (!isupper((int)s[0]))
+ WARNING("graph name %s must be capitalized", s);
+ for (p=graphname; (c = *s) != ' ' && c != '\t' && c != '\0'; )
+ *p++ = *s++;
+ *p = '\0';
+ n_strcpy(graphpos, s, sizeof(graphpos));
+ dprintf("graphname = <%s>, graphpos = <%s>\n", graphname, graphpos);
+ free(os);
+ }
+}
+
+void setup(void) /* done at each .G1 */
+{
+ static int firstG1 = 0;
+
+ reset();
+ opentemp();
+ frame_ht = frame_wid = -1; /* reset in frame() */
+ ticklen = getvar(lookup("ticklen", 0));
+ if (firstG1++ == 0)
+ do_first();
+ codegen = synerr = 0;
+ n_strcpy(graphname, "Graph", sizeof(graphname));
+ n_strcpy(graphpos, "", sizeof(graphpos));
+}
+
+void do_first(void) /* done at first .G1: definitions, etc. */
+{
+ extern int lib;
+ extern char *lib_defines;
+ static char buf[50], buf1[50]; /* static because pbstr uses them */
+ FILE *fp;
+ extern int getpid(void);
+
+ snprintf(buf, sizeof(buf), "define pid /%d/\n", getpid());
+ pbstr(buf);
+ if (lib != 0) {
+ if ((fp = fopen(lib_defines, "r")) != NULL) {
+ snprintf(buf1, sizeof(buf1), "copy \"%s\"\n",
+ lib_defines);
+ pbstr(buf1);
+ fclose(fp);
+ } else {
+ fprintf(stderr, "grap warning: can't open %s\n", lib_defines);
+ }
+ }
+}
+
+void reset(void) /* done at each "graph ..." statement */
+{
+ Obj *p, *np, *deflist;
+ extern int tlist, toffside, autodir;
+
+ curr_coord = dflt_coord;
+ ncoord = auto_x = 0;
+ autoticks = LEFT|BOT;
+ autodir = 0;
+ tside = tlist = toffside = 0;
+ tick_dir = OUT;
+ margin = MARGIN;
+ deflist = NULL;
+ for (p = objlist; p; p = np) {
+ np = p->next;
+ if (p->type == DEFNAME || p->type == VARNAME) {
+ p->next = deflist;
+ deflist = p;
+ } else {
+ free(p->name);
+ freeattr(p->attr);
+ free((char *) p);
+ }
+ }
+ objlist = deflist;
+}
+
+void opentemp(void)
+{
+ if (tfd != stdout) {
+ if (tfd != NULL)
+ fclose(tfd);
+ if ((tfd = fopen(tempfile, "w")) == NULL) {
+ fprintf(stderr, "grap: can't open %s\n", tempfile);
+ exit(1);
+ }
+ }
+}
diff --git a/grap/ticks.c b/grap/ticks.c
new file mode 100644
index 0000000000000..63a693d78a35e
--- /dev/null
+++ b/grap/ticks.c
@@ -0,0 +1,508 @@
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, October 2005.
+ *
+ * Derived from Plan 9 v4 /sys/src/cmd/grap/
+ *
+ * Copyright (C) 2003, Lucent Technologies Inc. and others.
+ * All Rights Reserved.
+ *
+ * Distributed under the terms of the Lucent Public License Version 1.02.
+ */
+
+/* Sccsid @(#)ticks.c 1.4 (gritter) 11/27/05 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "grap.h"
+#include "y.tab.h"
+
+#define MAXTICK 200
+int ntick = 0;
+double tickval[MAXTICK]; /* tick values (one axis at a time */
+char *tickstr[MAXTICK]; /* and labels */
+
+int tside = 0;
+int tlist = 0; /* 1 => explicit values given */
+int toffside = 0; /* no ticks on these sides */
+int goffside = 0; /* no ticks on grid on these sides */
+int tick_dir = OUT;
+double ticklen = TICKLEN; /* default tick length */
+int autoticks = LEFT|BOT;
+int autodir = 0; /* set LEFT, etc. if automatic ticks go in */
+
+void savetick(double f, char *s) /* remember tick location and label */
+{
+ if (ntick >= MAXTICK)
+ FATAL("too many ticks (%d)", MAXTICK);
+ tickval[ntick] = f;
+ tickstr[ntick] = s;
+ ntick++;
+}
+
+void dflt_tick(double f)
+{
+ if (f == 0) /* avoid negative zero */
+ f = 0;
+ if (f >= 0.0)
+ savetick(f, tostring("%g"));
+ else
+ savetick(f, tostring("\\%g"));
+}
+
+void tickside(int n) /* remember which side these ticks/gridlines go on */
+{
+ tside |= n;
+}
+
+void tickoff(int side) /* remember explicit sides */
+{
+ toffside |= side;
+}
+
+void gridtickoff(void) /* turn grid ticks off on the side previously specified (ugh) */
+{
+ goffside = tside;
+}
+
+void setlist(void) /* remember that there was an explicit list */
+{
+ tlist = 1;
+}
+
+void tickdir(int dir, double val, int explicit) /* remember in/out [expr] */
+{
+ tick_dir = dir;
+ if (explicit)
+ ticklen = val;
+}
+
+void ticks(void) /* set autoticks after ticks statement */
+{
+ /* was there an explicit "ticks [side] off"? */
+ if (toffside)
+ autoticks &= ~toffside;
+ /* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */
+ if (tlist) {
+ if (tside & (BOT|TOP))
+ autoticks &= ~(BOT|TOP);
+ if (tside & (LEFT|RIGHT))
+ autoticks &= ~(LEFT|RIGHT);
+ }
+ /* was there a side without a list? (eg "ticks left in") */
+ if (tside && !tlist) {
+ if (tick_dir == IN)
+ autodir |= tside;
+ if (tside & (BOT|TOP))
+ autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP));
+ if (tside & (LEFT|RIGHT))
+ autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT));
+ }
+ tlist = tside = toffside = goffside = 0;
+ tick_dir = OUT;
+}
+
+double modfloor(double f, double t)
+{
+ t = fabs(t);
+ return floor(f/t) * t;
+}
+
+double modceil(double f, double t)
+{
+ t = fabs(t);
+ return ceil(f/t) * t;
+}
+
+double xtmin, xtmax; /* range of ticks */
+double ytmin, ytmax;
+double xquant, xmult; /* quantization & scale for auto x ticks */
+double yquant, ymult;
+double lograt = 5;
+
+void do_autoticks(Obj *p) /* make set of ticks for default coord only */
+{
+ double x, xl, xu, q;
+
+ if (p == NULL)
+ return;
+ fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g",
+ p->pt.x, p->pt1.x, p->pt.y, p->pt1.y);
+ fprintf(tfd, "; xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n",
+ xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult);
+ if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) { /* make x ticks */
+ q = xquant;
+ xl = p->pt.x;
+ xu = p->pt1.x;
+ if (xl >= xu)
+ dflt_tick(xl);
+ else if ((p->log & XFLAG) && xu/xl >= lograt) {
+ for (x = q; x < xu; x *= 10) {
+ logtick(x, xl, xu);
+ if (xu/xl <= 100) {
+ logtick(2*x, xl, xu);
+ logtick(5*x, xl, xu);
+ }
+ }
+ } else {
+ xl = modceil(xtmin - q/100, q);
+ xu = modfloor(xtmax + q/100, q) + q/2;
+ for (x = xl; x <= xu; x += q)
+ dflt_tick(x);
+ }
+ tside = autoticks & (BOT|TOP);
+ ticklist(p, 0);
+ }
+ if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) { /* make y ticks */
+ q = yquant;
+ xl = p->pt.y;
+ xu = p->pt1.y;
+ if (xl >= xu)
+ dflt_tick(xl);
+ else if ((p->log & YFLAG) && xu/xl >= lograt) {
+ for (x = q; x < xu; x *= 10) {
+ logtick(x, xl, xu);
+ if (xu/xl <= 100) {
+ logtick(2*x, xl, xu);
+ logtick(5*x, xl, xu);
+ }
+ }
+ } else {
+ xl = modceil(ytmin - q/100, q);
+ xu = modfloor(ytmax + q/100, q) + q/2;
+ for (x = xl; x <= xu; x += q)
+ dflt_tick(x);
+ }
+ tside = autoticks & (LEFT|RIGHT);
+ ticklist(p, 0);
+ }
+}
+
+void logtick(double v, double lb, double ub)
+{
+ float slop = 1.0; /* was 1.001 */
+
+ if (slop * lb <= v && ub >= slop * v)
+ dflt_tick(v);
+}
+
+Obj *setauto(void) /* compute new min,max, and quant & mult */
+{
+ Obj *p, *q;
+
+ if ((q = lookup("lograt",0)) != NULL)
+ lograt = q->fval;
+ for (p = objlist; p; p = p->next)
+ if (p->type == NAME && strcmp(p->name,dflt_coord) == 0)
+ break;
+ if (p) {
+ if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt)
+ autolog(p, 'x');
+ else
+ autoside(p, 'x');
+ if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt)
+ autolog(p, 'y');
+ else
+ autoside(p, 'y');
+ }
+ return p;
+}
+
+void autoside(Obj *p, int side)
+{
+ double r, s, d, ub, lb;
+
+ if (side == 'x') {
+ xtmin = lb = p->pt.x;
+ xtmax = ub = p->pt1.x;
+ } else {
+ ytmin = lb = p->pt.y;
+ ytmax = ub = p->pt1.y;
+ }
+ if (ub <= lb)
+ return; /* cop out on little ranges */
+ d = ub - lb;
+ r = s = 1;
+ while (d * s < 10)
+ s *= 10;
+ d *= s;
+ while (10 * r < d)
+ r *= 10;
+ if (r > d/3)
+ r /= 2;
+ else if (r <= d/6)
+ r *= 2;
+ if (side == 'x') {
+ xquant = r / s;
+ } else {
+ yquant = r / s;
+ }
+}
+
+void autolog(Obj *p, int side)
+{
+ double r, s, t, ub, lb;
+ int flg;
+
+ if (side == 'x') {
+ xtmin = lb = p->pt.x;
+ xtmax = ub = p->pt1.x;
+ flg = p->coord & XFLAG;
+ } else {
+ ytmin = lb = p->pt.y;
+ ytmax = ub = p->pt1.y;
+ flg = p->coord & YFLAG;
+ }
+ for (s = 1; lb * s < 1; s *= 10)
+ ;
+ lb *= s;
+ ub *= s;
+ for (r = 1; 10 * r < lb; r *= 10)
+ ;
+ for (t = 1; t < ub; t *= 10)
+ ;
+ if (side == 'x')
+ xquant = r / s;
+ else
+ yquant = r / s;
+ if (flg)
+ return;
+ if (ub / lb < 100) {
+ if (lb >= 5 * r)
+ r *= 5;
+ else if (lb >= 2 * r)
+ r *= 2;
+ if (ub * 5 <= t)
+ t /= 5;
+ else if (ub * 2 <= t)
+ t /= 2;
+ if (side == 'x') {
+ xtmin = r / s;
+ xtmax = t / s;
+ } else {
+ ytmin = r / s;
+ ytmax = t / s;
+ }
+ }
+}
+
+void iterator(double from, double to, int op, double by, char *fmt) /* create an iterator */
+{
+ double x;
+
+ /* should validate limits, etc. */
+ /* punt for now */
+
+ dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n",
+ from, to, by, op, fmt ? fmt : "");
+ switch (op) {
+ case '+':
+ case ' ':
+ for (x = from; x <= to + (SLOP-1) * by; x += by)
+ if (fmt)
+ savetick(x, tostring(fmt));
+ else
+ dflt_tick(x);
+ break;
+ case '-':
+ for (x = from; x >= to; x -= by)
+ if (fmt)
+ savetick(x, tostring(fmt));
+ else
+ dflt_tick(x);
+ break;
+ case '*':
+ for (x = from; x <= SLOP * to; x *= by)
+ if (fmt)
+ savetick(x, tostring(fmt));
+ else
+ dflt_tick(x);
+ break;
+ case '/':
+ for (x = from; x >= to; x /= by)
+ if (fmt)
+ savetick(x, tostring(fmt));
+ else
+ dflt_tick(x);
+ break;
+ }
+ if (fmt)
+ free(fmt);
+}
+
+void ticklist(Obj *p, int explicit) /* fire out the accumulated ticks */
+ /* 1 => list, 0 => auto */
+{
+ if (p == NULL)
+ return;
+ fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen);
+ print_ticks(TICKS, explicit, p, "ticklen", "");
+}
+
+void print_ticks(int type, int explicit, Obj *p, char *lenstr, char *descstr)
+{
+ int i, logflag, inside;
+ char buf[100];
+ double tv;
+
+ for (i = 0; i < ntick; i++) /* any ticks given explicitly? */
+ if (tickstr[i] != NULL)
+ break;
+ if (i >= ntick && type == TICKS) /* no, so use values */
+ for (i = 0; i < ntick; i++) {
+ if (tickval[i] >= 0.0)
+ snprintf(buf, sizeof(buf), "%g", tickval[i]);
+ else
+ snprintf(buf, sizeof(buf), "\\-%g",
+ -tickval[i]);
+ tickstr[i] = tostring(buf);
+ }
+ else
+ for (i = 0; i < ntick; i++) {
+ if (tickstr[i] != NULL) {
+ snprintf(buf, sizeof(buf), tickstr[i],
+ tickval[i]);
+ free(tickstr[i]);
+ tickstr[i] = tostring(buf);
+ }
+ }
+ logflag = sidelog(p->log, tside);
+ for (i = 0; i < ntick; i++) {
+ tv = tickval[i];
+ halfrange(p, tside, tv);
+ if (logflag) {
+ if (tv <= 0.0)
+ FATAL("can't take log of tick value %g", tv);
+ logit(tv);
+ }
+ if (type == GRID)
+ inside = LEFT|RIGHT|TOP|BOT;
+ else if (explicit)
+ inside = (tick_dir == IN) ? tside : 0;
+ else
+ inside = autodir;
+ if (tside & BOT)
+ maketick(type, p->name, BOT, inside, tv, tickstr[i], lenstr, descstr);
+ if (tside & TOP)
+ maketick(type, p->name, TOP, inside, tv, tickstr[i], lenstr, descstr);
+ if (tside & LEFT)
+ maketick(type, p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr);
+ if (tside & RIGHT)
+ maketick(type, p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr);
+ if (tickstr[i]) {
+ free(tickstr[i]);
+ tickstr[i] = NULL;
+ }
+ }
+ ntick = 0;
+}
+
+void maketick(int type, char *name, int side, int inflag, double val, char *lab, char *lenstr, char *descstr)
+{
+ char *sidestr, *td;
+
+ fprintf(tfd, "\tline %s ", descstr);
+ inflag &= side;
+ switch (side) {
+ case BOT:
+ case 0:
+ td = inflag ? "up" : "down";
+ fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val);
+ break;
+ case TOP:
+ td = inflag ? "down" : "up";
+ fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val);
+ break;
+ case LEFT:
+ td = inflag ? "right" : "left";
+ fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val);
+ break;
+ case RIGHT:
+ td = inflag ? "left" : "right";
+ fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val);
+ break;
+ }
+ fprintf(tfd, "\n");
+ if (type == GRID && (side & goffside)) /* wanted no ticks on grid */
+ return;
+ sidestr = tick_dir == IN ? "start" : "end";
+ if (lab != NULL) {
+ /* BUG: should fix size of lab here */
+ double wid = strlen(lab)/7.5 + (tick_dir == IN ? 0 : 0.1); /* estimate width at 15 chars/inch */
+ switch (side) {
+ case BOT: case 0:
+ /* can drop "box invis" with new pic */
+ fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s",
+ lab, sidestr);
+ break;
+ case TOP:
+ fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s",
+ lab, sidestr);
+ break;
+ case LEFT:
+ fprintf(tfd, "\t\"%s \" wid %.2f rjust at last line.%s",
+ lab, wid, sidestr);
+ break;
+ case RIGHT:
+ fprintf(tfd, "\t\" %s\" wid %.2f ljust at last line.%s",
+ lab, wid, sidestr);
+ break;
+ }
+ /* BUG: works only if "down x" comes before "at wherever" */
+ lab_adjust();
+ fprintf(tfd, "\n");
+ }
+}
+
+Attr *grid_desc = 0;
+
+void griddesc(Attr *a)
+{
+ grid_desc = a;
+}
+
+void gridlist(Obj *p)
+{
+ char *framestr;
+
+ if ((tside & (BOT|TOP)) || tside == 0)
+ framestr = "frameht";
+ else
+ framestr = "framewid";
+ fprintf(tfd, "Grid_%s:\n", p->name);
+ tick_dir = IN;
+ print_ticks(GRID, 0, p, framestr, desc_str(grid_desc));
+ if (grid_desc) {
+ freeattr(grid_desc);
+ grid_desc = 0;
+ }
+}
+
+char *desc_str(Attr *a) /* convert DOT to "dotted", etc. */
+{
+ static char buf[50], *p;
+
+ if (a == NULL)
+ return p = "";
+ switch (a->type) {
+ case DOT: p = "dotted"; break;
+ case DASH: p = "dashed"; break;
+ case INVIS: p = "invis"; break;
+ default: p = "";
+ }
+ if (a->fval != 0.0) {
+ snprintf(buf, sizeof(buf), "%s %g", p, a->fval);
+ return buf;
+ } else
+ return p;
+}
+
+int sidelog(int logflag, int side) /* figure out whether to scale a side */
+{
+ if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0))
+ return 1;
+ else if ((logflag & YFLAG) && (side & (LEFT|RIGHT)))
+ return 1;
+ else
+ return 0;
+}
diff --git a/grap/version.c b/grap/version.c
new file mode 100644
index 0000000000000..177d8e0e7bea9
--- /dev/null
+++ b/grap/version.c
@@ -0,0 +1,30 @@
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define USED __attribute__ ((used))
+#elif defined __GNUC__
+#define USED __attribute__ ((unused))
+#else
+#define USED
+#endif
+static const char sccsid[] USED = "@(#)/usr/ucb/grap.sl 5.7 (gritter) 12/25/06";
+const char version[] = "version Dec 30, 1995 5.7 (gritter) 12/25/06";
+/* SLIST */
+/*
+coord.c: Sccsid @(#)coord.c 1.3 (gritter) 10/18/05
+for.c: Sccsid @(#)for.c 1.3 (gritter) 10/18/05
+frame.c: Sccsid @(#)frame.c 1.3 (gritter) 10/18/05
+grap.c: Sccsid @(#)grap.y 1.3 (gritter) 10/18/05
+grap.c: * Sccsid @(#)yaccpar 1.5 (gritter) 11/26/05
+grap.h: Sccsid @(#)grap.h 1.5 (gritter) 12/5/05
+grap.y: Sccsid @(#)grap.y 1.3 (gritter) 10/18/05
+grapl.c: Sccsid @(#)grapl.l 1.4 (gritter) 11/22/05
+grapl.c: * Sccsid @(#)ncform 1.4 (gritter) 11/18/05
+grapl.l: Sccsid @(#)grapl.l 1.4 (gritter) 11/22/05
+input.c: Sccsid @(#)input.c 1.7 (gritter) 12/25/06
+label.c: Sccsid @(#)label.c 1.2 (gritter) 10/18/05
+main.c: Sccsid @(#)main.c 1.5 (gritter) 12/5/05
+misc.c: Sccsid @(#)misc.c 1.3 (gritter) 10/18/05
+plot.c: Sccsid @(#)plot.c 1.3 (gritter) 10/18/05
+print.c: Sccsid @(#)print.c 1.3 (gritter) 10/18/05
+ticks.c: Sccsid @(#)ticks.c 1.4 (gritter) 11/27/05
+grap.defines:# Sccsid @(#)grap.defines 1.2 (gritter) 10/18/05
+*/