oops - fixed missing )
[unix-history] / usr / src / local / ditroff / ditroff.old.okeeffe / grn / main.c
CommitLineData
cada353f 1/* main.c 1.5 (Berkeley) 83/08/12
dc80306e
DS
2 *
3 * This file contains the main and file system dependent routines
4 * for processing gremlin files into troff input. The program watches
5 * input go by to standard output, only interpretting things between .GS
6 * and .GE lines. Default values may be overridden, as in gprint, on the
7 * command line and are further overridden by commands in the input.
8 *
9 * command options are:
10 *
11 * -1 # sets point size 1 to #. also for -2, -3, -4. Defaults
12 * are 12, 16, 24, 36.
13 *
14 * -r ss sets gremlin's roman font to troff font ss. Also for -i,
15 * -b and -s for italics, bold, and special fonts. This does
16 * NOT affect font changes imbedded into strings. A \fI, for
17 * instance, will get the italics font regardless of what -i
18 * is set to.
19 *
20 * -n # set narrow line thickness to # pixels. Also for -m (medium)
acf96fee 21 * and -t (thick). Defaults are 1, 3, and 5 pixels.
dc80306e
DS
22 *
23 * -x # scale the picture by x (integer or decimal).
24 *
25 * -Tdev Prepare output for "dev" printer. Default is for the varian
26 * and versatec printers. Devices acceptable are: ver, var, ip.
27 *
28 * -p prompt user for fonts, sizes and thicknesses.
29 */
30
31
acf96fee 32#include <ctype.h>
dc80306e
DS
33#include "gprint.h"
34#include "dev.h"
35
acf96fee 36extern char *calloc();
dc80306e
DS
37extern char *rindex();
38
39/* database imports */
40
41extern HGPrintElt();
42extern ELT *DBInit(), *DBRead();
43extern POINT *PTInit(), *PTMakePoint();
44
45
46char *doinput();
47
df168245 48#define GREMLIB "/usr/local/gremlib/"
dc80306e
DS
49#define DEVDIR "/usr/lib/font/dev"
50#define DEFAULTDEV "var"
51
52#define MAXINLINE 100 /* input line length */
53#define DEFTHICK 3 /* default thicknes */
54#define DEFSTYLE SOLID /* default line style */
55
56#define SCREENtoINCH 0.02 /* scaling factor, screen to inches */
57#define BIG 100000000000.0 /* unweildly large floating number */
58
59#define JLEFT -1 /* justification constants - for the */
60#define JCENTER 0 /* whole picture - where it will */
61#define JRIGHT 1 /* get placed within the line */
62
63
cada353f 64char SccsId[] = "main.c 1.5 83/08/12";
dc80306e
DS
65
66char *printer = DEFAULTDEV; /* device to look up resolution of */
67double res; /* that printer's resolution goes here */
68
69int linethickness; /* brush styles */
70int linmod;
71int lastx; /* point registers for printing elements */
72int lasty;
73int lastyline; /* a line's vertical position is NOT the same */
74 /* after that line is over, so for a line of */
75 /* drawing commands, vertical spacing is kept */
76 /* in lastyline */
77double scale = SCREENtoINCH; /* default scale to map gremlin screen to inches
78 (modified by -x command-line option) */
79
80 /* list of prompts for asking user to set default values */
81char *prompt[] = { /* used only for -p option */
82 "Roman font name? (%s): ", "Italic font name? (%s): ",
83 "Bold font name? (%s): ", "Special font name? (%s): ",
84 "font size 1? (%s): ", "font size 2? (%s): ",
85 "font size 3? (%s): ", "font size 4? (%s): ",
86 };
87
88 /* these are the default fonts, sizes, */
89 /* line styles, and thicknesses. These */
90 /* can be modified from command-line */
91 /* options, and are reset each time the */
92 /* start of a picture (.GS) is found. */
93
94char *defstring[] = {
95 "R\0 ", "I\0 ", "B\0 ", "S\0 ",
96 "10\0 ", "16\0 ", "24\0 ", "36\0 "
97 };
98int defthick[STYLES] = { 1, 1, 5, 1, 1, 3 }; /* defaults... */
99int style[STYLES] = { DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID };
100int thick[STYLES]; /* thicknesses set by defaults, then by commands */
101char *tfont[FONTS]; /* fonts originally set to defstring values, then */
102char *tsize[SIZES]; /* optionally changed by commands inside grn */
103
acf96fee 104double xscale; /* scaling factor from individual pictures */
dc80306e
DS
105double troffscale; /* scaling factor at output time */
106double width; /* user-request maximum width for picture (in inches) */
107double height; /* user-request height */
108
109double toppoint; /* remember the picture */
110double bottompoint; /* bounds in these variables */
111double leftpoint;
112double rightpoint;
113
114int ytop; /* these are integer versions of the above */
115int ybottom; /* so not to convert each time they're used */
116int xleft;
117int xright;
118
119int linenum = 0; /* line number of input file */
120char inputline[MAXINLINE]; /* spot to filter through the file */
121char *c1 = inputline; /* c1, c2, and c3 will be used to */
122char *c2 = inputline + 1; /* hunt for lines that begin with */
123char *c3 = inputline + 2; /* ".GS" by looking individually */
124char GScommand[MAXINLINE]; /* put user's ".GS" command line here */
125char gremlinfile[50]; /* filename to use for a picture */
126
127
128/*----------------------------------------------------------------------------*
129 | Routine: main (argument_count, argument_pointer)
130 |
131 | Results: parses the command line, accumulating input file names, then
132 | reads the inputs, passing it directly to output until a ".GS"
133 | line is read. Main then passes control to "conv" to do the
134 | gremlin file conversions.
135 |
136 | Bugs: a -p option ALWAYS reads standard input. Even if the input
137 | file is coming in that way.
138 *----------------------------------------------------------------------------*/
139
140main(argc, argv)
141int argc;
142char **argv;
143{
144 register FILE *fp = stdin;
145 register int k;
146 register char c;
147 char *file[50], string[50], *arg;
148 float mult;
149 int brsh, gfil = 0;
150
151
152 argc--;
153 argv++;
154 while (argc--) {
155 if (*(arg = *argv++) != '-')
156 file[gfil++] = arg;
157 else switch (c = *++arg) {
158
159 case '1': /* select sizes */
160 case '2':
161 case '3':
162 case '4':
163 if (*++arg == '\0' && argc--)
164 arg = *argv++;
165 strcpy(defstring[c + FONTS - '1'], arg);
166 break;
167 case 'r': /* select Roman font */
168 if (*++arg == '\0' && argc--)
169 arg = *argv++;
acf96fee 170 strcpy(defstring[0], arg);
dc80306e
DS
171 break;
172 case 'i': /* select italics font */
173 if (*++arg == '\0' && argc--)
174 arg = *argv++;
acf96fee 175 strcpy(defstring[1], arg);
dc80306e
DS
176 break;
177 case 'b': /* select bold font */
178 if (*++arg == '\0' && argc--)
179 arg = *argv++;
acf96fee 180 strcpy(defstring[2], arg);
dc80306e
DS
181 break;
182 case 's': /* select special font */
183 if (*++arg == '\0' && argc--)
184 arg = *argv++;
acf96fee 185 strcpy(defstring[3], arg);
dc80306e
DS
186 break;
187 case 'n': /* select narrow brush width */
188 if (*++arg == '\0' && argc--)
189 arg = *argv++;
190 (void) sscanf(arg, "%d", &brsh);
191 defthick[0]=defthick[1]=defthick[3]=defthick[4] = brsh;
192 break;
193 case 't': /* select thick brush width */
194 if (*++arg == '\0' && argc--)
195 arg = *argv++;
196 (void) sscanf(arg, "%d", &brsh);
197 defthick[2] = brsh;
198 break;
199 case 'm': /* select medium brush width */
200 if (*++arg == '\0' && argc--)
201 arg = *argv++;
202 (void) sscanf(arg, "%d", &brsh);
203 defthick[5] = brsh;
204 break;
205 case 'x': /* select scale */
206 if (*++arg == '\0' && argc--)
207 arg = *argv++;
208 sscanf(arg,"%f", &mult);
209 scale *= mult;
210 break;
211 case 'T': /* final output typesetter name */
212 printer = arg + 1;
213 break;
214 case 'p': /* prompt for font and size parameters */
215 for (k = 0; k < 8; k++) {
216 fprintf(stderr, prompt[k], string[k]);
217 gets(string);
218 if (*string != '\0') strcpy(string[k], string);
219 }
220 fprintf(stderr,"narrow brush size? (%d): ",defthick[0]);
221 gets(string);
222 if (*string != '\0') {
223 sscanf(string, "%d", &brsh);
224 defthick[0] = defthick[1] = defthick[3]
225 = defthick[4] = brsh;
226 }
227 fprintf(stderr,"medium brush size? (%d): ",defthick[5]);
228 gets(string);
229 if (*string != '\0') {
230 sscanf(string, "%d", &brsh);
231 defthick[5] = brsh;
232 }
233 fprintf(stderr, "thick brush size? (%d): ",defthick[2]);
234 gets(string);
235 if (*string != '\0') {
236 sscanf(string, "%d", &brsh);
237 defthick[2] = brsh;
238 }
239 break;
240 default:
241 fprintf(stderr, "unknown switch: %c\n", c);
242 }
243 }
244 /* set the resolution for an output device */
245 getres(printer); /* named in "printer" */
246
247 if (gfil == 0) { /* no filename, use standard input */
248 file[0] = NULL;
249 gfil++;
250 }
251 for (k=0; k<gfil; k++) {
252 if (file[k] != NULL) {
253 if ((fp = fopen(file[k], "r")) == NULL) {
254 fprintf(stderr, "grn: can't open %s\n", file[k]);
255 continue;
256 }
257 if (k == 0) {
258 if ((arg = rindex(file[k], '/')) == NULL)
259 arg = file[k];
260 else
261 arg++;
262 }
263 } else {
264 fp = stdin;
265 }
266
267 while (doinput(fp) != NULL) {
268 if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') {
269 conv(fp, linenum);
270 } else {
271 fputs(inputline, stdout);
272 }
273 }
274 }
275}
276
277
278/*----------------------------------------------------------------------------*
279 | Routine: getres (device_name)
280 |
281 | Results: sets "res" to the resolution of the output device specified
282 | by the string dev.
283 *----------------------------------------------------------------------------*/
284
285getres(name)
286char *name;
287{
288 int fin;
289 struct dev device;
290 char temp[60];
291
292 sprintf(temp, "%s%s/DESC.out", DEVDIR, name);
293 if ((fin = open(temp, 0)) < 0) {
294 fprintf(stderr, "can't open tables for %s\n", temp);
295 exit(1);
296 }
297 read(fin, &device, sizeof(struct dev));
298 res = (double) device.res;
299 close(fin);
300}
301
302
303/*----------------------------------------------------------------------------*
304 | Routine: char * doinput (file_pointer)
305 |
306 | Results: a line of input is read into "inputline".
307 |
308 | Side Efct: "linenum" is incremented.
309 |
310 | Bugs: lines longer than MAXINLINE are NOT checked, except for
311 | updating "linenum"
312 *----------------------------------------------------------------------------*/
313
314char *doinput(fp)
315FILE *fp;
316{
317 register char *k;
318
319
320 if ((k = fgets(inputline, MAXINLINE, fp)) == NULL)
321 return k;
322 if (index (inputline, '\n')) /* ++ only if it's a complete line */
323 linenum++;
324 return (char*) !NULL;
325}
326
327
328/*----------------------------------------------------------------------------*
329 | Routine: initpic ( )
330 |
331 | Results: sets all parameters to the normal defaults, possibly overridden
332 | by the command line flags. Initilaize the picture variables,
333 | and output the startup commands to troff to begin the picture.
334 *----------------------------------------------------------------------------*/
335
336initpic()
337{
338 register int i;
339
340 for (i = 0; i < STYLES; i++) { /* line thickness defaults */
341 thick[i] = defthick[i];
342 }
343 for (i = 0; i < FONTS; i++) { /* font name defaults */
344 tfont[i] = defstring[i];
345 }
346 for (i = 0; i < SIZES; i++) { /* font size defaults */
347 tsize[i] = defstring[FONTS + i];
348 }
349
350 gremlinfile[0] = 0; /* filename is "null" */
351
352 toppoint = BIG; /* set the picture bounds out */
353 bottompoint = 0.0; /* of range so they'll be set */
354 leftpoint = BIG; /* by "savebounds" on input */
355 rightpoint = 0.0;
356
acf96fee 357 xscale = scale; /* default scale of individual pictures */
dc80306e
DS
358 width = 0.0; /* size specifications input by user */
359 height = 0.0;
360
361 linethickness = DEFTHICK; /* brush styles */
362 linmod = DEFSTYLE;
363}
364
365
366/*----------------------------------------------------------------------------*
367 | Routine: conv (file_pointer, starting_line)
368 |
369 | Results: at this point, we just passed a ".GS" line in the input file.
370 | conv reads the input and calls "interpret" to process commands,
371 | gathering up information until a ".GE" line is found. It then
372 | calls "HGPrint" to do the translation of the gremlin file to
373 | troff commands.
374 *----------------------------------------------------------------------------*/
375
376conv(fp, baseline)
377register FILE *fp;
378int baseline;
379{
380 register FILE *gfp = NULL;
381 register int done = 0;
382 register ELT *e;
383 ELT *PICTURE;
384 double temp;
385 POINT ptr;
386
387
acf96fee
DS
388 initpic(); /* set defaults, ranges, etc. */
389 strcpy (GScommand, inputline); /* save ".GS" line for later */
dc80306e
DS
390 do {
391 done = (doinput(fp) == NULL); /* test for EOF */
392 done |= (*c1 == '.' && *c2 == 'G' && *c3 == 'E'); /* and .GE */
393
394 if (done) {
395 if (!gremlinfile[0]) {
396 fprintf(stderr, "grn: at line %d: no picture filename.\n",
397 baseline);
398 return;
399 }
400 if ((gfp = fopen(gremlinfile, "r")) == NULL) {
52ace37e
DS
401 char name[100]; /* if the file isn't in the current */
402 /* directory, try the gremlin library */
403 sprintf(name, "%s%s", GREMLIB, gremlinfile);
404 if ((gfp = fopen(name, "r")) == NULL) {
405 fprintf(stderr, "grn: can't open %s\n", gremlinfile);
406 return;
407 }
dc80306e 408 }
dc80306e
DS
409 PICTURE = DBRead(gfp); /* read picture file */
410 fclose(gfp);
411 if (DBNullelt(PICTURE))
412 return;
413 /* if a request is made to make the */
414 /* picture fit into a specific area, */
415 /* set the scale to do that. */
416 temp = (height != 0.0) ?
417 SCREENtoINCH * (bottompoint - toppoint) / height : BIG;
418 troffscale = (width != 0.0) ?
419 SCREENtoINCH * (rightpoint - leftpoint) / width : BIG;
420 if (temp == BIG && troffscale == BIG) {
acf96fee 421 troffscale = xscale;
dc80306e
DS
422 } else {
423 if (temp < troffscale) troffscale = temp;
424 }
425 troffscale *= res; /* change to device units from inches */
426
427 ytop = toppoint * troffscale; /* calculate integer */
428 ybottom = bottompoint * troffscale; /* versions of the */
429 xleft = leftpoint * troffscale; /* picture limits */
430 xright = rightpoint * troffscale;
431 /* save stuff in number registers, */
432 /* register gw = picture width and */
433 /* register gh = picture height, */
434 /* set vertical spacing, no fill, */
435 /* and break (to make sure picture */
436 /* starts on left), and put out the */
437 /* user's ".GS" line. */
dc80306e 438 printf(".nr gw %d\n.nr gh %d\n", xright-xleft, ybottom-ytop);
acf96fee
DS
439 printf(".br\n%s", GScommand);
440 printf(".nr g1 \\n(.f\n.nr g2 \\n(.s\n");
441 printf(".nr g3 \\n(.v\n.nr g4 \\n(.u\n.nf\n.vs 0");
dc80306e
DS
442
443 lastx = xleft; /* note where we are, (upper left */
444 lastyline = lasty = ytop; /* corner of the picture) */
445
446 e = PICTURE;
447 while (!DBNullelt(e)) {
448 HGPrintElt(e); /* traverse picture; print elements */
449 e = DBNextElt(e);
450 }
451 /* end picture at lower left */
452 ptr.x = leftpoint;
453 ptr.y = bottompoint;
52ace37e 454 tmove(&ptr); /* restore default line parameters, */
dc80306e
DS
455 /* put out the ".GE" line from user */
456 /* then restore everything to the way */
457 /* it was before the .GS */
52ace37e 458 printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE);
acf96fee
DS
459 printf(".ft \\n(g1\n.ps \\n(g2\n");
460 printf(".vs \\n(g3u\n.if \\n(g4 .fi\n%s", inputline);
dc80306e
DS
461 } else {
462 interpret(inputline); /* take commands from the input file */
463 }
464 } while (!done);
465}
466
467
468/*----------------------------------------------------------------------------*
469 | Routine: savebounds (x_coordinate, y_coordinate)
470 |
471 | Results: keeps track of the maximum and minimum extent of a picture
472 | in the global variables: left-, right-, top- and bottompoint.
473 | "savebounds" assumes that the points have been oriented to
474 | the correct direction. No scaling has taken place, though.
475 *----------------------------------------------------------------------------*/
476
477savebounds(x, y)
478float x;
479float y;
480{
481 if (x < leftpoint) {
482 leftpoint = x;
483 } else if (x > rightpoint) {
484 rightpoint = x;
485 }
486 if (y < toppoint) {
487 toppoint = y;
488 } else if (y > bottompoint) {
489 bottompoint = y;
490 }
491}
492
493
494/*----------------------------------------------------------------------------*
495 | Routine: interpret (character_string)
496 |
497 | Results: commands are taken from the input string and performed.
acf96fee
DS
498 | Commands are separated by the endofline, and are of the
499 | format:
500 | string1 string2
501 |
502 | where string1 is the command and string2 is the argument.
dc80306e
DS
503 |
504 | Side Efct: font and size strings, plus the gremlin file name and the
505 | width and height variables are set by this routine.
506 *----------------------------------------------------------------------------*/
507
508interpret (line)
acf96fee 509char *line;
dc80306e 510{
acf96fee
DS
511 char str1[MAXINLINE];
512 char str2[MAXINLINE];
513 register char *chr;
514
515 sscanf(line, "%s%s", &str1[0], &str2[0]);
516 for (chr = &str1[0]; *chr; chr++) /* convert command to */
cada353f 517 if(isupper(*chr)) *chr = tolower(*chr); /* lower case */
acf96fee
DS
518 switch (str1[0]) {
519
520 case '1':
521 case '2': /* font sizes */
522 case '3':
523 case '4':
524 tsize[str1[0] - '1'] = calloc(strlen(str2) + 1);
525 strcpy(tsize[str1[0] - '1'], str2);
526 break;
527
528 case 'r': /* roman */
529 tfont[0] = calloc(strlen(str2) + 1);
530 strcpy(tfont[0], str2);
531 break;
532
533 case 'i': /* italics */
534 tfont[1] = calloc(strlen(str2) + 1);
535 strcpy(tfont[1], str2);
536 break;
537
538 case 'b': /* bold */
539 tfont[2] = calloc(strlen(str2) + 1);
540 strcpy(tfont[2], str2);
541 break;
542
543 case 's': /* special */
544 if (str1[1] == 'c') goto scalecommand;
545 tfont[3] = calloc(strlen(str2) + 1);
546 strcpy(tfont[3], str2);
547 break;
548
549 case 't': /* thick */
550 thick[2] = atoi(str2);
551 break;
552
553 case 'm': /* medium */
554 thick[5] = atoi(str2);
555 break;
556
557 case 'n': /* narrow */
558 thick[0] = thick[1] = thick[3] = thick[4] = atoi(str2);
559 break;
560
561 case 'x': /* x */
562 scalecommand: /* scale */
563 xscale *= atof(str2);
564 if (xscale < 0.0) xscale = -xscale;
565 break;
566
567 case 'f': /* file */
568 strcpy(gremlinfile, str2);
569 break;
570
571 case 'w': /* width */
572 width = atof(str2);
573 if (width < 0.0) width = -width;
574 break;
575
576 case 'h': /* height */
577 height = atof(str2);
578 if (height < 0.0) height = -height;
579 break;
580
581 default:
582 break;
583 };
dc80306e 584}