1 #ifndef lint 2 static char Notice[] = "Copyright (c) 1985 Adobe Systems Incorporated"; 3 static char sccsid[] = "@(#)enscript.c 1.8 (Berkeley) 12/31/90"; 4 static char *RCSID = "$Header: enscript.c,v 1.7 89/03/12 01:31:55 van Exp $"; 5 6 #endif 7 /* 8 * enscript.c 9 * 10 * Copyright (c) 1985 Adobe Systems Incorporated 11 * 12 * inspired by Gosling's cz there have been major overhauls, but the input 13 * language is the same: new widths format generate PostScript (much easier 14 * than Press) new and renamed switches (to match 4.2bsd lpr spooler) obeys 15 * PostScript comment conventions doesn't worry so much about fonts 16 * (everything is scalable and rotatable, use PS font names, no face 17 * properties) 18 * 19 * enscript generates POSTSCRIPT print files of a special kind the coordinate 20 * system is in 20ths of a point. (1440 per inch) 21 * 22 * Edit History: Andrew Shore: Mon Nov 18 14:05:05 1985 End Edit History. 23 * 24 * RCSLOG: $Log: enscript.c,v $ 25 * Revision 1.7 89/03/12 01:31:55 van 26 * we have to escape special chars in title strings. 27 * 28 * Revision 1.6 89/03/10 00:30:39 van 29 * might as well let the user change everything. 30 * 31 * Revision 1.5 89/03/09 23:19:17 van 32 * gcc lint. 33 * 34 * Revision 1.4 89/03/09 23:08:50 van 35 * let user set the fonts used in 'gaudy' mode 36 * 37 * Revision 1.3 88/03/06 17:23:58 leres 38 * Fix logic bug; only spool output if that's want we want. 39 * 40 * Revision 1.2 86/07/03 00:06:31 van 41 * reformatted. removed SYSV ifdefs. 42 * Revision 1.1 86/07/03 00:03:12 van Initial 43 * revision 44 * 45 * Revision 2.1 85/11/24 11:48:55 shore Product Release 2.0 46 * 47 * Revision 1.3 85/11/20 00:10:01 shore Added System V support (input options 48 * and spooling) margins/linecount reworked (Dataproducts) incompatible 49 * options changes, getopt! Guy Riddle's Gaudy mode and other changes output 50 * spooling messages, pages, copies 51 * 52 * Revision 1.2 85/05/14 11:22:14 shore *** empty log message *** 53 * 54 * 55 */ 56 57 #define POSTSCRIPTPRINTER "PostScript" 58 59 #define BODYROMAN "Courier" 60 #define BODYSZ 10 61 #define HEADFONT "Courier-Bold" 62 #define HEADSZ 10 63 #define GHEADFONT "Helvetica-Bold" 64 #define GHEADSZ 14 65 #define SHEADFONT "Times-Bold" 66 #define SHEADSZ 12 67 #define PGNUMFONT "Helvetica-Bold" 68 #define PGNUMSZ 24 69 #define DATEFONT "Times-Bold" 70 #define DATESZ 12 71 72 #ifdef DEBUG 73 #define debugp(x) {fprintf x ; VOIDC fflush(stderr);} 74 #else 75 #define debugp(x) 76 #endif 77 78 #define UperInch (1440L) 79 #define PtsPerInch 72 80 #define UperPt 20 81 82 /* virtual page is 8 x 10.5 inches (for Toshiba compat) */ 83 #define PageWidth ((long) UperInch*8) 84 #define PageLength ((long)((UperInch*21)/2)) 85 86 /* #define PageLength ((long) ((long) (UperInch*(8*11-3)))/8) */ 87 /* #define PageWidth ((long) ((long) (UperInch*(8*17-3)))/8) */ 88 89 /* true page is 8.5 x 11 inches */ 90 #define TruePageWidth (UperInch*17/2) 91 #define TruePageLength ((long)(UperInch*11)) 92 93 #include <stdio.h> 94 #include <ctype.h> 95 #include <pwd.h> 96 #include <strings.h> 97 #include <sys/time.h> 98 #include <signal.h> 99 #include <sys/types.h> 100 #include <sys/stat.h> 101 #include "transcript.h" 102 103 #define LPR "lpr" 104 105 #define MAXBAD 20 /* number of bad chars to pass before 106 * complaint */ 107 108 private struct stat S; 109 110 extern double atof(); 111 extern char *optarg; /* getopt current opt char */ 112 extern int optind; /* getopt argv index */ 113 114 private VOID int1 (); 115 private FlushShow(); 116 117 #define FSIZEMAX 256 /* number of chars per font */ 118 119 /* the layout of a font information block */ 120 struct font { 121 char name[100]; /* PostScript font name */ 122 int dsize; /* size */ 123 int Xwid[FSIZEMAX]; /* X widths for each character */ 124 }; 125 126 private struct font fonts[16]; /* 16 possible fonts at one time */ 127 private int nf = 0; /* number of fonts known about */ 128 129 private int TabWidth; /* width of a tab */ 130 private int BSWidth; /* width of a backspace */ 131 132 private long UperLine = UperInch / 7; 133 private long UperHLine = UperInch / 7; 134 135 private char *prog; /* program name argv[0] */ 136 private char *libdir; /* place for prolog and widths files */ 137 private char *tempdir; /* place for temp file */ 138 private char TempName[100]; /* name of temporary PostScript file */ 139 private char OutName[256] = ""; /* filename for disk output */ 140 private int PipeOut = FALSE; /* output to stdout (-p -) */ 141 private int ListOmitted = FALSE;/* list omitted chars on the tty */ 142 private int BeQuiet = FALSE; /* suppress stderr error messages */ 143 private int Verbose = FALSE; /* silly informational messages */ 144 private int Gaudy = FALSE; /* pretty bars along the top */ 145 private int LPTsimulate = FALSE;/* an lpt should be simulated */ 146 private int Lines = 0; /* max lines per page */ 147 private int LinesLeft = 66; /* lines left on page when in LPT mode */ 148 private int LineMax = 64; /* ? */ 149 private int SeenText = TRUE; /* true if seen some text on this page */ 150 private int OutOnly = FALSE; /* PS file only wanted */ 151 private int Rotated = FALSE; /* pages to be rotated landscape */ 152 private int PreFeed = FALSE; /* prefeed should be enabled */ 153 private int TwoColumn = FALSE; /* two-column mode */ 154 private int FirstCol = TRUE; /* we're printing column 1 */ 155 private int NoTitle = FALSE; /* title line is suppressed */ 156 private int Cvted = FALSE; /* converted a file to PS format */ 157 158 private int IgnoreGarbage = FALSE; /* garbage should be ignored */ 159 private int SeenFont = FALSE; /* we've seen a font request */ 160 private int SeenFile = FALSE; /* a file has been processed */ 161 private int ScannedFonts = FALSE; /* we've scanned the font file */ 162 private char *FileName = 0; /* name of file currently being PSed */ 163 private char *FileDate = 0; /* last mod date of file being PSed */ 164 private char DateStr[27]; /* thanks, but no thanks ctime! */ 165 private int spoolNoBurst = FALSE; /* no break page flag for spooler */ 166 167 #ifdef BSD 168 private char *spoolJobClass = NULL; 169 private char *spoolJobName = NULL; 170 171 #endif 172 private char *PrinterName = NULL; 173 private int spoolNotify = 0; 174 private char *spoolCopies = "1"; 175 176 private char tempstr[256]; /* various path names */ 177 178 private int CurFont; /* current Font */ 179 private int fontindex[26]; /* table of fonts, indexed by font designator 180 * ('a' to 'z') */ 181 182 /* indexes for default fonts */ 183 184 #define Roman fontindex['r'-'a'] 185 #define HeaderFont fontindex['h'-'a'] 186 #define SHeaderFont fontindex['i'-'a'] 187 #define DateFont fontindex['j'-'a'] 188 #define PgNumFont fontindex['k'-'a'] 189 190 private long cX, cY; /* current page positions */ 191 private long dX, dY; /* desired page positions */ 192 private long lX, lY; /* page positions of the start of the line */ 193 private long crX, crY; /* X and Y increments to apply to CR's */ 194 private long maxX; /* maximum x coord on line */ 195 private long minY; /* minimum y coord on page */ 196 private long Xoffset; /* amount to offset left margin */ 197 198 #define None 0 199 #define RelX 1 200 #define RelY 2 201 #define RelXY 3 202 #define AbsX 4 203 #define AbsY 8 204 #define AbsXY 12 205 206 private int movepending; /* moveto pending coords on stack */ 207 private int showpending; /* number of characters waiting to be shown */ 208 private int pagepending; /* start on next page when have something to 209 * print */ 210 private char *UsersHeader = NULL; /* user specified heading */ 211 private char *Header = NULL; /* generated header (usually FileName) */ 212 private char *Header2 = NULL; /* second header line for Gaudy */ 213 private int Page = 0; /* current page number */ 214 private int TotalPages = 0; /* total number of pages printed */ 215 private int TruncChars = 0; /* number of characters truncated */ 216 private int UndefChars = 0; /* number of characters skipped because they 217 * weren't defined in some font */ 218 private int BadChars = 0; /* number of bad characters seen so far */ 219 private FILE *OutFile = NULL; /* output ps file */ 220 221 222 /* decode a fontname string - e.g. Courier10 Helvetica-Bold12 */ 223 private 224 decodefont (name, f) 225 register char *name; 226 register struct font *f; 227 { 228 register char *d, *p; 229 230 p = name; 231 d = f->name; 232 f->dsize = 0; 233 while (isascii (*p) && (isalpha (*p) || (*p == '-'))) { 234 *d++ = *p++; 235 } 236 *d++ = '\0'; 237 while (isascii (*p) && isdigit (*p)) { 238 f->dsize = f->dsize * 10 + *p++ - '0'; 239 } 240 if (*p || !f->dsize || !f->name[0]) { 241 fprintf (stderr, "%s: poorly formed font name & size: \"%s\"\n", 242 prog, name); 243 exit (1); 244 } 245 } 246 247 248 #define NOTDEF 0x8000 249 #define ForAllFonts(p) for(p = &fonts[nf-1]; p >= &fonts[0]; p--) 250 251 252 /* 253 * Scan the font metrics directory looking for entries that match the entries 254 * in ``fonts''. For entries that are found the data in the font description 255 * is filled in, if any are missing, it dies horribly. 256 */ 257 private VOID ScanFont () 258 { 259 register struct font *f; 260 register FILE *FontData;/* afm file */ 261 char *c; 262 int ccode, cwidth, inChars; 263 char FontFile[512]; /* afm file name */ 264 char afmbuf[BUFSIZ]; 265 266 267 if (!SeenFont) { 268 if (Lines == 0) 269 Lines = 64; 270 if (Rotated && TwoColumn) 271 fonts[Roman].dsize = 7; 272 } 273 /* loop through fonts, find and read metric entry in dir */ 274 ForAllFonts (f) { 275 VOIDC mstrcat (FontFile, libdir, "/", sizeof FontFile); 276 277 VOIDC mstrcat (FontFile, FontFile, f->name, sizeof FontFile); 278 279 VOIDC mstrcat (FontFile, FontFile, ".afm", sizeof FontFile); 280 281 if ((FontData = fopen (FontFile, "r")) == NULL) { 282 fprintf (stderr, "%s: can't open font metrics file %s\n", 283 prog, FontFile); 284 exit (1); 285 } 286 /* read the .afm file to get the widths */ 287 for (ccode = 0; ccode < FSIZEMAX; ccode++) 288 f->Xwid[ccode] = NOTDEF; 289 290 inChars = 0; 291 while (fgets (afmbuf, sizeof afmbuf, FontData) != NULL) { 292 /* strip off newline */ 293 if ((c = INDEX (afmbuf, '\n')) == 0) { 294 fprintf (stderr, "%s: AFM file %s line too long %s\n", 295 prog, FontFile, afmbuf); 296 exit (1); 297 } 298 *c = '\0'; 299 if (*afmbuf == '\0') 300 continue; 301 if (strcmp (afmbuf, "StartCharMetrics") == 0) { 302 inChars++; 303 continue; 304 } 305 if (strcmp (afmbuf, "EndCharMetrics") == 0) 306 break; 307 if (inChars == 1) { 308 if (sscanf (afmbuf, "C %d ; WX %d ;", &ccode, &cwidth) != 2) { 309 fprintf (stderr, "%s: trouble with AFM file %s\n", 310 prog, FontFile); 311 exit (1); 312 } 313 /* get out once we see an unencoded char */ 314 if (ccode == -1) 315 break; 316 if (ccode > 255) 317 continue; 318 f->Xwid[ccode] = 319 (short) (((long) cwidth * (long) f->dsize * (long) UperPt) 320 / 1000L); 321 continue; 322 } 323 } 324 VOIDC fclose (FontData); 325 } 326 327 /* 328 * Tab width is problematical for proportionally-spaced fonts. 329 * Attempt to make tabs wide enough that things hand-tabulated 330 * for monospaced fonts still fit in columns. 331 */ 332 if (fonts[Roman].Xwid['0'] == fonts[Roman].Xwid['M']) 333 TabWidth = fonts[Roman].Xwid['0'] * 8; /* 8 * figure width */ 334 else 335 TabWidth = fonts[Roman].Xwid['0'] * 10; /* 10 * figure width */ 336 BSWidth = fonts[Roman].Xwid[' ']; /* space width */ 337 338 UperLine = (fonts[Roman].dsize + 1) * UperPt; 339 340 if (LPTsimulate) { 341 UperHLine = UperLine; 342 Lines = LineMax = 66; 343 } else { 344 UperHLine = (fonts[HeaderFont].dsize + 1) * UperPt; 345 } 346 347 crX = 0; 348 crY = -UperLine; 349 350 } 351 352 353 /* 354 * Return a font number for the font with the indicated name and size. Adds 355 * info to the font list for the eventual search. 356 */ 357 private int 358 DefineFont (name, size) 359 char *name; 360 { 361 register struct font *p; 362 363 p = &fonts[nf]; 364 VOIDC strcpy (p->name, name); 365 366 p->dsize = size; 367 return (nf++); 368 } 369 370 ResetFont(indx, name, size) 371 char *name; 372 { 373 register struct font *p; 374 375 p = &fonts[indx]; 376 VOIDC strcpy (p->name, name); 377 p->dsize = size; 378 } 379 380 /* dump the fonts to the PS file for setup */ 381 private VOID 382 DumpFonts () 383 { 384 register struct font *f; 385 386 ForAllFonts (f) { 387 fprintf (OutFile, "%d %d /%s\n", f - &fonts[0], f->dsize * UperPt, f->name); 388 } 389 fprintf (OutFile, "%d SetUpFonts\n", nf); 390 } 391 392 /* add a shown character to the PS file */ 393 private VOID 394 OUTputc (c) 395 register int c; 396 { 397 if (!showpending) { 398 putc ('(', OutFile); 399 showpending = TRUE; 400 } 401 if (c == '\\' || c == '(' || c == ')') 402 putc ('\\', OutFile); 403 if ((c > 0176) || (c < 040)) { 404 putc ('\\', OutFile); 405 putc ((c >> 6) + '0', OutFile); 406 putc (((c >> 3) & 07) + '0', OutFile); 407 putc ((c & 07) + '0', OutFile); 408 } else 409 putc (c, OutFile); 410 } 411 412 /* put a correctly escaped string to the PS file */ 413 private VOID 414 OUTstr(s) 415 register char *s; 416 { 417 if (!showpending) { 418 putc ('(', OutFile); 419 showpending = TRUE; 420 } 421 while (*s) 422 OUTputc(*s++); 423 424 putc(')', OutFile); 425 showpending = FALSE; 426 } 427 428 /* Set the current font */ 429 private VOID 430 SetFont (f) 431 int f; 432 { 433 FlushShow (); 434 CurFont = f; 435 fprintf (OutFile, "%d F\n", f); 436 } 437 438 /* 439 * put a character onto the page at the desired X and Y positions. If the 440 * current position doesn't agree with the desired position, put out movement 441 * directives. Leave the current position updated to account for the 442 * character. 443 */ 444 private VOID 445 ShowChar (c) 446 register int c; 447 { 448 register struct font *f; 449 register long nX, nY; 450 static level = 0; 451 VOID PageEject(), InitPage(); 452 453 level++; 454 f = &fonts[CurFont]; 455 456 if (f->Xwid[c] == NOTDEF) { 457 UndefChars++; 458 if (ListOmitted) 459 fprintf (stderr, "%s: \\%03o not found in font %s\n", 460 prog, c, f->name); 461 if (level <= 1) { 462 ShowChar ('\\'); 463 ShowChar ((c >> 6) + '0'); 464 ShowChar (((c >> 3) & 07) + '0'); 465 ShowChar ((c & 07) + '0'); 466 } 467 level--; 468 return; 469 } 470 nX = dX + f->Xwid[c]; /* resulting position after showing this char */ 471 nY = dY; 472 473 if (c != ' ' || ((cX == dX) && (cY == dY))) { 474 /* 475 * If character doesn't fit on this line 476 * (and we're not at left margin), simulate newline 477 * and then call ourselves recursively. 478 */ 479 if (nX > maxX && dX > lX) { 480 SeenText = TRUE; 481 dY = lY = lY + crY; 482 dX = lX = lX + crX; 483 if ((dY < minY) || (--LinesLeft <= 0)) { 484 PageEject (); 485 if (pagepending) 486 InitPage (); 487 } 488 ShowChar(c); 489 level--; 490 return; 491 } 492 if (cX != dX) { 493 if (cY != dY) { 494 FlushShow (); 495 /* absolute x, relative y */ 496 fprintf (OutFile, "%ld %ld", dX, dY); 497 movepending = AbsXY; 498 } else { 499 FlushShow (); 500 fprintf (OutFile, "%ld", dX - cX); /* relative x */ 501 movepending = RelX; 502 } 503 } else if (cY != dY) { 504 FlushShow (); 505 fprintf (OutFile, "%ld", dY - cY); /* relative y */ 506 movepending = RelY; 507 } 508 OUTputc (c); 509 showpending = TRUE; 510 cX = nX; 511 cY = nY; 512 } 513 dX = nX; 514 dY = nY; 515 516 level--; 517 } 518 519 /* put out a shown string to the PS file */ 520 private VOID 521 ShowStr (s) 522 register char *s; 523 { 524 while (*s) { 525 if (*s >= 040) 526 ShowChar (*s); 527 s++; 528 } 529 } 530 531 /* flush pending show */ 532 private 533 FlushShow () 534 { 535 if (showpending) { 536 putc (')', OutFile); 537 switch (movepending) { 538 case RelX: 539 putc ('X', OutFile); 540 break; 541 case RelY: 542 putc ('Y', OutFile); 543 break; 544 case AbsXY: 545 putc ('B', OutFile); 546 break; 547 case None: 548 putc ('S', OutFile); 549 break; 550 } 551 putc ('\n', OutFile); 552 movepending = None; 553 showpending = FALSE; 554 } 555 } 556 557 /* put out a page heading to the PS file */ 558 private VOID 559 InitPage () 560 { 561 char header[200]; 562 register int OldFont = CurFont; 563 564 TotalPages++; 565 fprintf (OutFile, "%%%%Page: ? %d\n", TotalPages); 566 fprintf (OutFile, "StartPage\n"); 567 SeenText = FALSE; 568 cX = cY = -1; 569 showpending = pagepending = FALSE; 570 FirstCol = TRUE; 571 if (Rotated) { 572 fprintf (OutFile, "Landscape\n"); 573 lX = dX = UperInch / 4 + Xoffset; 574 lY = dY = PageLength - (UperHLine * 3) / 2; 575 maxX = TruePageLength; 576 /* minY = (PageLength - TruePageWidth) + 3*UperLine+480; */ 577 minY = (TruePageLength - TruePageWidth) + (TruePageWidth - PageWidth) / 2; 578 } else { 579 lX = dX = Xoffset + 580 (TwoColumn? (UperInch * 0.3) : ((UperInch * 5) / 8)); 581 lY = dY = PageLength - UperHLine; 582 maxX = TruePageWidth; 583 minY = (UperInch / 4); /* 0.25 inches */ 584 } 585 movepending = None; 586 cX = dX; 587 cY = dY; 588 589 if (!NoTitle) { 590 if (Gaudy) { 591 OUTstr(UsersHeader); 592 if (Header2) 593 OUTstr(Header2); 594 else 595 OUTstr(Header); 596 fprintf (OutFile, "[%s](%d)Gaudy\n", FileDate, ++Page); 597 cX = cY = 0; /* force moveto here */ 598 } else { 599 SetFont (HeaderFont); 600 fprintf (OutFile, "%ld %ld ", cX, cY); 601 movepending = AbsXY; 602 if (UsersHeader) { 603 if (*UsersHeader == 0) { 604 fprintf (OutFile, "()B\n"); 605 movepending = None; 606 showpending = FALSE; 607 } else 608 ShowStr (UsersHeader); 609 } else { 610 VOIDC sprintf (header, "%s %s %d", 611 Header? Header : " ", FileDate, ++Page); 612 613 ShowStr (header); 614 } 615 FlushShow (); 616 } 617 dX = lX = lX + crX * 2; 618 dY = lY = lY + crY * 2; 619 } else { 620 /* fake it to force a moveto */ 621 cX = cY = 0; 622 } 623 if (TwoColumn) 624 maxX = maxX / 2 - BSWidth; 625 else 626 maxX -= ((long) (UperInch * 0.3)); 627 LineMax = (lY - minY) / (-crY); 628 if ((Lines <= 0) || (Lines > LineMax)) 629 Lines = LinesLeft = LineMax; 630 else 631 LinesLeft = Lines; 632 SetFont (OldFont); 633 } 634 635 private VOID 636 ClosePage () 637 { 638 FlushShow (); 639 if (!pagepending) 640 fprintf (OutFile, "EndPage\n"); 641 pagepending = TRUE; 642 } 643 644 /* skip to a new page */ 645 private VOID 646 PageEject () 647 { 648 if (TwoColumn && FirstCol) { 649 FirstCol = FALSE; 650 if (Rotated) { 651 lY = dY = PageLength - (UperHLine * 3) / 2; 652 lX = dX = Xoffset + TruePageLength / 2; 653 maxX = TruePageLength - UperInch * 0.3; 654 } else { 655 lY = dY = PageLength - UperHLine; 656 lX = dX = Xoffset + TruePageWidth / 2; 657 maxX = TruePageWidth - UperInch * 0.3; 658 } 659 if (!NoTitle) { 660 dX = lX = lX + crX * 2; 661 dY = lY = lY + crY * 2; 662 } 663 } else 664 ClosePage (); 665 LinesLeft = Lines; 666 SeenText = FALSE; 667 } 668 669 private VOID 670 CommentHeader () 671 { 672 long clock; 673 struct passwd *pswd; 674 char hostname[40]; 675 676 /* copy the file, prepending a new comment header */ 677 fprintf (OutFile, "%%!%s\n", COMMENTVERSION); 678 fprintf (OutFile, "%%%%Creator: "); 679 pswd = getpwuid ((int) getuid ()); 680 VOIDC gethostname (hostname, (int) sizeof hostname); 681 682 fprintf (OutFile, "%s:%s (%s)\n", hostname, pswd->pw_name, pswd->pw_gecos); 683 fprintf (OutFile, "%%%%Title: %s\n", (FileName ? FileName : "stdin")); 684 fprintf (OutFile, "%%%%CreationDate: %s", (VOIDC time (&clock), ctime (&clock))); 685 } 686 687 /* Copy the standard input file to the PS file */ 688 private VOID 689 CopyFile () 690 { 691 register int c; 692 693 if (OutFile == 0) { 694 if (OutOnly) { 695 OutFile = PipeOut ? stdout : fopen (OutName, "w"); 696 } else { 697 VOIDC mktemp (mstrcat (TempName, tempdir, 698 ENSCRIPTTEMP, sizeof TempName)); 699 VOIDC strcpy (OutName, TempName); 700 701 VOIDC umask (077); 702 703 OutFile = fopen (TempName, "w"); 704 } 705 } 706 if (OutFile == NULL) { 707 fprintf (stderr, "%s: can't create PS file %s\n", prog, TempName); 708 exit (1); 709 } 710 if (!ScannedFonts) { 711 ScannedFonts = TRUE; 712 ScanFont (); 713 } 714 if (!Cvted) { 715 CommentHeader (); 716 if (nf) { 717 register struct font *f; 718 719 fprintf (OutFile, "%%%%DocumentFonts:"); 720 ForAllFonts (f) { 721 fprintf (OutFile, " %s", f->name); 722 } 723 fprintf (OutFile, "\n"); 724 } 725 /* copy in fixed prolog */ 726 if (copyfile (mstrcat (tempstr, libdir, ENSCRIPTPRO, sizeof tempstr), 727 OutFile)) { 728 fprintf (stderr, "%s: trouble copying prolog file\n", prog); 729 exit (1); 730 } 731 fprintf (OutFile, "StartEnscriptDoc %% end fixed prolog\n"); 732 DumpFonts (); 733 if (Gaudy) 734 fprintf (OutFile, "%s %s InitGaudy\n", 735 Rotated ? "10.55" : "8.0", TwoColumn ? "true" : "false"); 736 if (PreFeed) { 737 fprintf (OutFile, "true DoPreFeed\n"); 738 } 739 fprintf (OutFile, "%%%%EndProlog\n"); 740 } 741 Cvted = TRUE; 742 743 Page = 0; 744 BadChars = 0; /* give each file a clean slate */ 745 pagepending = TRUE; 746 while ((c = getchar ()) != EOF) 747 if ((c > 0177 || c < 0) && (!IgnoreGarbage)) { 748 if (BadChars++ > MAXBAD) { /* allow some kruft but 749 * not much */ 750 fprintf (stderr, "%s: \"%s\" not a text file? Try -g.\n", 751 prog, FileName ? FileName : "(stdin)"); 752 if (!PipeOut) 753 VOIDC unlink (OutName); 754 755 exit (1); 756 } 757 } else if (c >= ' ') { 758 if (pagepending) 759 InitPage (); 760 ShowChar (c); 761 } else 762 switch (c) { 763 case 010: /* backspace */ 764 dX -= BSWidth; 765 break; 766 case 015: /* carriage return ^M */ 767 dY = lY; 768 dX = lX; 769 break; 770 case 012: /* linefeed ^J */ 771 if (pagepending) 772 InitPage (); 773 if (dX != lX || dY != lY || !LPTsimulate || SeenText) { 774 SeenText = TRUE; 775 dY = lY = lY + crY; 776 dX = lX = lX + crX; 777 } else 778 LinesLeft = LineMax; 779 if ((dY < minY) || (--LinesLeft <= 0)) 780 PageEject (); 781 break; 782 case 033: /* escape */ 783 switch (c = getchar ()) { 784 case '7': /* backup one line */ 785 dY = lY = lY - crY; 786 dX = lX = lX - crX; 787 break; 788 case '8': /* backup 1/2 line */ 789 dY -= crY / 2; 790 dX -= crX / 2; 791 break; 792 case '9': /* forward 1/2 linefeed */ 793 dY += crY / 2; 794 dX += crX / 2; 795 break; 796 case 'F': /* font setting */ 797 c = getchar (); 798 if ('a' <= c && c <= 'z') 799 if (fontindex[c - 'a'] >= 0) 800 SetFont (fontindex[c - 'a']); 801 else { 802 fprintf (stderr, "%s: font '%c' not defined\n", 803 prog, c); 804 exit (1); 805 } 806 else { 807 fprintf (stderr, "%s: bad font code in file: '%c'\n", 808 prog, c); 809 exit (1); 810 } 811 break; 812 case 'D': /* date string */ 813 VOIDC fgets (DateStr, sizeof(DateStr), stdin); 814 FileDate = DateStr; 815 break; 816 case 'U': /* new "user's" heading */ 817 { 818 static char header[100]; 819 VOIDC fgets (header, sizeof(header), stdin); 820 821 UsersHeader = header; 822 break; 823 } 824 case 'H': /* new heading */ 825 { 826 static char header[100]; 827 828 VOIDC fgets (header, sizeof(header), stdin); 829 830 ClosePage (); 831 Header2 = header; 832 Page = 0; 833 break; 834 } 835 } 836 break; 837 case '%': /* included PostScript line */ 838 { 839 char psline[200]; 840 VOIDC fgets (psline, sizeof(psline), stdin); 841 842 fprintf (OutFile, "%s\n", psline); 843 break; 844 } 845 case 014: /* form feed ^L */ 846 PageEject (); 847 break; 848 case 011: /* tab ^I */ 849 if (pagepending) 850 InitPage (); 851 dX += TabWidth - ((dX - lX) % TabWidth); 852 break; 853 default: /* other control character, take your 854 * chances */ 855 if (pagepending) 856 InitPage (); 857 ShowChar (c); 858 } 859 ClosePage (); 860 } 861 862 863 /* 864 * close the PS file 865 */ 866 private VOID 867 ClosePS () 868 { 869 fprintf (OutFile, "%%%%Trailer\n"); 870 if (PreFeed) { 871 fprintf (OutFile, "false DoPreFeed\n"); 872 } 873 fprintf (OutFile, "EndEnscriptDoc\nEnscriptJob restore\n"); 874 } 875 876 877 private VOID 878 SetTime (tval) 879 long tval; 880 { 881 struct tm *tp; 882 883 if (Gaudy) { 884 tp = localtime (&tval); 885 VOIDC sprintf (DateStr, "(%02d/%02d/%02d)(%02d:%02d:%02d)", 886 tp->tm_year, tp->tm_mon + 1, tp->tm_mday, 887 tp->tm_hour, tp->tm_min, tp->tm_sec); 888 } else { 889 VOIDC strcpy (DateStr, ctime (&tval)); 890 891 DateStr[24] = '\0'; /* get rid of newline */ 892 } 893 894 FileDate = DateStr; 895 } 896 897 898 899 900 #define ARGS "12gGBlL:oqrRkKf:F:b:p:J:C:P:#:mhO:s:v" 901 902 private VOID ParseArgs (ac, av) 903 int ac; 904 char **av; 905 { 906 int argp; 907 908 while ((argp = getopt (ac, av, ARGS)) != EOF) { 909 debugp ((stderr, "option: %c\n", argp)); 910 switch (argp) { 911 case '1': 912 TwoColumn = FALSE; 913 break; 914 case '2': 915 TwoColumn = TRUE; 916 break; 917 case 'G': 918 Gaudy = TRUE; 919 if (UsersHeader == NULL) 920 UsersHeader = ""; 921 if (Header == NULL) 922 Header = ""; 923 /* warning: fonts must be defined in this order! */ 924 ResetFont(HeaderFont, GHEADFONT, GHEADSZ); 925 if (SHeaderFont == -1) 926 SHeaderFont = DefineFont(SHEADFONT, SHEADSZ); 927 DateFont = DefineFont(DATEFONT, DATESZ); 928 PgNumFont = DefineFont(PGNUMFONT, PGNUMSZ); 929 break; 930 case 'g': 931 IgnoreGarbage = TRUE; 932 break; 933 case 'B': 934 NoTitle = TRUE; 935 break; 936 case 'l': 937 LPTsimulate = TRUE; 938 NoTitle = TRUE; 939 Lines = 66; 940 break; 941 case 'L': 942 Lines = atoi (optarg); 943 break; 944 case 'o': 945 ListOmitted = TRUE; 946 break; 947 case 'q': 948 BeQuiet = TRUE; 949 break; 950 case 'r': 951 Rotated = TRUE; 952 break; 953 case 'R': 954 Rotated = FALSE; 955 break; 956 case 'k': 957 PreFeed = TRUE; 958 break; 959 case 'K': 960 PreFeed = FALSE; 961 break; 962 case 'f':{ 963 register char font = 'r'; 964 int *whichfont; 965 966 if (*optarg == '-') { 967 font = *++optarg; 968 optarg++; 969 } 970 if ((font < 'a') || ('z' < font)) { 971 fprintf (stderr, 972 "%s: '%c' isn't a valid font designator.\n", 973 prog, font); 974 exit (1); 975 } 976 whichfont = &fontindex[font - 'a']; 977 if (*whichfont < 0) 978 *whichfont = nf++; 979 decodefont (optarg, &fonts[*whichfont]); 980 if (font == 'r') 981 SeenFont++; 982 } 983 break; 984 case 'F': 985 if (HeaderFont == -1) 986 HeaderFont = nf++; 987 decodefont (optarg, &fonts[HeaderFont]); 988 break; 989 case 'b': 990 UsersHeader = optarg; 991 break; 992 case 's': 993 Header2 = optarg; 994 break; 995 case 'p': 996 OutOnly = TRUE; 997 VOIDC strcpy (OutName, optarg); 998 999 if (strcmp (OutName, "-") == 0) 1000 PipeOut = TRUE; 1001 break; 1002 case 'h': 1003 spoolNoBurst = TRUE; 1004 break; 1005 /* BSD lpr options processing */ 1006 case 'm': 1007 spoolNotify = argp; 1008 break; 1009 case '#': 1010 spoolCopies = optarg; 1011 break; 1012 case 'C': 1013 spoolJobClass = optarg; 1014 break; 1015 case 'J': 1016 spoolJobName = optarg; 1017 break; 1018 case 'P': 1019 PrinterName = optarg; 1020 break; 1021 case '?': 1022 /* bad option */ 1023 break; 1024 case 'O': 1025 Xoffset = atof(optarg) * (double)UperInch; 1026 if (Xoffset < 0) 1027 Xoffset = 0; 1028 break; 1029 case 'v': 1030 Verbose = TRUE; 1031 break; 1032 default: 1033 break; 1034 } 1035 } 1036 } 1037 1038 1039 /* addarg is used to construct an argv for the spooler */ 1040 private VOID 1041 addarg (argv, argstr, argc) 1042 char **argv; 1043 char *argstr; 1044 register int *argc; 1045 { 1046 register char *p = (char *) malloc ((unsigned) (strlen (argstr) + 1)); 1047 VOIDC strcpy (p, argstr); 1048 1049 argv[(*argc)++] = p; 1050 argv[*argc] = '\0'; 1051 } 1052 1053 1054 private VOID 1055 SpoolIt () 1056 { 1057 char temparg[200]; 1058 char *argstr[200]; 1059 int nargs = 0; 1060 1061 1062 addarg (argstr, LPR, &nargs); 1063 /* BSD spooler */ 1064 if (atoi (spoolCopies) > 1) { 1065 VOIDC sprintf (temparg, "-#%s", spoolCopies); 1066 1067 addarg (argstr, temparg, &nargs); 1068 } 1069 if ((PrinterName == NULL) && ((PrinterName = envget ("PRINTER")) == NULL)) { 1070 PrinterName = POSTSCRIPTPRINTER; 1071 } 1072 VOIDC sprintf (temparg, "-P%s", PrinterName); 1073 1074 addarg (argstr, temparg, &nargs); 1075 1076 if (spoolJobClass) { 1077 addarg (argstr, "-C", &nargs); 1078 addarg (argstr, spoolJobClass, &nargs); 1079 } 1080 addarg (argstr, "-J", &nargs); 1081 if (spoolJobName) { 1082 addarg (argstr, spoolJobName, &nargs); 1083 } else { 1084 if (!FileName) 1085 addarg (argstr, "stdin", &nargs); 1086 else 1087 addarg (argstr, FileName, &nargs); 1088 } 1089 if (spoolNotify) { 1090 addarg (argstr, "-m", &nargs); 1091 } 1092 if (spoolNoBurst) { 1093 addarg (argstr, "-h", &nargs); 1094 } 1095 /* remove the temporary file after spooling */ 1096 addarg (argstr, "-r", &nargs); /* should we use a symbolic link too? */ 1097 addarg (argstr, TempName, &nargs); 1098 1099 #ifdef DEBUG 1100 { 1101 int i; 1102 1103 fprintf (stderr, "called spooler with: "); 1104 for (i = 0; i < nargs; i++) 1105 fprintf (stderr, "(%s)", argstr[i]); 1106 fprintf (stderr, "\n"); 1107 } 1108 #endif 1109 1110 execvp (LPR, argstr); 1111 pexit2 (prog, "can't exec spooler", 1); 1112 } 1113 1114 1115 private char *eargv[60]; 1116 private int eargc = 1; 1117 1118 1119 main (argc, argv) 1120 int argc; 1121 char **argv; 1122 { 1123 register char *p; /* pointer to "ENSCRIPT" in env */ 1124 1125 prog = *argv; /* argv[0] is program name */ 1126 1127 debugp ((stderr, "PL %ld PW %ld TPL %ld TPW %ld\n", PageLength, PageWidth, TruePageLength, TruePageWidth)); 1128 1129 if (signal (SIGINT, int1) == SIG_IGN) { 1130 VOIDC signal (SIGINT, SIG_IGN); 1131 VOIDC signal (SIGQUIT, SIG_IGN); 1132 VOIDC signal (SIGHUP, SIG_IGN); 1133 VOIDC signal (SIGTERM, SIG_IGN); 1134 } else { 1135 VOIDC signal (SIGQUIT, int1); 1136 VOIDC signal (SIGHUP, int1); 1137 VOIDC signal (SIGTERM, int1); 1138 } 1139 1140 { 1141 register int i; 1142 1143 for (i = 0; i < 26; i++) 1144 fontindex[i] = -1; 1145 } 1146 1147 if ((libdir = envget ("PSLIBDIR")) == NULL) 1148 libdir = LibDir; 1149 if ((tempdir = envget ("PSTEMPDIR")) == NULL) 1150 tempdir = TempDir; 1151 1152 Roman = CurFont = DefineFont (BODYROMAN, BODYSZ); 1153 HeaderFont = DefineFont (HEADFONT, HEADSZ); 1154 1155 /* process args in environment variable ENSCRIPT */ 1156 if (p = envget ("ENSCRIPT")) { 1157 while (1) { 1158 register char quote = ' '; 1159 1160 while (*p == ' ') 1161 p++; 1162 if ((*p == '"') || (*p == '\'')) 1163 quote = *p++; 1164 eargv[eargc++] = p; 1165 while ((*p != quote) && (*p != '\0')) 1166 p++; 1167 if (*p == '\0') 1168 break; 1169 *p++ = '\0'; 1170 } 1171 ParseArgs (eargc, eargv); 1172 if (eargc != optind) { 1173 fprintf (stderr, "%s: bad environment variable ENSCRIPT \"%s\"\n", 1174 prog, envget ("ENSCRIPT")); 1175 exit (1); 1176 } 1177 } 1178 /* process the command line arguments */ 1179 optind = 1; /* reset getopt global */ 1180 ParseArgs (argc, argv); 1181 1182 /* process non-option args */ 1183 for (; optind < argc; optind++) { 1184 FileName = Header = argv[optind]; 1185 if (freopen (FileName, "r", stdin) == NULL) { 1186 fprintf (stderr, "%s: can't open %s\n", prog, FileName); 1187 exit (1); 1188 } 1189 VOIDC fstat (fileno (stdin), &S); 1190 1191 SetTime (S.st_mtime); 1192 CopyFile (); 1193 VOIDC fclose (stdin); 1194 1195 SeenFile = TRUE; 1196 } 1197 if (!SeenFile) { 1198 FileName = Header = Gaudy ? "" : 0; 1199 VOIDC fstat (fileno (stdin), &S); 1200 1201 if ((S.st_mode & S_IFMT) == S_IFREG) 1202 SetTime (S.st_mtime); 1203 else 1204 SetTime (time ((long *) 0)); 1205 CopyFile (); 1206 } 1207 if (Cvted) { 1208 ClosePS (); 1209 VOIDC fclose (OutFile); 1210 1211 OutFile = 0; 1212 } 1213 if (TruncChars && !BeQuiet) 1214 fprintf (stderr, "%s: %d characters omitted because of long lines.\n", 1215 prog, TruncChars); 1216 if (UndefChars && !BeQuiet) 1217 fprintf (stderr, "%s: %d characters omitted because of incomplete fonts.\n", 1218 prog, UndefChars); 1219 if (Verbose && (TotalPages > 0)) { 1220 fprintf(stderr,"[ %d page%s * %s cop%s ]\n", 1221 TotalPages, TotalPages > 1 ? "s" : "", 1222 spoolCopies, atoi(spoolCopies) > 1 ? "ies" : "y" ); 1223 } 1224 if (Cvted && !OutOnly) { 1225 SpoolIt (); /* does an exec */ 1226 } 1227 } 1228 1229 1230 /* signal catcher */ 1231 private VOID 1232 int1 () 1233 { 1234 if ((!PipeOut) && (OutName != NULL) && (*OutName != '\0')) { 1235 VOIDC unlink (OutName); 1236 } 1237 exit (1); 1238 } 1239