1 /* main.c 1.5 (Berkeley) 83/08/12 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) 21 * and -t (thick). Defaults are 1, 3, and 5 pixels. 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 32 #include <ctype.h> 33 #include "gprint.h" 34 #include "dev.h" 35 36 extern char *calloc(); 37 extern char *rindex(); 38 39 /* database imports */ 40 41 extern HGPrintElt(); 42 extern ELT *DBInit(), *DBRead(); 43 extern POINT *PTInit(), *PTMakePoint(); 44 45 46 char *doinput(); 47 48 #define GREMLIB "/usr/local/gremlib/" 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 64 char SccsId[] = "main.c 1.5 83/08/12"; 65 66 char *printer = DEFAULTDEV; /* device to look up resolution of */ 67 double res; /* that printer's resolution goes here */ 68 69 int linethickness; /* brush styles */ 70 int linmod; 71 int lastx; /* point registers for printing elements */ 72 int lasty; 73 int 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 */ 77 double 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 */ 81 char *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 94 char *defstring[] = { 95 "R\0 ", "I\0 ", "B\0 ", "S\0 ", 96 "10\0 ", "16\0 ", "24\0 ", "36\0 " 97 }; 98 int defthick[STYLES] = { 1, 1, 5, 1, 1, 3 }; /* defaults... */ 99 int style[STYLES] = { DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID }; 100 int thick[STYLES]; /* thicknesses set by defaults, then by commands */ 101 char *tfont[FONTS]; /* fonts originally set to defstring values, then */ 102 char *tsize[SIZES]; /* optionally changed by commands inside grn */ 103 104 double xscale; /* scaling factor from individual pictures */ 105 double troffscale; /* scaling factor at output time */ 106 double width; /* user-request maximum width for picture (in inches) */ 107 double height; /* user-request height */ 108 109 double toppoint; /* remember the picture */ 110 double bottompoint; /* bounds in these variables */ 111 double leftpoint; 112 double rightpoint; 113 114 int ytop; /* these are integer versions of the above */ 115 int ybottom; /* so not to convert each time they're used */ 116 int xleft; 117 int xright; 118 119 int linenum = 0; /* line number of input file */ 120 char inputline[MAXINLINE]; /* spot to filter through the file */ 121 char *c1 = inputline; /* c1, c2, and c3 will be used to */ 122 char *c2 = inputline + 1; /* hunt for lines that begin with */ 123 char *c3 = inputline + 2; /* ".GS" by looking individually */ 124 char GScommand[MAXINLINE]; /* put user's ".GS" command line here */ 125 char 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 140 main(argc, argv) 141 int argc; 142 char **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++; 170 strcpy(defstring[0], arg); 171 break; 172 case 'i': /* select italics font */ 173 if (*++arg == '\0' && argc--) 174 arg = *argv++; 175 strcpy(defstring[1], arg); 176 break; 177 case 'b': /* select bold font */ 178 if (*++arg == '\0' && argc--) 179 arg = *argv++; 180 strcpy(defstring[2], arg); 181 break; 182 case 's': /* select special font */ 183 if (*++arg == '\0' && argc--) 184 arg = *argv++; 185 strcpy(defstring[3], arg); 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 285 getres(name) 286 char *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 314 char *doinput(fp) 315 FILE *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 336 initpic() 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 357 xscale = scale; /* default scale of individual pictures */ 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 376 conv(fp, baseline) 377 register FILE *fp; 378 int 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 388 initpic(); /* set defaults, ranges, etc. */ 389 strcpy (GScommand, inputline); /* save ".GS" line for later */ 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) { 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 } 408 } 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) { 421 troffscale = xscale; 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. */ 438 printf(".nr gw %d\n.nr gh %d\n", xright-xleft, ybottom-ytop); 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"); 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; 454 tmove(&ptr); /* restore default line parameters, */ 455 /* put out the ".GE" line from user */ 456 /* then restore everything to the way */ 457 /* it was before the .GS */ 458 printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); 459 printf(".ft \\n(g1\n.ps \\n(g2\n"); 460 printf(".vs \\n(g3u\n.if \\n(g4 .fi\n%s", inputline); 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 477 savebounds(x, y) 478 float x; 479 float 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. 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. 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 508 interpret (line) 509 char *line; 510 { 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 */ 517 if(isupper(*chr)) *chr = tolower(*chr); /* lower case */ 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 }; 584 } 585