|
|
1.1 root 1: /*
2: * prps.c
3: * 7/10/92
4: * Produce PostScript pages containing input files.
5: * By default, each page has a header line and text enclosed in a box.
6: * See usage() for usage and options.
7: * Requires fp output: cc prps.c -f
8: */
9:
10: #include <stdio.h>
11: #include <time.h>
12: #if COHERENT
13: #include <sys/types.h>
14: #endif
15:
16: /* Manifest constants. */
17: #define VERSION "2.3"
18: #define DEFFONT "Courier" /* default font */
19: #define DEFFONTB "-Bold" /* default boldface font suffix */
20: #define DEFFONTI "-Oblique" /* default italic font suffix */
21: #define DEFFONTR "" /* default Roman font suffix */
22: #define DEFPTSIZE 10 /* default point size */
23: #define DEFPTSIZEL2 8 /* default point size with -l2 */
24: #define DEFTAB 8 /* default tab setting */
25: #define NBUF 512 /* buffer size */
26: #define PAGEDX 8.5 /* page width */
27:
28: /* Macros. */
29: #define inch(d) ((int)((d) * 72)) /* (double)d inches to (int)pts */
30:
31: /* Forward. */
32: void fatal();
33: void file();
34: int font_of();
35: char *Foption();
36: void init();
37: int printline();
38: char *PSstring();
39: void usage();
40:
41: /* External. */
42: double atof();
43: char *index();
44:
45: /* Global. */
46: char *argv0; /* Command name. */
47: int bflag; /* Suppress box. */
48: char buf[NBUF]; /* Input buffer. */
49: char buf2[NBUF]; /* Buffer for PSstring. */
50: char buf3[NBUF]; /* Buffer for printline. */
51: char curfont; /* Current font ('R','B','I'). */
52: int dodate = 1; /* Display local date/time */
53: char *fontname = DEFFONT; /* Font name. */
54: char *fontBsuffix = DEFFONTB; /* Boldace font suffix. */
55: char *fontIsuffix = DEFFONTI; /* Italic font suffix. */
56: char *fontRsuffix = DEFFONTR; /* Roman font suffix. */
57: int hflag; /* Suppress header. */
58: char *hdrname = NULL; /* Name for header line. */
59: int indent; /* Indent. */
60: int lflag; /* Landscape mode. */
61: int nlines; /* Lines per page. */
62: double ptsize; /* Point size. */
63: int rhpage; /* Right-hand page flag. */
64: int skip; /* Output pages to skip. */
65: int tab = DEFTAB; /* Tab setting. */
66:
67: /*
68: * Output page format.
69: * The page format is hardwired into this table for now;
70: * the page is assumed to be 8.5 x 11, or 11 x 8.5 in landscape mode.
71: * The format[] array is indexed by lflag:
72: * 0 portrait mode
73: * 1 landscape mode
74: * 2 landscape mode, two side-by-side pages per output page
75: */
76: struct pformat {
77: double p_boxx; /* box ll x */
78: double p_boxy; /* box ll y */
79: double p_boxdx; /* box width */
80: double p_boxdy; /* box height */
81: double p_hdry; /* header y */
82: double p_textx; /* text x */
83: double p_textdy; /* text height */
84: } format[3] = {
85: /* boxx boxy boxdx boxdy hdry textx textdy */
86: { .75, .50, 7.250, 9.750, 10.500, 1.000, 9.175 },
87: { .50, .50, 10.000, 7.125, 7.875, .750, 6.750 },
88: { .25, .25, 5.125, 7.500, 7.950, .375, 7.400 }
89: };
90:
91: main(argc, argv) int argc; char *argv[];
92: {
93: register char *s;
94: register char c;
95:
96: /* Process command line options. */
97: argv0 = argv[0];
98: while (argc > 1 && (argv[1][0] == '-' || argv[1][0] == '+')) {
99: s = &argv[1][1];
100: if (argv[1][0] == '+') {
101: skip = atoi(s);
102: --argc;
103: ++argv;
104: continue;
105: }
106: while ((c = *s++) != '\0') {
107: switch(c) {
108: case 'b':
109: ++bflag;
110: continue;
111: case 'd':
112: dodate = 0;
113: continue;
114: case 'f':
115: fontname = s;
116: break;
117: case 'F':
118: if (*s == 's') {
119: if ((c = *++s) == 'B')
120: fontBsuffix = ++s;
121: else if (c == 'I')
122: fontIsuffix = ++s;
123: else if (c == 'R')
124: fontRsuffix = ++s;
125: else
126: fatal("option \"-Fs\" must be followed by [RBI] and suffix");
127: break;
128: } else
129: s = Foption(s);
130: continue;
131: case 'h':
132: ++hflag;
133: continue;
134: case 'i':
135: indent = atoi(s);
136: if (indent < 0)
137: fatal("illegal \"-i\" argument");
138: break;
139: case 'l':
140: lflag = 1;
141: if (*s == '2') {
142: lflag = 2;
143: ++s;
144: }
145: continue;
146: case 'n':
147: hdrname = s;
148: break;
149: case 'p':
150: nlines = atoi(s);
151: if (nlines < 1)
152: fatal("illegal \"-p\" argument");
153: break;
154: case 't':
155: tab = atoi(s);
156: if (tab < 2)
157: fatal("tab setting must be 2 or larger");
158: break;
159: case 'V':
160: fprintf(stderr, "%s: V%s\n", argv0, VERSION);
161: continue;
162: default:
163: if (c >= '1' && c <= '9') {
164: ptsize = atof(--s);
165: break;
166: }
167: /* else fall through... */
168: case '?':
169: usage();
170: break;
171: }
172: while (*++s)
173: ; /* scan to end of arg */
174: }
175: --argc;
176: ++argv;
177: }
178:
179: /* Process input files. */
180: init();
181: if (argc == 1)
182: file(NULL);
183: else
184: while (--argc > 0)
185: file(*++argv);
186: if (lflag == 2 && rhpage)
187: printf("endpage\n");
188: printf("state restore\n");
189:
190: /* Done. */
191: exit(0);
192: }
193:
194: /*
195: * Cry and die.
196: */
197: /* VARARGS */
198: void
199: fatal(args) char *args;
200: {
201: fprintf(stderr, "%s: %r\n", argv0, &args);
202: exit(1);
203: }
204:
205: /*
206: * Process a file.
207: */
208: void
209: file(name) char *name;
210: {
211: register FILE *fp;
212: register int line, page;
213: time_t t;
214:
215: if (name == NULL)
216: fp = stdin;
217: else if ((fp = fopen(name, "r")) == NULL)
218: fatal("cannot open \"%s\"", name);
219:
220: /* Define name and date fields for header line. */
221: if (!hflag) {
222: printf("/hdrname %s def\n",
223: PSstring((hdrname != NULL) ? hdrname :
224: (name != NULL) ? name : ""));
225: time(&t);
226: printf("/hdrdate %s def\n\n",
227: dodate ? PSstring(asctime(localtime(&t)))
228: : PSstring(""));
229: }
230:
231: /* Process the file. */
232: if (skip) {
233: if (lflag == 2)
234: skip &= ~1; /* round down to even */
235: for (page = 0; page < skip; page++) {
236: for (line = 0; line < nlines; line++) {
237: if (fgets(buf, NBUF, fp) == NULL)
238: break;
239: if (index(buf, '\f') != NULL)
240: break;
241: }
242: }
243: }
244: line = 0;
245: page = skip + 1;
246: while (fgets(buf, NBUF, fp) != NULL) {
247: if (line++ == 0) {
248: /* Start of page. */
249: printf("%% Page %d.\n", page);
250: if (!hflag)
251: printf("/hdrpage (Page %d, line %d) def\n",
252: page, (page-1)*nlines+1);
253: if (lflag == 2)
254: printf("%chpage\n", (rhpage) ? 'r' : 'l');
255: else
256: printf("startpage\n");
257: curfont = 'R'; /* startpage sets Roman */
258: }
259: if (printline() || line == nlines) {
260: /* End of page. */
261: if (lflag == 2 && !rhpage != 0)
262: putchar('\n');
263: else
264: printf("endpage\n\n");
265: page++;
266: line = 0;
267: rhpage = !rhpage;
268: }
269: }
270: if (line != 0) {
271: if (lflag != 2 || rhpage)
272: printf("endpage\n\n");
273: rhpage = !rhpage;
274: }
275:
276: if (name != NULL)
277: fclose(fp);
278: }
279:
280: /*
281: * Return the font ('R', 'I', 'B', or 'W') of the non-NUL character *s.
282: * Return 'W' for whitespace, which always leaves font unchanged.
283: */
284: int
285: font_of(s) register char *s;
286: {
287: register char c1, c3;
288:
289: if ((c1 = *s) == ' ' || c1 == '\t' || c1 == '\n')
290: return 'W';
291: if (*++s != '\b')
292: return 'R'; /* Not "x\bx" nor "_\bx", i.e. Roman */
293: if ((c3 = *++s) == '\0')
294: return 'R'; /* unlikely */
295: if (c1 == '_')
296: return 'I'; /* Italic */
297: return ((c1 == c3) ? 'B' : 'R'); /* Bold or unlikely Roman */
298: }
299:
300: /*
301: * Process a -F command line font specification.
302: * Return a pointer past the last character used.
303: */
304: char *
305: Foption(s) register char *s;
306: {
307: register char c;
308:
309: switch (c = *s++) {
310: case 'A':
311: fontname = "AvantGarde";
312: fontBsuffix = "-Demi";
313: fontIsuffix = "-BookOblique";
314: fontRsuffix = "-Book";
315: break;
316: case 'B':
317: fontname = "Bookman";
318: fontBsuffix = "-Demi";
319: fontIsuffix = "-LightItalic";
320: fontRsuffix = "-Light";
321: break;
322: case 'H':
323: fontname = "Helvetica";
324: break;
325: case 'N':
326: fontname = "Helvetica-Narrow";
327: break;
328: case 'P':
329: fontname = "Palatino";
330: goto lab;
331: case 'S':
332: fontname = "NewCenturySchlbk";
333: goto lab;
334: case 'T':
335: fontname = "Times";
336: lab:
337: fontIsuffix = "-Italic";
338: fontRsuffix = "-Roman";
339: break;
340: default:
341: fatal("option \"-F\" must be followed by 's' or by one of [ABHNPST]");
342: break;
343: }
344: return s;
345: }
346:
347: /*
348: * Initialize PostScript program.
349: */
350: void
351: init()
352: {
353: register struct pformat *p;
354: double d, hdrx, hdrdx, texty;
355: int n;
356:
357: p = &format[lflag];
358: hdrx = p->p_boxx;
359: hdrdx = p->p_boxdx;
360: if (hflag) {
361: /* Reclaim the space reserved for the header. */
362: d = p->p_hdry - p->p_boxdy - p->p_boxy; /* added height */
363: p->p_boxdy += d;
364: p->p_textdy += d;
365: }
366:
367: /* Determine the point size and text lines per page. */
368: /* lines = inches * points/inch / points/line */
369: if (ptsize == 0 && nlines == 0) /* neither specified */
370: ptsize = (lflag == 2) ? DEFPTSIZEL2 : DEFPTSIZE;
371: else if (ptsize == 0) /* nlines specified */
372: ptsize = p->p_textdy * 72 / nlines;
373: else if (nlines != 0) { /* both specified */
374: n = p->p_textdy * 72 / ptsize;
375: if (n < nlines) {
376: fprintf(stderr, "%s: Warning: -p argument ignored (too large for point size)\n",
377: argv0);
378: nlines = n;
379: }
380: }
381: if (nlines == 0)
382: nlines = p->p_textdy * 72 / ptsize;
383:
384: /* Center text in the box. */
385: p->p_textdy = ptsize * nlines / 72; /* adjust length for roundoff */
386: texty = p->p_boxy + p->p_boxdy - (p->p_boxdy - p->p_textdy) / 2;
387:
388: /* PostScript globals. */
389: printf(
390: "%% Global definitions.\n"
391: "/state save def\n"
392: "/FS { findfont ptsize scalefont } bind def\n"
393: "/S { show } bind def\n"
394: );
395: printf("/ptsize %.2f def\n", ptsize);
396: printf("/fontH /%s findfont %d scalefont def\n",
397: DEFFONT, (lflag==2) ? DEFPTSIZEL2 : DEFPTSIZE);
398: printf("/fontR /%s%s FS def\n", fontname, fontRsuffix);
399: printf("/fontB /%s%s FS def\n", fontname, fontBsuffix);
400: printf("/fontI /%s%s FS def\n", fontname, fontIsuffix);
401: printf(
402: "/fH {fontH setfont} bind def\n"
403: "/fR {fontR setfont} bind def\n"
404: "/fB {fontB setfont} bind def\n"
405: "/fI {fontI setfont} bind def\n"
406: );
407: putchar('\n');
408:
409: /* PostScript routines. */
410: printf("%% Routines.\n");
411: if (!bflag)
412: printf(
413: "/box\t%% boxdx boxdy boxx boxy box -\n"
414: "{\n"
415: "\tnewpath\n"
416: "\tmoveto\n"
417: "\texch dup 0 rlineto\n"
418: "\texch 0 exch rlineto\n"
419: "\tneg 0 rlineto\n"
420: "\tclosepath\n"
421: "\tclip\n"
422: "\t0.02 setlinewidth\n"
423: "\tstroke\n"
424: "} bind def\n"
425: );
426: printf("/endpage {grestore showpage} bind def\n");
427: if (!hflag) {
428: printf(
429: "/hdr\t%% Uses hdrname, hdrdate, hdrpage.\n"
430: "{\n"
431: "\tgsave\n"
432: "\tfH\n"
433: );
434: printf("\t%d %d translate 0 0 moveto\n",
435: inch(hdrx), inch(p->p_hdry));
436: printf("\thdrname S\n");
437: printf("\t%d hdrdate stringwidth pop 2 div sub %d neg moveto\n",
438: inch(hdrdx/2), (lflag==2) ? DEFPTSIZEL2 : DEFPTSIZE);
439: printf("\thdrdate S\n");
440: printf("\t%d hdrpage stringwidth pop sub 0 moveto\n",
441: inch(hdrdx));
442: printf(
443: "\thdrpage S\n"
444: "\tgrestore\n"
445: "} bind def\n"
446: );
447: }
448: if (indent) {
449: printf("/indent fR (");
450: for (n = indent; n--; )
451: putchar(' ');
452: printf(") stringwidth pop def\n");
453: }
454: if (lflag == 2)
455: printf("/lhpage {90 rotate 0 %d translate startpage} bind def\n",
456: inch(-PAGEDX));
457: printf("/nl {0 %.2f translate 0 0 moveto} bind def\n", -ptsize);
458: printf("/BS { stringwidth pop neg 0 rmoveto } bind def\n");
459: printf("/N {show nl} bind def\n");
460: if (lflag == 2)
461: printf("/rhpage {grestore %d 0 translate startpage} bind def\n",
462: inch(p->p_boxx + p->p_boxdx));
463: printf("/startpage {\n");
464: printf("\tgsave\n");
465: if (lflag == 1)
466: printf("\t90 rotate 0 %d translate\n", inch(-PAGEDX));
467: if (!hflag)
468: printf("\thdr\n");
469: if (!bflag)
470: printf("\t%d %d %d %d box\n",
471: inch(p->p_boxdx), inch(p->p_boxdy),
472: inch(p->p_boxx), inch(p->p_boxy));
473: printf("\t%d%s %d translate\n",
474: inch(p->p_textx),
475: (indent) ? " indent add" : "",
476: inch(texty) - (int)ptsize);
477: printf("\t0 0 moveto\n\tfR\n} bind def\n");
478: printf("\n%% Text.\n");
479: }
480:
481: /*
482: * Print a line of text from buf[].
483: * This would be one line of code without the font handling.
484: */
485: printline()
486: {
487: register char *s, *cp;
488: char c;
489: int new;
490: int found_ff = 0; /* saw formfeed in input stream */
491:
492: s = buf; /* input pointer */
493: cp = buf3; /* output string pointer */
494: while ((c = *s) != '\0' && c != '\n') {
495: if (c == '\f') {
496: /* Formfeed. */
497: ++found_ff;
498: ++s;
499: continue;
500: } else if (c == '\b') {
501: /* Backspace. */
502: if (cp != buf3) {
503: *cp-- = '\0';
504: c = *cp; /* last char printed */
505: printf("%s S ", PSstring(buf3));
506: cp = buf3;
507: } else
508: c = ' '; /* at start of line */
509: printf("(%c) BS ", c); /* backspace */
510: ++s;
511: continue;
512: }
513: new = font_of(s);
514: if (new != curfont && new != 'W') {
515: /* Font change. */
516: if (cp != buf3) {
517: *cp = '\0';
518: printf("%s S ", PSstring(buf3));
519: cp = buf3;
520: }
521: printf("f%c ", new); /* switch to new font */
522: curfont = new;
523: }
524: if (new == 'R' || new == 'W')
525: s++;
526: else {
527: s += 2; /* skip 2 if bold or italic */
528: c = *s++; /* third gives the char */
529: if (new == 'B') {
530: /* Watch for Unix braindamage "c\bc\bc", GOK. */
531: while (*s == '\b' && *(s+1) == c)
532: s += 2;
533: }
534: }
535: *cp++ = c; /* store the character */
536: }
537: if (cp != buf3) {
538: *cp = '\0';
539: printf("%s N\n", PSstring(buf3));
540: } else
541: printf("nl\n");
542: return found_ff;
543: }
544:
545: /*
546: * Convert string cp to PostScript string in buf2[].
547: * PostScript understands tabs but the tab stops it uses seem screwy,
548: * so this routine expands tabs for now.
549: * The tab expansion here assumes the string starts at the left margin.
550: */
551: char *
552: PSstring(cp) register char *cp;
553: {
554: register char *s, c;
555: register int col;
556:
557: col = 1; /* current output column */
558: s = buf2;
559: *s++ = '(';
560: while ((c = *cp++) != '\n' && c != '\0') {
561: if (c == '\t') {
562: do {
563: *s++ = ' ';
564: } while ((col++ % tab) != 0);
565: } else {
566: if (c == '(' || c == ')' || c == '\\')
567: *s++ = '\\';
568: *s++ = c;
569: ++col;
570: }
571: }
572: *s++ = ')';
573: *s = '\0';
574: return buf2;
575: }
576:
577: /*
578: * Print a usage message and die.
579: */
580: void
581: usage()
582: {
583: fprintf(stderr,
584: "Usage: prps [ options ] [ file ... ]\n"
585: "Options:\n"
586: "\t+n\tSkip first n pages of output.\n"
587: "\t-n\tUse point size n (default: 10).\n"
588: "\t-b\tSuppress the box around the page text.\n"
589: "\t-d\tSuppress printing the date and time.\n"
590: "\t-ffont\tUse the given font name (default: Courier).\n"
591: "\t-FX\tUse font X, which must be [ABHNPST].\n"
592: "\t-FsXsfx\tUse sfx as suffix for font X, which must be [RBI].\n"
593: "\t\tDefault suffixes are \"\" (R), \"-Bold\" (B), \"-Oblique\" (I).\n"
594: "\t-h\tSuppress the header line.\n"
595: "\t-in\tIndent by an additional n spaces.\n"
596: "\t-l\tLandscape mode (default: portrait).\n"
597: "\t-l2\tLandscape mode, two pages per output page.\n"
598: "\t-nhead\tUse the given name instead of filename in the header line.\n"
599: "\t-pn\tPrint n lines of text per output page.\n"
600: "\t-tn\tSet tab stops to every n characters (default: 8).\n"
601: );
602: exit(1);
603: }
604:
605: /* end of prps.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.