1 /* @(#)psgrind.c 1.2 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 "asm", "auto", "break", "case", "char", "continue", "default", "do", 514 "double", "else", "entry", "enum", "extern", "float", "for", "fortran", 515 "goto", "if", "int", "long", "register", "return", "short", "sizeof", 516 "static", "struct", "switch", "typedef", "union", "unsigned", "void", 517 "while", 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; 700 *kwp != NULL && **kwp <= *tp; kwp++) 701 if (!strcmp(*kwp, tp)) { 702 IsKword = 1; 703 break; 704 } 705 if (IsKword) 706 SetFont(KwordFont); 707 ShowStr(tp); 708 col += strlen(tp); 709 if (IsKword) 710 SetFont(BodyFont); 711 } else if (fonts[CurFont].Xwid[c] != NOTDEF) { 712 /* other normal character */ 713 ShowChar (c); 714 col++; 715 } else { /* not in font, quote it */ 716 ShowChar ('\\'); 717 ShowChar ((c >> 6) + '0'); 718 ShowChar (((c >> 3) & 7) + '0'); 719 ShowChar ((c & 7) + '0'); 720 col += 4; 721 } 722 break; 723 } 724 } 725 last = c; 726 } 727 728 done: 729 ClosePage (); 730 } 731 732 /* dump the fonts to the PS file for setup */ 733 private DumpFonts () { 734 register struct font *f; 735 736 ForAllFonts (f) { 737 fprintf(OutFile,"%d %d /%s\n",f-&fonts[0],f->dsize*UperPt,f->name); 738 } 739 fprintf(OutFile, "%d SetUpFonts\n", nf); 740 } 741 742 743 /* 744 * close the PS file 745 */ 746 private ClosePS () { 747 fprintf(OutFile,"%%%%Trailer\n"); 748 if (PreFeed) { 749 fprintf(OutFile,"false DoPreFeed\n"); 750 } 751 fprintf(OutFile,"EndEnscriptDoc\nEnscriptJob restore\n"); 752 } 753 754 private ProcessArg (p) 755 register char *p; { 756 static enum State { 757 normal, PSname, 758 H_fontname, B_fontname, K_fontname, C_fontname, L_fontname, 759 grabheader, getclass, getjobname 760 } state = normal; 761 762 switch (state) { 763 case PSname: 764 strcpy (OutName, p); 765 if (strcmp(OutName,"-") == 0) PipeOut++; 766 state = normal; 767 break; 768 case H_fontname: 769 decodefont (p, &fonts[HeaderFont]); 770 state = normal; 771 break; 772 case B_fontname: 773 decodefont (p, &fonts[BodyFont]); 774 state = normal; 775 break; 776 case K_fontname: 777 decodefont (p, &fonts[KwordFont]); 778 state = normal; 779 break; 780 case L_fontname: 781 decodefont (p, &fonts[LiteralFont]); 782 state = normal; 783 break; 784 case C_fontname: 785 decodefont (p, &fonts[CommentFont]); 786 state = normal; 787 break; 788 case grabheader: 789 UsersHeader = p; 790 state = normal; 791 break; 792 case getclass: 793 spoolJobClass = p; 794 state = normal; 795 break; 796 case getjobname: 797 spoolJobName = p; 798 state = normal; 799 break; 800 default: 801 if (*p == '-') while (*++p) switch (*p) { 802 case '1': 803 TwoColumn = 0; 804 if (SeenFile) { 805 fprintf(stderr,"Specify -1 before any files\n"); 806 exit(1); 807 } 808 break; 809 case '2': 810 TwoColumn++; 811 if (SeenFile){ 812 fprintf(stderr,"Specify -2 before any files\n"); 813 exit(1); 814 } 815 break; 816 case 'v': 817 Reverse = 1; 818 break; 819 case 's': 820 PageSpec = (++p); 821 while (*p != '\0') p++; 822 return; 823 824 /* the following options allow uswer specification 825 of the five files used by the program */ 826 case 'H': state = H_fontname; break; 827 case 'B': state = B_fontname; break; 828 case 'K': state = K_fontname; break; 829 case 'L': state = L_fontname; break; 830 case 'C': state = C_fontname; break; 831 832 case 'g': IgnoreGarbage++; break; 833 case 'o': ListOmitted++; break; 834 case 'p': OutOnly++; state = PSname; break; 835 case 'r': 836 Rotated++; 837 if (SeenFile){ 838 fprintf(stderr,"Specify rotation before any files\n"); 839 exit(1); 840 } 841 break; 842 case 'R': 843 Rotated = 0; 844 if (SeenFile){ 845 fprintf(stderr,"Specify rotation before any files\n"); 846 exit(1); 847 } 848 break; 849 case 'k': 850 PreFeed++; 851 if (SeenFile){ 852 fprintf(stderr,"Specify prefeed before any files\n"); 853 exit(1); 854 } 855 break; 856 857 /* the following switches are as in lpr(1) and */ 858 /* are passed through when spooling to a printer */ 859 case 'P': /* printer name */ 860 PrinterName = (++p); 861 while (*p != '\0') p++; 862 return; 863 case 'J': /* job name (title) for the Job: field */ 864 state = getjobname; 865 break; 866 case 'm': /* notify by mail */ 867 spoolNotify = 1; 868 break; 869 case 'h': 870 spoolNoBurst = 1; 871 break; 872 case '#': 873 spoolCopies = atoi(++p); 874 if (spoolCopies < 1){ 875 fprintf(stderr,"Bad argument for -# (number of copies)\n"); 876 exit(1); 877 } 878 break; 879 880 default: 881 printf ("Unknown option: %c\n", *p); 882 SeenFile++; 883 break; 884 } 885 else {/* not a flag -- a filename */ 886 FileName = Header = p; 887 if (freopen (FileName, "r", stdin) == NULL) { 888 printf ("Can't open %s\n", FileName); 889 exit (1); 890 } 891 fstat (fileno (stdin), &S); 892 FileDate = strcpy(DateStr,ctime (&S.st_mtime)); 893 CopyFile (); 894 fclose (stdin); 895 SeenFile = 1; 896 } 897 } 898 } 899 900 main (argc, argv) 901 char **argv; { 902 register char *p, *arg; 903 904 prog = *argv; 905 906 BodyFont = LastFont = CurFont = DefineFont (BODYFONT, 10); 907 HeaderFont = DefineFont (HEADERFONT, 12); 908 KwordFont = DefineFont (KWORDFONT, 10); 909 CommentFont = DefineFont (COMMENTFONT, 10); 910 LiteralFont = DefineFont (LITERALFONT, 11); 911 912 /* process args in environment variable PSGRIND */ 913 if (p = getenv ("PSGRIND")) 914 while (1) { 915 register char quote = ' '; 916 while (*p == ' ') 917 p++; 918 if (*p == '"' || *p == '\'') 919 quote = *p++; 920 arg = p; 921 while (*p != quote && *p != '\0') 922 p++; 923 if (*p == '\0') { 924 if (*arg) 925 ProcessArg (arg); 926 break; 927 } 928 *p++ = '\0'; 929 ProcessArg (arg); 930 } 931 932 /* process the command line arguments */ 933 while (argc > 1) { 934 argc--; 935 ProcessArg (*++argv); 936 } 937 938 if (!SeenFile) { 939 FileName = Header = 0; 940 FileDate = ""; 941 fstat (fileno (stdin), &S); 942 943 if ((S.st_mode & S_IFMT) == S_IFREG) 944 FileDate = strcpy(DateStr, ctime (&S.st_mtime)); 945 CopyFile (); 946 } 947 948 if (Cvted) { 949 ClosePS (); 950 fclose (OutFile); 951 OutFile = 0; 952 } 953 if (TruncChars) 954 printf ("%d characters omitted because of long lines.\n", 955 TruncChars); 956 if (UndefChars) 957 printf ("%d characters omitted because of incomplete fonts.\n", 958 UndefChars); 959 /* PageMessage (TotalPages); */ 960 if (Cvted) { 961 if (OutOnly) { 962 if (Reverse || PageSpec) { 963 char temparg[200]; 964 char *sargs[200]; 965 int args = 0; 966 967 int cpid = 0; 968 /* feed Temporary through psrev */ 969 freopen(TempName, "r", stdin); 970 if (!PipeOut) freopen(OutName, "w", stdout); 971 unlink(TempName); 972 973 addarg(sargs, REVERSE, &args); 974 addarg(sargs, "-r", &args); 975 if (!Reverse) addarg(sargs, "-R", &args); 976 977 if (PageSpec) { 978 sprintf(temparg,"-s%s",PageSpec); 979 addarg(sargs, temparg, &args); 980 } 981 if ((cpid = fork()) < 0) pexit(prog,1); 982 if (cpid == 0) { 983 execvp(REVERSE, sargs); 984 pexit(prog,1); 985 } 986 else { 987 wait(0); 988 } 989 } 990 /* fprintf (stderr,"PS file left on %s\n", OutName); */ 991 } 992 else 993 SpoolIt(); 994 } 995 } 996 997 private addarg(argv, argstr, argc) 998 char **argv; 999 char *argstr; 1000 register int *argc; 1001 { 1002 register char *p = (char *) malloc (strlen(argstr) + 1); 1003 strcpy (p, argstr); 1004 argv[(*argc)++] = p; 1005 argv[*argc] = '\0'; 1006 } 1007 1008 private SpoolIt() 1009 { 1010 char temparg[200]; 1011 char *argstr[200]; 1012 int nargs = 0; 1013 1014 char *rargs[40]; 1015 int nr = 0; 1016 int cpid =0; 1017 int fdpipe[2]; 1018 1019 addarg(argstr, LPR, &nargs); 1020 if (spoolCopies > 1) { 1021 sprintf(temparg,"-#%d",spoolCopies); 1022 addarg(argstr, temparg, &nargs); 1023 } 1024 if (PrinterName) { 1025 sprintf(temparg,"-P%s",PrinterName); 1026 addarg(argstr, temparg, &nargs); 1027 } 1028 else if (getenv("PRINTER") == 0) { 1029 /* no printer name known anywhere, use default */ 1030 sprintf(temparg,"-P%s",POSTSCRIPTPRINTER); 1031 addarg(argstr, temparg, &nargs); 1032 } 1033 if (spoolJobClass) { 1034 addarg(argstr, "-C", &nargs); 1035 addarg(argstr, spoolJobClass, &nargs); 1036 } 1037 addarg(argstr, "-J", &nargs); 1038 if (spoolJobName) { 1039 addarg(argstr, spoolJobName, &nargs); 1040 } 1041 else { 1042 if (!FileName) addarg(argstr, "stdin", &nargs); 1043 else addarg(argstr, FileName, &nargs); 1044 } 1045 if (spoolNotify) { 1046 addarg(argstr, "-m", &nargs); 1047 } 1048 if (spoolNoBurst) { 1049 addarg(argstr, "-h", &nargs); 1050 } 1051 1052 if (Reverse || PageSpec) { 1053 /* lpr input will be stdin */ 1054 1055 addarg(rargs, REVERSE, &nr); 1056 addarg(rargs, "-r", &nr); 1057 if (!Reverse) addarg(rargs, "-R", &nr); 1058 if (PageSpec) { 1059 sprintf(temparg,"-s%s",PageSpec); 1060 addarg(rargs, temparg, &nr); 1061 } 1062 /* addarg(rargs, TempName, &nr); */ 1063 1064 freopen(TempName,"r",stdin); 1065 unlink(TempName); 1066 if (pipe(fdpipe)) pexit(prog,1); 1067 if ((cpid = fork()) < 0) pexit(prog,1); 1068 else if (!cpid) { /* child */ 1069 if (close(1)) { 1070 pexit(prog,1); 1071 } 1072 /* set stdout to be the output pipe */ 1073 if (dup (fdpipe[1]) == -1) { 1074 pexit(prog,1); 1075 } 1076 /* don't want to read or write the pipe itself, since dup */ 1077 if (close (fdpipe[1]) || close (fdpipe[0])) { 1078 pexit(prog,1); 1079 } 1080 /* leave stderr alone */ 1081 execvp (REVERSE, rargs); 1082 pexit(prog,1); 1083 } 1084 else { 1085 /* parent */ 1086 /* replace stdin with pipe */ 1087 if (close(0)) { 1088 pexit(prog,1); 1089 } 1090 1091 if (dup(fdpipe[0]) == -1) { 1092 pexit(prog,1); 1093 } 1094 if (close (fdpipe[0]) || close (fdpipe[1])) { 1095 pexit(prog,1); 1096 } 1097 1098 /* leave stdout and stderr alone */ 1099 execvp(LPR, argstr); 1100 pexit(prog,1); 1101 } 1102 } 1103 else { /* just do lpr */ 1104 /* remove the temporary file after spooling */ 1105 addarg(argstr, "-r", &nargs); /* should we use a symbolic link too? */ 1106 addarg(argstr, TempName, &nargs); 1107 execvp(LPR, argstr); 1108 pexit(prog,1); 1109 } 1110 } 1111 1112 char * 1113 basename(path) 1114 char *path; 1115 { 1116 register char *cp; 1117 1118 for (cp = path; *cp != '\0'; cp++) 1119 ; 1120 for (--cp; cp > path && *cp != '/'; cp--) 1121 ; 1122 if (*cp == '/' && *(cp+1) != '\0') 1123 return (cp + 1); 1124 else 1125 return (path); 1126 } 1127