Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / preproc / grn / main.cpp
1 /* Last non-groff version: main.c 1.23  (Berkeley)  85/08/05
2  *
3  * Adapted to GNU troff by Daniel Senderowicz 99/12/29.
4  *
5  * Further refinements by Werner Lemberg 00/02/20.
6  *
7  *
8  * This file contains the main and file system dependent routines for
9  * processing gremlin files into troff input.  The program watches input go
10  * by to standard output, only interpreting things between .GS and .GE
11  * lines.  Default values (font, size, scale, thickness) may be overridden
12  * with a `default' command and are further overridden by commands in the
13  * input.
14  *
15  * Inside the GS and GE, commands are accepted to reconfigure the picture. 
16  * At most one command may reside on each line, and each command is followed
17  * by a parameter separated by white space.  The commands are as follows,
18  * and may be abbreviated down to one character (with exception of `scale'
19  * and `stipple' down to "sc" and "st") and may be upper or lower case.
20  *
21  *                        default  -  Make all settings in the current
22  *                                    .GS/.GE the global defaults.  Height,
23  *                                    width and file are NOT saved.
24  *                     1, 2, 3, 4  -  Set size 1, 2, 3, or 4 (followed by an
25  *                                    integer point size).
26  *  roman, italics, bold, special  -  Set gremlin's fonts to any other troff
27  *                                    font (one or two characters).
28  *                     stipple, l  -  Use a stipple font for polygons.  Arg
29  *                                    is troff font name.  No Default.  Can
30  *                                    use only one stipple font per picture. 
31  *                                    (See below for stipple font index.)
32  *                       scale, x  -  Scale is IN ADDITION to the global
33  *                                    scale factor from the default.
34  *                     pointscale  -  Turn on scaling point sizes to match
35  *                                    `scale' commands.  (Optional operand
36  *                                    `off' to turn it off.)
37  *          narrow, medium, thick  -  Set widths of lines.
38  *                           file  -  Set the file name to read the gremlin
39  *                                    picture from.  If the file isn't in
40  *                                    the current directory, the gremlin
41  *                                    library is tried.
42  *                  width, height  -  These two commands override any
43  *                                    scaling factor that is in effect, and
44  *                                    forces the picture to fit into either
45  *                                    the height or width specified,
46  *                                    whichever makes the picture smaller. 
47  *                                    The operand for these two commands is
48  *                                    a floating-point number in units of
49  *                                    inches.
50  *            l<nn> (integer <nn>) -  Set association between stipple <nn>
51  *                                    and a stipple `character'.  <nn> must
52  *                                    be in the range 0 to NSTIPPLES (16)
53  *                                    inclusive.  The integer operand is an
54  *                                    index in the stipple font selected. 
55  *                                    Valid cf (cifplot) indices are 1-32
56  *                                    (although 24 is not defined), valid ug
57  *                                    (unigrafix) indices are 1-14, and
58  *                                    valid gs (gray scale) indices are
59  *                                    0-16.  Nonetheless, any number between
60  *                                    0 and 255 is accepted since new
61  *                                    stipple fonts may be added.  An
62  *                                    integer operand is required.
63  *
64  * Troff number registers used:  g1 through g9.  g1 is the width of the
65  * picture, and g2 is the height.  g3, and g4, save information, g8 and g9
66  * are used for text processing and g5-g7 are reserved.
67  */
68
69
70 #include "lib.h"
71
72 #include <ctype.h>
73 #include <stdlib.h>
74 #include "gprint.h"
75
76 #include "device.h"
77 #include "font.h"
78 #include "searchpath.h"
79 #include "macropath.h"
80
81 #include "errarg.h"
82 #include "error.h"
83 #include "defs.h"
84
85 extern "C" const char *Version_string;
86
87 /* database imports */
88
89 extern void HGPrintElt(ELT *element, int baseline);
90 extern ELT *DBInit();
91 extern ELT *DBRead(register FILE *file);
92 extern POINT *PTInit();
93 extern POINT *PTMakePoint(double x, double y, POINT **pplist);
94
95
96 #define SUN_SCALEFACTOR 0.70
97
98 /* #define DEFSTIPPLE    "gs" */
99 #define DEFSTIPPLE      "cf"
100
101 #define MAXINLINE       100     /* input line length */
102
103 #define SCREENtoINCH    0.02    /* scaling factor, screen to inches */
104
105 #define BIG     999999999999.0  /* unweildly large floating number */
106
107
108 static char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99";
109
110 int res;                        /* the printer's resolution goes here */
111
112 int dotshifter;                 /* for the length of dotted curves */
113
114 double linethickness;           /* brush styles */
115 int linmod;
116 int lastx;                      /* point registers for printing elements */
117 int lasty;
118 int lastyline;                  /* A line's vertical position is NOT the  */
119                                 /* same after that line is over, so for a */
120                                 /* line of drawing commands, vertical     */
121                                 /* spacing is kept in lastyline           */
122
123 /* These are the default fonts, sizes, line styles, */
124 /* and thicknesses.  They can be modified from a    */
125 /* `default' command and are reset each time the    */
126 /* start of a picture (.GS) is found.               */
127
128 const char *deffont[] =
129 {"R", "I", "B", "S"};
130 int defsize[] =
131 {10, 16, 24, 36};
132 /* #define BASE_THICKNESS 1.0 */
133 #define BASE_THICKNESS 0.15
134 double defthick[STYLES] =
135 {1 * BASE_THICKNESS,
136  1 * BASE_THICKNESS,
137  5 * BASE_THICKNESS,
138  1 * BASE_THICKNESS,
139  1 * BASE_THICKNESS,
140  3 * BASE_THICKNESS};
141
142 /* int cf_stipple_index[NSTIPPLES + 1] =                                  */
143 /* {0, 1, 3, 12, 14, 16, 19, 21, 23};                                     */
144 /* a logarithmic scale looks better than a linear one for the gray shades */
145 /*                                                                        */
146 /* int other_stipple_index[NSTIPPLES + 1] =                               */
147 /* {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};            */
148
149 int cf_stipple_index[NSTIPPLES + 1] =
150 {0, 18, 32, 56, 100, 178, 316, 562, 1000};      /* only 1-8 used */
151 int other_stipple_index[NSTIPPLES + 1] =
152 {0, 62, 125, 187, 250, 312, 375, 437, 500,
153  562, 625, 687, 750, 812, 875, 937, 1000};
154
155 /* int *defstipple_index = other_stipple_index; */
156 int *defstipple_index = cf_stipple_index;
157
158 int style[STYLES] =
159 {DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID};
160 double scale = 1.0;             /* no scaling, default */
161 int defpoint = 0;               /* flag for pointsize scaling */
162 char *defstipple = (char *) 0;
163 enum E {
164   OUTLINE, FILL, BOTH
165 } polyfill;
166
167 /* flag to controll filling of polygons */
168
169 double adj1 = 0.0;
170 double adj2 = 0.0;
171 double adj3 = 0.0;
172 double adj4 = 0.0;
173
174 double thick[STYLES];           /* thicknesses set by defaults, then by */
175                                 /* commands                             */
176 char *tfont[FONTS];             /* fonts originally set to deffont values, */
177                                 /* then                                    */
178 int tsize[SIZES];               /* optionally changed by commands inside */
179                                 /* grn                                   */
180 int stipple_index[NSTIPPLES + 1];       /* stipple font file indices */
181 char *stipple;
182
183 double xscale;                  /* scaling factor from individual pictures */
184 double troffscale;              /* scaling factor at output time */
185
186 double width;                   /* user-request maximum width for picture */
187                                 /* (in inches)                            */
188 double height;                  /* user-request height */
189 int pointscale;                 /* flag for pointsize scaling */
190 int setdefault;                 /* flag for a .GS/.GE to remember all */
191                                 /* settings                           */
192 int sflag;                      /* -s flag: sort order (do polyfill first) */
193
194 double toppoint;                /* remember the picture */
195 double bottompoint;             /* bounds in these variables */
196 double leftpoint;
197 double rightpoint;
198
199 int ytop;                       /* these are integer versions of the above */
200 int ybottom;                    /* so not to convert each time they're used */
201 int xleft;
202 int xright;
203
204 int linenum = 0;                /* line number of input file */
205 char inputline[MAXINLINE];      /* spot to filter through the file */
206 char *c1 = inputline;           /* c1, c2, and c3 will be used to */
207 char *c2 = inputline + 1;       /* hunt for lines that begin with */
208 char *c3 = inputline + 2;       /* ".GS" by looking individually */
209 char *c4 = inputline + 3;       /* needed for compatibility mode */
210 char GScommand[MAXINLINE];      /* put user's ".GS" command line here */
211 char gremlinfile[MAXINLINE];    /* filename to use for a picture */
212 int SUNFILE = FALSE;            /* TRUE if SUN gremlin file */
213 int compatibility_flag = FALSE; /* TRUE if in compatibility mode */
214
215
216 void getres();
217 int doinput(FILE *fp);
218 void conv(register FILE *fp, int baseline);
219 void savestate();
220 int has_polygon(register ELT *elist);
221 void interpret(char *line);
222
223
224 void
225 usage(FILE *stream)
226 {
227   fprintf(stream,
228           "usage: %s [ -vCs ] [ -M dir ] [ -F dir ] [ -T dev ] [ file ]\n",
229           program_name);
230 }
231
232
233 /*----------------------------------------------------------------------------*
234  | Routine:     main (argument_count, argument_pointer)
235  |
236  | Results:     Parses the command line, accumulating input file names, then
237  |              reads the inputs, passing it directly to output until a `.GS'
238  |              line is read.  Main then passes control to `conv' to do the
239  |              gremlin file conversions.
240  *----------------------------------------------------------------------------*/
241
242 int
243 main(int argc,
244      char **argv)
245 {
246   setlocale(LC_NUMERIC, "C");
247   program_name = argv[0];
248   register FILE *fp;
249   register int k;
250   register char c;
251   register int gfil = 0;
252   char *file[50];
253   char *operand(int *argcp, char ***argvp);
254
255   while (--argc) {
256     if (**++argv != '-')
257       file[gfil++] = *argv;
258     else
259       switch (c = (*argv)[1]) {
260
261       case 0:
262         file[gfil++] = NULL;
263         break;
264
265       case 'C':         /* compatibility mode */
266         compatibility_flag = TRUE;
267         break;
268
269       case 'F':         /* font path to find DESC */
270         font::command_line_font_dir(operand(&argc, &argv));
271         break;
272
273       case 'T':         /* final output typesetter name */
274         device = operand(&argc, &argv);
275         break;
276
277       case 'M':         /* set library directory */
278         macro_path.command_line_dir(operand(&argc, &argv));
279         break;
280
281       case 's':         /* preserve order of elements */
282         sflag = 1;
283         break;
284
285       case '-':
286         if (strcmp(*argv,"--version")==0) {
287       case 'v':
288           printf("GNU grn (groff) version %s\n", Version_string);
289           exit(0);
290           break;
291         }
292         if (strcmp(*argv,"--help")==0) {
293       case '?':
294           usage(stdout);
295           exit(0);
296           break;
297         }
298         // fallthrough
299       default:
300         error("unknown switch: %1", c);
301         usage(stderr);
302         exit(1);
303       }
304   }
305
306   getres();                     /* set the resolution for an output device */
307
308   if (gfil == 0) {              /* no filename, use standard input */
309     file[0] = NULL;
310     gfil++;
311   }
312
313   for (k = 0; k < gfil; k++) {
314     if (file[k] != NULL) {
315       if ((fp = fopen(file[k], "r")) == NULL)
316         fatal("can't open %1", file[k]);
317     } else
318       fp = stdin;
319
320     while (doinput(fp)) {
321       if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') {
322         if (compatibility_flag ||
323             *c4 == '\n' || *c4 == ' ' || *c4 == '\0')
324           conv(fp, linenum);
325         else
326           fputs(inputline, stdout);
327       } else
328         fputs(inputline, stdout);
329     }
330   }
331
332   return 0;
333 }
334
335
336 /*----------------------------------------------------------------------------*
337  | Routine:     char  * operand (& argc, & argv)
338  |
339  | Results:     Returns address of the operand given with a command-line
340  |              option.  It uses either `-Xoperand' or `-X operand', whichever
341  |              is present.  The program is terminated if no option is
342  |              present.
343  |
344  | Side Efct:   argc and argv are updated as necessary.
345  *----------------------------------------------------------------------------*/
346
347 char *
348 operand(int *argcp,
349         char ***argvp)
350 {
351   if ((**argvp)[2])
352     return (**argvp + 2);       /* operand immediately follows */
353   if ((--*argcp) <= 0) {        /* no operand */
354     error("command-line option operand missing.");
355     exit(8);
356   }
357   return (*(++(*argvp)));       /* operand is next word */
358 }
359
360
361 /*----------------------------------------------------------------------------*
362  | Routine:     getres ()
363  |
364  | Results:     Sets `res' to the resolution of the output device.
365  *----------------------------------------------------------------------------*/
366
367 void
368 getres()
369 {
370   int linepiece;
371
372   if (!font::load_desc())
373     fatal("sorry, I can't continue");
374
375   res = font::res;
376
377   /* Correct the brush thicknesses based on res */
378   /* if (res >= 256) {
379       defthick[0] = res >> 8;
380       defthick[1] = res >> 8;
381       defthick[2] = res >> 4;
382       defthick[3] = res >> 8;
383       defthick[4] = res >> 8;
384       defthick[5] = res >> 6;
385       } */
386
387   linepiece = res >> 9;
388   for (dotshifter = 0; linepiece; dotshifter++)
389     linepiece = linepiece >> 1;
390 }
391
392
393 /*----------------------------------------------------------------------------*
394  | Routine:     int  doinput (file_pointer)
395  |
396  | Results:     A line of input is read into `inputline'.
397  |
398  | Side Efct:   "linenum" is incremented.
399  |
400  | Bugs:        Lines longer than MAXINLINE are NOT checked, except for 
401  |              updating `linenum'.
402  *----------------------------------------------------------------------------*/
403
404 int
405 doinput(FILE *fp)
406 {
407   if (fgets(inputline, MAXINLINE, fp) == NULL)
408     return 0;
409   if (strchr(inputline, '\n'))  /* ++ only if it's a complete line */
410     linenum++;
411   return 1;
412 }
413
414
415 /*----------------------------------------------------------------------------*
416  | Routine:     initpic ( )
417  |
418  | Results:     Sets all parameters to the normal defaults, possibly
419  |              overridden by a setdefault command.  Initialize the picture
420  |              variables, and output the startup commands to troff to begin
421  |              the picture.
422  *----------------------------------------------------------------------------*/
423
424 void
425 initpic()
426 {
427   register int i;
428
429   for (i = 0; i < STYLES; i++) {        /* line thickness defaults */
430     thick[i] = defthick[i];
431   }
432   for (i = 0; i < FONTS; i++) {         /* font name defaults */
433     tfont[i] = (char *)deffont[i];
434   }
435   for (i = 0; i < SIZES; i++) {         /* font size defaults */
436     tsize[i] = defsize[i];
437   }
438   for (i = 0; i <= NSTIPPLES; i++) {    /* stipple font file default indices */
439     stipple_index[i] = defstipple_index[i];
440   }
441   stipple = defstipple;
442
443   gremlinfile[0] = 0;           /* filename is `null' */
444   setdefault = 0;               /* this is not the default settings (yet) */
445
446   toppoint = BIG;               /* set the picture bounds out */
447   bottompoint = -BIG;           /* of range so they'll be set */
448   leftpoint = BIG;              /* by `savebounds' on input */
449   rightpoint = -BIG;
450
451   pointscale = defpoint;        /* flag for scaling point sizes default */
452   xscale = scale;               /* default scale of individual pictures */
453   width = 0.0;                  /* size specifications input by user */
454   height = 0.0;
455
456   linethickness = DEFTHICK;     /* brush styles */
457   linmod = DEFSTYLE;
458 }
459
460
461 /*----------------------------------------------------------------------------*
462  | Routine:     conv (file_pointer, starting_line)
463  |
464  | Results:     At this point, we just passed a `.GS' line in the input
465  |              file.  conv reads the input and calls `interpret' to process
466  |              commands, gathering up information until a `.GE' line is
467  |              found.  It then calls `HGPrint' to do the translation of the
468  |              gremlin file to troff commands.
469  *----------------------------------------------------------------------------*/
470
471 void
472 conv(register FILE *fp,
473      int baseline)
474 {
475   register FILE *gfp = NULL;    /* input file pointer */
476   register int done = 0;        /* flag to remember if finished */
477   register ELT *e;              /* current element pointer */
478   ELT *PICTURE;                 /* whole picture data base pointer */
479   double temp;                  /* temporary calculating area */
480   /* POINT ptr; */              /* coordinates of a point to pass to `mov' */
481                                 /* routine                                 */
482   int flyback;                  /* flag `want to end up at the top of the */
483                                 /* picture?'                              */
484   int compat;                   /* test character after .GE or .GF */
485
486
487   initpic();                    /* set defaults, ranges, etc. */
488   strcpy(GScommand, inputline); /* save `.GS' line for later */
489
490   do {
491     done = !doinput(fp);                /* test for EOF */
492     flyback = (*c3 == 'F');             /* and .GE or .GF */
493     compat = (compatibility_flag ||
494               *c4 == '\n' || *c4 == ' ' || *c4 == '\0');
495     done |= (*c1 == '.' && *c2 == 'G' && (*c3 == 'E' || flyback) &&
496              compat);
497
498     if (done) {
499       if (setdefault)
500         savestate();
501
502       if (!gremlinfile[0]) {
503         if (!setdefault)
504           error("at line %1: no picture filename.\n", baseline);
505         return;
506       }
507       char *path;
508       gfp = macro_path.open_file(gremlinfile, &path);
509       if (!gfp)
510         return;
511       PICTURE = DBRead(gfp);    /* read picture file */
512       fclose(gfp);
513       a_delete path;
514       if (DBNullelt(PICTURE))
515         return;                 /* If a request is made to make the  */
516                                 /* picture fit into a specific area, */
517                                 /* set the scale to do that.         */
518
519       if (stipple == (char *) NULL)     /* if user forgot stipple    */
520         if (has_polygon(PICTURE))       /* and picture has a polygon */
521           stipple = (char *)DEFSTIPPLE;         /* then set the default      */
522
523       if ((temp = bottompoint - toppoint) < 0.1)
524         temp = 0.1;
525       temp = (height != 0.0) ? height / (temp * SCREENtoINCH) : BIG;
526       if ((troffscale = rightpoint - leftpoint) < 0.1)
527         troffscale = 0.1;
528       troffscale = (width != 0.0) ?
529           width / (troffscale * SCREENtoINCH) : BIG;
530       if (temp == BIG && troffscale == BIG)
531         troffscale = xscale;
532       else {
533         if (temp < troffscale)
534           troffscale = temp;
535       }                         /* here, troffscale is the */
536                                 /* picture's scaling factor */
537       if (pointscale) {
538         register int i;         /* do pointscaling here, when */
539                                 /* scale is known, before output */
540         for (i = 0; i < SIZES; i++)
541           tsize[i] = (int) (troffscale * (double) tsize[i] + 0.5);
542       }
543
544                                                 /* change to device units */
545       troffscale *= SCREENtoINCH * res;         /* from screen units */
546
547       ytop = (int) (toppoint * troffscale);             /* calculate integer */
548       ybottom = (int) (bottompoint * troffscale);       /* versions of the   */
549       xleft = (int) (leftpoint * troffscale);           /* picture limits    */
550       xright = (int) (rightpoint * troffscale);
551
552       /* save stuff in number registers,    */
553       /*   register g1 = picture width and  */
554       /*   register g2 = picture height,    */
555       /*   set vertical spacing, no fill,   */
556       /*   and break (to make sure picture  */
557       /*   starts on left), and put out the */
558       /*   user's `.GS' line.               */
559       printf(".br\n"
560              ".nr g1 %du\n"
561              ".nr g2 %du\n"
562              "%s"
563              ".nr g3 \\n(.f\n"
564              ".nr g4 \\n(.s\n"
565              "\\0\n"
566              ".sp -1\n",
567              xright - xleft, ybottom - ytop, GScommand);
568
569       if (stipple)              /* stipple requested for this picture */
570         printf(".st %s\n", stipple);
571       lastx = xleft;            /* note where we are (upper left */
572       lastyline = lasty = ytop; /* corner of the picture)        */
573
574       /* Just dump everything in the order it appears.
575        *
576        * If -s command-line option, traverse picture twice: First time,
577        * print only the interiors of filled polygons (as borderless
578        * polygons).  Second time, print the outline as series of line
579        * segments.  This way, postprocessors that overwrite rather than
580        * merge picture elements (such as Postscript) can still have text and
581        * graphics on a shaded background.
582        */
583       /* if (sflag) */
584       if (!sflag) {             /* changing the default for filled polygons */
585         e = PICTURE;
586         polyfill = FILL;
587         while (!DBNullelt(e)) {
588           printf(".mk\n");
589           if (e->type == POLYGON)
590             HGPrintElt(e, baseline);
591           printf(".rt\n");
592           lastx = xleft;
593           lastyline = lasty = ytop;
594           e = DBNextElt(e);
595         }
596       }
597       e = PICTURE;
598
599       /* polyfill = !sflag ? BOTH : OUTLINE; */
600       polyfill = sflag ? BOTH : OUTLINE;        /* changing the default */
601       while (!DBNullelt(e)) {
602         printf(".mk\n");
603         HGPrintElt(e, baseline);
604         printf(".rt\n");
605         lastx = xleft;
606         lastyline = lasty = ytop;
607         e = DBNextElt(e);
608       }
609
610       /* decide where to end picture */
611
612       /* I changed everything here.  I always use the combination .mk and */
613       /* .rt so once finished I just space down the heigth of the picture */
614       /* that is \n(g2u                                                   */
615       if (flyback) {            /* end picture at upper left */
616         /* ptr.x = leftpoint;
617            ptr.y = toppoint; */
618       } else {                  /* end picture at lower left */
619         /* ptr.x = leftpoint;
620            ptr.y = bottompoint; */
621         printf(".sp \\n(g2u\n");
622       }
623
624       /* tmove(&ptr); */        /* restore default line parameters */
625
626       /* restore everything to the way it was before the .GS, then put */
627       /* out the `.GE' line from user                                  */
628
629       /* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */
630       /* groff doesn't understand the \Ds command */
631
632       printf("\\D't %du'\n", DEFTHICK);
633       if (flyback)              /* make sure we end up at top of */
634         printf(".sp -1\n");     /* picture if `flying back'      */
635       if (stipple)              /* restore stipple to previous */
636         printf(".st\n");
637       printf(".br\n"
638              ".ft \\n(g3\n"
639              ".ps \\n(g4\n"
640              "%s", inputline);
641     } else
642       interpret(inputline);     /* take commands from the input file */
643   } while (!done);
644 }
645
646
647 /*----------------------------------------------------------------------------*
648  | Routine:     savestate  ( )
649  |
650  | Results:     all the current  scaling / font size / font name / thickness
651  |              / pointscale settings are saved to be the defaults.  Scaled
652  |              point sizes are NOT saved.  The scaling is done each time a
653  |              new picture is started.
654  |
655  | Side Efct:   scale, and def* are modified.
656  *----------------------------------------------------------------------------*/
657
658 void
659 savestate()
660 {
661   register int i;
662
663   for (i = 0; i < STYLES; i++)  /* line thickness defaults */
664     defthick[i] = thick[i];
665   for (i = 0; i < FONTS; i++)   /* font name defaults */
666     deffont[i] = tfont[i];
667   for (i = 0; i < SIZES; i++)   /* font size defaults */
668     defsize[i] = tsize[i];
669   for (i = 0; i <= NSTIPPLES; i++)      /* stipple font file default indices */
670     defstipple_index[i] = stipple_index[i];
671
672   defstipple = stipple;         /* if stipple has been set, it's remembered */
673   scale *= xscale;              /* default scale of individual pictures */
674   defpoint = pointscale;        /* flag for scaling pointsizes from x factors */
675 }
676
677
678 /*----------------------------------------------------------------------------*
679  | Routine:     savebounds (x_coordinate, y_coordinate)
680  |
681  | Results:     Keeps track of the maximum and minimum extent of a picture
682  |              in the global variables: left-, right-, top- and
683  |              bottompoint.  `savebounds' assumes that the points have been
684  |              oriented to the correct direction.  No scaling has taken
685  |              place, though.
686  *----------------------------------------------------------------------------*/
687
688 void
689 savebounds(double x,
690            double y)
691 {
692   if (x < leftpoint)
693     leftpoint = x;
694   if (x > rightpoint)
695     rightpoint = x;
696   if (y < toppoint)
697     toppoint = y;
698   if (y > bottompoint)
699     bottompoint = y;
700 }
701
702
703 /*----------------------------------------------------------------------------*
704  | Routine:     interpret (character_string)
705  |
706  | Results:     Commands are taken from the input string and performed.
707  |              Commands are separated by the endofline, and are of the
708  |              format:
709  |                      string1 string2
710  |
711  |              where string1 is the command and string2 is the argument.
712  |
713  | Side Efct:   Font and size strings, plus the gremlin file name and the
714  |              width and height variables are set by this routine.
715  *----------------------------------------------------------------------------*/
716
717 void
718 interpret(char *line)
719 {
720   char str1[MAXINLINE];
721   char str2[MAXINLINE];
722   register char *chr;
723   register int i;
724   double par;
725
726   str2[0] = '\0';
727   sscanf(line, "%80s%80s", &str1[0], &str2[0]);
728   for (chr = &str1[0]; *chr; chr++)     /* convert command to */
729     if (isupper(*chr))
730       *chr = tolower(*chr);     /* lower case */
731
732   switch (str1[0]) {
733
734   case '1':
735   case '2':                     /* font sizes */
736   case '3':
737   case '4':
738     i = atoi(str2);
739     if (i > 0 && i < 1000)
740       tsize[str1[0] - '1'] = i;
741     else
742       error("bad font size value at line %1", linenum);
743     break;
744
745   case 'r':                     /* roman */
746     if (str2[0] < '0')
747       goto nofont;
748     tfont[0] = (char *) malloc(strlen(str2) + 1);
749     strcpy(tfont[0], str2);
750     break;
751
752   case 'i':                     /* italics */
753     if (str2[0] < '0')
754       goto nofont;
755     tfont[1] = (char *) malloc(strlen(str2) + 1);
756     strcpy(tfont[1], str2);
757     break;
758
759   case 'b':                     /* bold */
760     if (str2[0] < '0')
761       goto nofont;
762     tfont[2] = (char *) malloc(strlen(str2) + 1);
763     strcpy(tfont[2], str2);
764     break;
765
766   case 's':                     /* special */
767     if (str1[1] == 'c')
768       goto scalecommand;        /* or scale */
769
770     if (str2[0] < '0') {
771   nofont:
772       error("no fontname specified in line %1", linenum);
773       break;
774     }
775     if (str1[1] == 't')
776       goto stipplecommand;      /* or stipple */
777
778     tfont[3] = (char *) malloc(strlen(str2) + 1);
779     strcpy(tfont[3], str2);
780     break;
781
782   case 'l':                     /* l */
783     if (isdigit(str1[1])) {     /* set stipple index */
784       int idx = atoi(str1 + 1), val;
785
786       if (idx < 0 || idx > NSTIPPLES) {
787         error("bad stipple number %1 at line %2", idx, linenum);
788         break;
789       }
790       if (!defstipple_index)
791         defstipple_index = other_stipple_index;
792       val = atoi(str2);
793       if (val >= 0 && val < 256)
794         stipple_index[idx] = val;
795       else
796         error("bad stipple index value at line %1", linenum);
797       break;
798     }
799
800   stipplecommand:               /* set stipple name */
801     stipple = (char *) malloc(strlen(str2) + 1);
802     strcpy(stipple, str2);
803     /* if its a `known' font (currently only `cf'), set indicies    */
804     if (strcmp(stipple, "cf") == 0)
805       defstipple_index = cf_stipple_index;
806     else
807       defstipple_index = other_stipple_index;
808     for (i = 0; i <= NSTIPPLES; i++)
809       stipple_index[i] = defstipple_index[i];
810     break;
811
812   case 'a':                     /* text adjust */
813     par = atof(str2);
814     switch (str1[1]) {
815     case '1':
816       adj1 = par;
817       break;
818     case '2':
819       adj2 = par;
820       break;
821     case '3':
822       adj3 = par;
823       break;
824     case '4':
825       adj4 = par;
826       break;
827     default:
828       error("bad adjust command at line %1", linenum);
829       break;
830     }
831     break;
832
833   case 't':                     /* thick */
834     thick[2] = defthick[0] * atof(str2);
835     break;
836
837   case 'm':                     /* medium */
838     thick[5] = defthick[0] * atof(str2);
839     break;
840
841   case 'n':                     /* narrow */
842     thick[0] = thick[1] = thick[3] = thick[4] =
843         defthick[0] * atof(str2);
844     break;
845
846   case 'x':                     /* x */
847   scalecommand:                 /* scale */
848     par = atof(str2);
849     if (par > 0.0)
850       xscale *= par;
851     else
852       error("invalid scale value on line %1", linenum);
853     break;
854
855   case 'f':                     /* file */
856     strcpy(gremlinfile, str2);
857     break;
858
859   case 'w':                     /* width */
860     width = atof(str2);
861     if (width < 0.0)
862       width = -width;
863     break;
864
865   case 'h':                     /* height */
866     height = atof(str2);
867     if (height < 0.0)
868       height = -height;
869     break;
870
871   case 'd':                     /* defaults */
872     setdefault = 1;
873     break;
874
875   case 'p':                     /* pointscale */
876     if (strcmp("off", str2))
877       pointscale = 1;
878     else
879       pointscale = 0;
880     break;
881
882   default:
883     error("unknown command `%1' on line %2", str1, linenum);
884     exit(8);
885     break;
886   };
887 }
888
889
890 /*
891  * return TRUE if picture contains a polygon
892  * otherwise FALSE
893  */
894
895 int
896 has_polygon(register ELT *elist)
897 {
898   while (!DBNullelt(elist)) {
899     if (elist->type == POLYGON)
900       return (1);
901     elist = DBNextElt(elist);
902   }
903
904   return (0);
905 }
906
907 /* EOF */