summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwlemb <wlemb>2000-02-20 20:52:41 +0000
committerwlemb <wlemb>2000-02-20 20:52:41 +0000
commit3db97d20e4ba1d638ba442523516b3cc0dff62bf (patch)
treeea45b33a10d3067fdce6e755c2161d3808fc1344
parentd3870161ba184b022f53bb6437143f4e3037b515 (diff)
downloadgroff-3db97d20e4ba1d638ba442523516b3cc0dff62bf.tar.gz
Initial revision
-rw-r--r--src/preproc/grn/Makefile.sub16
-rw-r--r--src/preproc/grn/README60
-rw-r--r--src/preproc/grn/gprint.h84
-rw-r--r--src/preproc/grn/grn.man356
-rw-r--r--src/preproc/grn/hdb.cc324
-rw-r--r--src/preproc/grn/hgraph.cc1041
-rw-r--r--src/preproc/grn/hpoint.cc49
-rw-r--r--src/preproc/grn/main.cc902
8 files changed, 2832 insertions, 0 deletions
diff --git a/src/preproc/grn/Makefile.sub b/src/preproc/grn/Makefile.sub
new file mode 100644
index 00000000..0e2aa79d
--- /dev/null
+++ b/src/preproc/grn/Makefile.sub
@@ -0,0 +1,16 @@
+PROG=grn
+MAN1=grn.n
+XLIBS=$(LIBGROFF)
+OBJS=\
+ hdb.o \
+ hpoint.o \
+ hgraph.o \
+ main.o
+CCSRCS=\
+ $(srcdir)/hdb.cc \
+ $(srcdir)/hpoint.cc \
+ $(srcdir)/hgraph.cc \
+ $(srcdir)/main.cc
+HDRS=\
+ $(srcdir)/gprint.h
+NAMEPREFIX=$(g)
diff --git a/src/preproc/grn/README b/src/preproc/grn/README
new file mode 100644
index 00000000..b5b9fc9a
--- /dev/null
+++ b/src/preproc/grn/README
@@ -0,0 +1,60 @@
+This is grn from the Berkeley ditroff distribution. It has no
+AT&T code and is therefore freely distributable.
+
+Tim Theisen <tim@cs.wisc.edu>
+
+=====================================================================
+
+This is the modified code for the groff. It uses the different
+devxxx format that is ascii rather than binary as in the
+Berkeley distribution. Since groff does not have the \Ds option
+for line drawing (dotted, dashed, etc.), this version includes
+the routines for drawing curves and arcs, so it does not use the
+\D~, \Da nor \Dc. Although also included in here is a routine
+for drawing the optional gremlin style curves, it is not used
+because the gremlin editor uses the conventional spline
+algorithm. The Berkeley grn has the choice of different
+stipples. Here, only different shades of gray will be painted
+depending on the gremlin file. It is possible to upgrade this at
+a later time. (Daniel Senderowicz <daniel@synchrods.com> 12/28/99)
+
+=====================================================================
+
+It has been further modified by Werner Lemberg <wl@gnu.org> to fit
+better into the groff package.
+
+ . Replaced Makefile with Makefile.sub.
+
+ . Removed dev.h since it is unused.
+
+ . Renamed grn.1 to grn.man; this man page has been extensively
+ revised.
+
+ . Used error() and fatal() from libgroff for all source files.
+
+ . Renamed *.c to *.cc; updates as needed for C++ (prototypes, proper
+ casts, standard header files etc). Heavy formatting.
+
+ . main.cc:
+
+ Using groff's default values instead of DEVDIR, DEFAULTDEV, PRINTER,
+ TYPESETTER, and GREMLIB.
+
+ `res' is now an integer.
+
+ Added `-C' command flag (for compatibility mode) as with other
+ preprocessors.
+
+ Added `-F' and `-v' option (similar to troff).
+
+ Renamed `-L' option to `-M' for consistence.
+
+ Removed `-P' option.
+
+ Using font::load_desc() for scanning DESC files.
+
+ Removed SYSV-specific code.
+
+ Using macro_path.open_file() for getting gremlin graphic files.
+
+ Added usage().
diff --git a/src/preproc/grn/gprint.h b/src/preproc/grn/gprint.h
new file mode 100644
index 00000000..b25305b3
--- /dev/null
+++ b/src/preproc/grn/gprint.h
@@ -0,0 +1,84 @@
+/* Last non-groff version: gprint.h 1.1 84/10/08
+ *
+ * This file contains standard definitions used by the gprint program.
+ */
+
+#include <stdio.h>
+#include <math.h>
+
+
+#define xorn(x,y) (x)
+ /* was 512 */
+#define yorn(x,y) (511 - (y)) /* switch direction for */
+ /* y-coordinates */
+
+#define STYLES 6
+#define SIZES 4
+#define FONTS 4
+#define SOLID -1
+#define DOTTED 004 /* 014 */
+#define DASHED 020 /* 034 */
+#define DOTDASHED 024 /* 054 */
+#define LONGDASHED 074
+
+#define DEFTHICK -1 /* default thicknes */
+#define DEFSTYLE SOLID /* default line style */
+
+#define TRUE 1
+#define FALSE 0
+
+#define nullelt -1
+#define nullpt -1
+#define nullun NULL
+
+#define BOTLEFT 0
+#define BOTRIGHT 1
+#define CENTCENT 2
+#define VECTOR 3
+#define ARC 4
+#define CURVE 5
+#define POLYGON 6
+#define TOPLEFT 10
+#define TOPCENT 11
+#define TOPRIGHT 12
+#define CENTLEFT 13
+#define CENTRIGHT 14
+#define BOTCENT 15
+#define TEXT(t) ( (t <= CENTCENT) || (t >= TOPLEFT) )
+
+/* WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * The above (TEXT) test is dependent on the relative values of the
+ * constants and will have to change if these values change or if new
+ * commands are added with value greater than BOTCENT
+ */
+
+#define NUSER 4
+#define NFONTS 4
+#define NBRUSHES 6
+#define NSIZES 4
+#define NJUSTS 9
+#define NSTIPPLES 16
+
+#define ADD 1
+#define DELETE 2
+#define MOD 3
+
+typedef struct point {
+ float x, y;
+ struct point *nextpt;
+} POINT;
+
+typedef struct elmt {
+ int type, brushf, size, textlength;
+ char *textpt;
+ POINT *ptlist;
+ struct elmt *nextelt, *setnext;
+} ELT;
+
+#define DBNextElt(elt) (elt->nextelt)
+#define DBNextofSet(elt) (elt->setnext)
+#define DBNullelt(elt) (elt == NULL)
+#define Nullpoint(pt) ((pt) == (POINT *) NULL)
+#define PTNextPoint(pt) (pt->nextpt)
+
+/* EOF */
diff --git a/src/preproc/grn/grn.man b/src/preproc/grn/grn.man
new file mode 100644
index 00000000..cee00f83
--- /dev/null
+++ b/src/preproc/grn/grn.man
@@ -0,0 +1,356 @@
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.\" Like TP, but if specified indent is more than half
+.\" the current line-length - indent, use the default indent.
+.de Tp
+.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
+.el .TP "\\$1"
+..
+.TH GRN @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+@g@grn \- groff preprocessor for gremlin files
+.SH SYNOPSIS
+.BR @g@grn
+[ options ] ... [
+.I file
+] ...
+.SH DESCRIPTION
+.I @g@grn
+is a preprocessor for including
+.I gremlin
+pictures in
+.I groff
+input.
+.I @g@grn
+writes to standard output, processing only input lines between two that
+start with
+.B .GS
+and
+.BR .GE.
+Those lines must contain
+.I @g@grn
+commands (see below).
+These commands request a
+.I gremlin
+file, and the picture in that file is
+converted and placed in the
+.I troff
+input stream.
+The
+.B .GS
+request may be followed by a C, L, or R to center, left, or right
+justify the whole
+.I gremlin
+picture (default justification is center).
+If no
+.I file
+is mentioned, the standard input is read.
+At the end of the picture, the position on the page is the bottom of the
+.I gremlin
+picture.
+If the
+.I @g@grn
+entry is ended with
+.B .GF
+instead of
+.BR .GE ,
+the position is left at the top of the picture.
+.PP
+Please note that currently only the \-me macro package has support for
+.BR .GS ,
+.BR .GE ,
+and
+.BR .GF .
+.PP
+The following command-line options are understood:
+.TP
+.BI \-T dev
+Prepare output for printer
+.IR dev .
+The default device is
+.BR @DEVICE@ .
+See
+.BR groff (@MAN1EXT@)
+for acceptable devices.
+.TP
+.BI \-M dir
+Set the library to directory
+.IR dir .
+If a
+.I gremlin
+file cannot be found in the current directory,
+.I dir
+is prepended to the filename for a second try.
+The default library directory is
+.BR @MACRODIR@ .
+.TP
+.BI \-F dir
+Search
+.I dir
+for subdirectories
+.BI dev name
+.RI ( name
+is the name of the device) for the
+.B DESC
+file before the normal
+.BR @FONTDIR@ .
+.TP
+.B \-C
+Recognize
+.B .GS
+and
+.B .GE
+(resp.
+.BR .GF )
+even when followed by a character other than space or newline.
+.TP
+.B \-s
+This switch causes the picture to be traversed twice:
+The first time, only the interiors of filled polygons (as borderless
+polygons) are printed.
+The second time, the outline is printed as a series of line segments.
+This way, postprocessors that overwrite rather than merge picture elements
+(such as Postscript) can still have text and graphics on a shaded
+background.
+.TP
+.B \-v
+Print the version number.
+.SH GRN COMMANDS
+Each input line between
+.B .GS
+and
+.B .GE
+may have one
+.I @g@grn
+command.
+Commands consist of one or two strings separated by white space, the first
+string being the command and the second its operand.
+Commands may be upper or lower case and abbreviated down to one character.
+.PP
+Commands that affect a picture's environment (those listed before
+.BR default ,
+see below) are only in effect for the current picture:
+The environment is reinitialized to the defaults at the start of the next
+picture.
+The commands are as follows:
+.TP
+.BI 1\ N
+.TQ
+.BI 2\ N
+.TQ
+.BI 3\ N
+.TQ
+.BI 4\ N
+Set
+.IR gremlin 's
+text size number 1 (2, 3, or 4) to
+.I N
+points.
+The default is 12 (resp. 16, 24, and 36).
+.TP
+.BI roman\ f
+.TQ
+.BI italics\ f
+.TQ
+.BI bold\ f
+.TQ
+.BI special\ f
+Set the roman (italics, bold, or special) font to
+.IR troff 's
+font
+.I f
+(either a name or number).
+The default is R (resp. I, B, and S).
+.TP
+.BI l\ f
+.TQ
+.BI stipple\ f
+Set the stipple font to
+.IR troff 's
+stipple font
+.I f
+(name or number).
+The command
+.B stipple
+may be abbreviated down as far as `st' (to avoid
+confusion with
+.BR special ).
+There is
+.I no
+default for stipples (unless one is set by the default command), and it is
+illegal to include a
+.I gremlin
+picture with polygons without specifying a
+stipple font.
+.TP
+.BI x\ N
+.TQ
+.BI scale\ N
+Magnify the picture (in addition to any default magnification) by
+.IR N ,
+a floating point number larger than zero.
+The command
+.B scale
+may be abbreviated down to `sc'.
+.TP
+.BI narrow\ N
+.TQ
+.BI medium\ N
+.TQ
+.BI thick\ N
+Set the thickness of
+.IR gremlin 's
+narrow (medium or thick) lines to
+.IR N .
+The default is 1 (resp. 3 and 5) pixels.
+.TP
+.BI pointscale\ <off/on>
+Scale text to match the picture.
+Gremlin text is usually printed in the point size specified with the
+commands
+.BR 1 ,\ 2 ,\ 3 ,\ or\ 4
+regardless of any scaling factors in the picture.
+Setting
+.B pointscale
+will cause the point sizes to scale with the picture (within
+.IR troff 's
+limitations, of course).
+An operand of anything but
+.I off
+will turn text scaling on.
+.TP
+.B default
+Reset the picture environment defaults to the settings in the current
+picture.
+This is meant to be used as a global parameter setting mechanism at the
+beginning of the
+.I troff
+input file, but can be used at any time to reset the
+default settings.
+.TP
+.BI width\ N
+Forces the picture to be
+.I N
+inches wide.
+This overrides any scaling factors present in the same picture.
+.RB ` width
+.IR 0 '
+is ignored.
+.TP
+.BI height\ N
+Forces picture to be
+.I N
+inches high, overriding other scaling factors.
+If both `width' and `height' are specified the tighter constraint will
+determine the scale of the picture.
+.B Height
+and
+.B width
+commands are not saved with a
+.B default
+command.
+They will, however, affect point size scaling if that option is set.
+.TP
+.BI file\ name
+Get picture from
+.I gremlin
+file
+.I name
+located the current directory (or in the library directory; see the
+.B \-M
+option above).
+If two
+.B file
+commands are given, the second one overrides the first.
+If
+.I name
+doesn't exist, an error message is reported and processing continues from
+the
+.B .GE
+line.
+.SH NOTES ABOUT GROFF
+Since
+.I @g@grn
+is a preprocessor, it doesn't know about current indents, point sizes,
+margins, number registers, etc.
+Consequently, no
+.I troff
+input can be placed between the
+.B .GS
+and
+.B .GE
+requests.
+However,
+.I gremlin
+text is now processed by
+.IR troff ,
+so anything legal in a single line of
+.I troff
+input is legal in a line of
+.I gremlin
+text (barring `.' directives at the beginning of a line).
+Thus, it is possible to have equations within a
+.I gremlin
+figure by including in the
+.I gremlin
+file
+.I eqn
+expressions enclosed by previously defined delimiters (e.g.
+.IR $$ ).
+.PP
+When using
+.I @g@grn
+along with other preprocessors, it is best to run
+.I tbl
+before
+.IR @g@grn ,
+.IR pic ,
+and/or
+.I ideal
+to avoid overworking
+.IR tbl .
+.I Eqn
+should always be run last.
+.PP
+A picture is considered an entity, but that doesn't stop
+.I troff
+from trying to break it up if it falls off the end of a page.
+Placing the picture between `keeps' in \-me macros will ensure proper
+placement.
+.PP
+.I @g@grn
+uses
+.IR troff 's
+number registers
+.B g1
+through
+.B g9
+and sets registers
+.B g1
+and
+.B g2
+to the width and height of the
+.I gremlin
+figure (in device units) before entering the
+.B .GS
+request (this is for those who want to rewrite these macros).
+.SH FILES
+.Tp \w'@FONTDIR@/devname/DESC'u+3n
+.BI @FONTDIR@/dev name /DESC
+Device description file for device
+.IR name .
+.SH SEE ALSO
+.BR gremlin (1),
+.BR groff (@MAN1EXT@),
+.BR pic (@MAN1EXT@),
+.BR ideal (1)
+.SH HISTORY
+.PP
+David Slattengren and Barry Roitblat wrote the original Berkeley
+.IR grn .
+.PP
+Daniel Senderowicz and Werner Lemberg modified it for
+.IR groff .
diff --git a/src/preproc/grn/hdb.cc b/src/preproc/grn/hdb.cc
new file mode 100644
index 00000000..1d860aae
--- /dev/null
+++ b/src/preproc/grn/hdb.cc
@@ -0,0 +1,324 @@
+/* Last non-groff version: hdb.c 1.8 (Berkeley) 84/10/20
+ *
+ * Copyright -C- 1982 Barry S. Roitblat
+ *
+ * This file contains database routines for the hard copy programs of the
+ * gremlin picture editor.
+ */
+
+#include "gprint.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "errarg.h"
+#include "error.h"
+
+#define MAXSTRING 128
+
+/* imports from main.cc */
+
+extern int linenum; /* current line number in input file */
+extern char gremlinfile[]; /* name of file currently reading */
+extern int SUNFILE; /* TRUE if SUN gremlin file */
+extern int savebounds(float x, float y);
+
+/* imports from hpoint.cc */
+
+extern POINT *PTInit();
+extern POINT *PTMakePoint(float x, float y, POINT ** pplist);
+
+
+int DBGetType(register char *s);
+
+
+/*
+ * This routine returns a pointer to an initialized database element which
+ * would be the only element in an empty list.
+ */
+ELT *
+DBInit(void)
+{
+ return ((ELT *) NULL);
+} /* end DBInit */
+
+
+/*
+ * This routine creates a new element with the specified attributes and
+ * links it into database.
+ */
+ELT *
+DBCreateElt(int type,
+ POINT * pointlist,
+ int brush,
+ int size,
+ char *text,
+ ELT **db)
+{
+ register ELT *temp;
+
+ temp = (ELT *) malloc(sizeof(ELT));
+ temp->nextelt = *db;
+ temp->type = type;
+ temp->ptlist = pointlist;
+ temp->brushf = brush;
+ temp->size = size;
+ temp->textpt = text;
+ *db = temp;
+ return (temp);
+} /* end CreateElt */
+
+
+/*
+ * This routine reads the specified file into a database and returns a
+ * pointer to that database.
+ */
+ELT *
+DBRead(register FILE *file)
+{
+ register int i;
+ register int done; /* flag for input exhausted */
+ register float nx; /* x holder so x is not set before orienting */
+ int type; /* element type */
+ ELT *elist; /* pointer to the file's elements */
+ POINT *plist; /* pointer for reading in points */
+ char string[MAXSTRING], *txt;
+ float x, y; /* x and y are read in point coords */
+ int len, brush, size;
+ int lastpoint;
+
+ SUNFILE = FALSE;
+ elist = DBInit();
+ (void) fscanf(file, "%s\n", string);
+ if (strcmp(string, "gremlinfile")) {
+ if (strcmp(string, "sungremlinfile")) {
+ error("`%1' is not a gremlin file", gremlinfile);
+ return (elist);
+ }
+ SUNFILE = TRUE;
+ }
+
+ (void) fscanf(file, "%d%f%f\n", &size, &x, &y);
+ /* ignore orientation and file positioning point */
+
+ done = FALSE;
+ while (!done) {
+ /* if (fscanf(file,"%s\n", string) == EOF) */
+ /* I changed the scanf format because the element */
+ /* can have two words (e.g. CURVE SPLINE) */
+ if (fscanf(file, "\n%[^\n]\n", string) == EOF) {
+ error("`%1', error in file format", gremlinfile);
+ return (elist);
+ }
+
+ type = DBGetType(string); /* interpret element type */
+ if (type < 0) { /* no more data */
+ done = TRUE;
+ (void) fclose(file);
+ } else {
+#ifdef UW_FASTSCAN
+ (void) xscanf(file, &x, &y); /* always one point */
+#else
+ (void) fscanf(file, "%f%f\n", &x, &y); /* always one point */
+#endif /* UW_FASTSCAN */
+ plist = PTInit(); /* NULL point list */
+
+ /*
+ * Files created on the SUN have point lists terminated by a line
+ * containing only an asterik ('*'). Files created on the AED have
+ * point lists terminated by the coordinate pair (-1.00 -1.00).
+ */
+ if (TEXT(type)) { /* read only first point for TEXT elements */
+ nx = xorn(x, y);
+ y = yorn(x, y);
+ (void) PTMakePoint(nx, y, &plist);
+ savebounds(nx, y);
+
+#ifdef UW_FASTSCAN
+ while (xscanf(file, &x, &y));
+#else
+ lastpoint = FALSE;
+ do {
+ fgets(string, MAXSTRING, file);
+ if (string[0] == '*') { /* SUN gremlin file */
+ lastpoint = TRUE;
+ } else {
+ (void) sscanf(string, "%f%f", &x, &y);
+ if ((x == -1.00 && y == -1.00) && (!SUNFILE))
+ lastpoint = TRUE;
+ }
+ } while (!lastpoint);
+#endif /* UW_FASTSCAN */
+ } else { /* not TEXT element */
+#ifdef UW_FASTSCAN
+ do {
+ nx = xorn(x, y);
+ y = yorn(x, y);
+ (void) PTMakePoint(nx, y, &plist);
+ savebounds(nx, y);
+ } while (xscanf(file, &x, &y));
+#else
+ lastpoint = FALSE;
+ while (!lastpoint) {
+ nx = xorn(x, y);
+ y = yorn(x, y);
+ (void) PTMakePoint(nx, y, &plist);
+ savebounds(nx, y);
+
+ fgets(string, MAXSTRING, file);
+ if (string[0] == '*') { /* SUN gremlin file */
+ lastpoint = TRUE;
+ } else {
+ (void) sscanf(string, "%f%f", &x, &y);
+ if ((x == -1.00 && y == -1.00) && (!SUNFILE))
+ lastpoint = TRUE;
+ }
+ }
+#endif /* UW_FASTSCAN */
+ }
+ (void) fscanf(file, "%d%d\n", &brush, &size);
+ (void) fscanf(file, "%d", &len); /* text length */
+ (void) getc(file); /* eat blank */
+ txt = (char *) malloc((unsigned) len + 1);
+ for (i = 0; i < len; ++i) { /* read text */
+ txt[i] = getc(file);
+ }
+ txt[len] = '\0';
+ (void) DBCreateElt(type, plist, brush, size, txt, &elist);
+ } /* end else */
+ } /* end while not done */ ;
+ return (elist);
+} /* end DBRead */
+
+
+/*
+ * Interpret element type in string s.
+ * Old file format consisted of integer element types.
+ * New file format has literal names for element types.
+ */
+int
+DBGetType(register char *s)
+{
+ if (isdigit(s[0]) || (s[0] == '-')) /* old element format or EOF */
+ return (atoi(s));
+
+ switch (s[0]) {
+ case 'P':
+ return (POLYGON);
+ case 'V':
+ return (VECTOR);
+ case 'A':
+ return (ARC);
+ case 'C':
+ if (s[1] == 'U')
+ return (CURVE);
+ switch (s[4]) {
+ case 'L':
+ return (CENTLEFT);
+ case 'C':
+ return (CENTCENT);
+ case 'R':
+ return (CENTRIGHT);
+ default:
+ fatal("unknown element type");
+ }
+ case 'B':
+ switch (s[3]) {
+ case 'L':
+ return (BOTLEFT);
+ case 'C':
+ return (BOTCENT);
+ case 'R':
+ return (BOTRIGHT);
+ default:
+ fatal("unknown element type");
+ }
+ case 'T':
+ switch (s[3]) {
+ case 'L':
+ return (TOPLEFT);
+ case 'C':
+ return (TOPCENT);
+ case 'R':
+ return (TOPRIGHT);
+ default:
+ fatal("unknown element type");
+ }
+ default:
+ fatal("unknown element type");
+ }
+}
+
+#ifdef UW_FASTSCAN
+/*
+ * Optimization hack added by solomon@crys.wisc.edu, 12/2/86.
+ * A huge fraction of the time was spent reading floating point numbers from
+ * the input file, but the numbers always have the format 'ddd.dd'. Thus
+ * the following special-purpose version of fscanf.
+ *
+ * xscanf(f,xp,yp) does roughly what fscanf(f,"%f%f",xp,yp) does except:
+ * -the next piece of input must be of the form
+ * <space>* <digit>*'.'<digit>* <space>* <digit>*'.'<digit>*
+ * -xscanf eats the character following the second number
+ * -xscanf returns 0 for "end-of-data" indication, 1 otherwise, where
+ * end-of-data is signalled by a '*' [in which case the rest of the
+ * line is gobbled], or by '-1.00 -1.00' [but only if !SUNFILE].
+ */
+int
+xscanf(FILE *f,
+ float *xp,
+ float *yp)
+{
+ register int c, i, j, m, frac;
+ int iscale = 1, jscale = 1; /* x = i/scale, y=j/jscale */
+
+ while ((c = getc(f)) == ' ');
+ if (c == '*') {
+ while ((c = getc(f)) != '\n');
+ return 0;
+ }
+ i = m = frac = 0;
+ while (isdigit(c) || c == '.' || c == '-') {
+ if (c == '-') {
+ m++;
+ c = getc(f);
+ continue;
+ }
+ if (c == '.')
+ frac = 1;
+ else {
+ if (frac)
+ iscale *= 10;
+ i = 10 * i + c - '0';
+ }
+ c = getc(f);
+ }
+ if (m)
+ i = -i;
+ *xp = (double) i / (double) iscale;
+
+ while ((c = getc(f)) == ' ');
+ j = m = frac = 0;
+ while (isdigit(c) || c == '.' || c == '-') {
+ if (c == '-') {
+ m++;
+ c = getc(f);
+ continue;
+ }
+ if (c == '.')
+ frac = 1;
+ else {
+ if (frac)
+ jscale *= 10;
+ j = 10 * j + c - '0';
+ }
+ c = getc(f);
+ }
+ if (m)
+ j = -j;
+ *yp = (double) j / (double) jscale;
+ return (SUNFILE || i != -iscale || j != -jscale);
+}
+#endif /* UW_FASTSCAN */
+
+/* EOF */
diff --git a/src/preproc/grn/hgraph.cc b/src/preproc/grn/hgraph.cc
new file mode 100644
index 00000000..4948e3b6
--- /dev/null
+++ b/src/preproc/grn/hgraph.cc
@@ -0,0 +1,1041 @@
+/* Last non-groff version: hgraph.c 1.14 (Berkeley) 84/11/27
+ *
+ * This file contains the graphics routines for converting gremlin pictures
+ * to troff input.
+ */
+
+#include "gprint.h"
+
+
+#define MAXVECT 40
+#define MAXPOINTS 200
+#define LINELENGTH 1
+#define PointsPerInterval 64
+#define pi 3.14159265358979324
+#define twopi (2.0 * pi)
+#define len(a, b) hypot((double)(b.x-a.x), (double)(b.y-a.y))
+
+
+extern int prevval; /* spacing between dots */
+extern int dotshifter; /* for the length of dotted curves */
+
+extern int style[]; /* line and character styles */
+extern int thick[];
+extern char *tfont[];
+extern int tsize[];
+extern int stipple_index[]; /* stipple font index for stipples 0 - 16 */
+extern char *stipple; /* stipple type (cf or ug) */
+
+
+extern double troffscale; /* imports from main.c */
+extern int linethickness;
+extern int linmod;
+extern int lastx;
+extern int lasty;
+extern int lastyline;
+extern int ytop;
+extern int ybottom;
+extern int xleft;
+extern int xright;
+extern enum {
+ OUTLINE, FILL, BOTH
+} polyfill;
+
+extern double adj1;
+extern double adj2;
+extern double adj3;
+extern double adj4;
+extern int res;
+
+void HGSetFont(int font, int size);
+void HGPutText(int justify, POINT pnt, register char *string);
+void HGSetBrush(int mode);
+void tmove2(int px, int py);
+void doarc(POINT cp, POINT sp, int angle);
+void tmove(POINT * ptr);
+void cr(void);
+void drawwig(POINT * ptr);
+void HGtline(int x1, int y1);
+void dx(double x);
+void dy(double y);
+void HGArc(register int cx, register int cy, int px, int py, int angle);
+void picurve(register int *x, register int *y, int npts);
+void Paramaterize(int x[], int y[], float h[], int n);
+void PeriodicSpline(float h[], int z[],
+ float dz[], float d2z[], float d3z[],
+ int npoints);
+void NaturalEndSpline(float h[], int z[],
+ float dz[], float d2z[], float d3z[],
+ int npoints);
+
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: HGPrintElt (element_pointer, baseline)
+ |
+ | Results: Examines a picture element and calls the appropriate
+ | routine(s) to print them according to their type. After the
+ | picture is drawn, current position is (lastx, lasty).
+ *----------------------------------------------------------------------------*/
+
+void
+HGPrintElt(ELT *element,
+ int baseline)
+{
+ register POINT *p1;
+ register POINT *p2;
+ register int length;
+ register int graylevel;
+
+ if (!DBNullelt(element) && !Nullpoint((p1 = element->ptlist))) {
+ /* p1 always has first point */
+ if (TEXT(element->type)) {
+ HGSetFont(element->brushf, element->size);
+ switch (element->size) {
+ case 1:
+ p1->y += adj1;
+ break;
+ case 2:
+ p1->y += adj2;
+ break;
+ case 3:
+ p1->y += adj3;
+ break;
+ case 4:
+ p1->y += adj4;
+ break;
+ default:
+ break;
+ }
+ HGPutText(element->type, *p1, element->textpt);
+ } else {
+ if (element->brushf) /* if there is a brush, the */
+ HGSetBrush(element->brushf); /* graphics need it set */
+
+ switch (element->type) {
+
+ case ARC:
+ p2 = PTNextPoint(p1);
+ tmove(p2);
+ doarc(*p1, *p2, element->size);
+ cr();
+ break;
+
+ case CURVE:
+ length = 0; /* keep track of line length */
+ drawwig(p1);
+ cr();
+ break;
+
+ case VECTOR:
+ length = 0; /* keep track of line length so */
+ tmove(p1); /* single lines don't get long */
+ while (!Nullpoint((p1 = PTNextPoint(p1)))) {
+ HGtline((int) (p1->x * troffscale),
+ (int) (p1->y * troffscale));
+ if (length++ > LINELENGTH) {
+ length = 0;
+ printf("\\\n");
+ }
+ } /* end while */
+ cr();
+ break;
+
+ case POLYGON:
+ {
+ /* brushf = style of outline; size = color of fill:
+ * on first pass (polyfill=FILL), do the interior using 'P'
+ * unless size=0
+ * on second pass (polyfill=OUTLINE), do the outline using a series
+ * of vectors. It might make more sense to use \D'p ...',
+ * but there is no uniform way to specify a 'fill character'
+ * that prints as 'no fill' on all output devices (and
+ * stipple fonts).
+ * If polyfill=BOTH, just use the \D'p ...' command.
+ */
+ float firstx = p1->x;
+ float firsty = p1->y;
+
+ length = 0; /* keep track of line length so */
+ /* single lines don't get long */
+
+ if (polyfill == FILL || polyfill == BOTH) {
+ /* do the interior */
+ char command = (polyfill == BOTH && element->brushf) ? 'p' : 'P';
+
+ /* include outline, if there is one and */
+ /* the -p flag was set */
+
+ /* switch based on what gremlin gives */
+ switch (element->size) {
+ case 1:
+ graylevel = 1;
+ break;
+ case 3:
+ graylevel = 2;
+ break;
+ case 12:
+ graylevel = 3;
+ break;
+ case 14:
+ graylevel = 4;
+ break;
+ case 16:
+ graylevel = 5;
+ break;
+ case 19:
+ graylevel = 6;
+ break;
+ case 21:
+ graylevel = 7;
+ break;
+ case 23:
+ graylevel = 8;
+ break;
+ default: /* who's giving something else? */
+ graylevel = NSTIPPLES;
+ break;
+ }
+ /* int graylevel = element->size; */
+
+ if (graylevel < 0)
+ break;
+ if (graylevel > NSTIPPLES)
+ graylevel = NSTIPPLES;
+ printf("\\h'-%du'\\D'f %du'",
+ stipple_index[graylevel],
+ stipple_index[graylevel]);
+ cr();
+ tmove(p1);
+ printf("\\D'%c", command);
+
+ while (!Nullpoint((PTNextPoint(p1)))) {
+ p1 = PTNextPoint(p1);
+ dx((double) p1->x);
+ dy((double) p1->y);
+ if (length++ > LINELENGTH) {
+ length = 0;
+ printf("\\\n");
+ }
+ } /* end while */
+
+ /* close polygon if not done so by user */
+ if ((firstx != p1->x) || (firsty != p1->y)) {
+ dx((double) firstx);
+ dy((double) firsty);
+ }
+ putchar('\'');
+ cr();
+ break;
+ }
+ /* else polyfill == OUTLINE; only draw the outline */
+ if (!(element->brushf))
+ break;
+ length = 0; /* keep track of line length */
+ tmove(p1);
+
+ while (!Nullpoint((PTNextPoint(p1)))) {
+ p1 = PTNextPoint(p1);
+ HGtline((int) (p1->x * troffscale),
+ (int) (p1->y * troffscale));
+ if (length++ > LINELENGTH) {
+ length = 0;
+ printf("\\\n");
+ }
+ } /* end while */
+
+ /* close polygon if not done so by user */
+ if ((firstx != p1->x) || (firsty != p1->y)) {
+ HGtline((int) (firstx * troffscale),
+ (int) (firsty * troffscale));
+ }
+ cr();
+ break;
+ } /* end case POLYGON */
+ } /* end switch */
+ } /* end else Text */
+ } /* end if */
+} /* end PrintElt */
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: HGPutText (justification, position_point, string)
+ |
+ | Results: Given the justification, a point to position with, and a
+ | string to put, HGPutText first sends the string into a
+ | diversion, moves to the positioning point, then outputs
+ | local vertical and horizontal motions as needed to justify
+ | the text. After all motions are done, the diversion is
+ | printed out.
+ *----------------------------------------------------------------------------*/
+
+void
+HGPutText(int justify,
+ POINT pnt,
+ register char *string)
+{
+ int savelasty = lasty; /* vertical motion for text is to be */
+ /* ignored. Save current y here */
+
+ printf(".nr g8 \\n(.d\n"); /* save current vertical position. */
+ printf(".ds g9 \""); /* define string containing the text. */
+ while (*string) { /* put out the string */
+ if (*string == '\\' &&
+ *(string + 1) == '\\') { /* one character at a */
+ printf("\\\\\\"); /* time replacing // */
+ string++; /* by //// to prevent */
+ } /* interpretation at */
+ printf("%c", *(string++)); /* printout time */
+ }
+ printf("\n");
+
+ tmove(&pnt); /* move to positioning point */
+
+ switch (justify) {
+ /* local vertical motions */
+ /* (the numbers here are used to be somewhat compatible with gprint) */
+ case CENTLEFT:
+ case CENTCENT:
+ case CENTRIGHT:
+ printf("\\v'0.85n'"); /* down half */
+ break;
+
+ case TOPLEFT:
+ case TOPCENT:
+ case TOPRIGHT:
+ printf("\\v'1.7n'"); /* down whole */
+ }
+
+ switch (justify) {
+ /* local horizontal motions */
+ case BOTCENT:
+ case CENTCENT:
+ case TOPCENT:
+ printf("\\h'-\\w'\\*(g9'u/2u'"); /* back half */
+ break;
+
+ case BOTRIGHT:
+ case CENTRIGHT:
+ case TOPRIGHT:
+ printf("\\h'-\\w'\\*(g9'u'"); /* back whole */
+ }
+
+ printf("\\&\\*(g9\n"); /* now print the text. */
+ printf(".sp |\\n(g8u\n"); /* restore vertical position */
+ lasty = savelasty; /* vertical position restored to where it */
+ lastx = xleft; /* was before text, also horizontal is at */
+ /* left */
+} /* end HGPutText */
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: doarc (center_point, start_point, angle)
+ |
+ | Results: Produces either drawarc command or a drawcircle command
+ | depending on the angle needed to draw through.
+ *----------------------------------------------------------------------------*/
+
+void
+doarc(POINT cp,
+ POINT sp,
+ int angle)
+{
+ if (angle) /* arc with angle */
+ HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
+ (int) (sp.x * troffscale), (int) (sp.y * troffscale), angle);
+ else /* a full circle (angle == 0) */
+ HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
+ (int) (sp.x * troffscale), (int) (sp.y * troffscale), 0);
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: HGSetFont (font_number, Point_size)
+ |
+ | Results: ALWAYS outputs a .ft and .ps directive to troff. This is
+ | done because someone may change stuff inside a text string.
+ | Changes thickness back to default thickness. Default
+ | thickness depends on font and pointsize.
+ *----------------------------------------------------------------------------*/
+
+void
+HGSetFont(int font,
+ int size)
+{
+ printf(".ft %s\n"
+ ".ps %d\n", tfont[font - 1], tsize[size - 1]);
+ linethickness = DEFTHICK;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: HGSetBrush (line_mode)
+ |
+ | Results: Generates the troff commands to set up the line width and
+ | style of subsequent lines. Does nothing if no change is
+ | needed.
+ |
+ | Side Efct: Sets `linmode' and `linethicknes'.
+ *----------------------------------------------------------------------------*/
+
+void
+HGSetBrush(int mode)
+{
+ register int printed = 0;
+
+ if (linmod != style[--mode]) {
+ /* Groff doesn't understand \Ds, so we take it out */
+ /* printf ("\\D's %du'", linmod = style[mode]); */
+ linmod = style[mode];
+ printed = 1;
+ }
+ if (linethickness != thick[mode]) {
+ linethickness = thick[mode];
+ printf("\\h'-%du'\\D't %du'", linethickness, linethickness);
+ printed = 1;
+ }
+ if (printed)
+ cr();
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: dx (x_destination)
+ |
+ | Results: Scales and outputs a number for delta x (with a leading
+ | space) given `lastx' and x_destination.
+ |
+ | Side Efct: Resets `lastx' to x_destination.
+ *----------------------------------------------------------------------------*/
+
+void
+dx(double x)
+{
+ register int ix = (int) (x * troffscale);
+
+ printf(" %du", ix - lastx);
+ lastx = ix;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: dy (y_destination)
+ |
+ | Results: Scales and outputs a number for delta y (with a leading
+ | space) given `lastyline' and y_destination.
+ |
+ | Side Efct: Resets `lastyline' to y_destination. Since `line' vertical
+ | motions don't affect `page' ones, `lasty' isn't updated.
+ *----------------------------------------------------------------------------*/
+
+void
+dy(double y)
+{
+ register int iy = (int) (y * troffscale);
+
+ printf(" %du", iy - lastyline);
+ lastyline = iy;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: tmove2 (px, py)
+ |
+ | Results: Produces horizontal and vertical moves for troff given the
+ | pair of points to move to and knowing the current position.
+ | Also puts out a horizontal move to start the line. This is
+ | a variation without the .sp command.
+ *----------------------------------------------------------------------------*/
+
+void
+tmove2(int px,
+ int py)
+{
+ register int dx;
+ register int dy;
+
+ if (dy = py - lasty) {
+ printf("\\v'%du'", dy);
+ }
+ lastyline = lasty = py; /* lasty is always set to current */
+ if (dx = px - lastx) {
+ printf("\\h'%du'", dx);
+ lastx = px;
+ }
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: tmove (point_pointer)
+ |
+ | Results: Produces horizontal and vertical moves for troff given the
+ | pointer of a point to move to and knowing the current
+ | position. Also puts out a horizontal move to start the
+ | line.
+ *----------------------------------------------------------------------------*/
+
+void
+tmove(POINT * ptr)
+{
+ register int ix = (int) (ptr->x * troffscale);
+ register int iy = (int) (ptr->y * troffscale);
+ register int dx;
+ register int dy;
+
+ if (dy = iy - lasty) {
+ printf(".sp %du\n", dy);
+ }
+ lastyline = lasty = iy; /* lasty is always set to current */
+ if (dx = ix - lastx) {
+ printf("\\h'%du'", dx);
+ lastx = ix;
+ }
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: cr ( )
+ |
+ | Results: Ends off an input line. `.sp -1' is also added to counteract
+ | the vertical move done at the end of text lines.
+ |
+ | Side Efct: Sets `lastx' to `xleft' for troff's return to left margin.
+ *----------------------------------------------------------------------------*/
+
+void
+cr(void)
+{
+ printf("\n.sp -1\n");
+ lastx = xleft;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: line ( )
+ |
+ | Results: Draws a single solid line to (x,y).
+ *----------------------------------------------------------------------------*/
+
+void
+line(int px,
+ int py)
+{
+ printf("\\D'l");
+ printf(" %du", px - lastx);
+ printf(" %du'", py - lastyline);
+ lastx = px;
+ lastyline = lasty = py;
+}
+
+
+/*----------------------------------------------------------------------------
+ | Routine: drawwig (ptr)
+ |
+ | Results: The point sequence found in the structure pointed by ptr is
+ | placed in integer arrays for further manipulation by the
+ | existing routing. With the proper parameters, HGCurve is
+ | called.
+ *----------------------------------------------------------------------------*/
+
+void
+drawwig(POINT * ptr)
+{
+ register int npts; /* point list index */
+ int x[MAXPOINTS], y[MAXPOINTS]; /* point list */
+
+ for (npts = 1; !Nullpoint(ptr); ptr = PTNextPoint(ptr), npts++) {
+ x[npts] = (int) (ptr->x * troffscale);
+ y[npts] = (int) (ptr->y * troffscale);
+ }
+ if (--npts) {
+ /* HGCurve(&x[0], &y[0], npts); */ /*Gremlin looks different, so... */
+ picurve(&x[0], &y[0], npts);
+ }
+}
+
+
+/*----------------------------------------------------------------------------
+ | Routine: HGArc (xcenter, ycenter, xstart, ystart, angle)
+ |
+ | Results: This routine plots an arc centered about (cx, cy) counter
+ | clockwise starting from the point (px, py) through `angle'
+ | degrees. If angle is 0, a full circle is drawn. It does so
+ | by creating a draw-path around the arc whose density of
+ | points depends on the size of the arc.
+ *----------------------------------------------------------------------------*/
+
+void
+HGArc(register int cx,
+ register int cy,
+ int px,
+ int py,
+ int angle)
+{
+ double xs, ys, resolution, fullcircle;
+ int m;
+ register int mask;
+ register int extent;
+ register int nx;
+ register int ny;
+ register int length;
+ register double epsilon;
+
+ xs = px - cx;
+ ys = py - cy;
+
+ length = 0;
+
+ resolution = (1.0 + hypot(xs, ys) / res) * PointsPerInterval;
+ /* mask = (1 << (int) log10(resolution + 1.0)) - 1; */
+ (void) frexp(resolution, &m); /* A bit more elegant than log10 */
+ for (mask = 1; mask < m; mask = mask << 1);
+ mask -= 1;
+
+ epsilon = 1.0 / resolution;
+ fullcircle = (2.0 * pi) * resolution;
+ if (angle == 0)
+ extent = (int) fullcircle;
+ else
+ extent = (int) (angle * fullcircle / 360.0);
+
+ HGtline(px, py);
+ while (--extent >= 0) {
+ xs += epsilon * ys;
+ nx = cx + (int) (xs + 0.5);
+ ys -= epsilon * xs;
+ ny = cy + (int) (ys + 0.5);
+ if (!(extent & mask)) {
+ HGtline(nx, ny); /* put out a point on circle */
+ if (length++ > LINELENGTH) {
+ length = 0;
+ printf("\\\n");
+ }
+ }
+ } /* end for */
+} /* end HGArc */
+
+
+/*----------------------------------------------------------------------------
+ | Routine: picurve (xpoints, ypoints, num_of_points)
+ |
+ | Results: Draws a curve delimited by (not through) the line segments
+ | traced by (xpoints, ypoints) point list. This is the `Pic'
+ | style curve.
+ *----------------------------------------------------------------------------*/
+
+void
+picurve(register int *x,
+ register int *y,
+ int npts)
+{
+ register int nseg; /* effective resolution for each curve */
+ register int xp; /* current point (and temporary) */
+ register int yp;
+ int pxp, pyp; /* previous point (to make lines from) */
+ int i; /* inner curve segment traverser */
+ int length = 0;
+ double w; /* position factor */
+ double t1, t2, t3; /* calculation temps */
+
+ if (x[1] == x[npts] && y[1] == y[npts]) {
+ x[0] = x[npts - 1]; /* if the lines' ends meet, make */
+ y[0] = y[npts - 1]; /* sure the curve meets */
+ x[npts + 1] = x[2];
+ y[npts + 1] = y[2];
+ } else { /* otherwise, make the ends of the */
+ x[0] = x[1]; /* curve touch the ending points of */
+ y[0] = y[1]; /* the line segments */
+ x[npts + 1] = x[npts];
+ y[npts + 1] = y[npts];
+ }
+
+ pxp = (x[0] + x[1]) / 2; /* make the last point pointers */
+ pyp = (y[0] + y[1]) / 2; /* point to the start of the 1st line */
+ tmove2(pxp, pyp);
+
+ for (; npts--; x++, y++) { /* traverse the line segments */
+ xp = x[0] - x[1];
+ yp = y[0] - y[1];
+ nseg = (int) hypot((double) xp, (double) yp);
+ xp = x[1] - x[2];
+ yp = y[1] - y[2];
+ /* `nseg' is the number of line */
+ /* segments that will be drawn for */
+ /* each curve segment. */
+ nseg = (int) ((double) (nseg + (int) hypot((double) xp, (double) yp)) /
+ res * PointsPerInterval);
+
+ for (i = 1; i < nseg; i++) {
+ w = (double) i / (double) nseg;
+ t1 = w * w;
+ t3 = t1 + 1.0 - (w + w);
+ t2 = 2.0 - (t3 + t1);
+ xp = (((int) (t1 * x[2] + t2 * x[1] + t3 * x[0])) + 1) / 2;
+ yp = (((int) (t1 * y[2] + t2 * y[1] + t3 * y[0])) + 1) / 2;
+
+ HGtline(xp, yp);
+ if (length++ > LINELENGTH) {
+ length = 0;
+ printf("\\\n");
+ }
+ }
+ }
+}
+
+
+/*----------------------------------------------------------------------------
+ | Routine: HGCurve(xpoints, ypoints, num_points)
+ |
+ | Results: This routine generates a smooth curve through a set of
+ | points. The method used is the parametric spline curve on
+ | unit knot mesh described in `Spline Curve Techniques' by
+ | Patrick Baudelaire, Robert Flegal, and Robert Sproull --
+ | Xerox Parc.
+ *----------------------------------------------------------------------------*/
+
+void
+HGCurve(int *x,
+ int *y,
+ int numpoints)
+{
+ float h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS];
+ float d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS];
+ float t, t2, t3;
+ register int j;
+ register int k;
+ register int nx;
+ register int ny;
+ int lx, ly;
+ int length = 0;
+
+ lx = x[1];
+ ly = y[1];
+ tmove2(lx, ly);
+
+ /*
+ * Solve for derivatives of the curve at each point separately for x and y
+ * (parametric).
+ */
+ Paramaterize(x, y, h, numpoints);
+
+ /* closed curve */
+ if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) {
+ PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
+ PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
+ } else {
+ NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
+ NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
+ }
+
+ /*
+ * generate the curve using the above information and PointsPerInterval
+ * vectors between each specified knot.
+ */
+
+ for (j = 1; j < numpoints; ++j) {
+ if ((x[j] == x[j + 1]) && (y[j] == y[j + 1]))
+ continue;
+ for (k = 0; k <= PointsPerInterval; ++k) {
+ t = (float) k *h[j] / (float) PointsPerInterval;
+ t2 = t * t;
+ t3 = t * t * t;
+ nx = x[j] + (int) (t * dx[j] + t2 * d2x[j] / 2 + t3 * d3x[j] / 6);
+ ny = y[j] + (int) (t * dy[j] + t2 * d2y[j] / 2 + t3 * d3y[j] / 6);
+ HGtline(nx, ny);
+ if (length++ > LINELENGTH) {
+ length = 0;
+ printf("\\\n");
+ }
+ } /* end for k */
+ } /* end for j */
+} /* end HGCurve */
+
+
+/*----------------------------------------------------------------------------
+ | Routine: Paramaterize (xpoints, ypoints, hparams, num_points)
+ |
+ | Results: This routine calculates parameteric values for use in
+ | calculating curves. The parametric values are returned
+ | in the array h. The values are an approximation of
+ | cumulative arc lengths of the curve (uses cord length).
+ | For additional information, see paper cited below.
+ *----------------------------------------------------------------------------*/
+
+void
+Paramaterize(int x[],
+ int y[],
+ float h[],
+ int n)
+{
+ register int dx;
+ register int dy;
+ register int i;
+ register int j;
+ float u[MAXPOINTS];
+
+ for (i = 1; i <= n; ++i) {
+ u[i] = 0;
+ for (j = 1; j < i; j++) {
+ dx = x[j + 1] - x[j];
+ dy = y[j + 1] - y[j];
+ /* Here was overflowing, so I changed it. */
+ /* u[i] += sqrt ((double) (dx * dx + dy * dy)); */
+ u[i] += hypot((double) dx, (double) dy);
+ }
+ }
+ for (i = 1; i < n; ++i)
+ h[i] = u[i + 1] - u[i];
+} /* end Paramaterize */
+
+
+/*----------------------------------------------------------------------------
+ | Routine: PeriodicSpline (h, z, dz, d2z, d3z, npoints)
+ |
+ | Results: This routine solves for the cubic polynomial to fit a spline
+ | curve to the the points specified by the list of values.
+ | The Curve generated is periodic. The algorithms for this
+ | curve are from the `Spline Curve Techniques' paper cited
+ | above.
+ *----------------------------------------------------------------------------*/
+
+void
+PeriodicSpline(float h[], /* paramaterization */
+ int z[], /* point list */
+ float dz[], /* to return the 1st derivative */
+ float d2z[], /* 2nd derivative */
+ float d3z[], /* 3rd derivative */
+ int npoints) /* number of valid points */
+{
+ float d[MAXPOINTS];
+ float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
+ float c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS];
+ int i;
+
+ /* step 1 */
+ for (i = 1; i < npoints; ++i) {
+ deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
+ }
+ h[0] = h[npoints - 1];
+ deltaz[0] = deltaz[npoints - 1];
+
+ /* step 2 */
+ for (i = 1; i < npoints - 1; ++i) {
+ d[i] = deltaz[i + 1] - deltaz[i];
+ }
+ d[0] = deltaz[1] - deltaz[0];
+
+ /* step 3a */
+ a[1] = 2 * (h[0] + h[1]);
+ b[1] = d[0];
+ c[1] = h[0];
+ for (i = 2; i < npoints - 1; ++i) {
+ a[i] = 2 * (h[i - 1] + h[i]) -
+ pow((double) h[i - 1], (double) 2.0) / a[i - 1];
+ b[i] = d[i - 1] - h[i - 1] * b[i - 1] / a[i - 1];
+ c[i] = -h[i - 1] * c[i - 1] / a[i - 1];
+ }
+
+ /* step 3b */
+ r[npoints - 1] = 1;
+ s[npoints - 1] = 0;
+ for (i = npoints - 2; i > 0; --i) {
+ r[i] = -(h[i] * r[i + 1] + c[i]) / a[i];
+ s[i] = (6 * b[i] - h[i] * s[i + 1]) / a[i];
+ }
+
+ /* step 4 */
+ d2z[npoints - 1] = (6 * d[npoints - 2] - h[0] * s[1]
+ - h[npoints - 1] * s[npoints - 2])
+ / (h[0] * r[1] + h[npoints - 1] * r[npoints - 2]
+ + 2 * (h[npoints - 2] + h[0]));
+ for (i = 1; i < npoints - 1; ++i) {
+ d2z[i] = r[i] * d2z[npoints - 1] + s[i];
+ }
+ d2z[npoints] = d2z[1];
+
+ /* step 5 */
+ for (i = 1; i < npoints; ++i) {
+ dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
+ d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
+ }
+} /* end PeriodicSpline */
+
+
+/*----------------------------------------------------------------------------
+ | Routine: NaturalEndSpline (h, z, dz, d2z, d3z, npoints)
+ |
+ | Results: This routine solves for the cubic polynomial to fit a spline
+ | curve the the points specified by the list of values. The
+ | alogrithms for this curve are from the `Spline Curve
+ | Techniques' paper cited above.
+ *----------------------------------------------------------------------------*/
+
+void
+NaturalEndSpline(float h[], /* parameterization */
+ int z[], /* Point list */
+ float dz[], /* to return the 1st derivative */
+ float d2z[], /* 2nd derivative */
+ float d3z[], /* 3rd derivative */
+ int npoints) /* number of valid points */
+{
+ float d[MAXPOINTS];
+ float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
+ int i;
+
+ /* step 1 */
+ for (i = 1; i < npoints; ++i) {
+ deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
+ }
+ deltaz[0] = deltaz[npoints - 1];
+
+ /* step 2 */
+ for (i = 1; i < npoints - 1; ++i) {
+ d[i] = deltaz[i + 1] - deltaz[i];
+ }
+ d[0] = deltaz[1] - deltaz[0];
+
+ /* step 3 */
+ a[0] = 2 * (h[2] + h[1]);
+ b[0] = d[1];
+ for (i = 1; i < npoints - 2; ++i) {
+ a[i] = 2 * (h[i + 1] + h[i + 2]) -
+ pow((double) h[i + 1], (double) 2.0) / a[i - 1];
+ b[i] = d[i + 1] - h[i + 1] * b[i - 1] / a[i - 1];
+ }
+
+ /* step 4 */
+ d2z[npoints] = d2z[1] = 0;
+ for (i = npoints - 1; i > 1; --i) {
+ d2z[i] = (6 * b[i - 2] - h[i] * d2z[i + 1]) / a[i - 2];
+ }
+
+ /* step 5 */
+ for (i = 1; i < npoints; ++i) {
+ dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
+ d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
+ }
+} /* end NaturalEndSpline */
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: change (x_position, y_position, visible_flag)
+ |
+ | Results: As HGtline passes from the invisible to visible (or vice
+ | versa) portion of a line, change is called to either draw
+ | the line, or initialize the beginning of the next one.
+ | Change calls line to draw segments if visible_flag is set
+ | (which means we're leaving a visible area).
+ *----------------------------------------------------------------------------*/
+
+void
+change(register int x,
+ register int y,
+ register int vis)
+{
+ static int xorg;
+ static int yorg;
+ static int length = 0;
+
+ if (vis) { /* leaving a visible area, draw it. */
+ line(x, y);
+ if (length++ > LINELENGTH) {
+ length = 0;
+ printf("\\\n");
+ }
+ } else { /* otherwise, we're entering one, remember */
+ /* beginning */
+ tmove2(x, y);
+ }
+}
+
+
+/*----------------------------------------------------------------------------
+ | Routine: HGtline (xstart, ystart, xend, yend)
+ |
+ | Results: Draws a line from current position to (x1,y1) using line(x1,
+ | y1) to place individual segments of dotted or dashed lines.
+ *----------------------------------------------------------------------------*/
+
+void
+HGtline(int x1,
+ int y1)
+{
+ register int x0 = lastx;
+ register int y0 = lasty;
+ register int dx;
+ register int dy;
+ register int oldcoord;
+ register int res1;
+ register int visible;
+ register int res2;
+ register int xinc;
+ register int yinc;
+ register int dotcounter;
+
+ if (linmod == SOLID) {
+ line(x1, y1);
+ return;
+ }
+
+ /* for handling different resolutions */
+ dotcounter = linmod << dotshifter;
+
+ xinc = 1;
+ yinc = 1;
+ if ((dx = x1 - x0) < 0) {
+ xinc = -xinc;
+ dx = -dx;
+ }
+ if ((dy = y1 - y0) < 0) {
+ yinc = -yinc;
+ dy = -dy;
+ }
+ res1 = 0;
+ res2 = 0;
+ visible = 0;
+ if (dx >= dy) {
+ oldcoord = y0;
+ while (x0 != x1) {
+ if ((x0 & dotcounter) && !visible) {
+ change(x0, y0, 0);
+ visible = 1;
+ } else if (visible && !(x0 & dotcounter)) {
+ change(x0 - xinc, oldcoord, 1);
+ visible = 0;
+ }
+ if (res1 > res2) {
+ oldcoord = y0;
+ res2 += dx - res1;
+ res1 = 0;
+ y0 += yinc;
+ }
+ res1 += dy;
+ x0 += xinc;
+ }
+ } else {
+ oldcoord = x0;
+ while (y0 != y1) {
+ if ((y0 & dotcounter) && !visible) {
+ change(x0, y0, 0);
+ visible = 1;
+ } else if (visible && !(y0 & dotcounter)) {
+ change(oldcoord, y0 - yinc, 1);
+ visible = 0;
+ }
+ if (res1 > res2) {
+ oldcoord = x0;
+ res2 += dy - res1;
+ res1 = 0;
+ x0 += xinc;
+ }
+ res1 += dx;
+ y0 += yinc;
+ }
+ }
+ if (visible)
+ change(x1, y1, 1);
+ else
+ change(x1, y1, 0);
+}
+
+/* EOF */
diff --git a/src/preproc/grn/hpoint.cc b/src/preproc/grn/hpoint.cc
new file mode 100644
index 00000000..f4e1ca82
--- /dev/null
+++ b/src/preproc/grn/hpoint.cc
@@ -0,0 +1,49 @@
+/* Last non-groff version: hpoint.c 1.1 84/10/08 */
+
+/*
+ * This file contains routines for manipulating the point data structures
+ * for the gremlin picture editor.
+ */
+
+#include <stdlib.h>
+#include "gprint.h"
+
+
+/*
+ * Return pointer to empty point list.
+ */
+POINT *
+PTInit()
+{
+ return ((POINT *) NULL);
+}
+
+
+/*
+ * This routine creates a new point with coordinates x and y and links it
+ * into the pointlist.
+ */
+POINT *
+PTMakePoint(float x,
+ float y,
+ POINT **pplist)
+{
+ register POINT *point;
+
+ if (Nullpoint(point = *pplist)) { /* empty list */
+ *pplist = (POINT *) malloc(sizeof(POINT));
+ point = *pplist;
+ } else {
+ while (!Nullpoint(point->nextpt))
+ point = point->nextpt;
+ point->nextpt = (POINT *) malloc(sizeof(POINT));
+ point = point->nextpt;
+ }
+
+ point->x = x;
+ point->y = y;
+ point->nextpt = PTInit();
+ return (point);
+} /* end PTMakePoint */
+
+/* EOF */
diff --git a/src/preproc/grn/main.cc b/src/preproc/grn/main.cc
new file mode 100644
index 00000000..5c6f0e57
--- /dev/null
+++ b/src/preproc/grn/main.cc
@@ -0,0 +1,902 @@
+/* Last non-groff version: main.cc 1.23 (Berkeley) 85/08/05
+ *
+ * Adapted to GNU troff by Daniel Senderowicz 99/12/29.
+ *
+ * Further refinements by Werner Lemberg 00/02/20.
+ *
+ *
+ * This file contains the main and file system dependent routines for
+ * processing gremlin files into troff input. The program watches input go
+ * by to standard output, only interpreting things between .GS and .GE
+ * lines. Default values (font, size, scale, thickness) may be overridden
+ * with a `default' command and are further overridden by commands in the
+ * input.
+ *
+ * Inside the GS and GE, commands are accepted to reconfigure the picture.
+ * At most one command may reside on each line, and each command is followed
+ * by a parameter separated by white space. The commands are as follows,
+ * and may be abbreviated down to one character (with exception of `scale'
+ * and `stipple' down to "sc" and "st") and may be upper or lower case.
+ *
+ * default - Make all settings in the current
+ * .GS/.GE the global defaults. Height,
+ * width and file are NOT saved.
+ * 1, 2, 3, 4 - Set size 1, 2, 3, or 4 (followed by an
+ * integer point size).
+ * roman, italics, bold, special - Set gremlin's fonts to any other troff
+ * font (one or two characters).
+ * stipple, l - Use a stipple font for polygons. Arg
+ * is troff font name. No Default. Can
+ * use only one stipple font per picture.
+ * (See below for stipple font index.)
+ * scale, x - Scale is IN ADDITION to the global
+ * scale factor from the default.
+ * pointscale - Turn on scaling point sizes to match
+ * `scale' commands. (Optional operand
+ * `off' to turn it off.)
+ * narrow, medium, thick - Set pixel widths of lines.
+ * file - Set the file name to read the gremlin
+ * picture from. If the file isn't in
+ * the current directory, the gremlin
+ * library is tried.
+ * width, height - These two commands override any
+ * scaling factor that is in effect, and
+ * forces the picture to fit into either
+ * the height or width specified,
+ * whichever makes the picture smaller.
+ * The operand for these two commands is
+ * a floating-point number in units of
+ * inches.
+ * l<nn> (integer <nn>) - Set association between stipple <nn>
+ * and a stipple `character'. <nn> must
+ * be in the range 0 to NSTIPPLES (16)
+ * inclusive. The integer operand is an
+ * index in the stipple font selected.
+ * Valid cf (cifplot) indices are 1-32
+ * (although 24 is not defined), valid ug
+ * (unigrafix) indices are 1-14, and
+ * valid gs (gray scale) indices are
+ * 0-16. Nonetheless, any number between
+ * 0 and 255 is accepted since new
+ * stipple fonts may be added. An
+ * integer operand is required.
+ *
+ * Troff number registers used: g1 through g9. g1 is the width of the
+ * picture, and g2 is the height. g3, and g4, save information, g8 and g9
+ * are used for text processing and g5-g7 are reserved.
+ */
+
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gprint.h"
+
+#include "device.h"
+#include "font.h"
+#include "searchpath.h"
+#include "macropath.h"
+
+#include "lib.h"
+#include "errarg.h"
+#include "error.h"
+#include "defs.h"
+
+/* database imports */
+
+extern void HGPrintElt(ELT *element, int baseline);
+extern ELT *DBInit(void);
+extern ELT *DBRead(register FILE *file);
+extern POINT *PTInit();
+extern POINT *PTMakePoint(float x, float y, POINT **pplist);
+
+
+#define SUN_SCALEFACTOR 0.70
+
+/* #define DEFSTIPPLE "gs" */
+#define DEFSTIPPLE "cf"
+
+#define MAXINLINE 100 /* input line length */
+
+#define SCREENtoINCH 0.02 /* scaling factor, screen to inches */
+
+#define BIG 999999999999.0 /* unweildly large floating number */
+
+
+static char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99";
+
+int res; /* the printer's resolution goes here */
+
+int prevval; /* spacing between dots */
+int dotshifter; /* for the length of dotted curves */
+
+int linethickness; /* brush styles */
+int linmod;
+int lastx; /* point registers for printing elements */
+int lasty;
+int lastyline; /* A line's vertical position is NOT the */
+ /* same after that line is over, so for a */
+ /* line of drawing commands, vertical */
+ /* spacing is kept in lastyline */
+
+/* These are the default fonts, sizes, line styles, */
+/* and thicknesses. They can be modified from a */
+/* `default' command and are reset each time the */
+/* start of a picture (.GS) is found. */
+
+char *deffont[] =
+{"R", "I", "B", "S"};
+int defsize[] =
+{10, 16, 24, 36};
+int defthick[STYLES] =
+{1, 1, 5, 1, 1, 3};
+
+/* int cf_stipple_index[NSTIPPLES + 1] = */
+/* { 0, 1, 3, 12, 14, 16, 19, 21, 23 }; */
+/* a logarithmic scale looks better than a linear one for the gray shades */
+
+/* int other_stipple_index[NSTIPPLES + 1] = */
+/*{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; */
+
+int cf_stipple_index[NSTIPPLES + 1] =
+{0, 18, 32, 56, 100, 178, 316, 562, 1000}; /* only 1-8 used */
+int other_stipple_index[NSTIPPLES + 1] =
+{0, 62, 125, 187, 250, 312, 375, 437, 500,
+ 562, 625, 687, 750, 812, 875, 937, 1000};
+
+/* int *defstipple_index = other_stipple_index; */
+int *defstipple_index = cf_stipple_index;
+
+int style[STYLES] =
+{DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID};
+double scale = 1.0; /* no scaling, default */
+int defpoint = 0; /* flag for pointsize scaling */
+char *defstipple = (char *) 0;
+enum {
+ OUTLINE, FILL, BOTH
+} polyfill;
+
+/* flag to controll filling of polygons */
+
+double adj1 = 0.0;
+double adj2 = 0.0;
+double adj3 = 0.0;
+double adj4 = 0.0;
+
+int thick[STYLES]; /* thicknesses set by defaults, then by */
+ /* commands */
+char *tfont[FONTS]; /* fonts originally set to deffont values, */
+ /* then */
+int tsize[SIZES]; /* optionally changed by commands inside */
+ /* grn */
+int stipple_index[NSTIPPLES + 1]; /* stipple font file indices */
+char *stipple;
+
+double xscale; /* scaling factor from individual pictures */
+double troffscale; /* scaling factor at output time */
+
+double width; /* user-request maximum width for picture */
+ /* (in inches) */
+double height; /* user-request height */
+int pointscale; /* flag for pointsize scaling */
+int setdefault; /* flag for a .GS/.GE to remember all */
+ /* settings */
+int sflag; /* -s flag: sort order (do polyfill first) */
+
+double toppoint; /* remember the picture */
+double bottompoint; /* bounds in these variables */
+double leftpoint;
+double rightpoint;
+
+int ytop; /* these are integer versions of the above */
+int ybottom; /* so not to convert each time they're used */
+int xleft;
+int xright;
+
+int linenum = 0; /* line number of input file */
+char inputline[MAXINLINE]; /* spot to filter through the file */
+char *c1 = inputline; /* c1, c2, and c3 will be used to */
+char *c2 = inputline + 1; /* hunt for lines that begin with */
+char *c3 = inputline + 2; /* ".GS" by looking individually */
+char *c4 = inputline + 3; /* needed for compatibility mode */
+char GScommand[MAXINLINE]; /* put user's ".GS" command line here */
+char gremlinfile[MAXINLINE]; /* filename to use for a picture */
+int SUNFILE = FALSE; /* TRUE if SUN gremlin file */
+int compatibility_flag = FALSE; /* TRUE if in compatibility mode */
+
+
+void getres(void);
+char *doinput(FILE *fp);
+void conv(register FILE *fp, int baseline);
+void savestate(void);
+int has_polygon(register ELT *elist);
+void interpret(char *line);
+
+
+void
+usage()
+{
+ fprintf(stderr,
+ "usage: %s [ -vCs ] [ -M dir ] [ -F dir ] [ -T dev ] [ file ]\n",
+ program_name);
+ exit(1);
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: main (argument_count, argument_pointer)
+ |
+ | Results: Parses the command line, accumulating input file names, then
+ | reads the inputs, passing it directly to output until a `.GS'
+ | line is read. Main then passes control to `conv' to do the
+ | gremlin file conversions.
+ *----------------------------------------------------------------------------*/
+
+int
+main(int argc,
+ char **argv)
+{
+ program_name = argv[0];
+ register FILE *fp;
+ register int k;
+ register char c;
+ register int gfil = 0;
+ char *file[50];
+ char *operand(int *argcp, char ***argvp);
+ char *p;
+
+ while (--argc) {
+ if (**++argv != '-')
+ file[gfil++] = *argv;
+ else
+ switch (c = (*argv)[1]) {
+
+ case 0:
+ file[gfil++] = NULL;
+ break;
+
+ case 'v':
+ {
+ extern const char *Version_string;
+ fprintf(stderr, "GNU grn version %s\n", Version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'C': /* compatibility mode */
+ compatibility_flag = TRUE;
+ break;
+
+ case 'F': /* font path to find DESC */
+ font::command_line_font_dir(operand(&argc, &argv));
+ break;
+
+ case 'T': /* final output typesetter name */
+ device = operand(&argc, &argv);
+ break;
+
+ case 'M': /* set library directory */
+ macro_path.command_line_dir(operand(&argc, &argv));
+ break;
+
+ case 's': /* preserve order of elements */
+ sflag = 1;
+ break;
+
+ case '?':
+ usage();
+ break;
+
+ default:
+ error("unknown switch: %1", c);
+ usage();
+ }
+ }
+
+ getres(); /* set the resolution for an output device */
+
+ if (gfil == 0) { /* no filename, use standard input */
+ file[0] = NULL;
+ gfil++;
+ }
+
+ for (k = 0; k < gfil; k++) {
+ if (file[k] != NULL) {
+ if ((fp = fopen(file[k], "r")) == NULL)
+ fatal("can't open %1", file[k]);
+ } else
+ fp = stdin;
+
+ while (doinput(fp) != NULL) {
+ if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') {
+ if (compatibility_flag ||
+ *c4 == '\n' || *c4 == ' ' || *c4 == '\0')
+ conv(fp, linenum);
+ else
+ fputs(inputline, stdout);
+ } else
+ fputs(inputline, stdout);
+ }
+ }
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: char * operand (& argc, & argv)
+ |
+ | Results: Returns address of the operand given with a command-line
+ | option. It uses either `-Xoperand' or `-X operand', whichever
+ | is present. The program is terminated if no option is
+ | present.
+ |
+ | Side Efct: argc and argv are updated as necessary.
+ *----------------------------------------------------------------------------*/
+
+char *
+operand(int *argcp,
+ char ***argvp)
+{
+ if ((**argvp)[2])
+ return (**argvp + 2); /* operand immediately follows */
+ if ((--*argcp) <= 0) { /* no operand */
+ error("command-line option operand missing.");
+ exit(8);
+ }
+ return (*(++(*argvp))); /* operand is next word */
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: getres ()
+ |
+ | Results: Sets `res' to the resolution of the output device.
+ *----------------------------------------------------------------------------*/
+
+void
+getres(void)
+{
+ int linepiece;
+
+ if (!font::load_desc())
+ fatal("sorry, I can't continue");
+
+ res = font::res;
+
+ /* Correct the brush thicknesses based on res */
+ if (res >= 256) {
+ defthick[0] = res >> 8;
+ defthick[1] = res >> 8;
+ defthick[2] = res >> 4;
+ defthick[3] = res >> 8;
+ defthick[4] = res >> 8;
+ defthick[5] = res >> 6;
+ }
+
+ /* Set up the spacing between dots in a dotted line, not used */
+ prevval = res >> 4;
+
+ linepiece = res >> 9;
+ for (dotshifter = 0; linepiece; dotshifter++)
+ linepiece = linepiece >> 1;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: char * doinput (file_pointer)
+ |
+ | Results: A line of input is read into `inputline'.
+ |
+ | Side Efct: "linenum" is incremented.
+ |
+ | Bugs: Lines longer than MAXINLINE are NOT checked, except for
+ | updating `linenum'.
+ *----------------------------------------------------------------------------*/
+
+char *
+doinput(FILE *fp)
+{
+ char *k;
+
+ if ((k = fgets(inputline, MAXINLINE, fp)) == NULL)
+ return k;
+ if (strchr(inputline, '\n')) /* ++ only if it's a complete line */
+ linenum++;
+ return (char *) !NULL;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: initpic ( )
+ |
+ | Results: Sets all parameters to the normal defaults, possibly
+ | overridden by a setdefault command. Initialize the picture
+ | variables, and output the startup commands to troff to begin
+ | the picture.
+ *----------------------------------------------------------------------------*/
+
+void
+initpic(void)
+{
+ register int i;
+
+ for (i = 0; i < STYLES; i++) { /* line thickness defaults */
+ thick[i] = defthick[i];
+ }
+ for (i = 0; i < FONTS; i++) { /* font name defaults */
+ tfont[i] = deffont[i];
+ }
+ for (i = 0; i < SIZES; i++) { /* font size defaults */
+ tsize[i] = defsize[i];
+ }
+ for (i = 0; i <= NSTIPPLES; i++) { /* stipple font file default indices */
+ stipple_index[i] = defstipple_index[i];
+ }
+ stipple = defstipple;
+
+ gremlinfile[0] = 0; /* filename is `null' */
+ setdefault = 0; /* this is not the default settings (yet) */
+
+ toppoint = BIG; /* set the picture bounds out */
+ bottompoint = -BIG; /* of range so they'll be set */
+ leftpoint = BIG; /* by `savebounds' on input */
+ rightpoint = -BIG;
+
+ pointscale = defpoint; /* flag for scaling point sizes default */
+ xscale = scale; /* default scale of individual pictures */
+ width = 0.0; /* size specifications input by user */
+ height = 0.0;
+
+ linethickness = DEFTHICK; /* brush styles */
+ linmod = DEFSTYLE;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: conv (file_pointer, starting_line)
+ |
+ | Results: At this point, we just passed a `.GS' line in the input
+ | file. conv reads the input and calls `interpret' to process
+ | commands, gathering up information until a `.GE' line is
+ | found. It then calls `HGPrint' to do the translation of the
+ | gremlin file to troff commands.
+ *----------------------------------------------------------------------------*/
+
+void
+conv(register FILE *fp,
+ int baseline)
+{
+ register FILE *gfp = NULL; /* input file pointer */
+ register int done = 0; /* flag to remember if finished */
+ register ELT *e; /* current element pointer */
+ ELT *PICTURE; /* whole picture data base pointer */
+ double temp; /* temporary calculating area */
+ POINT ptr; /* coordinates of a point to pass to `mov' */
+ /* routine */
+ int flyback; /* flag `want to end up at the top of the */
+ /* picture?' */
+ int compat; /* test character after .GE or .GF */
+
+
+ initpic(); /* set defaults, ranges, etc. */
+ strcpy(GScommand, inputline); /* save `.GS' line for later */
+
+ do {
+ done = (doinput(fp) == NULL); /* test for EOF */
+ flyback = (*c3 == 'F'); /* and .GE or .GF */
+ compat = (compatibility_flag ||
+ *c4 == '\n' || *c4 == ' ' || *c4 == '\0');
+ done |= (*c1 == '.' && *c2 == 'G' && (*c3 == 'E' || flyback) &&
+ compat);
+
+ if (done) {
+ if (setdefault)
+ savestate();
+
+ if (!gremlinfile[0]) {
+ if (!setdefault)
+ error("at line %1: no picture filename.\n", baseline);
+ return;
+ }
+ char *path;
+ gfp = macro_path.open_file(gremlinfile, &path);
+ if (!gfp)
+ return;
+ PICTURE = DBRead(gfp); /* read picture file */
+ fclose(gfp);
+ a_delete path;
+ if (DBNullelt(PICTURE))
+ return; /* If a request is made to make the */
+ /* picture fit into a specific area, */
+ /* set the scale to do that. */
+
+ if (stipple == (char *) NULL) /* if user forgot stipple */
+ if (has_polygon(PICTURE)) /* and picture has a polygon */
+ stipple = DEFSTIPPLE; /* then set the default */
+
+ if ((temp = bottompoint - toppoint) < 0.1)
+ temp = 0.1;
+ temp = (height != 0.0) ? height / (temp * SCREENtoINCH) : BIG;
+ if ((troffscale = rightpoint - leftpoint) < 0.1)
+ troffscale = 0.1;
+ troffscale = (width != 0.0) ?
+ width / (troffscale * SCREENtoINCH) : BIG;
+ if (temp == BIG && troffscale == BIG)
+ troffscale = xscale;
+ else {
+ if (temp < troffscale)
+ troffscale = temp;
+ } /* here, troffscale is the */
+ /* picture's scaling factor */
+ if (pointscale) {
+ register int i; /* do pointscaling here, when */
+ /* scale is known, before output */
+ for (i = 0; i < SIZES; i++)
+ tsize[i] = (int) (troffscale * (double) tsize[i] + 0.5);
+ }
+
+ /* change to device units */
+ troffscale *= SCREENtoINCH * res; /* from screen units */
+
+ ytop = (int) (toppoint * troffscale); /* calculate integer */
+ ybottom = (int) (bottompoint * troffscale); /* versions of the */
+ xleft = (int) (leftpoint * troffscale); /* picture limits */
+ xright = (int) (rightpoint * troffscale);
+
+ /* save stuff in number registers, */
+ /* register g1 = picture width and */
+ /* register g2 = picture height, */
+ /* set vertical spacing, no fill, */
+ /* and break (to make sure picture */
+ /* starts on left), and put out the */
+ /* user's `.GS' line. */
+ printf(".br\n"
+ ".nr g1 %du\n"
+ ".nr g2 %du\n"
+ "%s"
+ ".nr g3 \\n(.f\n"
+ ".nr g4 \\n(.s\n"
+ "\\0\n"
+ ".sp -1\n",
+ xright - xleft, ybottom - ytop, GScommand);
+
+ if (stipple) /* stipple requested for this picture */
+ printf(".st %s\n", stipple);
+ lastx = xleft; /* note where we are, (upper left */
+ lastyline = lasty = ytop; /* corner of the picture) */
+
+ /* Just dump everything in the order it appears.
+ *
+ * If -s command-line option, traverse picture twice: First time,
+ * print only the interiors of filled polygons (as borderless
+ * polygons). Second time, print the outline as series of line
+ * segments. This way, postprocessors that overwrite rather than
+ * merge picture elements (such as Postscript) can still have text and
+ * graphics on a shaded background.
+ */
+ /* if (sflag) */
+ if (!sflag) { /* changing the default for filled polygons */
+ e = PICTURE;
+ polyfill = FILL;
+ while (!DBNullelt(e)) {
+ printf(".mk\n");
+ if (e->type == POLYGON)
+ HGPrintElt(e, baseline);
+ printf(".rt\n");
+ lastx = xleft;
+ lastyline = lasty = ytop;
+ e = DBNextElt(e);
+ }
+ }
+ e = PICTURE;
+
+ /* polyfill = !sflag ? BOTH : OUTLINE; */
+ polyfill = sflag ? BOTH : OUTLINE; /* changing the default */
+ while (!DBNullelt(e)) {
+ printf(".mk\n");
+ HGPrintElt(e, baseline);
+ printf(".rt\n");
+ lastx = xleft;
+ lastyline = lasty = ytop;
+ e = DBNextElt(e);
+ }
+
+ /* decide where to end picture */
+
+ /* I changed everything here. I always use the combination .mk and */
+ /* .rt so once finished I just space down the heigth of the picture */
+ /* that is \n(g2u */
+ if (flyback) { /* end picture at upper left */
+ /* ptr.x = leftpoint;
+ ptr.y = toppoint; */
+ } else { /* end picture at lower left */
+ /* ptr.x = leftpoint;
+ ptr.y = bottompoint; */
+ printf(".sp \\n(g2u\n");
+ }
+
+ /* tmove(&ptr); */ /* restore default line parameters */
+
+ /* restore everything to the way it was before the .GS, then put */
+ /* out the `.GE' line from user */
+
+ /* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */
+ /* groff doesn't understand the \Ds command */
+
+ printf("\\D't %du'\n", DEFTHICK);
+ if (flyback) /* make sure we end up at top of */
+ printf(".sp -1\n"); /* picture if `flying back' */
+ if (stipple) /* restore stipple to previous */
+ printf(".st\n");
+ printf(".br\n"
+ ".ft \\n(g3\n"
+ ".ps \\n(g4\n"
+ "%s", inputline);
+ } else
+ interpret(inputline); /* take commands from the input file */
+ } while (!done);
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: savestate ( )
+ |
+ | Results: all the current scaling / font size / font name / thickness
+ | / pointscale settings are saved to be the defaults. Scaled
+ | point sizes are NOT saved. The scaling is done each time a
+ | new picture is started.
+ |
+ | Side Efct: scale, and def* are modified.
+ *----------------------------------------------------------------------------*/
+
+void
+savestate(void)
+{
+ register int i;
+
+ for (i = 0; i < STYLES; i++) /* line thickness defaults */
+ defthick[i] = thick[i];
+ for (i = 0; i < FONTS; i++) /* font name defaults */
+ deffont[i] = tfont[i];
+ for (i = 0; i < SIZES; i++) /* font size defaults */
+ defsize[i] = tsize[i];
+ for (i = 0; i <= NSTIPPLES; i++) /* stipple font file default indices */
+ defstipple_index[i] = stipple_index[i];
+
+ defstipple = stipple; /* if stipple has been set, it's remembered */
+ scale *= xscale; /* default scale of individual pictures */
+ defpoint = pointscale; /* flag for scaling pointsizes from x factors */
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: savebounds (x_coordinate, y_coordinate)
+ |
+ | Results: Keeps track of the maximum and minimum extent of a picture
+ | in the global variables: left-, right-, top- and
+ | bottompoint. `savebounds' assumes that the points have been
+ | oriented to the correct direction. No scaling has taken
+ | place, though.
+ *----------------------------------------------------------------------------*/
+
+int
+savebounds(float x,
+ float y)
+{
+ if (x < leftpoint)
+ leftpoint = x;
+ if (x > rightpoint)
+ rightpoint = x;
+ if (y < toppoint)
+ toppoint = y;
+ if (y > bottompoint)
+ bottompoint = y;
+}
+
+
+/*----------------------------------------------------------------------------*
+ | Routine: interpret (character_string)
+ |
+ | Results: Commands are taken from the input string and performed.
+ | Commands are separated by the endofline, and are of the
+ | format:
+ | string1 string2
+ |
+ | where string1 is the command and string2 is the argument.
+ |
+ | Side Efct: Font and size strings, plus the gremlin file name and the
+ | width and height variables are set by this routine.
+ *----------------------------------------------------------------------------*/
+
+void
+interpret(char *line)
+{
+ char str1[MAXINLINE];
+ char str2[MAXINLINE];
+ register char *chr;
+ register int i;
+ double par;
+
+ str2[0] = '\0';
+ sscanf(line, "%80s%80s", &str1[0], &str2[0]);
+ for (chr = &str1[0]; *chr; chr++) /* convert command to */
+ if (isupper(*chr))
+ *chr = tolower(*chr); /* lower case */
+
+ switch (str1[0]) {
+
+ case '1':
+ case '2': /* font sizes */
+ case '3':
+ case '4':
+ i = atoi(str2);
+ if (i > 0 && i < 1000)
+ tsize[str1[0] - '1'] = i;
+ else
+ error("bad font size value at line %1", linenum);
+ break;
+
+ case 'r': /* roman */
+ if (str2[0] < '0')
+ goto nofont;
+ tfont[0] = (char *) malloc(strlen(str2) + 1);
+ strcpy(tfont[0], str2);
+ break;
+
+ case 'i': /* italics */
+ if (str2[0] < '0')
+ goto nofont;
+ tfont[1] = (char *) malloc(strlen(str2) + 1);
+ strcpy(tfont[1], str2);
+ break;
+
+ case 'b': /* bold */
+ if (str2[0] < '0')
+ goto nofont;
+ tfont[2] = (char *) malloc(strlen(str2) + 1);
+ strcpy(tfont[2], str2);
+ break;
+
+ case 's': /* special */
+ if (str1[1] == 'c')
+ goto scalecommand; /* or scale */
+
+ if (str2[0] < '0') {
+ nofont:
+ error("no fontname specified in line %1", linenum);
+ break;
+ }
+ if (str1[1] == 't')
+ goto stipplecommand; /* or stipple */
+
+ tfont[3] = (char *) malloc(strlen(str2) + 1);
+ strcpy(tfont[3], str2);
+ break;
+
+ case 'l': /* l */
+ if (isdigit(str1[1])) { /* set stipple index */
+ int index = atoi(str1 + 1), val;
+
+ if (index < 0 || index > NSTIPPLES) {
+ error("bad stipple number %1 at line %2", index, linenum);
+ break;
+ }
+ if (!defstipple_index)
+ defstipple_index = other_stipple_index;
+ val = atoi(str2);
+ if (val >= 0 && val < 256)
+ stipple_index[index] = val;
+ else
+ error("bad stipple index value at line %1", linenum);
+ break;
+ }
+
+ stipplecommand: /* set stipple name */
+ stipple = (char *) malloc(strlen(str2) + 1);
+ strcpy(stipple, str2);
+ /* if its a `known' font (currently only `cf'), set indicies */
+ if (strcmp(stipple, "cf") == 0)
+ defstipple_index = cf_stipple_index;
+ else
+ defstipple_index = other_stipple_index;
+ for (i = 0; i <= NSTIPPLES; i++)
+ stipple_index[i] = defstipple_index[i];
+ break;
+
+ case 'a': /* text adjust */
+ par = atof(str2);
+ switch (str1[1]) {
+ case '1':
+ adj1 = par;
+ break;
+ case '2':
+ adj2 = par;
+ break;
+ case '3':
+ adj3 = par;
+ break;
+ case '4':
+ adj4 = par;
+ break;
+ default:
+ error("bad adjust command at line %1", linenum);
+ break;
+ }
+ break;
+
+ case 't': /* thick */
+ /* thick[2] = atoi(str2); */
+ thick[2] = defthick[0] * atoi(str2);
+ break;
+
+ case 'm': /* medium */
+ /* thick[5] = atoi(str2); */
+ thick[5] = defthick[0] * atoi(str2);
+ break;
+
+ case 'n': /* narrow */
+ /* thick[0] = thick[1] = thick[3] = thick[4] = atoi(str2); */
+ thick[0] = thick[1] = thick[3] = thick[4] =
+ defthick[0] * atoi(str2);
+ break;
+
+ case 'x': /* x */
+ scalecommand: /* scale */
+ par = atof(str2);
+ if (par > 0.0)
+ xscale *= par;
+ else
+ error("illegal scale value on line %1", linenum);
+ break;
+
+ case 'f': /* file */
+ strcpy(gremlinfile, str2);
+ break;
+
+ case 'w': /* width */
+ width = atof(str2);
+ if (width < 0.0)
+ width = -width;
+ break;
+
+ case 'h': /* height */
+ height = atof(str2);
+ if (height < 0.0)
+ height = -height;
+ break;
+
+ case 'd': /* defaults */
+ setdefault = 1;
+ break;
+
+ case 'p': /* pointscale */
+ if (strcmp("off", str2))
+ pointscale = 1;
+ else
+ pointscale = 0;
+ break;
+
+ default:
+ error("unknown command `%1' on line %2", str1, linenum);
+ exit(8);
+ break;
+ };
+}
+
+
+/*
+ * return TRUE if picture contains a polygon
+ * otherwise FALSE
+ */
+
+int
+has_polygon(register ELT *elist)
+{
+ while (!DBNullelt(elist)) {
+ if (elist->type == POLYGON)
+ return (1);
+ elist = DBNextElt(elist);
+ }
+
+ return (0);
+}
+
+/* EOF */