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