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