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