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