|
|
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.