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