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