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