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
decodefont(name,f)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 */
ScanFont()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
DefineFont(name,size)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
ResetFont(indx,name,size)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
DumpFonts()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
OUTputc(c)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
OUTstr(s)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
SetFont(f)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
ShowChar(c)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
ShowStr(s)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
FlushShow()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
InitPage()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
ClosePage()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
PageEject()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
CommentHeader()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
CopyFile()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
ClosePS()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
SetTime(tval)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
ParseArgs(ac,av)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
addarg(argv,argstr,argc)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
SpoolIt()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
main(argc,argv)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
int1()1232 int1 ()
1233 {
1234 if ((!PipeOut) && (OutName != NULL) && (*OutName != '\0')) {
1235 VOIDC unlink (OutName);
1236 }
1237 exit (1);
1238 }
1239