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