summaryrefslogtreecommitdiffstats
path: root/src/preproc/grn/main.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:44:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:44:05 +0000
commitd318611dd6f23fcfedd50e9b9e24620b102ba96a (patch)
tree8b9eef82ca40fdd5a8deeabf07572074c236095d /src/preproc/grn/main.cpp
parentInitial commit. (diff)
downloadgroff-upstream.tar.xz
groff-upstream.zip
Adding upstream version 1.23.0.upstream/1.23.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/preproc/grn/main.cpp977
1 files changed, 977 insertions, 0 deletions
diff --git a/src/preproc/grn/main.cpp b/src/preproc/grn/main.cpp
new file mode 100644
index 0000000..6d6d586
--- /dev/null
+++ b/src/preproc/grn/main.cpp
@@ -0,0 +1,977 @@
+/* Last non-groff version: main.c 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 (1 or 2 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 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 "lib.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h> // errno
+#include "gprint.h"
+
+#include "device.h"
+#include "font.h"
+#include "searchpath.h"
+#include "macropath.h"
+
+#include "errarg.h"
+#include "error.h"
+#include "defs.h"
+
+extern "C" const char *Version_string;
+
+/* database imports */
+
+extern void HGPrintElt(ELT *element, int baseline);
+extern ELT *DBInit();
+extern ELT *DBRead(FILE *file);
+extern POINT *PTInit();
+extern POINT *PTMakePoint(double x, double y, POINT **pplist);
+
+#define INIT_FILE_SIZE 50 /* Initial sz of file array from cmd line. */
+#define FILE_SIZE_INCR 50 /* Amount to increase array of files by. */
+
+#define SUN_SCALEFACTOR 0.70
+
+/* #define DEFSTIPPLE "gs" */
+#define DEFSTIPPLE "cf"
+/*
+ * This grn implementation emits '.st' requests to control stipple
+ * effects, but groff does not (currently) support any such request.
+ *
+ * This hack disables the emission of such requests, without destroying
+ * the infrastructure necessary to support the feature in the future; to
+ * enable the emission of '.st' requests, at a future date when groff
+ * can support them, simply rewrite the following #define as:
+ *
+ * #define USE_ST_REQUEST stipple
+ *
+ * with accompanying comment: "emit '.st' requests as required".
+ */
+#define USE_ST_REQUEST 0 /* never emit '.st' requests */
+
+#define MAXINLINE 100 /* input line length */
+
+#define SCREENtoINCH 0.02 /* scaling factor, screen to inches */
+
+#define BIG 999999999999.0 /* unwieldy large floating number */
+
+
+/* static char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99"; */
+
+int res; /* the printer's resolution goes here */
+
+int dotshifter; /* for the length of dotted curves */
+
+double linethickness; /* brush styles */
+int linmod;
+int lastx; /* point registers for printing */
+int lasty; /* elements */
+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. */
+
+const char *deffont[] =
+{"R", "I", "B", "S"};
+int defsize[] =
+{10, 16, 24, 36};
+/* #define BASE_THICKNESS 1.0 */
+#define BASE_THICKNESS 0.15
+double defthick[STYLES] =
+{1 * BASE_THICKNESS,
+ 1 * BASE_THICKNESS,
+ 5 * BASE_THICKNESS,
+ 1 * BASE_THICKNESS,
+ 1 * BASE_THICKNESS,
+ 3 * BASE_THICKNESS};
+
+/* 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 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 point size scaling */
+char *defstipple = (char *) 0;
+enum E {
+ OUTLINE, FILL, BOTH
+} polyfill;
+
+/* flag to control filling of polygons */
+
+double adj1 = 0.0;
+double adj2 = 0.0;
+double adj3 = 0.0;
+double adj4 = 0.0;
+
+double thick[STYLES]; /* thicknesses set by defaults, then */
+ /* by commands */
+char *tfont[FONTS]; /* fonts originally set to deffont */
+ /* values, then optionally changed by */
+int tsize[SIZES]; /* 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 point size 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;
+
+static int linenum = 0; /* line number of troff 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();
+int doinput(FILE *fp);
+void conv(FILE *fp, int baseline);
+void savestate();
+int has_polygon(ELT *elist);
+void interpret(char *line);
+
+void *
+grnmalloc(size_t size,
+ const char *what)
+{
+ void *ptr = 0;
+ ptr = malloc(size);
+ if (!ptr) {
+ fatal("memory allocation failed for %1: %2", what, strerror(errno));
+ }
+ return ptr;
+}
+
+void
+usage(FILE *stream)
+{
+ fprintf(stream,
+ "usage: %s [-Cs] [-M dir] [-F dir] [-T dev] [file ...]\n"
+ "usage: %s {-v | --version}\n"
+ "usage: %s --help\n",
+ program_name, program_name, program_name);
+}
+
+
+/* Add a new file entry in the array, expanding array if needs be. */
+
+char **
+add_file(char **file,
+ char *new_file,
+ int *count,
+ int *cur_size)
+{
+ if (*count >= *cur_size) {
+ *cur_size += FILE_SIZE_INCR;
+ file = (char **) realloc(file, *cur_size * sizeof(char *));
+ if (file == NULL) {
+ fatal("unable to extend file array");
+ }
+ }
+ file[*count] = new_file;
+ *count += 1;
+
+ return file;
+}
+
+
+/*--------------------------------------------------------------------*
+ | 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)
+{
+ setlocale(LC_NUMERIC, "C");
+ program_name = argv[0];
+ FILE *fp;
+ int k;
+ char c;
+ int gfil = 0;
+ char **file = NULL;
+ int file_cur_size = INIT_FILE_SIZE;
+ char *operand(int *argcp, char ***argvp);
+
+ file = (char **) grnmalloc(file_cur_size * sizeof(char *),
+ "file array");
+ while (--argc) {
+ if (**++argv != '-')
+ file = add_file(file, *argv, &gfil, &file_cur_size);
+ else
+ switch (c = (*argv)[1]) {
+
+ case 0:
+ file = add_file(file, NULL, &gfil, &file_cur_size);
+ 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 '-':
+ if (strcmp(*argv,"--version")==0) {
+ case 'v':
+ printf("GNU grn (groff) version %s\n", Version_string);
+ exit(0);
+ break;
+ }
+ if (strcmp(*argv,"--help")==0) {
+ case '?':
+ usage(stdout);
+ exit(0);
+ break;
+ }
+ // fallthrough
+ default:
+ error("unknown switch: %1", c);
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ 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)) {
+ 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);
+ }
+ }
+
+ return 0;
+}
+
+
+/*--------------------------------------------------------------------*
+ | 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()
+{
+ int linepiece;
+
+ if (0 /* nullptr */ == font::load_desc())
+ fatal("cannot load 'DESC' description file for device '%1'",
+ device);
+
+ 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;
+ } */
+
+ linepiece = res >> 9;
+ for (dotshifter = 0; linepiece; dotshifter++)
+ linepiece = linepiece >> 1;
+}
+
+
+/*--------------------------------------------------------------------*
+ | Routine: int 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'.
+ *--------------------------------------------------------------------*/
+
+int
+doinput(FILE *fp)
+{
+ if (fgets(inputline, MAXINLINE, fp) == NULL)
+ return 0;
+ if (strchr(inputline, '\n')) /* ++ only if it's a complete line */
+ linenum++;
+ return 1;
+}
+
+
+/*--------------------------------------------------------------------*
+ | 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()
+{
+ 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] = (char *)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; /* 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(FILE *fp,
+ int baseline)
+{
+ FILE *gfp = NULL; /* input file pointer */
+ int done = 0; /* flag to remember if finished */
+ 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); /* 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("no picture file name at line %1", baseline);
+ return;
+ }
+ char *path;
+ gfp = macro_path.open_file(gremlinfile, &path);
+ if (0 /* nullptr */ == gfp) {
+ error("cannot open picture file '%1'", gremlinfile);
+ return;
+ }
+ PICTURE = DBRead(gfp); /* read picture file */
+ fclose(gfp);
+ free(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 = (char *)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) {
+ int i; /* do point scaling 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 */
+
+ /* Calculate integer versions of the picture limits. */
+ ytop = (int) (toppoint * troffscale);
+ ybottom = (int) (bottompoint * troffscale);
+ xleft = (int) (leftpoint * troffscale);
+ 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 (USE_ST_REQUEST) /* 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 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 [Senderowicz?] changed everything here. I always use the */
+ /* combination .mk and .rt, so once finished I just space down */
+ /* height 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 (USE_ST_REQUEST) /* 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 made 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()
+{
+ 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];
+ /* stipple font file default indices */
+ for (i = 0; i <= NSTIPPLES; i++)
+ 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 to scale point sizes 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.
+ *--------------------------------------------------------------------*/
+
+void
+savebounds(double x,
+ double 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 newlines, and are of the
+ | format:
+ | string1 string2
+ | where string1 is the command, string2 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];
+ char *chr;
+ 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 *) grnmalloc(strlen(str2) + 1, "roman command");
+ strcpy(tfont[0], str2);
+ break;
+
+ case 'i': /* italics */
+ if (str2[0] < '0')
+ goto nofont;
+ tfont[1] = (char *) grnmalloc(strlen(str2) + 1, "italics command");
+ strcpy(tfont[1], str2);
+ break;
+
+ case 'b': /* bold */
+ if (str2[0] < '0')
+ goto nofont;
+ tfont[2] = (char *) grnmalloc(strlen(str2) + 1, "bold command");
+ strcpy(tfont[2], str2);
+ break;
+
+ case 's': /* special */
+ if (str1[1] == 'c')
+ goto scalecommand; /* or scale */
+
+ if (str2[0] < '0') {
+ nofont:
+ error("no font name specified in line %1", linenum);
+ break;
+ }
+ if (str1[1] == 't')
+ goto stipplecommand; /* or stipple */
+
+ tfont[3] = (char *) grnmalloc(strlen(str2) + 1, "special command");
+ strcpy(tfont[3], str2);
+ break;
+
+ case 'l': /* l */
+ if (isdigit(str1[1])) { /* set stipple index */
+ int idx = atoi(str1 + 1), val;
+
+ if (idx < 0 || idx > NSTIPPLES) {
+ error("bad stipple number %1 at line %2", idx, linenum);
+ break;
+ }
+ if (!defstipple_index)
+ defstipple_index = other_stipple_index;
+ val = atoi(str2);
+ if (val >= 0 && val < 256)
+ stipple_index[idx] = val;
+ else
+ error("bad stipple index value at line %1", linenum);
+ break;
+ }
+
+ stipplecommand: /* set stipple name */
+ stipple = (char *) grnmalloc(strlen(str2) + 1, "stipple command");
+ strcpy(stipple, str2);
+ /* if it's a 'known' font (currently only 'cf'), set indices */
+ 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] = defthick[0] * atof(str2);
+ break;
+
+ case 'm': /* medium */
+ thick[5] = defthick[0] * atof(str2);
+ break;
+
+ case 'n': /* narrow */
+ thick[0] = thick[1] = thick[3] = thick[4] =
+ defthick[0] * atof(str2);
+ break;
+
+ case 'x': /* x */
+ scalecommand: /* scale */
+ par = atof(str2);
+ if (par > 0.0)
+ xscale *= par;
+ else
+ error("invalid 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(ELT *elist)
+{
+ while (!DBNullelt(elist)) {
+ if (elist->type == POLYGON)
+ return (1);
+ elist = DBNextElt(elist);
+ }
+
+ return (0);
+}
+
+// Local Variables:
+// fill-column: 72
+// mode: C++
+// End:
+// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: