1114402Sru/* Last non-groff version: main.c 1.23 (Berkeley) 85/08/05 2114402Sru * 3114402Sru * Adapted to GNU troff by Daniel Senderowicz 99/12/29. 4114402Sru * 5114402Sru * Further refinements by Werner Lemberg 00/02/20. 6114402Sru * 7114402Sru * 8114402Sru * This file contains the main and file system dependent routines for 9114402Sru * processing gremlin files into troff input. The program watches input go 10114402Sru * by to standard output, only interpreting things between .GS and .GE 11114402Sru * lines. Default values (font, size, scale, thickness) may be overridden 12114402Sru * with a `default' command and are further overridden by commands in the 13114402Sru * input. 14114402Sru * 15114402Sru * Inside the GS and GE, commands are accepted to reconfigure the picture. 16114402Sru * At most one command may reside on each line, and each command is followed 17114402Sru * by a parameter separated by white space. The commands are as follows, 18114402Sru * and may be abbreviated down to one character (with exception of `scale' 19114402Sru * and `stipple' down to "sc" and "st") and may be upper or lower case. 20114402Sru * 21114402Sru * default - Make all settings in the current 22114402Sru * .GS/.GE the global defaults. Height, 23114402Sru * width and file are NOT saved. 24114402Sru * 1, 2, 3, 4 - Set size 1, 2, 3, or 4 (followed by an 25114402Sru * integer point size). 26114402Sru * roman, italics, bold, special - Set gremlin's fonts to any other troff 27114402Sru * font (one or two characters). 28114402Sru * stipple, l - Use a stipple font for polygons. Arg 29114402Sru * is troff font name. No Default. Can 30114402Sru * use only one stipple font per picture. 31114402Sru * (See below for stipple font index.) 32114402Sru * scale, x - Scale is IN ADDITION to the global 33114402Sru * scale factor from the default. 34114402Sru * pointscale - Turn on scaling point sizes to match 35114402Sru * `scale' commands. (Optional operand 36114402Sru * `off' to turn it off.) 37114402Sru * narrow, medium, thick - Set widths of lines. 38114402Sru * file - Set the file name to read the gremlin 39114402Sru * picture from. If the file isn't in 40114402Sru * the current directory, the gremlin 41114402Sru * library is tried. 42114402Sru * width, height - These two commands override any 43114402Sru * scaling factor that is in effect, and 44114402Sru * forces the picture to fit into either 45114402Sru * the height or width specified, 46114402Sru * whichever makes the picture smaller. 47114402Sru * The operand for these two commands is 48114402Sru * a floating-point number in units of 49114402Sru * inches. 50114402Sru * l<nn> (integer <nn>) - Set association between stipple <nn> 51114402Sru * and a stipple `character'. <nn> must 52114402Sru * be in the range 0 to NSTIPPLES (16) 53114402Sru * inclusive. The integer operand is an 54114402Sru * index in the stipple font selected. 55114402Sru * Valid cf (cifplot) indices are 1-32 56114402Sru * (although 24 is not defined), valid ug 57114402Sru * (unigrafix) indices are 1-14, and 58114402Sru * valid gs (gray scale) indices are 59114402Sru * 0-16. Nonetheless, any number between 60114402Sru * 0 and 255 is accepted since new 61114402Sru * stipple fonts may be added. An 62114402Sru * integer operand is required. 63114402Sru * 64114402Sru * Troff number registers used: g1 through g9. g1 is the width of the 65114402Sru * picture, and g2 is the height. g3, and g4, save information, g8 and g9 66114402Sru * are used for text processing and g5-g7 are reserved. 67114402Sru */ 68114402Sru 69114402Sru 70114402Sru#include "lib.h" 71114402Sru 72114402Sru#include <ctype.h> 73114402Sru#include <stdlib.h> 74114402Sru#include "gprint.h" 75114402Sru 76114402Sru#include "device.h" 77114402Sru#include "font.h" 78114402Sru#include "searchpath.h" 79114402Sru#include "macropath.h" 80114402Sru 81114402Sru#include "errarg.h" 82114402Sru#include "error.h" 83114402Sru#include "defs.h" 84114402Sru 85114402Sruextern "C" const char *Version_string; 86114402Sru 87114402Sru/* database imports */ 88114402Sru 89114402Sruextern void HGPrintElt(ELT *element, int baseline); 90114402Sruextern ELT *DBInit(); 91114402Sruextern ELT *DBRead(register FILE *file); 92114402Sruextern POINT *PTInit(); 93151497Sruextern POINT *PTMakePoint(double x, double y, POINT **pplist); 94114402Sru 95114402Sru 96114402Sru#define SUN_SCALEFACTOR 0.70 97114402Sru 98114402Sru/* #define DEFSTIPPLE "gs" */ 99114402Sru#define DEFSTIPPLE "cf" 100114402Sru 101114402Sru#define MAXINLINE 100 /* input line length */ 102114402Sru 103114402Sru#define SCREENtoINCH 0.02 /* scaling factor, screen to inches */ 104114402Sru 105114402Sru#define BIG 999999999999.0 /* unweildly large floating number */ 106114402Sru 107114402Sru 108114402Srustatic char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99"; 109114402Sru 110114402Sruint res; /* the printer's resolution goes here */ 111114402Sru 112114402Sruint dotshifter; /* for the length of dotted curves */ 113114402Sru 114114402Srudouble linethickness; /* brush styles */ 115114402Sruint linmod; 116114402Sruint lastx; /* point registers for printing elements */ 117114402Sruint lasty; 118114402Sruint lastyline; /* A line's vertical position is NOT the */ 119114402Sru /* same after that line is over, so for a */ 120114402Sru /* line of drawing commands, vertical */ 121114402Sru /* spacing is kept in lastyline */ 122114402Sru 123114402Sru/* These are the default fonts, sizes, line styles, */ 124114402Sru/* and thicknesses. They can be modified from a */ 125114402Sru/* `default' command and are reset each time the */ 126114402Sru/* start of a picture (.GS) is found. */ 127114402Sru 128151497Sruconst char *deffont[] = 129114402Sru{"R", "I", "B", "S"}; 130114402Sruint defsize[] = 131114402Sru{10, 16, 24, 36}; 132114402Sru/* #define BASE_THICKNESS 1.0 */ 133114402Sru#define BASE_THICKNESS 0.15 134114402Srudouble defthick[STYLES] = 135114402Sru{1 * BASE_THICKNESS, 136114402Sru 1 * BASE_THICKNESS, 137114402Sru 5 * BASE_THICKNESS, 138114402Sru 1 * BASE_THICKNESS, 139114402Sru 1 * BASE_THICKNESS, 140114402Sru 3 * BASE_THICKNESS}; 141114402Sru 142114402Sru/* int cf_stipple_index[NSTIPPLES + 1] = */ 143114402Sru/* {0, 1, 3, 12, 14, 16, 19, 21, 23}; */ 144114402Sru/* a logarithmic scale looks better than a linear one for the gray shades */ 145114402Sru/* */ 146114402Sru/* int other_stipple_index[NSTIPPLES + 1] = */ 147114402Sru/* {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; */ 148114402Sru 149114402Sruint cf_stipple_index[NSTIPPLES + 1] = 150114402Sru{0, 18, 32, 56, 100, 178, 316, 562, 1000}; /* only 1-8 used */ 151114402Sruint other_stipple_index[NSTIPPLES + 1] = 152114402Sru{0, 62, 125, 187, 250, 312, 375, 437, 500, 153114402Sru 562, 625, 687, 750, 812, 875, 937, 1000}; 154114402Sru 155114402Sru/* int *defstipple_index = other_stipple_index; */ 156114402Sruint *defstipple_index = cf_stipple_index; 157114402Sru 158114402Sruint style[STYLES] = 159114402Sru{DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID}; 160114402Srudouble scale = 1.0; /* no scaling, default */ 161114402Sruint defpoint = 0; /* flag for pointsize scaling */ 162114402Sruchar *defstipple = (char *) 0; 163151497Sruenum E { 164114402Sru OUTLINE, FILL, BOTH 165114402Sru} polyfill; 166114402Sru 167114402Sru/* flag to controll filling of polygons */ 168114402Sru 169114402Srudouble adj1 = 0.0; 170114402Srudouble adj2 = 0.0; 171114402Srudouble adj3 = 0.0; 172114402Srudouble adj4 = 0.0; 173114402Sru 174114402Srudouble thick[STYLES]; /* thicknesses set by defaults, then by */ 175114402Sru /* commands */ 176114402Sruchar *tfont[FONTS]; /* fonts originally set to deffont values, */ 177114402Sru /* then */ 178114402Sruint tsize[SIZES]; /* optionally changed by commands inside */ 179114402Sru /* grn */ 180114402Sruint stipple_index[NSTIPPLES + 1]; /* stipple font file indices */ 181114402Sruchar *stipple; 182114402Sru 183114402Srudouble xscale; /* scaling factor from individual pictures */ 184114402Srudouble troffscale; /* scaling factor at output time */ 185114402Sru 186114402Srudouble width; /* user-request maximum width for picture */ 187114402Sru /* (in inches) */ 188114402Srudouble height; /* user-request height */ 189114402Sruint pointscale; /* flag for pointsize scaling */ 190114402Sruint setdefault; /* flag for a .GS/.GE to remember all */ 191114402Sru /* settings */ 192114402Sruint sflag; /* -s flag: sort order (do polyfill first) */ 193114402Sru 194114402Srudouble toppoint; /* remember the picture */ 195114402Srudouble bottompoint; /* bounds in these variables */ 196114402Srudouble leftpoint; 197114402Srudouble rightpoint; 198114402Sru 199114402Sruint ytop; /* these are integer versions of the above */ 200114402Sruint ybottom; /* so not to convert each time they're used */ 201114402Sruint xleft; 202114402Sruint xright; 203114402Sru 204114402Sruint linenum = 0; /* line number of input file */ 205114402Sruchar inputline[MAXINLINE]; /* spot to filter through the file */ 206114402Sruchar *c1 = inputline; /* c1, c2, and c3 will be used to */ 207114402Sruchar *c2 = inputline + 1; /* hunt for lines that begin with */ 208114402Sruchar *c3 = inputline + 2; /* ".GS" by looking individually */ 209114402Sruchar *c4 = inputline + 3; /* needed for compatibility mode */ 210114402Sruchar GScommand[MAXINLINE]; /* put user's ".GS" command line here */ 211114402Sruchar gremlinfile[MAXINLINE]; /* filename to use for a picture */ 212114402Sruint SUNFILE = FALSE; /* TRUE if SUN gremlin file */ 213114402Sruint compatibility_flag = FALSE; /* TRUE if in compatibility mode */ 214114402Sru 215114402Sru 216114402Sruvoid getres(); 217151497Sruint doinput(FILE *fp); 218114402Sruvoid conv(register FILE *fp, int baseline); 219114402Sruvoid savestate(); 220114402Sruint has_polygon(register ELT *elist); 221114402Sruvoid interpret(char *line); 222114402Sru 223114402Sru 224114402Sruvoid 225114402Sruusage(FILE *stream) 226114402Sru{ 227114402Sru fprintf(stream, 228114402Sru "usage: %s [ -vCs ] [ -M dir ] [ -F dir ] [ -T dev ] [ file ]\n", 229114402Sru program_name); 230114402Sru} 231114402Sru 232114402Sru 233114402Sru/*----------------------------------------------------------------------------* 234114402Sru | Routine: main (argument_count, argument_pointer) 235114402Sru | 236114402Sru | Results: Parses the command line, accumulating input file names, then 237114402Sru | reads the inputs, passing it directly to output until a `.GS' 238114402Sru | line is read. Main then passes control to `conv' to do the 239114402Sru | gremlin file conversions. 240114402Sru *----------------------------------------------------------------------------*/ 241114402Sru 242114402Sruint 243114402Srumain(int argc, 244114402Sru char **argv) 245114402Sru{ 246114402Sru setlocale(LC_NUMERIC, "C"); 247114402Sru program_name = argv[0]; 248114402Sru register FILE *fp; 249114402Sru register int k; 250114402Sru register char c; 251114402Sru register int gfil = 0; 252114402Sru char *file[50]; 253114402Sru char *operand(int *argcp, char ***argvp); 254114402Sru 255114402Sru while (--argc) { 256114402Sru if (**++argv != '-') 257114402Sru file[gfil++] = *argv; 258114402Sru else 259114402Sru switch (c = (*argv)[1]) { 260114402Sru 261114402Sru case 0: 262114402Sru file[gfil++] = NULL; 263114402Sru break; 264114402Sru 265114402Sru case 'C': /* compatibility mode */ 266114402Sru compatibility_flag = TRUE; 267114402Sru break; 268114402Sru 269114402Sru case 'F': /* font path to find DESC */ 270114402Sru font::command_line_font_dir(operand(&argc, &argv)); 271114402Sru break; 272114402Sru 273114402Sru case 'T': /* final output typesetter name */ 274114402Sru device = operand(&argc, &argv); 275114402Sru break; 276114402Sru 277114402Sru case 'M': /* set library directory */ 278114402Sru macro_path.command_line_dir(operand(&argc, &argv)); 279114402Sru break; 280114402Sru 281114402Sru case 's': /* preserve order of elements */ 282114402Sru sflag = 1; 283114402Sru break; 284114402Sru 285114402Sru case '-': 286114402Sru if (strcmp(*argv,"--version")==0) { 287114402Sru case 'v': 288114402Sru printf("GNU grn (groff) version %s\n", Version_string); 289114402Sru exit(0); 290114402Sru break; 291114402Sru } 292114402Sru if (strcmp(*argv,"--help")==0) { 293114402Sru case '?': 294114402Sru usage(stdout); 295114402Sru exit(0); 296114402Sru break; 297114402Sru } 298114402Sru // fallthrough 299114402Sru default: 300114402Sru error("unknown switch: %1", c); 301114402Sru usage(stderr); 302114402Sru exit(1); 303114402Sru } 304114402Sru } 305114402Sru 306114402Sru getres(); /* set the resolution for an output device */ 307114402Sru 308114402Sru if (gfil == 0) { /* no filename, use standard input */ 309114402Sru file[0] = NULL; 310114402Sru gfil++; 311114402Sru } 312114402Sru 313114402Sru for (k = 0; k < gfil; k++) { 314114402Sru if (file[k] != NULL) { 315114402Sru if ((fp = fopen(file[k], "r")) == NULL) 316114402Sru fatal("can't open %1", file[k]); 317114402Sru } else 318114402Sru fp = stdin; 319114402Sru 320151497Sru while (doinput(fp)) { 321114402Sru if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') { 322114402Sru if (compatibility_flag || 323114402Sru *c4 == '\n' || *c4 == ' ' || *c4 == '\0') 324114402Sru conv(fp, linenum); 325114402Sru else 326114402Sru fputs(inputline, stdout); 327114402Sru } else 328114402Sru fputs(inputline, stdout); 329114402Sru } 330114402Sru } 331151497Sru 332151497Sru return 0; 333114402Sru} 334114402Sru 335114402Sru 336114402Sru/*----------------------------------------------------------------------------* 337114402Sru | Routine: char * operand (& argc, & argv) 338114402Sru | 339114402Sru | Results: Returns address of the operand given with a command-line 340114402Sru | option. It uses either `-Xoperand' or `-X operand', whichever 341114402Sru | is present. The program is terminated if no option is 342114402Sru | present. 343114402Sru | 344114402Sru | Side Efct: argc and argv are updated as necessary. 345114402Sru *----------------------------------------------------------------------------*/ 346114402Sru 347114402Sruchar * 348114402Sruoperand(int *argcp, 349114402Sru char ***argvp) 350114402Sru{ 351114402Sru if ((**argvp)[2]) 352114402Sru return (**argvp + 2); /* operand immediately follows */ 353114402Sru if ((--*argcp) <= 0) { /* no operand */ 354114402Sru error("command-line option operand missing."); 355114402Sru exit(8); 356114402Sru } 357114402Sru return (*(++(*argvp))); /* operand is next word */ 358114402Sru} 359114402Sru 360114402Sru 361114402Sru/*----------------------------------------------------------------------------* 362114402Sru | Routine: getres () 363114402Sru | 364114402Sru | Results: Sets `res' to the resolution of the output device. 365114402Sru *----------------------------------------------------------------------------*/ 366114402Sru 367114402Sruvoid 368114402Srugetres() 369114402Sru{ 370114402Sru int linepiece; 371114402Sru 372114402Sru if (!font::load_desc()) 373114402Sru fatal("sorry, I can't continue"); 374114402Sru 375114402Sru res = font::res; 376114402Sru 377114402Sru /* Correct the brush thicknesses based on res */ 378114402Sru /* if (res >= 256) { 379114402Sru defthick[0] = res >> 8; 380114402Sru defthick[1] = res >> 8; 381114402Sru defthick[2] = res >> 4; 382114402Sru defthick[3] = res >> 8; 383114402Sru defthick[4] = res >> 8; 384114402Sru defthick[5] = res >> 6; 385114402Sru } */ 386114402Sru 387114402Sru linepiece = res >> 9; 388114402Sru for (dotshifter = 0; linepiece; dotshifter++) 389114402Sru linepiece = linepiece >> 1; 390114402Sru} 391114402Sru 392114402Sru 393114402Sru/*----------------------------------------------------------------------------* 394151497Sru | Routine: int doinput (file_pointer) 395114402Sru | 396114402Sru | Results: A line of input is read into `inputline'. 397114402Sru | 398114402Sru | Side Efct: "linenum" is incremented. 399114402Sru | 400114402Sru | Bugs: Lines longer than MAXINLINE are NOT checked, except for 401114402Sru | updating `linenum'. 402114402Sru *----------------------------------------------------------------------------*/ 403114402Sru 404151497Sruint 405114402Srudoinput(FILE *fp) 406114402Sru{ 407151497Sru if (fgets(inputline, MAXINLINE, fp) == NULL) 408151497Sru return 0; 409114402Sru if (strchr(inputline, '\n')) /* ++ only if it's a complete line */ 410114402Sru linenum++; 411151497Sru return 1; 412114402Sru} 413114402Sru 414114402Sru 415114402Sru/*----------------------------------------------------------------------------* 416114402Sru | Routine: initpic ( ) 417114402Sru | 418114402Sru | Results: Sets all parameters to the normal defaults, possibly 419114402Sru | overridden by a setdefault command. Initialize the picture 420114402Sru | variables, and output the startup commands to troff to begin 421114402Sru | the picture. 422114402Sru *----------------------------------------------------------------------------*/ 423114402Sru 424114402Sruvoid 425114402Sruinitpic() 426114402Sru{ 427114402Sru register int i; 428114402Sru 429114402Sru for (i = 0; i < STYLES; i++) { /* line thickness defaults */ 430114402Sru thick[i] = defthick[i]; 431114402Sru } 432114402Sru for (i = 0; i < FONTS; i++) { /* font name defaults */ 433151497Sru tfont[i] = (char *)deffont[i]; 434114402Sru } 435114402Sru for (i = 0; i < SIZES; i++) { /* font size defaults */ 436114402Sru tsize[i] = defsize[i]; 437114402Sru } 438114402Sru for (i = 0; i <= NSTIPPLES; i++) { /* stipple font file default indices */ 439114402Sru stipple_index[i] = defstipple_index[i]; 440114402Sru } 441114402Sru stipple = defstipple; 442114402Sru 443114402Sru gremlinfile[0] = 0; /* filename is `null' */ 444114402Sru setdefault = 0; /* this is not the default settings (yet) */ 445114402Sru 446114402Sru toppoint = BIG; /* set the picture bounds out */ 447114402Sru bottompoint = -BIG; /* of range so they'll be set */ 448114402Sru leftpoint = BIG; /* by `savebounds' on input */ 449114402Sru rightpoint = -BIG; 450114402Sru 451114402Sru pointscale = defpoint; /* flag for scaling point sizes default */ 452114402Sru xscale = scale; /* default scale of individual pictures */ 453114402Sru width = 0.0; /* size specifications input by user */ 454114402Sru height = 0.0; 455114402Sru 456114402Sru linethickness = DEFTHICK; /* brush styles */ 457114402Sru linmod = DEFSTYLE; 458114402Sru} 459114402Sru 460114402Sru 461114402Sru/*----------------------------------------------------------------------------* 462114402Sru | Routine: conv (file_pointer, starting_line) 463114402Sru | 464114402Sru | Results: At this point, we just passed a `.GS' line in the input 465114402Sru | file. conv reads the input and calls `interpret' to process 466114402Sru | commands, gathering up information until a `.GE' line is 467114402Sru | found. It then calls `HGPrint' to do the translation of the 468114402Sru | gremlin file to troff commands. 469114402Sru *----------------------------------------------------------------------------*/ 470114402Sru 471114402Sruvoid 472114402Sruconv(register FILE *fp, 473114402Sru int baseline) 474114402Sru{ 475114402Sru register FILE *gfp = NULL; /* input file pointer */ 476114402Sru register int done = 0; /* flag to remember if finished */ 477114402Sru register ELT *e; /* current element pointer */ 478114402Sru ELT *PICTURE; /* whole picture data base pointer */ 479114402Sru double temp; /* temporary calculating area */ 480114402Sru /* POINT ptr; */ /* coordinates of a point to pass to `mov' */ 481114402Sru /* routine */ 482114402Sru int flyback; /* flag `want to end up at the top of the */ 483114402Sru /* picture?' */ 484114402Sru int compat; /* test character after .GE or .GF */ 485114402Sru 486114402Sru 487114402Sru initpic(); /* set defaults, ranges, etc. */ 488114402Sru strcpy(GScommand, inputline); /* save `.GS' line for later */ 489114402Sru 490114402Sru do { 491151497Sru done = !doinput(fp); /* test for EOF */ 492114402Sru flyback = (*c3 == 'F'); /* and .GE or .GF */ 493114402Sru compat = (compatibility_flag || 494114402Sru *c4 == '\n' || *c4 == ' ' || *c4 == '\0'); 495114402Sru done |= (*c1 == '.' && *c2 == 'G' && (*c3 == 'E' || flyback) && 496114402Sru compat); 497114402Sru 498114402Sru if (done) { 499114402Sru if (setdefault) 500114402Sru savestate(); 501114402Sru 502114402Sru if (!gremlinfile[0]) { 503114402Sru if (!setdefault) 504114402Sru error("at line %1: no picture filename.\n", baseline); 505114402Sru return; 506114402Sru } 507114402Sru char *path; 508114402Sru gfp = macro_path.open_file(gremlinfile, &path); 509114402Sru if (!gfp) 510114402Sru return; 511114402Sru PICTURE = DBRead(gfp); /* read picture file */ 512114402Sru fclose(gfp); 513114402Sru a_delete path; 514114402Sru if (DBNullelt(PICTURE)) 515114402Sru return; /* If a request is made to make the */ 516114402Sru /* picture fit into a specific area, */ 517114402Sru /* set the scale to do that. */ 518114402Sru 519114402Sru if (stipple == (char *) NULL) /* if user forgot stipple */ 520114402Sru if (has_polygon(PICTURE)) /* and picture has a polygon */ 521151497Sru stipple = (char *)DEFSTIPPLE; /* then set the default */ 522114402Sru 523114402Sru if ((temp = bottompoint - toppoint) < 0.1) 524114402Sru temp = 0.1; 525114402Sru temp = (height != 0.0) ? height / (temp * SCREENtoINCH) : BIG; 526114402Sru if ((troffscale = rightpoint - leftpoint) < 0.1) 527114402Sru troffscale = 0.1; 528114402Sru troffscale = (width != 0.0) ? 529114402Sru width / (troffscale * SCREENtoINCH) : BIG; 530114402Sru if (temp == BIG && troffscale == BIG) 531114402Sru troffscale = xscale; 532114402Sru else { 533114402Sru if (temp < troffscale) 534114402Sru troffscale = temp; 535114402Sru } /* here, troffscale is the */ 536114402Sru /* picture's scaling factor */ 537114402Sru if (pointscale) { 538114402Sru register int i; /* do pointscaling here, when */ 539114402Sru /* scale is known, before output */ 540114402Sru for (i = 0; i < SIZES; i++) 541114402Sru tsize[i] = (int) (troffscale * (double) tsize[i] + 0.5); 542114402Sru } 543114402Sru 544114402Sru /* change to device units */ 545114402Sru troffscale *= SCREENtoINCH * res; /* from screen units */ 546114402Sru 547114402Sru ytop = (int) (toppoint * troffscale); /* calculate integer */ 548114402Sru ybottom = (int) (bottompoint * troffscale); /* versions of the */ 549114402Sru xleft = (int) (leftpoint * troffscale); /* picture limits */ 550114402Sru xright = (int) (rightpoint * troffscale); 551114402Sru 552114402Sru /* save stuff in number registers, */ 553114402Sru /* register g1 = picture width and */ 554114402Sru /* register g2 = picture height, */ 555114402Sru /* set vertical spacing, no fill, */ 556114402Sru /* and break (to make sure picture */ 557114402Sru /* starts on left), and put out the */ 558114402Sru /* user's `.GS' line. */ 559114402Sru printf(".br\n" 560114402Sru ".nr g1 %du\n" 561114402Sru ".nr g2 %du\n" 562114402Sru "%s" 563114402Sru ".nr g3 \\n(.f\n" 564114402Sru ".nr g4 \\n(.s\n" 565114402Sru "\\0\n" 566114402Sru ".sp -1\n", 567114402Sru xright - xleft, ybottom - ytop, GScommand); 568114402Sru 569114402Sru if (stipple) /* stipple requested for this picture */ 570114402Sru printf(".st %s\n", stipple); 571114402Sru lastx = xleft; /* note where we are (upper left */ 572114402Sru lastyline = lasty = ytop; /* corner of the picture) */ 573114402Sru 574114402Sru /* Just dump everything in the order it appears. 575114402Sru * 576114402Sru * If -s command-line option, traverse picture twice: First time, 577114402Sru * print only the interiors of filled polygons (as borderless 578114402Sru * polygons). Second time, print the outline as series of line 579114402Sru * segments. This way, postprocessors that overwrite rather than 580114402Sru * merge picture elements (such as Postscript) can still have text and 581114402Sru * graphics on a shaded background. 582114402Sru */ 583114402Sru /* if (sflag) */ 584114402Sru if (!sflag) { /* changing the default for filled polygons */ 585114402Sru e = PICTURE; 586114402Sru polyfill = FILL; 587114402Sru while (!DBNullelt(e)) { 588114402Sru printf(".mk\n"); 589114402Sru if (e->type == POLYGON) 590114402Sru HGPrintElt(e, baseline); 591114402Sru printf(".rt\n"); 592114402Sru lastx = xleft; 593114402Sru lastyline = lasty = ytop; 594114402Sru e = DBNextElt(e); 595114402Sru } 596114402Sru } 597114402Sru e = PICTURE; 598114402Sru 599114402Sru /* polyfill = !sflag ? BOTH : OUTLINE; */ 600114402Sru polyfill = sflag ? BOTH : OUTLINE; /* changing the default */ 601114402Sru while (!DBNullelt(e)) { 602114402Sru printf(".mk\n"); 603114402Sru HGPrintElt(e, baseline); 604114402Sru printf(".rt\n"); 605114402Sru lastx = xleft; 606114402Sru lastyline = lasty = ytop; 607114402Sru e = DBNextElt(e); 608114402Sru } 609114402Sru 610114402Sru /* decide where to end picture */ 611114402Sru 612114402Sru /* I changed everything here. I always use the combination .mk and */ 613114402Sru /* .rt so once finished I just space down the heigth of the picture */ 614114402Sru /* that is \n(g2u */ 615114402Sru if (flyback) { /* end picture at upper left */ 616114402Sru /* ptr.x = leftpoint; 617114402Sru ptr.y = toppoint; */ 618114402Sru } else { /* end picture at lower left */ 619114402Sru /* ptr.x = leftpoint; 620114402Sru ptr.y = bottompoint; */ 621114402Sru printf(".sp \\n(g2u\n"); 622114402Sru } 623114402Sru 624114402Sru /* tmove(&ptr); */ /* restore default line parameters */ 625114402Sru 626114402Sru /* restore everything to the way it was before the .GS, then put */ 627114402Sru /* out the `.GE' line from user */ 628114402Sru 629114402Sru /* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */ 630114402Sru /* groff doesn't understand the \Ds command */ 631114402Sru 632114402Sru printf("\\D't %du'\n", DEFTHICK); 633114402Sru if (flyback) /* make sure we end up at top of */ 634114402Sru printf(".sp -1\n"); /* picture if `flying back' */ 635114402Sru if (stipple) /* restore stipple to previous */ 636114402Sru printf(".st\n"); 637114402Sru printf(".br\n" 638114402Sru ".ft \\n(g3\n" 639114402Sru ".ps \\n(g4\n" 640114402Sru "%s", inputline); 641114402Sru } else 642114402Sru interpret(inputline); /* take commands from the input file */ 643114402Sru } while (!done); 644114402Sru} 645114402Sru 646114402Sru 647114402Sru/*----------------------------------------------------------------------------* 648114402Sru | Routine: savestate ( ) 649114402Sru | 650114402Sru | Results: all the current scaling / font size / font name / thickness 651114402Sru | / pointscale settings are saved to be the defaults. Scaled 652114402Sru | point sizes are NOT saved. The scaling is done each time a 653114402Sru | new picture is started. 654114402Sru | 655114402Sru | Side Efct: scale, and def* are modified. 656114402Sru *----------------------------------------------------------------------------*/ 657114402Sru 658114402Sruvoid 659114402Srusavestate() 660114402Sru{ 661114402Sru register int i; 662114402Sru 663114402Sru for (i = 0; i < STYLES; i++) /* line thickness defaults */ 664114402Sru defthick[i] = thick[i]; 665114402Sru for (i = 0; i < FONTS; i++) /* font name defaults */ 666114402Sru deffont[i] = tfont[i]; 667114402Sru for (i = 0; i < SIZES; i++) /* font size defaults */ 668114402Sru defsize[i] = tsize[i]; 669114402Sru for (i = 0; i <= NSTIPPLES; i++) /* stipple font file default indices */ 670114402Sru defstipple_index[i] = stipple_index[i]; 671114402Sru 672114402Sru defstipple = stipple; /* if stipple has been set, it's remembered */ 673114402Sru scale *= xscale; /* default scale of individual pictures */ 674114402Sru defpoint = pointscale; /* flag for scaling pointsizes from x factors */ 675114402Sru} 676114402Sru 677114402Sru 678114402Sru/*----------------------------------------------------------------------------* 679114402Sru | Routine: savebounds (x_coordinate, y_coordinate) 680114402Sru | 681114402Sru | Results: Keeps track of the maximum and minimum extent of a picture 682114402Sru | in the global variables: left-, right-, top- and 683114402Sru | bottompoint. `savebounds' assumes that the points have been 684114402Sru | oriented to the correct direction. No scaling has taken 685114402Sru | place, though. 686114402Sru *----------------------------------------------------------------------------*/ 687114402Sru 688114402Sruvoid 689151497Srusavebounds(double x, 690151497Sru double y) 691114402Sru{ 692114402Sru if (x < leftpoint) 693114402Sru leftpoint = x; 694114402Sru if (x > rightpoint) 695114402Sru rightpoint = x; 696114402Sru if (y < toppoint) 697114402Sru toppoint = y; 698114402Sru if (y > bottompoint) 699114402Sru bottompoint = y; 700114402Sru} 701114402Sru 702114402Sru 703114402Sru/*----------------------------------------------------------------------------* 704114402Sru | Routine: interpret (character_string) 705114402Sru | 706114402Sru | Results: Commands are taken from the input string and performed. 707114402Sru | Commands are separated by the endofline, and are of the 708114402Sru | format: 709114402Sru | string1 string2 710114402Sru | 711114402Sru | where string1 is the command and string2 is the argument. 712114402Sru | 713114402Sru | Side Efct: Font and size strings, plus the gremlin file name and the 714114402Sru | width and height variables are set by this routine. 715114402Sru *----------------------------------------------------------------------------*/ 716114402Sru 717114402Sruvoid 718114402Sruinterpret(char *line) 719114402Sru{ 720114402Sru char str1[MAXINLINE]; 721114402Sru char str2[MAXINLINE]; 722114402Sru register char *chr; 723114402Sru register int i; 724114402Sru double par; 725114402Sru 726114402Sru str2[0] = '\0'; 727114402Sru sscanf(line, "%80s%80s", &str1[0], &str2[0]); 728114402Sru for (chr = &str1[0]; *chr; chr++) /* convert command to */ 729114402Sru if (isupper(*chr)) 730114402Sru *chr = tolower(*chr); /* lower case */ 731114402Sru 732114402Sru switch (str1[0]) { 733114402Sru 734114402Sru case '1': 735114402Sru case '2': /* font sizes */ 736114402Sru case '3': 737114402Sru case '4': 738114402Sru i = atoi(str2); 739114402Sru if (i > 0 && i < 1000) 740114402Sru tsize[str1[0] - '1'] = i; 741114402Sru else 742114402Sru error("bad font size value at line %1", linenum); 743114402Sru break; 744114402Sru 745114402Sru case 'r': /* roman */ 746114402Sru if (str2[0] < '0') 747114402Sru goto nofont; 748114402Sru tfont[0] = (char *) malloc(strlen(str2) + 1); 749114402Sru strcpy(tfont[0], str2); 750114402Sru break; 751114402Sru 752114402Sru case 'i': /* italics */ 753114402Sru if (str2[0] < '0') 754114402Sru goto nofont; 755114402Sru tfont[1] = (char *) malloc(strlen(str2) + 1); 756114402Sru strcpy(tfont[1], str2); 757114402Sru break; 758114402Sru 759114402Sru case 'b': /* bold */ 760114402Sru if (str2[0] < '0') 761114402Sru goto nofont; 762114402Sru tfont[2] = (char *) malloc(strlen(str2) + 1); 763114402Sru strcpy(tfont[2], str2); 764114402Sru break; 765114402Sru 766114402Sru case 's': /* special */ 767114402Sru if (str1[1] == 'c') 768114402Sru goto scalecommand; /* or scale */ 769114402Sru 770114402Sru if (str2[0] < '0') { 771114402Sru nofont: 772114402Sru error("no fontname specified in line %1", linenum); 773114402Sru break; 774114402Sru } 775114402Sru if (str1[1] == 't') 776114402Sru goto stipplecommand; /* or stipple */ 777114402Sru 778114402Sru tfont[3] = (char *) malloc(strlen(str2) + 1); 779114402Sru strcpy(tfont[3], str2); 780114402Sru break; 781114402Sru 782114402Sru case 'l': /* l */ 783114402Sru if (isdigit(str1[1])) { /* set stipple index */ 784151497Sru int idx = atoi(str1 + 1), val; 785114402Sru 786151497Sru if (idx < 0 || idx > NSTIPPLES) { 787151497Sru error("bad stipple number %1 at line %2", idx, linenum); 788114402Sru break; 789114402Sru } 790114402Sru if (!defstipple_index) 791114402Sru defstipple_index = other_stipple_index; 792114402Sru val = atoi(str2); 793114402Sru if (val >= 0 && val < 256) 794151497Sru stipple_index[idx] = val; 795114402Sru else 796114402Sru error("bad stipple index value at line %1", linenum); 797114402Sru break; 798114402Sru } 799114402Sru 800114402Sru stipplecommand: /* set stipple name */ 801114402Sru stipple = (char *) malloc(strlen(str2) + 1); 802114402Sru strcpy(stipple, str2); 803114402Sru /* if its a `known' font (currently only `cf'), set indicies */ 804114402Sru if (strcmp(stipple, "cf") == 0) 805114402Sru defstipple_index = cf_stipple_index; 806114402Sru else 807114402Sru defstipple_index = other_stipple_index; 808114402Sru for (i = 0; i <= NSTIPPLES; i++) 809114402Sru stipple_index[i] = defstipple_index[i]; 810114402Sru break; 811114402Sru 812114402Sru case 'a': /* text adjust */ 813114402Sru par = atof(str2); 814114402Sru switch (str1[1]) { 815114402Sru case '1': 816114402Sru adj1 = par; 817114402Sru break; 818114402Sru case '2': 819114402Sru adj2 = par; 820114402Sru break; 821114402Sru case '3': 822114402Sru adj3 = par; 823114402Sru break; 824114402Sru case '4': 825114402Sru adj4 = par; 826114402Sru break; 827114402Sru default: 828114402Sru error("bad adjust command at line %1", linenum); 829114402Sru break; 830114402Sru } 831114402Sru break; 832114402Sru 833114402Sru case 't': /* thick */ 834114402Sru thick[2] = defthick[0] * atof(str2); 835114402Sru break; 836114402Sru 837114402Sru case 'm': /* medium */ 838114402Sru thick[5] = defthick[0] * atof(str2); 839114402Sru break; 840114402Sru 841114402Sru case 'n': /* narrow */ 842114402Sru thick[0] = thick[1] = thick[3] = thick[4] = 843114402Sru defthick[0] * atof(str2); 844114402Sru break; 845114402Sru 846114402Sru case 'x': /* x */ 847114402Sru scalecommand: /* scale */ 848114402Sru par = atof(str2); 849114402Sru if (par > 0.0) 850114402Sru xscale *= par; 851114402Sru else 852114402Sru error("invalid scale value on line %1", linenum); 853114402Sru break; 854114402Sru 855114402Sru case 'f': /* file */ 856114402Sru strcpy(gremlinfile, str2); 857114402Sru break; 858114402Sru 859114402Sru case 'w': /* width */ 860114402Sru width = atof(str2); 861114402Sru if (width < 0.0) 862114402Sru width = -width; 863114402Sru break; 864114402Sru 865114402Sru case 'h': /* height */ 866114402Sru height = atof(str2); 867114402Sru if (height < 0.0) 868114402Sru height = -height; 869114402Sru break; 870114402Sru 871114402Sru case 'd': /* defaults */ 872114402Sru setdefault = 1; 873114402Sru break; 874114402Sru 875114402Sru case 'p': /* pointscale */ 876114402Sru if (strcmp("off", str2)) 877114402Sru pointscale = 1; 878114402Sru else 879114402Sru pointscale = 0; 880114402Sru break; 881114402Sru 882114402Sru default: 883114402Sru error("unknown command `%1' on line %2", str1, linenum); 884114402Sru exit(8); 885114402Sru break; 886114402Sru }; 887114402Sru} 888114402Sru 889114402Sru 890114402Sru/* 891114402Sru * return TRUE if picture contains a polygon 892114402Sru * otherwise FALSE 893114402Sru */ 894114402Sru 895114402Sruint 896114402Sruhas_polygon(register ELT *elist) 897114402Sru{ 898114402Sru while (!DBNullelt(elist)) { 899114402Sru if (elist->type == POLYGON) 900114402Sru return (1); 901114402Sru elist = DBNextElt(elist); 902114402Sru } 903114402Sru 904114402Sru return (0); 905114402Sru} 906114402Sru 907114402Sru/* EOF */ 908