1114402Sru/* Last non-groff version: main.c 1.23  (Berkeley)  85/08/05
2114402Sru *
3114402Sru * Adapted to GNU troff by Daniel Senderowicz 99/12/29.
4114402Sru *
5114402Sru * Further refinements by Werner Lemberg 00/02/20.
6114402Sru *
7114402Sru *
8114402Sru * This file contains the main and file system dependent routines for
9114402Sru * processing gremlin files into troff input.  The program watches input go
10114402Sru * by to standard output, only interpreting things between .GS and .GE
11114402Sru * lines.  Default values (font, size, scale, thickness) may be overridden
12114402Sru * with a `default' command and are further overridden by commands in the
13114402Sru * input.
14114402Sru *
15114402Sru * Inside the GS and GE, commands are accepted to reconfigure the picture.
16114402Sru * At most one command may reside on each line, and each command is followed
17114402Sru * by a parameter separated by white space.  The commands are as follows,
18114402Sru * and may be abbreviated down to one character (with exception of `scale'
19114402Sru * and `stipple' down to "sc" and "st") and may be upper or lower case.
20114402Sru *
21114402Sru *                        default  -  Make all settings in the current
22114402Sru *                                    .GS/.GE the global defaults.  Height,
23114402Sru *                                    width and file are NOT saved.
24114402Sru *                     1, 2, 3, 4  -  Set size 1, 2, 3, or 4 (followed by an
25114402Sru *                                    integer point size).
26114402Sru *  roman, italics, bold, special  -  Set gremlin's fonts to any other troff
27114402Sru *                                    font (one or two characters).
28114402Sru *                     stipple, l  -  Use a stipple font for polygons.  Arg
29114402Sru *                                    is troff font name.  No Default.  Can
30114402Sru *                                    use only one stipple font per picture.
31114402Sru *                                    (See below for stipple font index.)
32114402Sru *                       scale, x  -  Scale is IN ADDITION to the global
33114402Sru *                                    scale factor from the default.
34114402Sru *                     pointscale  -  Turn on scaling point sizes to match
35114402Sru *                                    `scale' commands.  (Optional operand
36114402Sru *                                    `off' to turn it off.)
37114402Sru *          narrow, medium, thick  -  Set widths of lines.
38114402Sru *                           file  -  Set the file name to read the gremlin
39114402Sru *                                    picture from.  If the file isn't in
40114402Sru *                                    the current directory, the gremlin
41114402Sru *                                    library is tried.
42114402Sru *                  width, height  -  These two commands override any
43114402Sru *                                    scaling factor that is in effect, and
44114402Sru *                                    forces the picture to fit into either
45114402Sru *                                    the height or width specified,
46114402Sru *                                    whichever makes the picture smaller.
47114402Sru *                                    The operand for these two commands is
48114402Sru *                                    a floating-point number in units of
49114402Sru *                                    inches.
50114402Sru *            l<nn> (integer <nn>) -  Set association between stipple <nn>
51114402Sru *                                    and a stipple `character'.  <nn> must
52114402Sru *                                    be in the range 0 to NSTIPPLES (16)
53114402Sru *                                    inclusive.  The integer operand is an
54114402Sru *                                    index in the stipple font selected.
55114402Sru *                                    Valid cf (cifplot) indices are 1-32
56114402Sru *                                    (although 24 is not defined), valid ug
57114402Sru *                                    (unigrafix) indices are 1-14, and
58114402Sru *                                    valid gs (gray scale) indices are
59114402Sru *                                    0-16.  Nonetheless, any number between
60114402Sru *                                    0 and 255 is accepted since new
61114402Sru *                                    stipple fonts may be added.  An
62114402Sru *                                    integer operand is required.
63114402Sru *
64114402Sru * Troff number registers used:  g1 through g9.  g1 is the width of the
65114402Sru * picture, and g2 is the height.  g3, and g4, save information, g8 and g9
66114402Sru * are used for text processing and g5-g7 are reserved.
67114402Sru */
68114402Sru
69114402Sru
70114402Sru#include "lib.h"
71114402Sru
72114402Sru#include <ctype.h>
73114402Sru#include <stdlib.h>
74114402Sru#include "gprint.h"
75114402Sru
76114402Sru#include "device.h"
77114402Sru#include "font.h"
78114402Sru#include "searchpath.h"
79114402Sru#include "macropath.h"
80114402Sru
81114402Sru#include "errarg.h"
82114402Sru#include "error.h"
83114402Sru#include "defs.h"
84114402Sru
85114402Sruextern "C" const char *Version_string;
86114402Sru
87114402Sru/* database imports */
88114402Sru
89114402Sruextern void HGPrintElt(ELT *element, int baseline);
90114402Sruextern ELT *DBInit();
91114402Sruextern ELT *DBRead(register FILE *file);
92114402Sruextern POINT *PTInit();
93151497Sruextern POINT *PTMakePoint(double x, double y, POINT **pplist);
94114402Sru
95114402Sru
96114402Sru#define SUN_SCALEFACTOR 0.70
97114402Sru
98114402Sru/* #define DEFSTIPPLE    "gs" */
99114402Sru#define DEFSTIPPLE	"cf"
100114402Sru
101114402Sru#define MAXINLINE	100	/* input line length */
102114402Sru
103114402Sru#define SCREENtoINCH	0.02	/* scaling factor, screen to inches */
104114402Sru
105114402Sru#define BIG	999999999999.0	/* unweildly large floating number */
106114402Sru
107114402Sru
108114402Srustatic char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99";
109114402Sru
110114402Sruint res;			/* the printer's resolution goes here */
111114402Sru
112114402Sruint dotshifter;			/* for the length of dotted curves */
113114402Sru
114114402Srudouble linethickness;		/* brush styles */
115114402Sruint linmod;
116114402Sruint lastx;			/* point registers for printing elements */
117114402Sruint lasty;
118114402Sruint lastyline;			/* A line's vertical position is NOT the  */
119114402Sru				/* same after that line is over, so for a */
120114402Sru				/* line of drawing commands, vertical     */
121114402Sru				/* spacing is kept in lastyline           */
122114402Sru
123114402Sru/* These are the default fonts, sizes, line styles, */
124114402Sru/* and thicknesses.  They can be modified from a    */
125114402Sru/* `default' command and are reset each time the    */
126114402Sru/* start of a picture (.GS) is found.               */
127114402Sru
128151497Sruconst char *deffont[] =
129114402Sru{"R", "I", "B", "S"};
130114402Sruint defsize[] =
131114402Sru{10, 16, 24, 36};
132114402Sru/* #define BASE_THICKNESS 1.0 */
133114402Sru#define BASE_THICKNESS 0.15
134114402Srudouble defthick[STYLES] =
135114402Sru{1 * BASE_THICKNESS,
136114402Sru 1 * BASE_THICKNESS,
137114402Sru 5 * BASE_THICKNESS,
138114402Sru 1 * BASE_THICKNESS,
139114402Sru 1 * BASE_THICKNESS,
140114402Sru 3 * BASE_THICKNESS};
141114402Sru
142114402Sru/* int cf_stipple_index[NSTIPPLES + 1] =                                  */
143114402Sru/* {0, 1, 3, 12, 14, 16, 19, 21, 23};                                     */
144114402Sru/* a logarithmic scale looks better than a linear one for the gray shades */
145114402Sru/*                                                                        */
146114402Sru/* int other_stipple_index[NSTIPPLES + 1] =                               */
147114402Sru/* {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};            */
148114402Sru
149114402Sruint cf_stipple_index[NSTIPPLES + 1] =
150114402Sru{0, 18, 32, 56, 100, 178, 316, 562, 1000};	/* only 1-8 used */
151114402Sruint other_stipple_index[NSTIPPLES + 1] =
152114402Sru{0, 62, 125, 187, 250, 312, 375, 437, 500,
153114402Sru 562, 625, 687, 750, 812, 875, 937, 1000};
154114402Sru
155114402Sru/* int *defstipple_index = other_stipple_index; */
156114402Sruint *defstipple_index = cf_stipple_index;
157114402Sru
158114402Sruint style[STYLES] =
159114402Sru{DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID};
160114402Srudouble scale = 1.0;		/* no scaling, default */
161114402Sruint defpoint = 0;		/* flag for pointsize scaling */
162114402Sruchar *defstipple = (char *) 0;
163151497Sruenum E {
164114402Sru  OUTLINE, FILL, BOTH
165114402Sru} polyfill;
166114402Sru
167114402Sru/* flag to controll filling of polygons */
168114402Sru
169114402Srudouble adj1 = 0.0;
170114402Srudouble adj2 = 0.0;
171114402Srudouble adj3 = 0.0;
172114402Srudouble adj4 = 0.0;
173114402Sru
174114402Srudouble thick[STYLES];		/* thicknesses set by defaults, then by */
175114402Sru				/* commands                             */
176114402Sruchar *tfont[FONTS];		/* fonts originally set to deffont values, */
177114402Sru				/* then                                    */
178114402Sruint tsize[SIZES];		/* optionally changed by commands inside */
179114402Sru				/* grn                                   */
180114402Sruint stipple_index[NSTIPPLES + 1];	/* stipple font file indices */
181114402Sruchar *stipple;
182114402Sru
183114402Srudouble xscale;			/* scaling factor from individual pictures */
184114402Srudouble troffscale;		/* scaling factor at output time */
185114402Sru
186114402Srudouble width;			/* user-request maximum width for picture */
187114402Sru				/* (in inches)                            */
188114402Srudouble height;			/* user-request height */
189114402Sruint pointscale;			/* flag for pointsize scaling */
190114402Sruint setdefault;			/* flag for a .GS/.GE to remember all */
191114402Sru				/* settings                           */
192114402Sruint sflag;			/* -s flag: sort order (do polyfill first) */
193114402Sru
194114402Srudouble toppoint;		/* remember the picture */
195114402Srudouble bottompoint;		/* bounds in these variables */
196114402Srudouble leftpoint;
197114402Srudouble rightpoint;
198114402Sru
199114402Sruint ytop;			/* these are integer versions of the above */
200114402Sruint ybottom;			/* so not to convert each time they're used */
201114402Sruint xleft;
202114402Sruint xright;
203114402Sru
204114402Sruint linenum = 0;		/* line number of input file */
205114402Sruchar inputline[MAXINLINE];	/* spot to filter through the file */
206114402Sruchar *c1 = inputline;		/* c1, c2, and c3 will be used to */
207114402Sruchar *c2 = inputline + 1;	/* hunt for lines that begin with */
208114402Sruchar *c3 = inputline + 2;	/* ".GS" by looking individually */
209114402Sruchar *c4 = inputline + 3;	/* needed for compatibility mode */
210114402Sruchar GScommand[MAXINLINE];	/* put user's ".GS" command line here */
211114402Sruchar gremlinfile[MAXINLINE];	/* filename to use for a picture */
212114402Sruint SUNFILE = FALSE;		/* TRUE if SUN gremlin file */
213114402Sruint compatibility_flag = FALSE;	/* TRUE if in compatibility mode */
214114402Sru
215114402Sru
216114402Sruvoid getres();
217151497Sruint doinput(FILE *fp);
218114402Sruvoid conv(register FILE *fp, int baseline);
219114402Sruvoid savestate();
220114402Sruint has_polygon(register ELT *elist);
221114402Sruvoid interpret(char *line);
222114402Sru
223114402Sru
224114402Sruvoid
225114402Sruusage(FILE *stream)
226114402Sru{
227114402Sru  fprintf(stream,
228114402Sru	  "usage: %s [ -vCs ] [ -M dir ] [ -F dir ] [ -T dev ] [ file ]\n",
229114402Sru	  program_name);
230114402Sru}
231114402Sru
232114402Sru
233114402Sru/*----------------------------------------------------------------------------*
234114402Sru | Routine:	main (argument_count, argument_pointer)
235114402Sru |
236114402Sru | Results:	Parses the command line, accumulating input file names, then
237114402Sru |		reads the inputs, passing it directly to output until a `.GS'
238114402Sru |		line is read.  Main then passes control to `conv' to do the
239114402Sru |		gremlin file conversions.
240114402Sru *----------------------------------------------------------------------------*/
241114402Sru
242114402Sruint
243114402Srumain(int argc,
244114402Sru     char **argv)
245114402Sru{
246114402Sru  setlocale(LC_NUMERIC, "C");
247114402Sru  program_name = argv[0];
248114402Sru  register FILE *fp;
249114402Sru  register int k;
250114402Sru  register char c;
251114402Sru  register int gfil = 0;
252114402Sru  char *file[50];
253114402Sru  char *operand(int *argcp, char ***argvp);
254114402Sru
255114402Sru  while (--argc) {
256114402Sru    if (**++argv != '-')
257114402Sru      file[gfil++] = *argv;
258114402Sru    else
259114402Sru      switch (c = (*argv)[1]) {
260114402Sru
261114402Sru      case 0:
262114402Sru	file[gfil++] = NULL;
263114402Sru	break;
264114402Sru
265114402Sru      case 'C':		/* compatibility mode */
266114402Sru	compatibility_flag = TRUE;
267114402Sru	break;
268114402Sru
269114402Sru      case 'F':		/* font path to find DESC */
270114402Sru	font::command_line_font_dir(operand(&argc, &argv));
271114402Sru	break;
272114402Sru
273114402Sru      case 'T':		/* final output typesetter name */
274114402Sru	device = operand(&argc, &argv);
275114402Sru	break;
276114402Sru
277114402Sru      case 'M':		/* set library directory */
278114402Sru	macro_path.command_line_dir(operand(&argc, &argv));
279114402Sru	break;
280114402Sru
281114402Sru      case 's':		/* preserve order of elements */
282114402Sru	sflag = 1;
283114402Sru	break;
284114402Sru
285114402Sru      case '-':
286114402Sru	if (strcmp(*argv,"--version")==0) {
287114402Sru      case 'v':
288114402Sru	  printf("GNU grn (groff) version %s\n", Version_string);
289114402Sru	  exit(0);
290114402Sru	  break;
291114402Sru	}
292114402Sru	if (strcmp(*argv,"--help")==0) {
293114402Sru      case '?':
294114402Sru	  usage(stdout);
295114402Sru	  exit(0);
296114402Sru	  break;
297114402Sru	}
298114402Sru	// fallthrough
299114402Sru      default:
300114402Sru	error("unknown switch: %1", c);
301114402Sru	usage(stderr);
302114402Sru	exit(1);
303114402Sru      }
304114402Sru  }
305114402Sru
306114402Sru  getres();			/* set the resolution for an output device */
307114402Sru
308114402Sru  if (gfil == 0) {		/* no filename, use standard input */
309114402Sru    file[0] = NULL;
310114402Sru    gfil++;
311114402Sru  }
312114402Sru
313114402Sru  for (k = 0; k < gfil; k++) {
314114402Sru    if (file[k] != NULL) {
315114402Sru      if ((fp = fopen(file[k], "r")) == NULL)
316114402Sru	fatal("can't open %1", file[k]);
317114402Sru    } else
318114402Sru      fp = stdin;
319114402Sru
320151497Sru    while (doinput(fp)) {
321114402Sru      if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') {
322114402Sru	if (compatibility_flag ||
323114402Sru	    *c4 == '\n' || *c4 == ' ' || *c4 == '\0')
324114402Sru	  conv(fp, linenum);
325114402Sru	else
326114402Sru	  fputs(inputline, stdout);
327114402Sru      } else
328114402Sru	fputs(inputline, stdout);
329114402Sru    }
330114402Sru  }
331151497Sru
332151497Sru  return 0;
333114402Sru}
334114402Sru
335114402Sru
336114402Sru/*----------------------------------------------------------------------------*
337114402Sru | Routine:	char  * operand (& argc, & argv)
338114402Sru |
339114402Sru | Results:	Returns address of the operand given with a command-line
340114402Sru |		option.  It uses either `-Xoperand' or `-X operand', whichever
341114402Sru |		is present.  The program is terminated if no option is
342114402Sru |		present.
343114402Sru |
344114402Sru | Side Efct:	argc and argv are updated as necessary.
345114402Sru *----------------------------------------------------------------------------*/
346114402Sru
347114402Sruchar *
348114402Sruoperand(int *argcp,
349114402Sru	char ***argvp)
350114402Sru{
351114402Sru  if ((**argvp)[2])
352114402Sru    return (**argvp + 2);	/* operand immediately follows */
353114402Sru  if ((--*argcp) <= 0) {	/* no operand */
354114402Sru    error("command-line option operand missing.");
355114402Sru    exit(8);
356114402Sru  }
357114402Sru  return (*(++(*argvp)));	/* operand is next word */
358114402Sru}
359114402Sru
360114402Sru
361114402Sru/*----------------------------------------------------------------------------*
362114402Sru | Routine:	getres ()
363114402Sru |
364114402Sru | Results:	Sets `res' to the resolution of the output device.
365114402Sru *----------------------------------------------------------------------------*/
366114402Sru
367114402Sruvoid
368114402Srugetres()
369114402Sru{
370114402Sru  int linepiece;
371114402Sru
372114402Sru  if (!font::load_desc())
373114402Sru    fatal("sorry, I can't continue");
374114402Sru
375114402Sru  res = font::res;
376114402Sru
377114402Sru  /* Correct the brush thicknesses based on res */
378114402Sru  /* if (res >= 256) {
379114402Sru      defthick[0] = res >> 8;
380114402Sru      defthick[1] = res >> 8;
381114402Sru      defthick[2] = res >> 4;
382114402Sru      defthick[3] = res >> 8;
383114402Sru      defthick[4] = res >> 8;
384114402Sru      defthick[5] = res >> 6;
385114402Sru      } */
386114402Sru
387114402Sru  linepiece = res >> 9;
388114402Sru  for (dotshifter = 0; linepiece; dotshifter++)
389114402Sru    linepiece = linepiece >> 1;
390114402Sru}
391114402Sru
392114402Sru
393114402Sru/*----------------------------------------------------------------------------*
394151497Sru | Routine:	int  doinput (file_pointer)
395114402Sru |
396114402Sru | Results:	A line of input is read into `inputline'.
397114402Sru |
398114402Sru | Side Efct:	"linenum" is incremented.
399114402Sru |
400114402Sru | Bugs:	Lines longer than MAXINLINE are NOT checked, except for
401114402Sru |		updating `linenum'.
402114402Sru *----------------------------------------------------------------------------*/
403114402Sru
404151497Sruint
405114402Srudoinput(FILE *fp)
406114402Sru{
407151497Sru  if (fgets(inputline, MAXINLINE, fp) == NULL)
408151497Sru    return 0;
409114402Sru  if (strchr(inputline, '\n'))	/* ++ only if it's a complete line */
410114402Sru    linenum++;
411151497Sru  return 1;
412114402Sru}
413114402Sru
414114402Sru
415114402Sru/*----------------------------------------------------------------------------*
416114402Sru | Routine:	initpic ( )
417114402Sru |
418114402Sru | Results:	Sets all parameters to the normal defaults, possibly
419114402Sru |		overridden by a setdefault command.  Initialize the picture
420114402Sru |		variables, and output the startup commands to troff to begin
421114402Sru |		the picture.
422114402Sru *----------------------------------------------------------------------------*/
423114402Sru
424114402Sruvoid
425114402Sruinitpic()
426114402Sru{
427114402Sru  register int i;
428114402Sru
429114402Sru  for (i = 0; i < STYLES; i++) {	/* line thickness defaults */
430114402Sru    thick[i] = defthick[i];
431114402Sru  }
432114402Sru  for (i = 0; i < FONTS; i++) {		/* font name defaults */
433151497Sru    tfont[i] = (char *)deffont[i];
434114402Sru  }
435114402Sru  for (i = 0; i < SIZES; i++) {		/* font size defaults */
436114402Sru    tsize[i] = defsize[i];
437114402Sru  }
438114402Sru  for (i = 0; i <= NSTIPPLES; i++) {	/* stipple font file default indices */
439114402Sru    stipple_index[i] = defstipple_index[i];
440114402Sru  }
441114402Sru  stipple = defstipple;
442114402Sru
443114402Sru  gremlinfile[0] = 0;		/* filename is `null' */
444114402Sru  setdefault = 0;		/* this is not the default settings (yet) */
445114402Sru
446114402Sru  toppoint = BIG;		/* set the picture bounds out */
447114402Sru  bottompoint = -BIG;		/* of range so they'll be set */
448114402Sru  leftpoint = BIG;		/* by `savebounds' on input */
449114402Sru  rightpoint = -BIG;
450114402Sru
451114402Sru  pointscale = defpoint;	/* flag for scaling point sizes default */
452114402Sru  xscale = scale;		/* default scale of individual pictures */
453114402Sru  width = 0.0;			/* size specifications input by user */
454114402Sru  height = 0.0;
455114402Sru
456114402Sru  linethickness = DEFTHICK;	/* brush styles */
457114402Sru  linmod = DEFSTYLE;
458114402Sru}
459114402Sru
460114402Sru
461114402Sru/*----------------------------------------------------------------------------*
462114402Sru | Routine:	conv (file_pointer, starting_line)
463114402Sru |
464114402Sru | Results:	At this point, we just passed a `.GS' line in the input
465114402Sru |		file.  conv reads the input and calls `interpret' to process
466114402Sru |		commands, gathering up information until a `.GE' line is
467114402Sru |		found.  It then calls `HGPrint' to do the translation of the
468114402Sru |		gremlin file to troff commands.
469114402Sru *----------------------------------------------------------------------------*/
470114402Sru
471114402Sruvoid
472114402Sruconv(register FILE *fp,
473114402Sru     int baseline)
474114402Sru{
475114402Sru  register FILE *gfp = NULL;	/* input file pointer */
476114402Sru  register int done = 0;	/* flag to remember if finished */
477114402Sru  register ELT *e;		/* current element pointer */
478114402Sru  ELT *PICTURE;			/* whole picture data base pointer */
479114402Sru  double temp;			/* temporary calculating area */
480114402Sru  /* POINT ptr; */		/* coordinates of a point to pass to `mov' */
481114402Sru				/* routine                                 */
482114402Sru  int flyback;			/* flag `want to end up at the top of the */
483114402Sru				/* picture?'                              */
484114402Sru  int compat;			/* test character after .GE or .GF */
485114402Sru
486114402Sru
487114402Sru  initpic();			/* set defaults, ranges, etc. */
488114402Sru  strcpy(GScommand, inputline);	/* save `.GS' line for later */
489114402Sru
490114402Sru  do {
491151497Sru    done = !doinput(fp);		/* test for EOF */
492114402Sru    flyback = (*c3 == 'F');		/* and .GE or .GF */
493114402Sru    compat = (compatibility_flag ||
494114402Sru	      *c4 == '\n' || *c4 == ' ' || *c4 == '\0');
495114402Sru    done |= (*c1 == '.' && *c2 == 'G' && (*c3 == 'E' || flyback) &&
496114402Sru	     compat);
497114402Sru
498114402Sru    if (done) {
499114402Sru      if (setdefault)
500114402Sru	savestate();
501114402Sru
502114402Sru      if (!gremlinfile[0]) {
503114402Sru	if (!setdefault)
504114402Sru	  error("at line %1: no picture filename.\n", baseline);
505114402Sru	return;
506114402Sru      }
507114402Sru      char *path;
508114402Sru      gfp = macro_path.open_file(gremlinfile, &path);
509114402Sru      if (!gfp)
510114402Sru	return;
511114402Sru      PICTURE = DBRead(gfp);	/* read picture file */
512114402Sru      fclose(gfp);
513114402Sru      a_delete path;
514114402Sru      if (DBNullelt(PICTURE))
515114402Sru	return;			/* If a request is made to make the  */
516114402Sru				/* picture fit into a specific area, */
517114402Sru				/* set the scale to do that.         */
518114402Sru
519114402Sru      if (stipple == (char *) NULL)	/* if user forgot stipple    */
520114402Sru	if (has_polygon(PICTURE))	/* and picture has a polygon */
521151497Sru	  stipple = (char *)DEFSTIPPLE;		/* then set the default      */
522114402Sru
523114402Sru      if ((temp = bottompoint - toppoint) < 0.1)
524114402Sru	temp = 0.1;
525114402Sru      temp = (height != 0.0) ? height / (temp * SCREENtoINCH) : BIG;
526114402Sru      if ((troffscale = rightpoint - leftpoint) < 0.1)
527114402Sru	troffscale = 0.1;
528114402Sru      troffscale = (width != 0.0) ?
529114402Sru	  width / (troffscale * SCREENtoINCH) : BIG;
530114402Sru      if (temp == BIG && troffscale == BIG)
531114402Sru	troffscale = xscale;
532114402Sru      else {
533114402Sru	if (temp < troffscale)
534114402Sru	  troffscale = temp;
535114402Sru      }				/* here, troffscale is the */
536114402Sru				/* picture's scaling factor */
537114402Sru      if (pointscale) {
538114402Sru	register int i;		/* do pointscaling here, when */
539114402Sru				/* scale is known, before output */
540114402Sru	for (i = 0; i < SIZES; i++)
541114402Sru	  tsize[i] = (int) (troffscale * (double) tsize[i] + 0.5);
542114402Sru      }
543114402Sru
544114402Sru						/* change to device units */
545114402Sru      troffscale *= SCREENtoINCH * res;		/* from screen units */
546114402Sru
547114402Sru      ytop = (int) (toppoint * troffscale);		/* calculate integer */
548114402Sru      ybottom = (int) (bottompoint * troffscale);	/* versions of the   */
549114402Sru      xleft = (int) (leftpoint * troffscale);		/* picture limits    */
550114402Sru      xright = (int) (rightpoint * troffscale);
551114402Sru
552114402Sru      /* save stuff in number registers,    */
553114402Sru      /*   register g1 = picture width and  */
554114402Sru      /*   register g2 = picture height,    */
555114402Sru      /*   set vertical spacing, no fill,   */
556114402Sru      /*   and break (to make sure picture  */
557114402Sru      /*   starts on left), and put out the */
558114402Sru      /*   user's `.GS' line.               */
559114402Sru      printf(".br\n"
560114402Sru	     ".nr g1 %du\n"
561114402Sru	     ".nr g2 %du\n"
562114402Sru	     "%s"
563114402Sru	     ".nr g3 \\n(.f\n"
564114402Sru	     ".nr g4 \\n(.s\n"
565114402Sru	     "\\0\n"
566114402Sru	     ".sp -1\n",
567114402Sru	     xright - xleft, ybottom - ytop, GScommand);
568114402Sru
569114402Sru      if (stipple)		/* stipple requested for this picture */
570114402Sru	printf(".st %s\n", stipple);
571114402Sru      lastx = xleft;		/* note where we are (upper left */
572114402Sru      lastyline = lasty = ytop;	/* corner of the picture)        */
573114402Sru
574114402Sru      /* Just dump everything in the order it appears.
575114402Sru       *
576114402Sru       * If -s command-line option, traverse picture twice: First time,
577114402Sru       * print only the interiors of filled polygons (as borderless
578114402Sru       * polygons).  Second time, print the outline as series of line
579114402Sru       * segments.  This way, postprocessors that overwrite rather than
580114402Sru       * merge picture elements (such as Postscript) can still have text and
581114402Sru       * graphics on a shaded background.
582114402Sru       */
583114402Sru      /* if (sflag) */
584114402Sru      if (!sflag) {		/* changing the default for filled polygons */
585114402Sru	e = PICTURE;
586114402Sru	polyfill = FILL;
587114402Sru	while (!DBNullelt(e)) {
588114402Sru	  printf(".mk\n");
589114402Sru	  if (e->type == POLYGON)
590114402Sru	    HGPrintElt(e, baseline);
591114402Sru	  printf(".rt\n");
592114402Sru	  lastx = xleft;
593114402Sru	  lastyline = lasty = ytop;
594114402Sru	  e = DBNextElt(e);
595114402Sru	}
596114402Sru      }
597114402Sru      e = PICTURE;
598114402Sru
599114402Sru      /* polyfill = !sflag ? BOTH : OUTLINE; */
600114402Sru      polyfill = sflag ? BOTH : OUTLINE;	/* changing the default */
601114402Sru      while (!DBNullelt(e)) {
602114402Sru	printf(".mk\n");
603114402Sru	HGPrintElt(e, baseline);
604114402Sru	printf(".rt\n");
605114402Sru	lastx = xleft;
606114402Sru	lastyline = lasty = ytop;
607114402Sru	e = DBNextElt(e);
608114402Sru      }
609114402Sru
610114402Sru      /* decide where to end picture */
611114402Sru
612114402Sru      /* I changed everything here.  I always use the combination .mk and */
613114402Sru      /* .rt so once finished I just space down the heigth of the picture */
614114402Sru      /* that is \n(g2u                                                   */
615114402Sru      if (flyback) {		/* end picture at upper left */
616114402Sru	/* ptr.x = leftpoint;
617114402Sru	   ptr.y = toppoint; */
618114402Sru      } else {			/* end picture at lower left */
619114402Sru	/* ptr.x = leftpoint;
620114402Sru	   ptr.y = bottompoint; */
621114402Sru	printf(".sp \\n(g2u\n");
622114402Sru      }
623114402Sru
624114402Sru      /* tmove(&ptr); */	/* restore default line parameters */
625114402Sru
626114402Sru      /* restore everything to the way it was before the .GS, then put */
627114402Sru      /* out the `.GE' line from user                                  */
628114402Sru
629114402Sru      /* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */
630114402Sru      /* groff doesn't understand the \Ds command */
631114402Sru
632114402Sru      printf("\\D't %du'\n", DEFTHICK);
633114402Sru      if (flyback)		/* make sure we end up at top of */
634114402Sru	printf(".sp -1\n");	/* picture if `flying back'      */
635114402Sru      if (stipple)		/* restore stipple to previous */
636114402Sru	printf(".st\n");
637114402Sru      printf(".br\n"
638114402Sru	     ".ft \\n(g3\n"
639114402Sru	     ".ps \\n(g4\n"
640114402Sru	     "%s", inputline);
641114402Sru    } else
642114402Sru      interpret(inputline);	/* take commands from the input file */
643114402Sru  } while (!done);
644114402Sru}
645114402Sru
646114402Sru
647114402Sru/*----------------------------------------------------------------------------*
648114402Sru | Routine:	savestate  ( )
649114402Sru |
650114402Sru | Results:	all the current  scaling / font size / font name / thickness
651114402Sru |		/ pointscale settings are saved to be the defaults.  Scaled
652114402Sru |		point sizes are NOT saved.  The scaling is done each time a
653114402Sru |		new picture is started.
654114402Sru |
655114402Sru | Side Efct:	scale, and def* are modified.
656114402Sru *----------------------------------------------------------------------------*/
657114402Sru
658114402Sruvoid
659114402Srusavestate()
660114402Sru{
661114402Sru  register int i;
662114402Sru
663114402Sru  for (i = 0; i < STYLES; i++)	/* line thickness defaults */
664114402Sru    defthick[i] = thick[i];
665114402Sru  for (i = 0; i < FONTS; i++)	/* font name defaults */
666114402Sru    deffont[i] = tfont[i];
667114402Sru  for (i = 0; i < SIZES; i++)	/* font size defaults */
668114402Sru    defsize[i] = tsize[i];
669114402Sru  for (i = 0; i <= NSTIPPLES; i++)	/* stipple font file default indices */
670114402Sru    defstipple_index[i] = stipple_index[i];
671114402Sru
672114402Sru  defstipple = stipple;		/* if stipple has been set, it's remembered */
673114402Sru  scale *= xscale;		/* default scale of individual pictures */
674114402Sru  defpoint = pointscale;	/* flag for scaling pointsizes from x factors */
675114402Sru}
676114402Sru
677114402Sru
678114402Sru/*----------------------------------------------------------------------------*
679114402Sru | Routine:	savebounds (x_coordinate, y_coordinate)
680114402Sru |
681114402Sru | Results:	Keeps track of the maximum and minimum extent of a picture
682114402Sru |		in the global variables: left-, right-, top- and
683114402Sru |		bottompoint.  `savebounds' assumes that the points have been
684114402Sru |		oriented to the correct direction.  No scaling has taken
685114402Sru |		place, though.
686114402Sru *----------------------------------------------------------------------------*/
687114402Sru
688114402Sruvoid
689151497Srusavebounds(double x,
690151497Sru	   double y)
691114402Sru{
692114402Sru  if (x < leftpoint)
693114402Sru    leftpoint = x;
694114402Sru  if (x > rightpoint)
695114402Sru    rightpoint = x;
696114402Sru  if (y < toppoint)
697114402Sru    toppoint = y;
698114402Sru  if (y > bottompoint)
699114402Sru    bottompoint = y;
700114402Sru}
701114402Sru
702114402Sru
703114402Sru/*----------------------------------------------------------------------------*
704114402Sru | Routine:	interpret (character_string)
705114402Sru |
706114402Sru | Results:	Commands are taken from the input string and performed.
707114402Sru |		Commands are separated by the endofline, and are of the
708114402Sru |		format:
709114402Sru |			string1 string2
710114402Sru |
711114402Sru |		where string1 is the command and string2 is the argument.
712114402Sru |
713114402Sru | Side Efct:	Font and size strings, plus the gremlin file name and the
714114402Sru |		width and height variables are set by this routine.
715114402Sru *----------------------------------------------------------------------------*/
716114402Sru
717114402Sruvoid
718114402Sruinterpret(char *line)
719114402Sru{
720114402Sru  char str1[MAXINLINE];
721114402Sru  char str2[MAXINLINE];
722114402Sru  register char *chr;
723114402Sru  register int i;
724114402Sru  double par;
725114402Sru
726114402Sru  str2[0] = '\0';
727114402Sru  sscanf(line, "%80s%80s", &str1[0], &str2[0]);
728114402Sru  for (chr = &str1[0]; *chr; chr++)	/* convert command to */
729114402Sru    if (isupper(*chr))
730114402Sru      *chr = tolower(*chr);	/* lower case */
731114402Sru
732114402Sru  switch (str1[0]) {
733114402Sru
734114402Sru  case '1':
735114402Sru  case '2':			/* font sizes */
736114402Sru  case '3':
737114402Sru  case '4':
738114402Sru    i = atoi(str2);
739114402Sru    if (i > 0 && i < 1000)
740114402Sru      tsize[str1[0] - '1'] = i;
741114402Sru    else
742114402Sru      error("bad font size value at line %1", linenum);
743114402Sru    break;
744114402Sru
745114402Sru  case 'r':			/* roman */
746114402Sru    if (str2[0] < '0')
747114402Sru      goto nofont;
748114402Sru    tfont[0] = (char *) malloc(strlen(str2) + 1);
749114402Sru    strcpy(tfont[0], str2);
750114402Sru    break;
751114402Sru
752114402Sru  case 'i':			/* italics */
753114402Sru    if (str2[0] < '0')
754114402Sru      goto nofont;
755114402Sru    tfont[1] = (char *) malloc(strlen(str2) + 1);
756114402Sru    strcpy(tfont[1], str2);
757114402Sru    break;
758114402Sru
759114402Sru  case 'b':			/* bold */
760114402Sru    if (str2[0] < '0')
761114402Sru      goto nofont;
762114402Sru    tfont[2] = (char *) malloc(strlen(str2) + 1);
763114402Sru    strcpy(tfont[2], str2);
764114402Sru    break;
765114402Sru
766114402Sru  case 's':			/* special */
767114402Sru    if (str1[1] == 'c')
768114402Sru      goto scalecommand;	/* or scale */
769114402Sru
770114402Sru    if (str2[0] < '0') {
771114402Sru  nofont:
772114402Sru      error("no fontname specified in line %1", linenum);
773114402Sru      break;
774114402Sru    }
775114402Sru    if (str1[1] == 't')
776114402Sru      goto stipplecommand;	/* or stipple */
777114402Sru
778114402Sru    tfont[3] = (char *) malloc(strlen(str2) + 1);
779114402Sru    strcpy(tfont[3], str2);
780114402Sru    break;
781114402Sru
782114402Sru  case 'l':			/* l */
783114402Sru    if (isdigit(str1[1])) {	/* set stipple index */
784151497Sru      int idx = atoi(str1 + 1), val;
785114402Sru
786151497Sru      if (idx < 0 || idx > NSTIPPLES) {
787151497Sru	error("bad stipple number %1 at line %2", idx, linenum);
788114402Sru	break;
789114402Sru      }
790114402Sru      if (!defstipple_index)
791114402Sru	defstipple_index = other_stipple_index;
792114402Sru      val = atoi(str2);
793114402Sru      if (val >= 0 && val < 256)
794151497Sru	stipple_index[idx] = val;
795114402Sru      else
796114402Sru	error("bad stipple index value at line %1", linenum);
797114402Sru      break;
798114402Sru    }
799114402Sru
800114402Sru  stipplecommand:		/* set stipple name */
801114402Sru    stipple = (char *) malloc(strlen(str2) + 1);
802114402Sru    strcpy(stipple, str2);
803114402Sru    /* if its a `known' font (currently only `cf'), set indicies    */
804114402Sru    if (strcmp(stipple, "cf") == 0)
805114402Sru      defstipple_index = cf_stipple_index;
806114402Sru    else
807114402Sru      defstipple_index = other_stipple_index;
808114402Sru    for (i = 0; i <= NSTIPPLES; i++)
809114402Sru      stipple_index[i] = defstipple_index[i];
810114402Sru    break;
811114402Sru
812114402Sru  case 'a':			/* text adjust */
813114402Sru    par = atof(str2);
814114402Sru    switch (str1[1]) {
815114402Sru    case '1':
816114402Sru      adj1 = par;
817114402Sru      break;
818114402Sru    case '2':
819114402Sru      adj2 = par;
820114402Sru      break;
821114402Sru    case '3':
822114402Sru      adj3 = par;
823114402Sru      break;
824114402Sru    case '4':
825114402Sru      adj4 = par;
826114402Sru      break;
827114402Sru    default:
828114402Sru      error("bad adjust command at line %1", linenum);
829114402Sru      break;
830114402Sru    }
831114402Sru    break;
832114402Sru
833114402Sru  case 't':			/* thick */
834114402Sru    thick[2] = defthick[0] * atof(str2);
835114402Sru    break;
836114402Sru
837114402Sru  case 'm':			/* medium */
838114402Sru    thick[5] = defthick[0] * atof(str2);
839114402Sru    break;
840114402Sru
841114402Sru  case 'n':			/* narrow */
842114402Sru    thick[0] = thick[1] = thick[3] = thick[4] =
843114402Sru	defthick[0] * atof(str2);
844114402Sru    break;
845114402Sru
846114402Sru  case 'x':			/* x */
847114402Sru  scalecommand:			/* scale */
848114402Sru    par = atof(str2);
849114402Sru    if (par > 0.0)
850114402Sru      xscale *= par;
851114402Sru    else
852114402Sru      error("invalid scale value on line %1", linenum);
853114402Sru    break;
854114402Sru
855114402Sru  case 'f':			/* file */
856114402Sru    strcpy(gremlinfile, str2);
857114402Sru    break;
858114402Sru
859114402Sru  case 'w':			/* width */
860114402Sru    width = atof(str2);
861114402Sru    if (width < 0.0)
862114402Sru      width = -width;
863114402Sru    break;
864114402Sru
865114402Sru  case 'h':			/* height */
866114402Sru    height = atof(str2);
867114402Sru    if (height < 0.0)
868114402Sru      height = -height;
869114402Sru    break;
870114402Sru
871114402Sru  case 'd':			/* defaults */
872114402Sru    setdefault = 1;
873114402Sru    break;
874114402Sru
875114402Sru  case 'p':			/* pointscale */
876114402Sru    if (strcmp("off", str2))
877114402Sru      pointscale = 1;
878114402Sru    else
879114402Sru      pointscale = 0;
880114402Sru    break;
881114402Sru
882114402Sru  default:
883114402Sru    error("unknown command `%1' on line %2", str1, linenum);
884114402Sru    exit(8);
885114402Sru    break;
886114402Sru  };
887114402Sru}
888114402Sru
889114402Sru
890114402Sru/*
891114402Sru * return TRUE if picture contains a polygon
892114402Sru * otherwise FALSE
893114402Sru */
894114402Sru
895114402Sruint
896114402Sruhas_polygon(register ELT *elist)
897114402Sru{
898114402Sru  while (!DBNullelt(elist)) {
899114402Sru    if (elist->type == POLYGON)
900114402Sru      return (1);
901114402Sru    elist = DBNextElt(elist);
902114402Sru  }
903114402Sru
904114402Sru  return (0);
905114402Sru}
906114402Sru
907114402Sru/* EOF */
908