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