/* main.c 1.20 (Berkeley) 84/12/29
* This file contains the main and file system dependent routines
* for processing gremlin files into troff input. The program watches
* input go by to standard output, only interpretting things between .GS
* and .GE lines. Default values (font, size, scale, thickness) may be
* overridden with a "default" command and are further overridden by
* commands in the input. A description of the command-line options are
* listed below. A space is NOT required for the operand of an option.
* -L dir set the library directory to dir. If a file is not found
* in the current directory, it is looked for in dir (default
* -T dev Prepare output for "dev" printer. Default is for the varian
* -P dev and versatec printers. Devices acceptable are: ver, var, ip.
* Inside the GS and GE, commands are accepted to reconfigure
* the picture. At most one command may reside on each line, and
* each command is followed by a parameter separated by white space.
* The commands are as follows, and may be abbreviated down to one
* character (with exception of "scale" and "stipple" down to "sc"
* and "st") and may be upper or lower case.
* default - make all settings in the current
* .GS/.GE the global defaults.
* Height, width and file are NOT saved.
* 1, 2, 3, 4 - set size 1, 2, 3, or 4 (followed
* by an integer point size).
* roman, italics, bold, special - set gremlin's fonts to any other
* troff font (one or two characters)
* stipple, l - use a stipple font for polygons. Arg
* is troff font name. No Default. Can
* use only one stipple font per picture.
* (see below for stipple font index)
* scale, x - scale is IN ADDITION to the global
* scale factor from the default.
* pointscale - turn on scaling point sizes to
* match "scale" commands. (optional
* operand "off" to turn it off)
* narrow, medium, thick - set pixel widths of lines.
* file - set the file name to read the
* gremlin picture from. If the file
* isn't in the current directory, the
* gremlin library is tried.
* width, height - these two commands override any
* scaling factor that is in effect,
* and forces the picture to fit into
* either the height or width specified,
* whichever makes the picture smaller.
* The operand for these two commands is
* a floating-point number in units of
* l1, l2, l3, l4, l5, l6, l7, l8 - set association between stipples
* (1 - 8) and the stipple font file
* index. Valid cifplot indices are
* 1 - 32 (although 24 is not defined)
* and valid unigrafix indices are
* 1 - 64. Nonetheless, any number
* between 0 and 255 is accepted since
* new stipple fonts may be added.
* An integer operand is required.
* Troff number registers used: g1 through g9. g1 is the width of the
* picture, and g2 is the height. g3, and g4, save information, g8
* and g9 are used for text processing and g5-g7 are reserved.
extern ELT
*DBInit(), *DBRead();
extern POINT
*PTInit(), *PTMakePoint();
#define GREMLIB "/usr/local/lib/gremlin/"
#define GREMLIB "/usr/local/gremlib/"
#define SUN_SCALEFACTOR 0.70
#define DEVDIR "/usr/lib/font"
#define MAXINLINE 100 /* input line length */
#define DEFTHICK 3 /* default thicknes */
#define DEFSTYLE SOLID /* default line style */
#define SCREENtoINCH 0.02 /* scaling factor, screen to inches */
double SCREENtoINCH
; /* scaling factor, screen to inches */
#define BIG 999999999999.0 /* unweildly large floating number */
static char sccsid
[] = "@(#) (Berkeley) %G%";
char *printer
= DEFAULTDEV
; /* device to look up resolution of */
char *gremlib
= GREMLIB
; /* place to find files after current dir. */
double res
; /* that printer's resolution goes here */
int linethickness
; /* brush styles */
int lastx
; /* point registers for printing elements */
int lastyline
; /* a line's vertical position is NOT the same */
/* after that line is over, so for a line of */
/* drawing commands, vertical spacing is kept */
/* these are the default fonts, sizes, line styles, */
/* and thicknesses. These can be modified from a */
/* "default" command and are reset each time the */
/* start of a picture (.GS) is found. */
char * deffont
[] = { "R", "I", "B", "S" };
int defsize
[] = { 10, 16, 24, 36 };
int defthick
[STYLES
] = { 1, 1, 5, 1, 1, 3 };
int defstipple_index
[NSTIPPLES
] = { 1, 3, 12, 14, 16, 19, 21, 23 };
int style
[STYLES
] = { DOTTED
, DOTDASHED
, SOLID
, DASHED
, SOLID
, SOLID
};
double scale
= 1.0; /* no scaling, default */
int defpoint
= 0; /* flag for pointsize scaling */
char * defstipple
= (char *) 0;
int thick
[STYLES
]; /* thicknesses set by defaults, then by commands */
char *tfont
[FONTS
]; /* fonts originally set to deffont values, then */
int tsize
[SIZES
]; /* optionally changed by commands inside grn */
int stipple_index
[NSTIPPLES
]; /* stipple font file indices */
double xscale
; /* scaling factor from individual pictures */
double troffscale
; /* scaling factor at output time */
double width
; /* user-request maximum width for picture (in inches) */
double height
; /* user-request height */
int pointscale
; /* flag for pointsize scaling */
int setdefault
; /* flag for a .GS/.GE to remember all settings */
double toppoint
; /* remember the picture */
double bottompoint
; /* bounds in these variables */
int ytop
; /* these are integer versions of the above */
int ybottom
; /* so not to convert each time they're used */
int linenum
= 0; /* line number of input file */
char inputline
[MAXINLINE
]; /* spot to filter through the file */
char *c1
= inputline
; /* c1, c2, and c3 will be used to */
char *c2
= inputline
+ 1; /* hunt for lines that begin with */
char *c3
= inputline
+ 2; /* ".GS" by looking individually */
char GScommand
[MAXINLINE
]; /* put user's ".GS" command line here */
char gremlinfile
[MAXINLINE
]; /* filename to use for a picture */
int SUNFILE
= FALSE
; /* TRUE if SUN gremlin file */
/*----------------------------------------------------------------------------*
| Routine: main (argument_count, argument_pointer)
| Results: parses the command line, accumulating input file names, then
| reads the inputs, passing it directly to output until a ".GS"
| line is read. Main then passes control to "conv" to do the
| gremlin file conversions.
*----------------------------------------------------------------------------*/
register FILE *fp
= stdin
;
switch (c
= (*argv
)[1]) {
case 'T': /* final output typesetter name */
printer
= operand(&argc
, &argv
);
case 'L': /* set library directory */
gremlib
= operand(&argc
, &argv
);
error("unknown switch: %c", c
);
/* set the resolution for an output device */
getres(printer
); /* named in "printer" */
if (gfil
== 0) { /* no filename, use standard input */
if ((fp
= fopen(file
[k
], "r")) == NULL
) {
error("can't open %s", file
[k
]);
while (doinput(fp
) != NULL
) {
if (*c1
== '.' && *c2
== 'G' && *c3
== 'S') {
fputs(inputline
, stdout
);
/*----------------------------------------------------------------------------*
| Routine: error (control_string, args, . . . )
| Results: prints ("grn: ", the control_string + args, "\n") to stderr
*----------------------------------------------------------------------------*/
fprintf(stderr
, "grn: ");
fprintf(stderr
, s
, a1
, a2
, a3
, a4
);
/*----------------------------------------------------------------------------*
| Routine: char * operand (& argc, & argv)
| Results: returns address of the operand given with a command-line
| option. It uses either "-Xoperand" or "-X operand", whichever
| is present. The program is terminated if no option is present.
| Side Efct: argc and argv are updated as necessary.
*----------------------------------------------------------------------------*/
char *operand(argcp
, argvp
)
if ((**argvp
)[2]) return(**argvp
+ 2); /* operand immediately follows */
if ((--*argcp
) <= 0) { /* no operand */
error("command-line option operand missing.");
return(*(++(*argvp
))); /* operand is next word */
/*----------------------------------------------------------------------------*
| Routine: getres (device_name)
| Results: sets "res" to the resolution of the output device specified
*----------------------------------------------------------------------------*/
sprintf(temp
, "%s/dev%s/DESC.out", DEVDIR
, name
);
if ((fin
= open(temp
, 0)) < 0) {
error("can't open tables for %s", temp
);
read(fin
, &device
, sizeof(struct dev
));
res
= (double) device
.res
;
/*----------------------------------------------------------------------------*
| Routine: char * doinput (file_pointer)
| Results: a line of input is read into "inputline".
| Side Efct: "linenum" is incremented.
| Bugs: lines longer than MAXINLINE are NOT checked, except for
*----------------------------------------------------------------------------*/
if ((k
= fgets(inputline
, MAXINLINE
, fp
)) == NULL
)
if (index (inputline
, '\n')) /* ++ only if it's a complete line */
/*----------------------------------------------------------------------------*
| Results: sets all parameters to the normal defaults, possibly overridden
| by a setdefault command. Initilaize the picture variables,
| and output the startup commands to troff to begin the picture.
*----------------------------------------------------------------------------*/
for (i
= 0; i
< STYLES
; i
++) { /* line thickness defaults */
for (i
= 0; i
< FONTS
; i
++) { /* font name defaults */
for (i
= 0; i
< SIZES
; i
++) { /* font size defaults */
for (i
= 0; i
< NSTIPPLES
; i
++) { /* stipple font file default indices */
stipple_index
[i
] = defstipple_index
[i
];
gremlinfile
[0] = 0; /* filename is "null" */
setdefault
= 0; /* this is not the default settings (yet) */
toppoint
= BIG
; /* set the picture bounds out */
bottompoint
= 0.0; /* of range so they'll be set */
leftpoint
= BIG
; /* by "savebounds" on input */
pointscale
= defpoint
; /* Flag for scaling point sizes default. */
xscale
= scale
; /* default scale of individual pictures */
width
= 0.0; /* size specifications input by user */
linethickness
= DEFTHICK
; /* brush styles */
/*----------------------------------------------------------------------------*
| Routine: conv (file_pointer, starting_line)
| Results: at this point, we just passed a ".GS" line in the input file.
| conv reads the input and calls "interpret" to process commands,
| gathering up information until a ".GE" line is found. It then
| calls "HGPrint" to do the translation of the gremlin file to
*----------------------------------------------------------------------------*/
register FILE *gfp
= NULL
; /* input file pointer */
register int done
= 0; /* flag to remember if finished */
register ELT
*e
; /* current element pointer */
ELT
*PICTURE
; /* whole picture data base pointer */
double temp
; /* temporary calculating area */
POINT ptr
; /* coordinates of a point to pass to "mov" routine */
int flyback
; /* flag "want to end up at the top of the picture?" */
initpic(); /* set defaults, ranges, etc. */
strcpy (GScommand
, inputline
); /* save ".GS" line for later */
done
= (doinput(fp
) == NULL
); /* test for EOF */
flyback
= *c3
== 'F'; /* and .GE or .GF */
done
|= (*c1
== '.' && *c2
== 'G' && (*c3
== 'E' || flyback
));
if (setdefault
) savestate();
error("at line %d: no picture filename.\n", baseline
);
if ((gfp
= fopen(gremlinfile
, "r")) == NULL
) {
char name
[MAXINLINE
]; /* if the file isn't in the current */
/* directory, try the gremlin library */
sprintf(name
, "%s%s", gremlib
, gremlinfile
);
if ((gfp
= fopen(name
, "r")) == NULL
) {
error("can't open %s", gremlinfile
);
PICTURE
= DBRead(gfp
); /* read picture file */
return; /* if a request is made to make the */
/* picture fit into a specific area, */
/* set the scale to do that. */
SCREENtoINCH
= (SUNFILE
) ? 0.014 : 0.02;
if (stipple
== (char *) NULL
) /* if user forgot stipple */
if (has_polygon(PICTURE
)) /* and picture has a polygon */
stipple
= DEFSTIPPLE
; /* then set the default */
if ((temp
= bottompoint
- toppoint
) < 0.1) temp
= 0.1;
temp
= (height
!= 0.0) ? height
/ (temp
* SCREENtoINCH
) : BIG
;
if ((troffscale
= rightpoint
- leftpoint
) < 0.1) troffscale
=0.1;
troffscale
= (width
!= 0.0) ?
width
/ (troffscale
* SCREENtoINCH
) : BIG
;
if (temp
== BIG
&& troffscale
== BIG
) {
if (temp
< troffscale
) troffscale
= temp
;
} /* here, troffscale is the */
/* picture's scaling factor */
register int i
; /* do pointscaling here, when */
/* scale is known, before output */
for (i
= 0; i
< SIZES
; i
++)
tsize
[i
] = (int) (troffscale
* (double) tsize
[i
] + 0.5);
/* change to device units */
troffscale
*= SCREENtoINCH
* res
; /* from screen units */
ytop
= toppoint
* troffscale
; /* calculate integer */
ybottom
= bottompoint
* troffscale
; /* versions of the */
xleft
= leftpoint
* troffscale
; /* picture limits */
xright
= rightpoint
* troffscale
;
/* save stuff in number registers, */
/* register g1 = picture width and */
/* register g2 = picture height, */
/* set vertical spacing, no fill, */
/* and break (to make sure picture */
/* starts on left), and put out the */
".br\n.nr g1 %du\n.nr g2 %du\n%s.nr g3 \\n(.f\n.nr g4 \\n(.s\n\\0\n.sp -1\n",
xright
-xleft
, ybottom
-ytop
, GScommand
);
if (stipple
) { /* stipple requested for this picture */
printf(".st %s\n", stipple
);
lastx
= xleft
; /* note where we are, (upper left */
lastyline
= lasty
= ytop
; /* corner of the picture) */
while (!DBNullelt(e
)) { /* traverse picture; print elements */
/* decide where to end picture */
if (flyback
) { /* end piture at upper left */
} else { /* end picture at lower left */
tmove(&ptr
); /* restore default line parameters, */
/* restore everything to the way */
/* it was before the .GS, then put */
/* out the ".GE" line from user */
printf("\\D't %du'\\D's %du'\n", DEFTHICK
, DEFSTYLE
);
if (flyback
) { /* make sure we end up at top of */
printf(".sp -1\n"); /* picture if "flying back" */
if (stipple
) { /* restore stipple to previous */
printf(".br\n.ft \\n(g3\n.ps \\n(g4\n%s", inputline
);
interpret(inputline
); /* take commands from the input file */
/*----------------------------------------------------------------------------*
| Results: all the current scaling / font size / font name / thickness /
| pointscale settings are saved to be the defaults. Scaled
| point sizes are NOT saved. The scaling is done each time a
| new picture is started.
| Side Efct: scale, and def* are modified.
*----------------------------------------------------------------------------*/
for (i
= 0; i
< STYLES
; i
++) { /* line thickness defaults */
for (i
= 0; i
< FONTS
; i
++) { /* font name defaults */
for (i
= 0; i
< SIZES
; i
++) { /* font size defaults */
for (i
= 0; i
< NSTIPPLES
; i
++) { /* stipple font file default indices */
defstipple_index
[i
] = stipple_index
[i
];
defstipple
= stipple
; /* if stipple has been set, it's remembered */
scale
*= xscale
; /* default scale of individual pictures */
defpoint
= pointscale
; /* flag for scaling pointsizes from x factors */
/*----------------------------------------------------------------------------*
| Routine: savebounds (x_coordinate, y_coordinate)
| Results: keeps track of the maximum and minimum extent of a picture
| in the global variables: left-, right-, top- and bottompoint.
| "savebounds" assumes that the points have been oriented to
| the correct direction. No scaling has taken place, though.
*----------------------------------------------------------------------------*/
if (x
< leftpoint
) leftpoint
= x
;
if (x
> rightpoint
) rightpoint
= x
;
if (y
< toppoint
) toppoint
= y
;
if (y
> bottompoint
) bottompoint
= y
;
/*----------------------------------------------------------------------------*
| Routine: interpret (character_string)
| Results: commands are taken from the input string and performed.
| Commands are separated by the endofline, and are of the
| where string1 is the command and string2 is the argument.
| Side Efct: font and size strings, plus the gremlin file name and the
| width and height variables are set by this routine.
*----------------------------------------------------------------------------*/
sscanf(line
, "%80s%80s", &str1
[0], &str2
[0]);
for (chr
= &str1
[0]; *chr
; chr
++) /* convert command to */
if(isupper(*chr
)) *chr
= tolower(*chr
); /* lower case */
case '2': /* font sizes */
tsize
[str1
[0] - '1'] = i
;
error("bad font size value at line %d", linenum
);
if(str2
[0] < '0') goto nofont
;
tfont
[0] = malloc(strlen(str2
) + 1);
if(str2
[0] < '0') goto nofont
;
tfont
[1] = malloc(strlen(str2
) + 1);
if(str2
[0] < '0') goto nofont
;
tfont
[2] = malloc(strlen(str2
) + 1);
if (str1
[1] == 'c') goto scalecommand
; /* or scale */
nofont
: error("no fontname specified in line %d", linenum
);
if (str1
[1] == 't') goto stipplecommand
; /* or stipple */
tfont
[3] = malloc(strlen(str2
) + 1);
if ((str1
[1] < '1') || (str1
[1] > '8'))
/* else set stipple index */
stipple_index
[str1
[1] - '1'] = i
;
error("bad stipple index value at line %d", linenum
);
stipplecommand
: /* stipple */
stipple
= malloc(strlen(str2
) + 1);
thick
[0] = thick
[1] = thick
[3] = thick
[4] = atoi(str2
);
scalecommand
: /* scale */
error("illegal scale value on line %d", linenum
);
strcpy(gremlinfile
, str2
);
if (width
< 0.0) width
= -width
;
if (height
< 0.0) height
= -height
;
case 'p': /* pointscale */
error("unknown command, %s, on line %d", str1
, linenum
);
* return TRUE if picture contains a polygon
while (!DBNullelt(elist
)) {
if (elist
->type
== POLYGON
)
elist
= DBNextElt(elist
);