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