1 /* @(#)psgrind.c 1.1 09/15/87 */ 2 /* 3 * psgrind - quick hack to grind C source files directly into 4 * PostScript. 5 * 6 * John Coker 7 * University of California, Berkeley 8 * 9 * The basis for this program is the enscript utility provided 10 * by TranScript to driver the Apple LaserWriter printer. This 11 * code was taken and mangled without permission of any kind; 12 * don't tell anyone. -john 13 */ 14 15 #define POSTSCRIPTPRINTER "gp" 16 17 #define HEADERFONT "Helvetica-Bold" 18 #define BODYFONT "Helvetica" 19 #define KWORDFONT "Helvetica-Bold" 20 #define COMMENTFONT "Helvetica-Oblique" 21 #define LITERALFONT "Courier" 22 23 #ifndef PSGRINDPRO 24 #define PSGRINDPRO "/psgrind.pro" 25 #endif !PSGRINDPRO 26 27 #ifndef PSGRINDTEMP 28 #define PSGRINDTEMP "/GRXXXXXX" 29 #endif !PSGRINDTEMP 30 31 #define UperInch 1440 32 #define PtsPerInch 72 33 #define UperPt 20 34 #define TruePageWidth (UperInch*17/2) 35 #define PageWidth (UperInch*(8*17-3)/4) 36 #define PageLength (UperInch*(8*11-3)/8) 37 #define TruePageLength (UperInch*11) 38 39 #include <stdio.h> 40 #include <ctype.h> 41 #include <strings.h> 42 #include <pwd.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include "transcript.h" 46 47 #define LPR "lpr" 48 #define REVERSE "psrev" 49 50 #define MAXBAD 20 /* number of bad chars to pass before complaint */ 51 52 private struct stat S; 53 char *ctime (); 54 char *getenv (); 55 char *rindex (); 56 57 #define FSIZEMAX 256 /* number of chars per font */ 58 59 /* the layout of a font information block */ 60 struct font { 61 char name[100]; /* PostScript font name */ 62 int dsize; /* size */ 63 int Xwid[FSIZEMAX]; /* X widths for each character */ 64 }; 65 66 private struct font fonts[16]; /* 16 possible fonts at one time */ 67 private int nf = 0; /* number of fonts known about */ 68 69 private int HeaderFont = -1; /* handle for header font */ 70 private int BodyFont = -1; /* handle for body font */ 71 private int KwordFont = -1; /* handle for keyword font */ 72 private int LiteralFont = -1; /* handle for literal font */ 73 private int CommentFont = -1; /* handle for comment font */ 74 75 private int TabWidth = TruePageWidth / 10; /* width of a tab */ 76 private int BSWidth; /* width of a backspace */ 77 78 private int UperLine = UperInch / 7; 79 private int UperHLine = UperInch / 7; 80 81 private char *prog; /* program name argv[0] */ 82 private char TempName[100]; /* name of temporary PostScript file */ 83 private char OutName[256] = 0; /* filename for disk output */ 84 private int PipeOut = 0; /* true if output to stdout (-p -) */ 85 private int ListOmitted = 0; /* list omitted chars on the tty */ 86 private int LPTsimulate = 0; /* true if an lpt should be simulated */ 87 private int LinesLeft = 64; /* lines left on page when in LPT mode */ 88 private int LineNo; /* line number in current file */ 89 private int SeenText = 1; /* true if seen some text on this page */ 90 private int OutOnly = 0; /* true if PS file only wanted */ 91 private int Rotated = 0; /* true if the page is to be rotated */ 92 private int Reverse = 0; /* output should be piped to psrev */ 93 private char *PageSpec = 0; /* ditto */ 94 private int PreFeed = 0; /* true if prefeed should be enabled */ 95 private int TwoColumn = 0; /* true of if in two-column mode */ 96 private int FirstCol = 1; /* true if we're printing column 1 */ 97 private int NoTitle = 0; /* true if title line is to be suppressed */ 98 private int Cvted = 0; /* true if converted a file to PS format */ 99 100 private int IgnoreGarbage = 0; /* true if garbage should be ignored */ 101 private int SeenFile = 0; /* true if a file has been processed */ 102 private int SeenFont = 0; /* true if we've seen a font request */ 103 private int ScannedFonts = 0; /* true if we've scanned the font file */ 104 private char *FileName = 0; /* name of file currently being PSed */ 105 private char *FileDate = 0; /* last mod date of file being PSed */ 106 private char DateStr[27]; /* thanks, but no thanks ctime! */ 107 108 private char *spoolJobClass = 0; 109 private char *spoolJobName = 0; 110 private char *PrinterName = 0; 111 private int spoolNotify = 0; 112 private int spoolNoBurst = 0; 113 private int spoolCopies = 1; 114 115 private char tempstr[256]; /* various path names */ 116 117 private int CurFont; /* current Font */ 118 private int LastFont; /* previous Font */ 119 120 private int cX, cY; /* current page positions */ 121 private int dX, dY; /* desired page positions */ 122 private int lX, lY; /* page positions of the start of the line */ 123 private int crX, crY; /* X and Y increments to apply to CR's */ 124 125 #define None 0 126 #define RelX 1 127 #define RelY 2 128 #define RelXY 3 129 #define AbsX 4 130 #define AbsY 8 131 #define AbsXY 12 132 133 private int movepending; /* moveto pending coords on stack */ 134 private int showpending; /* number of characters waiting to be shown */ 135 private char *UsersHeader = 0; /* user specified heading */ 136 private char *Header = 0; /* generated header (usually FileName) */ 137 private int Page = 0; /* current page number */ 138 private int TotalPages = 0; /* total number of pages printed */ 139 private int TruncChars = 0; /* number of characters truncated */ 140 private int UndefChars = 0; /* number of characters skipped because 141 they weren't defined in some font */ 142 private int BadChars = 0; /* number of bad characters seen so far */ 143 144 private FILE *OutFile = 0; /* output ps file */ 145 146 /* decode a fontname string - e.g. Courier10 Helvetica-Bold12 */ 147 private decodefont (name, f) 148 register char *name; 149 register struct font *f; { 150 register char *d, *p; 151 152 SeenFont++; 153 if (ScannedFonts) { 154 fprintf(stderr,"Fonts must be specified before any files are processed\n"); 155 exit(1); 156 } 157 p = name; 158 d = f->name; 159 while (isascii(*p) && (isalpha(*p) || (*p == '-'))) {*d++ = *p++;} 160 *d++ = '\0'; 161 if (isascii(*p) && isdigit(*p)) { 162 f->dsize = 0; 163 do 164 f->dsize = f->dsize * 10 + *p++ - '0'; 165 while ('0' <= *p && *p <= '9'); 166 } 167 if (*p || !f->dsize || !f->name[0]) { 168 fprintf (stderr, "Poorly formed font name: \"%s\"\n", name); 169 exit (1); 170 } 171 } 172 173 174 #define NOTDEF 0x8000 175 #define ForAllFonts(p) for(p = &fonts[nf-1]; p >= &fonts[0]; p--) 176 177 /* Scan the font metrics directory looking for entries that match the 178 * entries in ``fonts''. For entries 179 * that are found the data in the font description is filled in, 180 * if any are missing, it dies horribly. 181 */ 182 private ScanFont () { 183 register struct font *f; 184 register FILE *FontData; /* afm file */ 185 char *c; 186 int ccode, cwidth, inChars; 187 char *MetricsDir = (char *) getenv ("METRICS"); 188 char FontFile[512]; /* afm file name */ 189 char afmbuf[BUFSIZ]; 190 191 if (MetricsDir == 0) 192 MetricsDir = LibDir; 193 194 if (!SeenFont & Rotated & TwoColumn) { 195 fonts[HeaderFont].dsize = 10; 196 fonts[BodyFont].dsize = 7; 197 fonts[KwordFont].dsize = 7; 198 fonts[LiteralFont].dsize = 8; 199 fonts[CommentFont].dsize = 7; 200 } 201 202 /* loop through fonts, find and read metric entry in dir */ 203 ForAllFonts (f) { 204 mstrcat(FontFile, MetricsDir, "/", sizeof FontFile); 205 mstrcat(FontFile, FontFile, f->name, sizeof FontFile); 206 mstrcat(FontFile, FontFile, ".afm", sizeof FontFile); 207 if ((FontData = fopen(FontFile,"r")) == NULL){ 208 fprintf(stderr,"Can't open font metrics file %s\n",FontFile); 209 exit(1); 210 } 211 /* read the .afm file to get the widths */ 212 for (ccode = 0; ccode < FSIZEMAX; ccode++) f->Xwid[ccode] = NOTDEF; 213 214 inChars = 0; 215 while(fgets(afmbuf, sizeof afmbuf, FontData) != NULL) { 216 /* strip off newline */ 217 if ((c = index(afmbuf, '\n')) == 0) { 218 fprintf(stderr, "AFM file %s line too long %s\n", FontFile, afmbuf); 219 exit(1); 220 } 221 *c = '\0'; 222 if (*afmbuf == '\0') continue; 223 if (strcmp(afmbuf, "StartCharMetrics") == 0) { 224 inChars++; 225 continue; 226 } 227 if (strcmp(afmbuf, "EndCharMetrics") == 0) break; 228 if (inChars == 1) { 229 if (sscanf(afmbuf, "C %d ; WX %d ;",&ccode,&cwidth) != 2) { 230 fprintf(stderr,"Trouble with AFM file %s\n",FontFile); 231 exit(1); 232 } 233 /* get out once we see an unencoded char */ 234 if (ccode == -1) break; 235 if (ccode > 255) continue; 236 f->Xwid[ccode] = (cwidth * f->dsize * UperPt) / 1000; 237 continue; 238 } 239 } 240 fclose (FontData); 241 } 242 243 TabWidth = fonts[BodyFont].Xwid['0'] * 8; /* 8 * figure width */ 244 BSWidth = fonts[BodyFont].Xwid[' ']; /* space width */ 245 246 UperLine = (fonts[BodyFont].dsize + 1) * UperPt; 247 248 if (LPTsimulate) 249 UperHLine = UperLine; 250 else 251 UperHLine = (fonts[HeaderFont].dsize + 1) * UperPt; 252 253 crX = 0; 254 crY = -UperLine; 255 } 256 257 /* Return a font number for the font with the indicated name 258 * and size. Adds info to the font list for the eventual search. 259 */ 260 private DefineFont (name, size) 261 char *name; { 262 register struct font *p; 263 p = &fonts[nf]; 264 strcpy (p->name, name); 265 p->dsize = size; 266 return (nf++); 267 } 268 269 /* add a shown character to the PS file */ 270 private OUTputc (c) 271 unsigned char c; { 272 if (showpending == 0) {putc('(', OutFile); showpending++;} 273 if (c == '\\' || c=='(' || c == ')') putc('\\', OutFile); 274 if ((c > 0176) || (c < 040)) { 275 putc('\\',OutFile); 276 putc((c >> 6) +'0',OutFile); 277 putc(((c >> 3) & 07)+'0', OutFile); 278 putc((c & 07)+'0',OutFile); 279 } 280 else putc (c, OutFile); 281 } 282 283 /* Set the current font */ 284 private SetFont (f) { 285 FlushShow(); 286 LastFont = CurFont; 287 fprintf(OutFile, "%d F\n", CurFont = f); 288 } 289 290 /* Reset to previous font */ 291 private PrevFont () { 292 int temp; 293 294 FlushShow(); 295 temp = CurFont; 296 CurFont = LastFont; 297 LastFont = temp; 298 fprintf(OutFile, "%d F\n", CurFont); 299 } 300 301 /* put a character onto the page at the desired X and Y positions. 302 * If the current position doesn't agree with the desired position, put out 303 * movement directives. Leave the current position updated 304 * to account for the character. 305 */ 306 private ShowChar (c) 307 register int c; { 308 register struct font *f; 309 register nX, nY; 310 static level = 0; 311 312 level++; 313 f = &fonts[CurFont]; 314 315 if (f->Xwid[c] == NOTDEF) { 316 UndefChars++; 317 if(ListOmitted) 318 printf("\'%c\' (%03o) not found in font %s\n",c,c,f->name); 319 if(level<=1){ 320 ShowChar('\\'); 321 ShowChar((c>>6)+'0'); 322 ShowChar(((c>>3)&07)+'0'); 323 ShowChar((c&07)+'0'); 324 } 325 level--; 326 return; 327 } 328 nX = dX + f->Xwid[c]; /* resulting position after showing this char */ 329 nY = dY; 330 331 if (c != ' ' || ((cX == dX) && (cY == dY))) 332 if ((!Rotated && (nX <= PageWidth) && (nY <= PageLength)) 333 || (Rotated && (nX <= PageLength) && (nY <= PageWidth))) { 334 if (cX != dX) { 335 if (cY != dY) { 336 FlushShow(); 337 /* absolute x, relative y */ 338 fprintf(OutFile,"%d %d",dX, dY); 339 movepending = AbsXY; 340 } 341 else { 342 FlushShow(); 343 fprintf(OutFile,"%d",dX-cX); /* relative x */ 344 movepending = RelX; 345 } 346 } 347 else if (cY != dY) { 348 FlushShow(); 349 fprintf(OutFile,"%d",dY-cY); /* relative y */ 350 movepending = RelY; 351 } 352 OUTputc (c); 353 showpending++; 354 cX = nX; 355 cY = nY; 356 } 357 else 358 TruncChars++; 359 dX = nX; 360 dY = nY; 361 362 level--; 363 } 364 365 /* put out a shown string to the PS file */ 366 private ShowStr (s) 367 register char *s; { 368 while (*s) { 369 if (*s >= 040) ShowChar (*s); 370 s++; 371 } 372 } 373 374 /* flush pending show */ 375 private FlushShow() { 376 if (showpending) { 377 putc(')',OutFile); 378 switch (movepending) { 379 case RelX: 380 putc('X',OutFile); 381 break; 382 case RelY: 383 putc('Y',OutFile); 384 break; 385 case AbsXY: 386 putc('B',OutFile); 387 break; 388 case None: 389 putc('S',OutFile); 390 break; 391 } 392 putc('\n',OutFile); 393 movepending = None; 394 showpending = 0; 395 } 396 } 397 398 /* put out a page heading to the PS file */ 399 private InitPage () { 400 char *basename(); 401 char header[200]; 402 register int OldFont = CurFont; 403 404 TotalPages++; 405 fprintf(OutFile, "%%%%Page: ? %d\n", TotalPages); 406 fprintf(OutFile, "StartPage\n"); 407 LinesLeft = 64; 408 SeenText = 0; 409 cX = cY = -1; 410 showpending = 0; 411 FirstCol = 1; 412 lX = dX = UperInch; 413 lY = dY = PageLength - UperHLine * 3 / 2; 414 if (Rotated) { 415 fprintf(OutFile, "Landscape\n"); 416 lX = dX = UperInch / 4; 417 } 418 movepending = None; 419 cX = dX; cY = dY; 420 if (!NoTitle) { 421 SetFont (HeaderFont); 422 fprintf(OutFile, "%d %d ", cX, cY); 423 movepending = AbsXY; 424 if (UsersHeader) { 425 if (*UsersHeader == 0) { 426 fprintf(OutFile,"()B\n"); 427 movepending = None; 428 showpending = 0; 429 } 430 else ShowStr (UsersHeader); 431 } 432 else { 433 Page++; 434 if (FileName == 0) 435 sprintf(header, "Page %d", Page); 436 else 437 sprintf (header, "%s, page %d", basename(FileName), Page); 438 ShowStr (header); 439 } 440 FlushShow(); 441 dX = lX = lX + crX * 3; 442 dY = lY = lY + crY * 3; 443 } 444 else { 445 /* fake it to force a moveto */ 446 cX = cY = 0; 447 } 448 SetFont (OldFont); 449 } 450 451 /* terminate a page. */ 452 private ClosePage () { 453 FlushShow(); 454 fprintf(OutFile,"EndPage\n"); 455 } 456 457 /* skip to a new page */ 458 private PageEject () { 459 if (TwoColumn && FirstCol) { 460 FirstCol = 0; 461 lX = dX = TruePageWidth / 2; 462 lY = dY = PageLength - (UperHLine * 3 / 2); 463 if (Rotated) { 464 lX = dX = TruePageLength / 2; 465 } 466 if (!NoTitle) { 467 dX = lX = lX + crX * 3; 468 dY = lY = lY + crY * 3; 469 } 470 } 471 else { 472 ClosePage (); 473 InitPage (); 474 } 475 LinesLeft = 64; 476 SeenText = 0; 477 } 478 479 #if 0 480 /* commented out AIS Fri Feb 22 10:00:36 1985 */ 481 private PageMessage (TotalPages) 482 { 483 if (TotalPages > 0) { 484 printf ("psgrind formatted[ %d page%s * %d cop%s ]\n", 485 TotalPages, TotalPages > 1 ? "s" : "", 486 spoolCopies, spoolCopies > 1 ? "ies" : "y" ); 487 } 488 } 489 #endif 490 491 private CommentHeader() { 492 long clock; 493 struct passwd *pswd; 494 char hostname[40]; 495 /* copy the file, prepending a new comment header */ 496 fprintf(OutFile,"%%!%s\n",COMMENTVERSION); 497 fprintf(OutFile,"%%%%Creator: "); 498 pswd = getpwuid(getuid()); 499 gethostname(hostname, (int) sizeof hostname); 500 fprintf(OutFile,"%s:%s (%s)%s\n", hostname, pswd->pw_name, 501 pswd->pw_gecos, spoolJobClass); 502 503 fprintf(OutFile,"%%%%Title: %s %s\n", 504 (FileName?FileName:"stdin"), 505 spoolJobName); 506 507 fprintf(OutFile,"%%%%CreationDate: %s",(time(&clock),ctime(&clock))); 508 } 509 510 511 /* list of C keywords to put in KwordFont */ 512 private char *KeyWordList[] = { 513 "int", "char", "float", "double", "struct", "union", 514 "long", "short", "unsigned", "auto", "extern", "register", 515 "typedef", "static", "goto", "return", "sizeof", "break", 516 "continue", "if", "else", "for", "do", "while", "switch", 517 "case", "default", "entry", NULL 518 }; 519 520 /* macros identifying C identifiers */ 521 #define isfirst(c) (isalpha(c) || (c) == '_') 522 #define isident(c) (isalnum(c) || (c) == '_') 523 524 /* Copy the standard input file to the PS file */ 525 private CopyFile () { 526 register int c, last; 527 register int col = 1; 528 int InComment, InString, InChar, IsKword; 529 char token[50], *tend = token + sizeof (token) - 1; 530 register char *tp, **kwp; 531 532 if (OutFile == 0) { 533 if (OutOnly && !(PageSpec || Reverse)) { 534 OutFile = PipeOut ? stdout : fopen(OutName,"w"); 535 } 536 else { 537 mktemp(mstrcat(TempName,TempDir,PSGRINDTEMP,sizeof TempName)); 538 OutFile = fopen (TempName, "w"); 539 } 540 } 541 if (OutFile == NULL) { 542 fprintf(stderr, "Can't create PS file %s\n",TempName); 543 exit(1); 544 } 545 if (!ScannedFonts) { 546 ScannedFonts++; 547 ScanFont(); 548 } 549 if (!Cvted) { 550 CommentHeader(); 551 if (nf) { 552 register struct font *f; 553 fprintf(OutFile,"%%%%DocumentFonts:"); 554 ForAllFonts(f) { 555 fprintf(OutFile," %s",f->name); 556 } 557 fprintf(OutFile,"\n"); 558 } 559 /* copy in fixed prolog */ 560 if (copyfile(mstrcat(tempstr,LibDir,PSGRINDPRO,sizeof tempstr), 561 OutFile)) { 562 fprintf(stderr,"trouble copying prolog file \"%s\".\n",tempstr); 563 exit(1); 564 } 565 fprintf(OutFile,"StartEnscriptDoc %% end fixed prolog\n"); 566 DumpFonts(); 567 fprintf(OutFile,"%%%%EndProlog\n"); 568 if (PreFeed) { 569 fprintf(OutFile,"true DoPreFeed\n"); 570 } 571 } 572 Cvted++; 573 574 Page = 0; 575 LineNo = 1; 576 BadChars = 0; /* give each file a clean slate */ 577 InitPage (); 578 last = '\0'; 579 InComment = InChar = InString = 0; 580 while ((c = getchar ()) != EOF) { 581 if ((c > 0177 || c < 0) && (!IgnoreGarbage)) { 582 if (BadChars++ > MAXBAD) {/* allow some kruft but not much */ 583 fprintf(stderr,"\"%s\" not a text file? - char '\\%03o'@0%o\nTry -g.\n", 584 FileName ? FileName : "stdin", c, ftell (stdin) - 1); 585 exit(1); 586 } 587 } else { 588 switch (c) { 589 case 010: /* backspace */ 590 dX -= BSWidth; 591 break; 592 case 015: /* carriage return ^M */ 593 dY = lY; 594 dX = lX; 595 break; 596 case 012: /* linefeed ^J */ 597 LineNo++; 598 if (dX != lX || dY != lY || !LPTsimulate || SeenText){ 599 SeenText++; 600 dY = lY = lY + crY; 601 dX = lX = lX + crX; 602 } 603 else 604 LinesLeft = 64; 605 if (((!Rotated) && (dY < UperLine)) 606 || (Rotated && (dY < ((PageLength-TruePageWidth) + 607 3*UperLine+480))) 608 || (LPTsimulate && (--LinesLeft <= 0))) 609 PageEject (); 610 col = 1; 611 break; 612 case 014: /* form feed ^L */ 613 PageEject (); 614 col = 1; 615 break; 616 case 011: /* tab ^I */ 617 col = (col - 1) / 8 * 8 + 9; 618 dX = lX + (col - 1) / 8 * TabWidth; 619 break; 620 case '\\': /* special escape */ 621 last = c; 622 if ((c = getchar()) == EOF) 623 goto done; 624 ShowChar('\\'); 625 col++; 626 if (c == '\n') { 627 /* want to leave newlines alone */ 628 ungetc(c, stdin); 629 } else { 630 ShowChar(c); 631 col++; 632 } 633 break; 634 case '"': /* a string quote mark */ 635 if (InComment || InChar) { 636 /* just put out the quote */ 637 ShowChar('"'); 638 col++; 639 } else if (InString) { 640 ShowChar('"'); 641 col++; 642 PrevFont(); 643 InString = 0; 644 } else { 645 SetFont(LiteralFont); 646 ShowChar('"'); 647 col++; 648 InString = 1; 649 } 650 break; 651 case '\'': /* a char quote mark */ 652 if (InComment || InString) { 653 /* just put out the character */ 654 ShowChar('\''); 655 col++; 656 } else if (InChar) { 657 ShowChar('\''); 658 col++; 659 PrevFont(); 660 InChar = 0; 661 } else { 662 SetFont(LiteralFont); 663 ShowChar('\''); 664 col++; 665 InChar = 1; 666 } 667 break; 668 case '/': 669 if (InComment && last == '*') { 670 ShowChar('/'); 671 col++; 672 SetFont(BodyFont); 673 InComment = 0; 674 } else if ((c = getchar()) == '*' && !InComment) { 675 SetFont(CommentFont); 676 InComment = 1; 677 ShowChar('/'); 678 ShowChar('*'); 679 col += 2; 680 } else { 681 ungetc(c, stdin); 682 ShowChar('/'); 683 col++; 684 c = '/'; 685 } 686 break; 687 default: /* plain text, put it out */ 688 if (!InComment && !InString && isfirst(c)) { 689 tp = token; 690 while (isident(c) && tp < tend) { 691 *tp++ = c; 692 last = c; 693 c = getchar(); 694 } 695 *tp = '\0'; 696 ungetc(c, stdin); 697 tp = token; 698 IsKword = 0; 699 for (kwp = KeyWordList; *kwp != NULL; kwp++) 700 if (!strcmp(*kwp, tp)) { 701 IsKword = 1; 702 break; 703 } 704 if (IsKword) 705 SetFont(KwordFont); 706 ShowStr(tp); 707 col += strlen(tp); 708 if (IsKword) 709 SetFont(BodyFont); 710 } else if (fonts[CurFont].Xwid[c] != NOTDEF) { 711 /* other normal character */ 712 ShowChar (c); 713 col++; 714 } else { /* not in font, quote it */ 715 ShowChar ('\\'); 716 ShowChar ((c >> 6) + '0'); 717 ShowChar (((c >> 3) & 7) + '0'); 718 ShowChar ((c & 7) + '0'); 719 col += 4; 720 } 721 break; 722 } 723 } 724 last = c; 725 } 726 727 done: 728 ClosePage (); 729 } 730 731 /* dump the fonts to the PS file for setup */ 732 private DumpFonts () { 733 register struct font *f; 734 735 ForAllFonts (f) { 736 fprintf(OutFile,"%d %d /%s\n",f-&fonts[0],f->dsize*UperPt,f->name); 737 } 738 fprintf(OutFile, "%d SetUpFonts\n", nf); 739 } 740 741 742 /* 743 * close the PS file 744 */ 745 private ClosePS () { 746 fprintf(OutFile,"%%%%Trailer\n"); 747 if (PreFeed) { 748 fprintf(OutFile,"false DoPreFeed\n"); 749 } 750 fprintf(OutFile,"EndEnscriptDoc\nEnscriptJob restore\n"); 751 } 752 753 private ProcessArg (p) 754 register char *p; { 755 static enum State { 756 normal, PSname, 757 H_fontname, B_fontname, K_fontname, C_fontname, L_fontname, 758 grabheader, getclass, getjobname 759 } state = normal; 760 761 switch (state) { 762 case PSname: 763 strcpy (OutName, p); 764 if (strcmp(OutName,"-") == 0) PipeOut++; 765 state = normal; 766 break; 767 case H_fontname: 768 decodefont (p, &fonts[HeaderFont]); 769 state = normal; 770 break; 771 case B_fontname: 772 decodefont (p, &fonts[BodyFont]); 773 state = normal; 774 break; 775 case K_fontname: 776 decodefont (p, &fonts[KwordFont]); 777 state = normal; 778 break; 779 case L_fontname: 780 decodefont (p, &fonts[LiteralFont]); 781 state = normal; 782 break; 783 case C_fontname: 784 decodefont (p, &fonts[CommentFont]); 785 state = normal; 786 break; 787 case grabheader: 788 UsersHeader = p; 789 state = normal; 790 break; 791 case getclass: 792 spoolJobClass = p; 793 state = normal; 794 break; 795 case getjobname: 796 spoolJobName = p; 797 state = normal; 798 break; 799 default: 800 if (*p == '-') while (*++p) switch (*p) { 801 case '1': 802 TwoColumn = 0; 803 if (SeenFile) { 804 fprintf(stderr,"Specify -1 before any files\n"); 805 exit(1); 806 } 807 break; 808 case '2': 809 TwoColumn++; 810 if (SeenFile){ 811 fprintf(stderr,"Specify -2 before any files\n"); 812 exit(1); 813 } 814 break; 815 case 'v': 816 Reverse = 1; 817 break; 818 case 's': 819 PageSpec = (++p); 820 while (*p != '\0') p++; 821 return; 822 823 /* the following options allow uswer specification 824 of the five files used by the program */ 825 case 'H': state = H_fontname; break; 826 case 'B': state = B_fontname; break; 827 case 'K': state = K_fontname; break; 828 case 'L': state = L_fontname; break; 829 case 'C': state = C_fontname; break; 830 831 case 'g': IgnoreGarbage++; break; 832 case 'o': ListOmitted++; break; 833 case 'p': OutOnly++; state = PSname; break; 834 case 'r': 835 Rotated++; 836 if (SeenFile){ 837 fprintf(stderr,"Specify rotation before any files\n"); 838 exit(1); 839 } 840 break; 841 case 'R': 842 Rotated = 0; 843 if (SeenFile){ 844 fprintf(stderr,"Specify rotation before any files\n"); 845 exit(1); 846 } 847 break; 848 case 'k': 849 PreFeed++; 850 if (SeenFile){ 851 fprintf(stderr,"Specify prefeed before any files\n"); 852 exit(1); 853 } 854 break; 855 856 /* the following switches are as in lpr(1) and */ 857 /* are passed through when spooling to a printer */ 858 case 'P': /* printer name */ 859 PrinterName = (++p); 860 while (*p != '\0') p++; 861 return; 862 case 'J': /* job name (title) for the Job: field */ 863 state = getjobname; 864 break; 865 case 'm': /* notify by mail */ 866 spoolNotify = 1; 867 break; 868 case 'h': 869 spoolNoBurst = 1; 870 break; 871 case '#': 872 spoolCopies = atoi(++p); 873 if (spoolCopies < 1){ 874 fprintf(stderr,"Bad argument for -# (number of copies)\n"); 875 exit(1); 876 } 877 break; 878 879 default: 880 printf ("Unknown option: %c\n", *p); 881 SeenFile++; 882 break; 883 } 884 else {/* not a flag -- a filename */ 885 FileName = Header = p; 886 if (freopen (FileName, "r", stdin) == NULL) { 887 printf ("Can't open %s\n", FileName); 888 exit (1); 889 } 890 fstat (fileno (stdin), &S); 891 FileDate = strcpy(DateStr,ctime (&S.st_mtime)); 892 CopyFile (); 893 fclose (stdin); 894 SeenFile = 1; 895 } 896 } 897 } 898 899 main (argc, argv) 900 char **argv; { 901 register char *p, *arg; 902 903 prog = *argv; 904 905 BodyFont = LastFont = CurFont = DefineFont (BODYFONT, 10); 906 HeaderFont = DefineFont (HEADERFONT, 12); 907 KwordFont = DefineFont (KWORDFONT, 10); 908 CommentFont = DefineFont (COMMENTFONT, 10); 909 LiteralFont = DefineFont (LITERALFONT, 11); 910 911 /* process args in environment variable PSGRIND */ 912 if (p = getenv ("PSGRIND")) 913 while (1) { 914 register char quote = ' '; 915 while (*p == ' ') 916 p++; 917 if (*p == '"' || *p == '\'') 918 quote = *p++; 919 arg = p; 920 while (*p != quote && *p != '\0') 921 p++; 922 if (*p == '\0') { 923 if (*arg) 924 ProcessArg (arg); 925 break; 926 } 927 *p++ = '\0'; 928 ProcessArg (arg); 929 } 930 931 /* process the command line arguments */ 932 while (argc > 1) { 933 argc--; 934 ProcessArg (*++argv); 935 } 936 937 if (!SeenFile) { 938 FileName = Header = 0; 939 FileDate = ""; 940 fstat (fileno (stdin), &S); 941 942 if ((S.st_mode & S_IFMT) == S_IFREG) 943 FileDate = strcpy(DateStr, ctime (&S.st_mtime)); 944 CopyFile (); 945 } 946 947 if (Cvted) { 948 ClosePS (); 949 fclose (OutFile); 950 OutFile = 0; 951 } 952 if (TruncChars) 953 printf ("%d characters omitted because of long lines.\n", 954 TruncChars); 955 if (UndefChars) 956 printf ("%d characters omitted because of incomplete fonts.\n", 957 UndefChars); 958 /* PageMessage (TotalPages); */ 959 if (Cvted) { 960 if (OutOnly) { 961 if (Reverse || PageSpec) { 962 char temparg[200]; 963 char *sargs[200]; 964 int args = 0; 965 966 int cpid = 0; 967 /* feed Temporary through psrev */ 968 freopen(TempName, "r", stdin); 969 if (!PipeOut) freopen(OutName, "w", stdout); 970 unlink(TempName); 971 972 addarg(sargs, REVERSE, &args); 973 addarg(sargs, "-r", &args); 974 if (!Reverse) addarg(sargs, "-R", &args); 975 976 if (PageSpec) { 977 sprintf(temparg,"-s%s",PageSpec); 978 addarg(sargs, temparg, &args); 979 } 980 if ((cpid = fork()) < 0) pexit(prog,1); 981 if (cpid == 0) { 982 execvp(REVERSE, sargs); 983 pexit(prog,1); 984 } 985 else { 986 wait(0); 987 } 988 } 989 /* fprintf (stderr,"PS file left on %s\n", OutName); */ 990 } 991 else 992 SpoolIt(); 993 } 994 } 995 996 private addarg(argv, argstr, argc) 997 char **argv; 998 char *argstr; 999 register int *argc; 1000 { 1001 register char *p = (char *) malloc (strlen(argstr) + 1); 1002 strcpy (p, argstr); 1003 argv[(*argc)++] = p; 1004 argv[*argc] = '\0'; 1005 } 1006 1007 private SpoolIt() 1008 { 1009 char temparg[200]; 1010 char *argstr[200]; 1011 int nargs = 0; 1012 1013 char *rargs[40]; 1014 int nr = 0; 1015 int cpid =0; 1016 int fdpipe[2]; 1017 1018 addarg(argstr, LPR, &nargs); 1019 if (spoolCopies > 1) { 1020 sprintf(temparg,"-#%d",spoolCopies); 1021 addarg(argstr, temparg, &nargs); 1022 } 1023 if (PrinterName) { 1024 sprintf(temparg,"-P%s",PrinterName); 1025 addarg(argstr, temparg, &nargs); 1026 } 1027 else if (getenv("PRINTER") == 0) { 1028 /* no printer name known anywhere, use default */ 1029 sprintf(temparg,"-P%s",POSTSCRIPTPRINTER); 1030 addarg(argstr, temparg, &nargs); 1031 } 1032 if (spoolJobClass) { 1033 addarg(argstr, "-C", &nargs); 1034 addarg(argstr, spoolJobClass, &nargs); 1035 } 1036 addarg(argstr, "-J", &nargs); 1037 if (spoolJobName) { 1038 addarg(argstr, spoolJobName, &nargs); 1039 } 1040 else { 1041 if (!FileName) addarg(argstr, "stdin", &nargs); 1042 else addarg(argstr, FileName, &nargs); 1043 } 1044 if (spoolNotify) { 1045 addarg(argstr, "-m", &nargs); 1046 } 1047 if (spoolNoBurst) { 1048 addarg(argstr, "-h", &nargs); 1049 } 1050 1051 if (Reverse || PageSpec) { 1052 /* lpr input will be stdin */ 1053 1054 addarg(rargs, REVERSE, &nr); 1055 addarg(rargs, "-r", &nr); 1056 if (!Reverse) addarg(rargs, "-R", &nr); 1057 if (PageSpec) { 1058 sprintf(temparg,"-s%s",PageSpec); 1059 addarg(rargs, temparg, &nr); 1060 } 1061 /* addarg(rargs, TempName, &nr); */ 1062 1063 freopen(TempName,"r",stdin); 1064 unlink(TempName); 1065 if (pipe(fdpipe)) pexit(prog,1); 1066 if ((cpid = fork()) < 0) pexit(prog,1); 1067 else if (!cpid) { /* child */ 1068 if (close(1)) { 1069 pexit(prog,1); 1070 } 1071 /* set stdout to be the output pipe */ 1072 if (dup (fdpipe[1]) == -1) { 1073 pexit(prog,1); 1074 } 1075 /* don't want to read or write the pipe itself, since dup */ 1076 if (close (fdpipe[1]) || close (fdpipe[0])) { 1077 pexit(prog,1); 1078 } 1079 /* leave stderr alone */ 1080 execvp (REVERSE, rargs); 1081 pexit(prog,1); 1082 } 1083 else { 1084 /* parent */ 1085 /* replace stdin with pipe */ 1086 if (close(0)) { 1087 pexit(prog,1); 1088 } 1089 1090 if (dup(fdpipe[0]) == -1) { 1091 pexit(prog,1); 1092 } 1093 if (close (fdpipe[0]) || close (fdpipe[1])) { 1094 pexit(prog,1); 1095 } 1096 1097 /* leave stdout and stderr alone */ 1098 execvp(LPR, argstr); 1099 pexit(prog,1); 1100 } 1101 } 1102 else { /* just do lpr */ 1103 /* remove the temporary file after spooling */ 1104 addarg(argstr, "-r", &nargs); /* should we use a symbolic link too? */ 1105 addarg(argstr, TempName, &nargs); 1106 execvp(LPR, argstr); 1107 pexit(prog,1); 1108 } 1109 } 1110 1111 char * 1112 basename(path) 1113 char *path; 1114 { 1115 register char *cp; 1116 1117 for (cp = path; *cp != '\0'; cp++) 1118 ; 1119 for (--cp; cp > path && *cp != '/'; cp--) 1120 ; 1121 if (*cp == '/' && *(cp+1) != '\0') 1122 return (cp + 1); 1123 else 1124 return (path); 1125 } 1126