1 /* Last non-groff version: main.cc 1.23 (Berkeley) 85/08/05
3 * Adapted to GNU troff by Daniel Senderowicz 99/12/29.
5 * Further refinements by Werner Lemberg 00/02/20.
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
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.
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
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
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.
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.
77 #include "searchpath.h"
78 #include "macropath.h"
85 /* database imports */
87 extern void HGPrintElt(ELT
*element
, int baseline
);
89 extern ELT
*DBRead(register FILE *file
);
90 extern POINT
*PTInit();
91 extern POINT
*PTMakePoint(float x
, float y
, POINT
**pplist
);
94 #define SUN_SCALEFACTOR 0.70
96 /* #define DEFSTIPPLE "gs" */
97 #define DEFSTIPPLE "cf"
99 #define MAXINLINE 100 /* input line length */
101 #define SCREENtoINCH 0.02 /* scaling factor, screen to inches */
103 #define BIG 999999999999.0 /* unweildly large floating number */
106 static char sccsid
[] = "@(#) (Berkeley) 8/5/85, 12/28/99";
108 int res
; /* the printer's resolution goes here */
110 int dotshifter
; /* for the length of dotted curves */
112 double linethickness
; /* brush styles */
114 int lastx
; /* point registers for printing elements */
116 int lastyline
; /* A line's vertical position is NOT the */
117 /* same after that line is over, so for a */
118 /* line of drawing commands, vertical */
119 /* spacing is kept in lastyline */
121 /* These are the default fonts, sizes, line styles, */
122 /* and thicknesses. They can be modified from a */
123 /* `default' command and are reset each time the */
124 /* start of a picture (.GS) is found. */
127 {"R", "I", "B", "S"};
130 /* #define BASE_THICKNESS 1.0 */
131 #define BASE_THICKNESS 0.15
132 double defthick
[STYLES
] =
140 /* int cf_stipple_index[NSTIPPLES + 1] = */
141 /* {0, 1, 3, 12, 14, 16, 19, 21, 23}; */
142 /* a logarithmic scale looks better than a linear one for the gray shades */
144 /* int other_stipple_index[NSTIPPLES + 1] = */
145 /* {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; */
147 int cf_stipple_index
[NSTIPPLES
+ 1] =
148 {0, 18, 32, 56, 100, 178, 316, 562, 1000}; /* only 1-8 used */
149 int other_stipple_index
[NSTIPPLES
+ 1] =
150 {0, 62, 125, 187, 250, 312, 375, 437, 500,
151 562, 625, 687, 750, 812, 875, 937, 1000};
153 /* int *defstipple_index = other_stipple_index; */
154 int *defstipple_index
= cf_stipple_index
;
157 {DOTTED
, DOTDASHED
, SOLID
, DASHED
, SOLID
, SOLID
};
158 double scale
= 1.0; /* no scaling, default */
159 int defpoint
= 0; /* flag for pointsize scaling */
160 char *defstipple
= (char *) 0;
165 /* flag to controll filling of polygons */
172 double thick
[STYLES
]; /* thicknesses set by defaults, then by */
174 char *tfont
[FONTS
]; /* fonts originally set to deffont values, */
176 int tsize
[SIZES
]; /* optionally changed by commands inside */
178 int stipple_index
[NSTIPPLES
+ 1]; /* stipple font file indices */
181 double xscale
; /* scaling factor from individual pictures */
182 double troffscale
; /* scaling factor at output time */
184 double width
; /* user-request maximum width for picture */
186 double height
; /* user-request height */
187 int pointscale
; /* flag for pointsize scaling */
188 int setdefault
; /* flag for a .GS/.GE to remember all */
190 int sflag
; /* -s flag: sort order (do polyfill first) */
192 double toppoint
; /* remember the picture */
193 double bottompoint
; /* bounds in these variables */
197 int ytop
; /* these are integer versions of the above */
198 int ybottom
; /* so not to convert each time they're used */
202 int linenum
= 0; /* line number of input file */
203 char inputline
[MAXINLINE
]; /* spot to filter through the file */
204 char *c1
= inputline
; /* c1, c2, and c3 will be used to */
205 char *c2
= inputline
+ 1; /* hunt for lines that begin with */
206 char *c3
= inputline
+ 2; /* ".GS" by looking individually */
207 char *c4
= inputline
+ 3; /* needed for compatibility mode */
208 char GScommand
[MAXINLINE
]; /* put user's ".GS" command line here */
209 char gremlinfile
[MAXINLINE
]; /* filename to use for a picture */
210 int SUNFILE
= FALSE
; /* TRUE if SUN gremlin file */
211 int compatibility_flag
= FALSE
; /* TRUE if in compatibility mode */
215 char *doinput(FILE *fp
);
216 void conv(register FILE *fp
, int baseline
);
218 int has_polygon(register ELT
*elist
);
219 void interpret(char *line
);
226 "usage: %s [ -vCs ] [ -M dir ] [ -F dir ] [ -T dev ] [ file ]\n",
231 /*----------------------------------------------------------------------------*
232 | Routine: main (argument_count, argument_pointer)
234 | Results: Parses the command line, accumulating input file names, then
235 | reads the inputs, passing it directly to output until a `.GS'
236 | line is read. Main then passes control to `conv' to do the
237 | gremlin file conversions.
238 *----------------------------------------------------------------------------*/
244 program_name
= argv
[0];
248 register int gfil
= 0;
250 char *operand(int *argcp
, char ***argvp
);
254 file
[gfil
++] = *argv
;
256 switch (c
= (*argv
)[1]) {
262 case 'C': /* compatibility mode */
263 compatibility_flag
= TRUE
;
266 case 'F': /* font path to find DESC */
267 font::command_line_font_dir(operand(&argc
, &argv
));
270 case 'T': /* final output typesetter name */
271 device
= operand(&argc
, &argv
);
274 case 'M': /* set library directory */
275 macro_path
.command_line_dir(operand(&argc
, &argv
));
278 case 's': /* preserve order of elements */
283 if (strcmp(*argv
,"--version")==0) {
285 extern const char *Version_string
;
286 printf("GNU grn (groff) version %s\n", Version_string
);
290 if (strcmp(*argv
,"--help")==0) {
298 error("unknown switch: %1", c
);
304 getres(); /* set the resolution for an output device */
306 if (gfil
== 0) { /* no filename, use standard input */
311 for (k
= 0; k
< gfil
; k
++) {
312 if (file
[k
] != NULL
) {
313 if ((fp
= fopen(file
[k
], "r")) == NULL
)
314 fatal("can't open %1", file
[k
]);
318 while (doinput(fp
) != NULL
) {
319 if (*c1
== '.' && *c2
== 'G' && *c3
== 'S') {
320 if (compatibility_flag
||
321 *c4
== '\n' || *c4
== ' ' || *c4
== '\0')
324 fputs(inputline
, stdout
);
326 fputs(inputline
, stdout
);
332 /*----------------------------------------------------------------------------*
333 | Routine: char * operand (& argc, & argv)
335 | Results: Returns address of the operand given with a command-line
336 | option. It uses either `-Xoperand' or `-X operand', whichever
337 | is present. The program is terminated if no option is
340 | Side Efct: argc and argv are updated as necessary.
341 *----------------------------------------------------------------------------*/
348 return (**argvp
+ 2); /* operand immediately follows */
349 if ((--*argcp
) <= 0) { /* no operand */
350 error("command-line option operand missing.");
353 return (*(++(*argvp
))); /* operand is next word */
357 /*----------------------------------------------------------------------------*
360 | Results: Sets `res' to the resolution of the output device.
361 *----------------------------------------------------------------------------*/
368 if (!font::load_desc())
369 fatal("sorry, I can't continue");
373 /* Correct the brush thicknesses based on res */
375 defthick[0] = res >> 8;
376 defthick[1] = res >> 8;
377 defthick[2] = res >> 4;
378 defthick[3] = res >> 8;
379 defthick[4] = res >> 8;
380 defthick[5] = res >> 6;
383 linepiece
= res
>> 9;
384 for (dotshifter
= 0; linepiece
; dotshifter
++)
385 linepiece
= linepiece
>> 1;
389 /*----------------------------------------------------------------------------*
390 | Routine: char * doinput (file_pointer)
392 | Results: A line of input is read into `inputline'.
394 | Side Efct: "linenum" is incremented.
396 | Bugs: Lines longer than MAXINLINE are NOT checked, except for
397 | updating `linenum'.
398 *----------------------------------------------------------------------------*/
405 if ((k
= fgets(inputline
, MAXINLINE
, fp
)) == NULL
)
407 if (strchr(inputline
, '\n')) /* ++ only if it's a complete line */
409 return (char *) !NULL
;
413 /*----------------------------------------------------------------------------*
414 | Routine: initpic ( )
416 | Results: Sets all parameters to the normal defaults, possibly
417 | overridden by a setdefault command. Initialize the picture
418 | variables, and output the startup commands to troff to begin
420 *----------------------------------------------------------------------------*/
427 for (i
= 0; i
< STYLES
; i
++) { /* line thickness defaults */
428 thick
[i
] = defthick
[i
];
430 for (i
= 0; i
< FONTS
; i
++) { /* font name defaults */
431 tfont
[i
] = deffont
[i
];
433 for (i
= 0; i
< SIZES
; i
++) { /* font size defaults */
434 tsize
[i
] = defsize
[i
];
436 for (i
= 0; i
<= NSTIPPLES
; i
++) { /* stipple font file default indices */
437 stipple_index
[i
] = defstipple_index
[i
];
439 stipple
= defstipple
;
441 gremlinfile
[0] = 0; /* filename is `null' */
442 setdefault
= 0; /* this is not the default settings (yet) */
444 toppoint
= BIG
; /* set the picture bounds out */
445 bottompoint
= -BIG
; /* of range so they'll be set */
446 leftpoint
= BIG
; /* by `savebounds' on input */
449 pointscale
= defpoint
; /* flag for scaling point sizes default */
450 xscale
= scale
; /* default scale of individual pictures */
451 width
= 0.0; /* size specifications input by user */
454 linethickness
= DEFTHICK
; /* brush styles */
459 /*----------------------------------------------------------------------------*
460 | Routine: conv (file_pointer, starting_line)
462 | Results: At this point, we just passed a `.GS' line in the input
463 | file. conv reads the input and calls `interpret' to process
464 | commands, gathering up information until a `.GE' line is
465 | found. It then calls `HGPrint' to do the translation of the
466 | gremlin file to troff commands.
467 *----------------------------------------------------------------------------*/
470 conv(register FILE *fp
,
473 register FILE *gfp
= NULL
; /* input file pointer */
474 register int done
= 0; /* flag to remember if finished */
475 register ELT
*e
; /* current element pointer */
476 ELT
*PICTURE
; /* whole picture data base pointer */
477 double temp
; /* temporary calculating area */
478 /* POINT ptr; */ /* coordinates of a point to pass to `mov' */
480 int flyback
; /* flag `want to end up at the top of the */
482 int compat
; /* test character after .GE or .GF */
485 initpic(); /* set defaults, ranges, etc. */
486 strcpy(GScommand
, inputline
); /* save `.GS' line for later */
489 done
= (doinput(fp
) == NULL
); /* test for EOF */
490 flyback
= (*c3
== 'F'); /* and .GE or .GF */
491 compat
= (compatibility_flag
||
492 *c4
== '\n' || *c4
== ' ' || *c4
== '\0');
493 done
|= (*c1
== '.' && *c2
== 'G' && (*c3
== 'E' || flyback
) &&
500 if (!gremlinfile
[0]) {
502 error("at line %1: no picture filename.\n", baseline
);
506 gfp
= macro_path
.open_file(gremlinfile
, &path
);
509 PICTURE
= DBRead(gfp
); /* read picture file */
512 if (DBNullelt(PICTURE
))
513 return; /* If a request is made to make the */
514 /* picture fit into a specific area, */
515 /* set the scale to do that. */
517 if (stipple
== (char *) NULL
) /* if user forgot stipple */
518 if (has_polygon(PICTURE
)) /* and picture has a polygon */
519 stipple
= DEFSTIPPLE
; /* then set the default */
521 if ((temp
= bottompoint
- toppoint
) < 0.1)
523 temp
= (height
!= 0.0) ? height
/ (temp
* SCREENtoINCH
) : BIG
;
524 if ((troffscale
= rightpoint
- leftpoint
) < 0.1)
526 troffscale
= (width
!= 0.0) ?
527 width
/ (troffscale
* SCREENtoINCH
) : BIG
;
528 if (temp
== BIG
&& troffscale
== BIG
)
531 if (temp
< troffscale
)
533 } /* here, troffscale is the */
534 /* picture's scaling factor */
536 register int i
; /* do pointscaling here, when */
537 /* scale is known, before output */
538 for (i
= 0; i
< SIZES
; i
++)
539 tsize
[i
] = (int) (troffscale
* (double) tsize
[i
] + 0.5);
542 /* change to device units */
543 troffscale
*= SCREENtoINCH
* res
; /* from screen units */
545 ytop
= (int) (toppoint
* troffscale
); /* calculate integer */
546 ybottom
= (int) (bottompoint
* troffscale
); /* versions of the */
547 xleft
= (int) (leftpoint
* troffscale
); /* picture limits */
548 xright
= (int) (rightpoint
* troffscale
);
550 /* save stuff in number registers, */
551 /* register g1 = picture width and */
552 /* register g2 = picture height, */
553 /* set vertical spacing, no fill, */
554 /* and break (to make sure picture */
555 /* starts on left), and put out the */
556 /* user's `.GS' line. */
565 xright
- xleft
, ybottom
- ytop
, GScommand
);
567 if (stipple
) /* stipple requested for this picture */
568 printf(".st %s\n", stipple
);
569 lastx
= xleft
; /* note where we are (upper left */
570 lastyline
= lasty
= ytop
; /* corner of the picture) */
572 /* Just dump everything in the order it appears.
574 * If -s command-line option, traverse picture twice: First time,
575 * print only the interiors of filled polygons (as borderless
576 * polygons). Second time, print the outline as series of line
577 * segments. This way, postprocessors that overwrite rather than
578 * merge picture elements (such as Postscript) can still have text and
579 * graphics on a shaded background.
582 if (!sflag
) { /* changing the default for filled polygons */
585 while (!DBNullelt(e
)) {
587 if (e
->type
== POLYGON
)
588 HGPrintElt(e
, baseline
);
591 lastyline
= lasty
= ytop
;
597 /* polyfill = !sflag ? BOTH : OUTLINE; */
598 polyfill
= sflag
? BOTH
: OUTLINE
; /* changing the default */
599 while (!DBNullelt(e
)) {
601 HGPrintElt(e
, baseline
);
604 lastyline
= lasty
= ytop
;
608 /* decide where to end picture */
610 /* I changed everything here. I always use the combination .mk and */
611 /* .rt so once finished I just space down the heigth of the picture */
613 if (flyback
) { /* end picture at upper left */
614 /* ptr.x = leftpoint;
616 } else { /* end picture at lower left */
617 /* ptr.x = leftpoint;
618 ptr.y = bottompoint; */
619 printf(".sp \\n(g2u\n");
622 /* tmove(&ptr); */ /* restore default line parameters */
624 /* restore everything to the way it was before the .GS, then put */
625 /* out the `.GE' line from user */
627 /* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */
628 /* groff doesn't understand the \Ds command */
630 printf("\\D't %du'\n", DEFTHICK
);
631 if (flyback
) /* make sure we end up at top of */
632 printf(".sp -1\n"); /* picture if `flying back' */
633 if (stipple
) /* restore stipple to previous */
640 interpret(inputline
); /* take commands from the input file */
645 /*----------------------------------------------------------------------------*
646 | Routine: savestate ( )
648 | Results: all the current scaling / font size / font name / thickness
649 | / pointscale settings are saved to be the defaults. Scaled
650 | point sizes are NOT saved. The scaling is done each time a
651 | new picture is started.
653 | Side Efct: scale, and def* are modified.
654 *----------------------------------------------------------------------------*/
661 for (i
= 0; i
< STYLES
; i
++) /* line thickness defaults */
662 defthick
[i
] = thick
[i
];
663 for (i
= 0; i
< FONTS
; i
++) /* font name defaults */
664 deffont
[i
] = tfont
[i
];
665 for (i
= 0; i
< SIZES
; i
++) /* font size defaults */
666 defsize
[i
] = tsize
[i
];
667 for (i
= 0; i
<= NSTIPPLES
; i
++) /* stipple font file default indices */
668 defstipple_index
[i
] = stipple_index
[i
];
670 defstipple
= stipple
; /* if stipple has been set, it's remembered */
671 scale
*= xscale
; /* default scale of individual pictures */
672 defpoint
= pointscale
; /* flag for scaling pointsizes from x factors */
676 /*----------------------------------------------------------------------------*
677 | Routine: savebounds (x_coordinate, y_coordinate)
679 | Results: Keeps track of the maximum and minimum extent of a picture
680 | in the global variables: left-, right-, top- and
681 | bottompoint. `savebounds' assumes that the points have been
682 | oriented to the correct direction. No scaling has taken
684 *----------------------------------------------------------------------------*/
701 /*----------------------------------------------------------------------------*
702 | Routine: interpret (character_string)
704 | Results: Commands are taken from the input string and performed.
705 | Commands are separated by the endofline, and are of the
709 | where string1 is the command and string2 is the argument.
711 | Side Efct: Font and size strings, plus the gremlin file name and the
712 | width and height variables are set by this routine.
713 *----------------------------------------------------------------------------*/
716 interpret(char *line
)
718 char str1
[MAXINLINE
];
719 char str2
[MAXINLINE
];
725 sscanf(line
, "%80s%80s", &str1
[0], &str2
[0]);
726 for (chr
= &str1
[0]; *chr
; chr
++) /* convert command to */
728 *chr
= tolower(*chr
); /* lower case */
733 case '2': /* font sizes */
737 if (i
> 0 && i
< 1000)
738 tsize
[str1
[0] - '1'] = i
;
740 error("bad font size value at line %1", linenum
);
743 case 'r': /* roman */
746 tfont
[0] = (char *) malloc(strlen(str2
) + 1);
747 strcpy(tfont
[0], str2
);
750 case 'i': /* italics */
753 tfont
[1] = (char *) malloc(strlen(str2
) + 1);
754 strcpy(tfont
[1], str2
);
760 tfont
[2] = (char *) malloc(strlen(str2
) + 1);
761 strcpy(tfont
[2], str2
);
764 case 's': /* special */
766 goto scalecommand
; /* or scale */
770 error("no fontname specified in line %1", linenum
);
774 goto stipplecommand
; /* or stipple */
776 tfont
[3] = (char *) malloc(strlen(str2
) + 1);
777 strcpy(tfont
[3], str2
);
781 if (isdigit(str1
[1])) { /* set stipple index */
782 int index
= atoi(str1
+ 1), val
;
784 if (index
< 0 || index
> NSTIPPLES
) {
785 error("bad stipple number %1 at line %2", index
, linenum
);
788 if (!defstipple_index
)
789 defstipple_index
= other_stipple_index
;
791 if (val
>= 0 && val
< 256)
792 stipple_index
[index
] = val
;
794 error("bad stipple index value at line %1", linenum
);
798 stipplecommand
: /* set stipple name */
799 stipple
= (char *) malloc(strlen(str2
) + 1);
800 strcpy(stipple
, str2
);
801 /* if its a `known' font (currently only `cf'), set indicies */
802 if (strcmp(stipple
, "cf") == 0)
803 defstipple_index
= cf_stipple_index
;
805 defstipple_index
= other_stipple_index
;
806 for (i
= 0; i
<= NSTIPPLES
; i
++)
807 stipple_index
[i
] = defstipple_index
[i
];
810 case 'a': /* text adjust */
826 error("bad adjust command at line %1", linenum
);
831 case 't': /* thick */
832 thick
[2] = defthick
[0] * atof(str2
);
835 case 'm': /* medium */
836 thick
[5] = defthick
[0] * atof(str2
);
839 case 'n': /* narrow */
840 thick
[0] = thick
[1] = thick
[3] = thick
[4] =
841 defthick
[0] * atof(str2
);
845 scalecommand
: /* scale */
850 error("illegal scale value on line %1", linenum
);
854 strcpy(gremlinfile
, str2
);
857 case 'w': /* width */
863 case 'h': /* height */
869 case 'd': /* defaults */
873 case 'p': /* pointscale */
874 if (strcmp("off", str2
))
881 error("unknown command `%1' on line %2", str1
, linenum
);
889 * return TRUE if picture contains a polygon
894 has_polygon(register ELT
*elist
)
896 while (!DBNullelt(elist
)) {
897 if (elist
->type
== POLYGON
)
899 elist
= DBNextElt(elist
);