|
|
1.1 ! root 1: /* ! 2: * hp.c ! 3: * 11/13/90 ! 4: * Hewlett Packard LaserJet printer filter. ! 5: * Translate page format and nroff font information ! 6: * into HP LaserJet printer escape sequences (PCL). ! 7: * Usage: hp [-acflr] [-in] [-pn] [-tn] [file ...] ! 8: * Options: ! 9: * -a Use HP font acute accent character for '\''; default is '\''. ! 10: * -c Font cartridge not available, use underline for italics. ! 11: * -f [Archaic] Print pages in normal order; this is now the default. ! 12: * -in Set left margin (indent) to n; default is 0. ! 13: * -l Print in landscape mode; default is portrait mode. ! 14: * -pn Set text length to n; default is NLINES, i.e. 66. ! 15: * -r Print pages in reverse order (for LaserJet I). ! 16: * [Writes to temp FILE 'output', then readback() rewrites ! 17: * temp file to stdout with pages reversed.] ! 18: * -tn Set top margin to n; default is 0. ! 19: * Exit status is 0 if successful, 1 if error, 2 if interrupted. ! 20: * ! 21: * Edit history: ! 22: * 3/21/85 (jtk) -- Changed so that pages were printed in reverse order, ! 23: * and fixed bug where trailing lines with only ! 24: * non-blank character were deleted. ! 25: * 4/09/85 (ella) -- Changed so that pages were printed in ! 26: * the landscape mode with the pitch 16.66, and ! 27: * fixed bug where underlining in the landscape mode ! 28: * and/or !cartridge wasn't ever terminated. ! 29: * Incorporated rma's fix (-a option) to reflect the ! 30: * manual page and properly process acute accents: ! 31: * default: straight (apostrophe), with -a: slanted ! 32: * (single quote). ! 33: * Included all available options into Usage message. ! 34: * 10/31/90 (norm) -- fixed the brain damage regarding ! 35: * formfeeds. Change default to printing pages in ! 36: * order since almost all printers do. Close any ! 37: * files that we open. Guess that shows how much testing ! 38: * was done by the author... ! 39: * 11/7/90 (steve) -- Reordered and rewrote text extensively ! 40: * for legibility, hopefully no substantive changes. ! 41: */ ! 42: ! 43: #include <stdio.h> ! 44: #include <signal.h> ! 45: ! 46: extern long ftell(); ! 47: ! 48: /* Miscellany. */ ! 49: #define VERSION "1.3" ! 50: #define ACCENTACUTE 0xA8 ! 51: #define ACCENTGRAVE 0xA9 ! 52: #define LINESZ 512 ! 53: #define NLINES 66 ! 54: #define NPAGES 1000 ! 55: #define USAGEMSG "Usage: hp [ -acflr ] [ -in ] [ -pn ] [ -tn ] [ file ... ]" ! 56: ! 57: /* Fonts. */ ! 58: #define ROMAN_F 0 /* all except below means Roman */ ! 59: #define BOLD_F 1 /* "x\bx" means bold 'x' */ ! 60: #define ITALIC_F 2 /* "_\bx" means italic '_' */ ! 61: ! 62: /* HP Printer Control Language (PCL) commands. */ ! 63: /* These are printf() format strings, some require additional arguments. */ ! 64: #define HMOVEFWD "\033&a+%dH" ! 65: #define HMOVEBACK "\033&a-%dH" ! 66: #define LANDSCAPE "\033&l%dO" /* arg 0==portrait, 1==landscape */ ! 67: #define LEFTMARGIN "\033&a%dL" ! 68: #define LINESPACING "\033&l%dD" ! 69: #define MOVETOCOL "\033&a%dC" ! 70: #define PAGELENGTH "\033&l%dP" ! 71: #define PITCH16 "\033(s16.66H" /* pitch 16.66 cpi */ ! 72: #define RESET "\033E" ! 73: #define STROKEWEIGHT "\033(s%dB" ! 74: #define STYLE "\033(s%dS" ! 75: #define STYLEWEIGHT "\033(s%ds%dB" ! 76: #define TEXTLENGTH "\033&l%dF" ! 77: #define TOPMARGIN "\033&l%dE" ! 78: #define UNDEROFF "\033&d@" ! 79: #define UNDERON "\033&dD" ! 80: ! 81: /* Forward. */ ! 82: #if 0 ! 83: void debug(); ! 84: #endif ! 85: void done(); ! 86: void fakebold(); ! 87: void fatal(); ! 88: int hasFF(); ! 89: void initialize(); ! 90: void newfont(); ! 91: int nonblank(); ! 92: void printfile(); ! 93: void printline(); ! 94: void readback(); ! 95: void trap(); ! 96: void usage(); ! 97: ! 98: /* Globals. */ ! 99: int aflag; /* Accent flag */ ! 100: char *argv0; /* Command name for error messages */ ! 101: int cartridge = 1; /* Font cartridge is available */ ! 102: int font = ROMAN_F; /* Current font */ ! 103: int landscape; /* 0 for portrait mode, 1 for landscape */ ! 104: int leftmargin; /* Left margin */ ! 105: int linespacing = 6; /* Vertical lines per inch */ ! 106: int nfiles; /* Number of files to print */ ! 107: int npages; /* Number of pages marked on input */ ! 108: FILE *output = NULL; /* FILE containing unreversed pages */ ! 109: char page[NLINES][LINESZ]; /* Current page buffer */ ! 110: long pageaddr[NPAGES]; /* Seek pointers to top of output pages */ ! 111: int quit; /* Signal to interrupt program */ ! 112: int rflag; /* Reverse page order */ ! 113: char tempfile[20]; /* Temporary file name */ ! 114: int textlength = NLINES; /* Text length -- must satisfy */ ! 115: /* textlength <= NLINES-topmargin */ ! 116: int topmargin; /* Top margin */ ! 117: ! 118: main(argc, argv) int argc; char *argv[]; ! 119: { ! 120: /* Process arguments. */ ! 121: argv0 = argv[0]; ! 122: argc--; ! 123: argv++; ! 124: while (argc > 0) { ! 125: switch(**argv) { ! 126: case '-': ! 127: switch(*++*argv) { ! 128: case 'a': ! 129: aflag = 1; ! 130: break; ! 131: case 'c': ! 132: cartridge = 0; ! 133: break; ! 134: case 'f': ! 135: /* Recognized for historical reasons, ignore. */ ! 136: break; ! 137: case 'i': ! 138: leftmargin = atoi(++*argv); ! 139: break; ! 140: case 'l': ! 141: landscape = 1; ! 142: linespacing = 8; ! 143: break; ! 144: case 'p': ! 145: textlength = atoi(++*argv); ! 146: break; ! 147: case 'r': ! 148: rflag = 1; ! 149: break; ! 150: case 't': ! 151: topmargin = atoi(++*argv); ! 152: break; ! 153: case 'V': ! 154: fprintf(stderr, "%s: V%s\n", argv0, VERSION); ! 155: break; ! 156: default: ! 157: usage(); ! 158: break; ! 159: } ! 160: break; ! 161: default: ! 162: if (nfiles++ == 0) ! 163: initialize(); ! 164: printfile(*argv); ! 165: break; ! 166: } ! 167: argv++; ! 168: argc--; ! 169: } ! 170: ! 171: /* If no command line files, process stdin. */ ! 172: if (nfiles == 0) { ! 173: initialize(); ! 174: printfile(NULL); ! 175: } ! 176: ! 177: /* Done. */ ! 178: if (rflag) ! 179: readback(); ! 180: done(0); ! 181: } ! 182: ! 183: #if 0 ! 184: /* ! 185: * Print debugging output to file "hp.db". ! 186: */ ! 187: /* VARARGS */ ! 188: void ! 189: debug(s) char *s; ! 190: { ! 191: register FILE *fp; ! 192: ! 193: if ((fp = fopen("hp.db", "ar")) == NULL) ! 194: return; ! 195: fprintf(fp, "hp: %r\n" &s); ! 196: fclose(fp); ! 197: } ! 198: #endif ! 199: ! 200: /* ! 201: * Finish up. Remove temporary file if it has been opened, then exit. ! 202: */ ! 203: void ! 204: done(status) int status; ! 205: { ! 206: printf(RESET); ! 207: if (output != NULL) { ! 208: fclose(output); ! 209: if (output != stdout) ! 210: unlink(tempfile); ! 211: } ! 212: exit(status); ! 213: } ! 214: ! 215: /* ! 216: * Fake boldface of given character when font not available. ! 217: */ ! 218: void ! 219: fakebold(c) register int c; ! 220: { ! 221: register int d; ! 222: ! 223: if (font != ROMAN_F) ! 224: newfont(ROMAN_F); /* terminate previous font */ ! 225: d = (landscape) ? 7 : 8; /* decipoint distance */ ! 226: putc(c, output); /* print it */ ! 227: fprintf(output, MOVETOCOL, -1); /* move back one column */ ! 228: fprintf(output, HMOVEFWD, d); /* and forward d decipoints */ ! 229: putc(c, output); /* print it again */ ! 230: fprintf(output, HMOVEBACK, d); /* and move back d decipoints */ ! 231: } ! 232: ! 233: /* ! 234: * Print a fatal error message and die. ! 235: */ ! 236: /* VARARGS */ ! 237: void ! 238: fatal(s) char *s; ! 239: { ! 240: fprintf(stderr, "%s: %r\n", argv0, &s); ! 241: done(1); ! 242: } ! 243: ! 244: /* ! 245: * Test whether string s contains a formfeed. ! 246: */ ! 247: int ! 248: hasFF(s) register char *s; ! 249: { ! 250: register char c; ! 251: ! 252: while (c = *s++) ! 253: if (c == '\f') ! 254: return 1; ! 255: return 0; ! 256: } ! 257: ! 258: /* ! 259: * Set interrupt trap and initialize the printer. ! 260: * Open temporary file if rflag is specified, ! 261: * otherwise output just goes to stdout. ! 262: */ ! 263: void ! 264: initialize() ! 265: { ! 266: /* Trap SIGINT to set quit flag. */ ! 267: signal(SIGINT, trap); ! 268: ! 269: /* HP initialization. */ ! 270: printf(RESET); ! 271: if (landscape) ! 272: printf(PITCH16); ! 273: printf(LANDSCAPE, landscape); ! 274: printf(PAGELENGTH, NLINES); ! 275: printf(LINESPACING, linespacing); ! 276: printf(TOPMARGIN, topmargin); ! 277: printf(TEXTLENGTH, textlength); ! 278: printf(LEFTMARGIN, leftmargin); ! 279: ! 280: /* Initialize output file. */ ! 281: if (quit) ! 282: done(2); ! 283: if (rflag) { ! 284: sprintf(tempfile, "/tmp/hptmp.%d", getpid()); ! 285: if ((output = fopen(tempfile, "wr")) == NULL) ! 286: fatal("cannot open temporary file \"%s\"", tempfile); ! 287: } else ! 288: output = stdout; ! 289: } ! 290: ! 291: /* ! 292: * Change to a new font. ! 293: * For each of the three fonts (ROMAN_F, BOLD_F, ITALIC_F), ! 294: * this routine prints the font escape appropriate to the given configuration. ! 295: * There are currently four possible printer configurations: ! 296: * normal portrait && cartridge ! 297: * -l landscape && cartridge ! 298: * -c portrait && no cartridge ! 299: * -c -l landscape && no cartridge ! 300: * In the first case, do bold and italic with style and weight changes. ! 301: * bold is faked from printline() per-character in the other cases, ! 302: * italic is underlined Roman in the other cases. ! 303: */ ! 304: void ! 305: newfont(new) int new; ! 306: { ! 307: static int style = 0; /* initial style == upright */ ! 308: static int weight = 0; /* initial weight == medium */ ! 309: static int under = 0; /* initial underline state == off */ ! 310: register int newstyle, newweight, newunder; ! 311: ! 312: if (font == new) ! 313: return; /* unchanged */ ! 314: font = new; ! 315: newstyle = newweight = newunder = 0; /* defaults */ ! 316: switch(font) { ! 317: case ROMAN_F: ! 318: break; /* upright medium */ ! 319: case BOLD_F: ! 320: newweight = 1; /* bold */ ! 321: break; ! 322: case ITALIC_F: ! 323: if (cartridge && !landscape) { ! 324: newstyle = 1; /* italic */ ! 325: newweight = -1; /* weight -1 */ ! 326: } else ! 327: newunder = 1; /* underlined upright medium */ ! 328: break; ! 329: default: ! 330: fatal("unrecognized font type %d", font); ! 331: break; ! 332: } ! 333: if (under != newunder) { ! 334: under = newunder; ! 335: fprintf(output, (under) ? UNDERON : UNDEROFF); ! 336: } ! 337: if (style != newstyle && weight != newweight) { ! 338: style = newstyle; ! 339: weight = newweight; ! 340: fprintf(output, STYLEWEIGHT, style, weight); ! 341: } else if (style != newstyle) { ! 342: style = newstyle; ! 343: fprintf(output, STYLE, style); ! 344: } else if (weight != newweight) { ! 345: weight = newweight; ! 346: fprintf(output, STROKEWEIGHT, weight); ! 347: } ! 348: } ! 349: ! 350: /* ! 351: * Return 1 if line s is not blank. ! 352: */ ! 353: int ! 354: nonblank(s) register char *s; ! 355: { ! 356: register int c; ! 357: ! 358: while ((c = *s) == ' ' || c == '\t') ! 359: s++; ! 360: return (c != '\0' && c != '\n' && c != '\f'); ! 361: } ! 362: ! 363: /* ! 364: * Print a file. ! 365: * NULL means stdin. ! 366: */ ! 367: void ! 368: printfile(file) char *file; ! 369: { ! 370: FILE *fp; ! 371: register int i; ! 372: int last, end; ! 373: ! 374: if (file == NULL) ! 375: fp = stdin; ! 376: else if ((fp = fopen(file, "r")) == NULL) ! 377: fatal("cannot open file \"%s\"", file); ! 378: ! 379: if (font != ROMAN_F) ! 380: newfont(ROMAN_F); ! 381: for (end = 0; !end; ) { ! 382: if (rflag) { ! 383: if (npages >= NPAGES) ! 384: fatal("more than %d pages", NPAGES); ! 385: pageaddr[npages++] = ftell(output); ! 386: } ! 387: for (i = 0; i < NLINES; i++) { ! 388: if (fgets(&page[i][0], LINESZ, fp) == NULL) { ! 389: if (i == 0) { ! 390: npages--; /* last page empty */ ! 391: return; ! 392: } ! 393: end = 1; ! 394: break; ! 395: } else if (hasFF(page[i])) { /* formfeed seen */ ! 396: ++i; ! 397: break; ! 398: } ! 399: } ! 400: for (last = --i; last >= 0; --last) ! 401: if (nonblank(page[last])) ! 402: break; /* nonblank line */ ! 403: for (i = 0; i <= last; i++) ! 404: printline(page[i]); ! 405: putc('\r', output); ! 406: if (last < NLINES - 1) ! 407: putc('\f', output); ! 408: } ! 409: if (file != NULL) ! 410: fclose(fp); ! 411: } ! 412: ! 413: /* ! 414: * Print one line, substituting special characters from the HP character set. ! 415: */ ! 416: void ! 417: printline(cp) register char *cp; ! 418: { ! 419: register int c1, c2, new; ! 420: char *s; ! 421: ! 422: /* Replace accents with equivalents from the extended character set. */ ! 423: for (s = cp; *s != '\0'; ++s) { ! 424: if (*s == '\'' && aflag) ! 425: *s = ACCENTACUTE; ! 426: else if (*s == '`') ! 427: *s = ACCENTGRAVE; ! 428: } ! 429: ! 430: /* Look for nroff font sequences. */ ! 431: while ((c1 = *cp++) != '\0') { ! 432: ! 433: /* Check for the interrupt signal. */ ! 434: if (quit) ! 435: done(2); ! 436: ! 437: /* By default, Roman c1 gets printed at the end of this loop. */ ! 438: new = ROMAN_F; ! 439: if (c1 == '\f') ! 440: return; /* chars after FF on line get eaten */ ! 441: else if (c1 == ' ' || c1 == '\t') ! 442: new = font; /* no font change on whitespace */ ! 443: else if (c1 == '_') { ! 444: if ((c2 = *cp++) == '\b') { ! 445: /* "_\bx" means italic x. */ ! 446: new = ITALIC_F; ! 447: c1 = *cp++; ! 448: } else ! 449: cp--; /* put back c2 */ ! 450: } else if ((c2 = *cp++) == '\b') { ! 451: if ((c2 = *cp++) == c1) { ! 452: /* "x\bx" means bold x. */ ! 453: if (!cartridge || landscape) { ! 454: fakebold(c1); /* fake it */ ! 455: continue; ! 456: } else ! 457: new = BOLD_F; ! 458: } else ! 459: cp -= 2; /* put back '\b' and c2 */ ! 460: } else ! 461: cp--; /* put back c2 */ ! 462: if (font != new) ! 463: newfont(new); /* font change */ ! 464: putc(c1, output); /* print c1 in new font */ ! 465: } ! 466: } ! 467: ! 468: /* ! 469: * Copy the temporary file to stdout with the pages in reverse order. ! 470: */ ! 471: void ! 472: readback() ! 473: { ! 474: char c; ! 475: ! 476: while (--npages >= 0) { ! 477: /* Check for interrupt signal at each page. */ ! 478: if (quit) ! 479: done(2); ! 480: fseek(output, pageaddr[npages], 0); ! 481: while ((c = getc(output)) != '\f') ! 482: putchar(c); ! 483: putchar(c); ! 484: } ! 485: } ! 486: ! 487: /* ! 488: * Set quit flag when interrupt signal is received. ! 489: */ ! 490: void ! 491: trap() ! 492: { ! 493: quit = 1; ! 494: } ! 495: ! 496: /* ! 497: * Print a usage message and die. ! 498: */ ! 499: void ! 500: usage() ! 501: { ! 502: fprintf(stderr, "%s\n", USAGEMSG); ! 503: exit(1); ! 504: } ! 505: ! 506: /* end of hp.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.