| Commit | Line | Data |
|---|---|---|
| 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 | ||
| 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(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 | ||
| 122 | static char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99"; | |
| 123 | ||
| 124 | int res; /* the printer's resolution goes here */ | |
| 125 | ||
| 126 | int dotshifter; /* for the length of dotted curves */ | |
| 127 | ||
| 128 | double linethickness; /* brush styles */ | |
| 129 | int linmod; | |
| 130 | int lastx; /* point registers for printing elements */ | |
| 131 | int lasty; | |
| 132 | int 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 | ||
| 142 | const char *deffont[] = | |
| 143 | {"R", "I", "B", "S"}; | |
| 144 | int defsize[] = | |
| 145 | {10, 16, 24, 36}; | |
| 146 | /* #define BASE_THICKNESS 1.0 */ | |
| 147 | #define BASE_THICKNESS 0.15 | |
| 148 | double 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 | ||
| 163 | int cf_stipple_index[NSTIPPLES + 1] = | |
| 164 | {0, 18, 32, 56, 100, 178, 316, 562, 1000}; /* only 1-8 used */ | |
| 165 | int 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; */ | |
| 170 | int *defstipple_index = cf_stipple_index; | |
| 171 | ||
| 172 | int style[STYLES] = | |
| 173 | {DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID}; | |
| 174 | double scale = 1.0; /* no scaling, default */ | |
| 175 | int defpoint = 0; /* flag for pointsize scaling */ | |
| 176 | char *defstipple = (char *) 0; | |
| 177 | enum E { | |
| 178 | OUTLINE, FILL, BOTH | |
| 179 | } polyfill; | |
| 180 | ||
| 181 | /* flag to controll filling of polygons */ | |
| 182 | ||
| 183 | double adj1 = 0.0; | |
| 184 | double adj2 = 0.0; | |
| 185 | double adj3 = 0.0; | |
| 186 | double adj4 = 0.0; | |
| 187 | ||
| 188 | double thick[STYLES]; /* thicknesses set by defaults, then by */ | |
| 189 | /* commands */ | |
| 190 | char *tfont[FONTS]; /* fonts originally set to deffont values, */ | |
| 191 | /* then */ | |
| 192 | int tsize[SIZES]; /* optionally changed by commands inside */ | |
| 193 | /* grn */ | |
| 194 | int stipple_index[NSTIPPLES + 1]; /* stipple font file indices */ | |
| 195 | char *stipple; | |
| 196 | ||
| 197 | double xscale; /* scaling factor from individual pictures */ | |
| 198 | double troffscale; /* scaling factor at output time */ | |
| 199 | ||
| 200 | double width; /* user-request maximum width for picture */ | |
| 201 | /* (in inches) */ | |
| 202 | double height; /* user-request height */ | |
| 203 | int pointscale; /* flag for pointsize scaling */ | |
| 204 | int setdefault; /* flag for a .GS/.GE to remember all */ | |
| 205 | /* settings */ | |
| 206 | int sflag; /* -s flag: sort order (do polyfill first) */ | |
| 207 | ||
| 208 | double toppoint; /* remember the picture */ | |
| 209 | double bottompoint; /* bounds in these variables */ | |
| 210 | double leftpoint; | |
| 211 | double rightpoint; | |
| 212 | ||
| 213 | int ytop; /* these are integer versions of the above */ | |
| 214 | int ybottom; /* so not to convert each time they're used */ | |
| 215 | int xleft; | |
| 216 | int xright; | |
| 217 | ||
| 218 | int linenum = 0; /* line number of input file */ | |
| 219 | char inputline[MAXINLINE]; /* spot to filter through the file */ | |
| 220 | char *c1 = inputline; /* c1, c2, and c3 will be used to */ | |
| 221 | char *c2 = inputline + 1; /* hunt for lines that begin with */ | |
| 4d3e9548 | 222 | char *c3 = inputline + 2; /* `.GS' by looking individually */ |
| 92d0a6a6 | 223 | char *c4 = inputline + 3; /* needed for compatibility mode */ |
| 4d3e9548 | 224 | char GScommand[MAXINLINE]; /* put user's `.GS' command line here */ |
| 92d0a6a6 JR |
225 | char gremlinfile[MAXINLINE]; /* filename to use for a picture */ |
| 226 | int SUNFILE = FALSE; /* TRUE if SUN gremlin file */ | |
| 227 | int compatibility_flag = FALSE; /* TRUE if in compatibility mode */ | |
| 228 | ||
| 229 | ||
| 230 | void getres(); | |
| 465b256c | 231 | int doinput(FILE *fp); |
| 92d0a6a6 JR |
232 | void conv(register FILE *fp, int baseline); |
| 233 | void savestate(); | |
| 234 | int has_polygon(register ELT *elist); | |
| 235 | void interpret(char *line); | |
| 236 | ||
| 237 | ||
| 238 | void | |
| 239 | usage(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 | ||
| 256 | int | |
| 257 | main(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 | ||
| 361 | char * | |
| 362 | operand(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 | ||
| 381 | void | |
| 382 | getres() | |
| 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 | 418 | int |
| 92d0a6a6 JR |
419 | doinput(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 | ||
| 438 | void | |
| 439 | initpic() | |
| 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 | ||
| 485 | void | |
| 486 | conv(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 | ||
| 672 | void | |
| 673 | savestate() | |
| 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 | ||
| 702 | void | |
| 703 | savebounds(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 | ||
| 731 | void | |
| 732 | interpret(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 | ||
| 909 | int | |
| 910 | has_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 */ |