/* * HPP -- Format a text file in a decent way for a HP Laserjet (PCL) * * $Id: hpp.c,v 1.10 2007-12-14 15:34:56+00 mgk25 Exp $ * * Markus Kuhn * * HP PCL command codes: * http://www.hp.com/cposupport/printers/support_doc/bpl02705.html */ #include #include #include #include #include #include #include #ifndef __STDC_ISO_10646__ #error This software requires wchar_t to be ISO 10646 encoded #endif #define VERSION "2.2" #define FINAL_FF /* define if printing system does not append a FF */ char usage[] = "HPP " VERSION " -- Markus Kuhn -- HP LaserJet text formatter\n\n" "usage: %s [options] [ | -]\n\n" "options:\n\n" "\t-d\t\tdouble column format\n" "\t-l\t\tlandscape format\n" "\t-h\t\tno headline\n" "\t-m\t\tno left margin\n" "\t-t \"title\"\tset title line (default: filename)\n" "\t-r\t\tlist the supported Unicode characters >U+00FF and exit\n\n" "Result is sent to standard output. Paper format is ISO A4.\n" "The character encoding is determined by locale (LANG, LC_CTYPE, LC_ALL).\n"; /* charset switching codes */ char *charset[] = { "\x1b(0N", /* 8859-1 */ "\x1b(2N" , /* 8859-2 */ "\x1b(5N", /* 8859-9 */ "\x1b(10U", /* CP437 */ "\x1b(10J", /* PS stdenc */ "\x1b(5M", /* PS symbol */ "\x1b(19U", /* CP1252 */ "\x1b(12U" /* CP850 */ }; struct codepair { wchar_t ucs; char c; char set; } codemap[] = { { 0x0102, 0xc3, 1 }, // LATIN CAPITAL LETTER A WITH BREVE (8859_2) { 0x0103, 0xe3, 1 }, // LATIN SMALL LETTER A WITH BREVE (8859_2) { 0x0104, 0xa1, 1 }, // LATIN CAPITAL LETTER A WITH OGONEK (8859_2) { 0x0105, 0xb1, 1 }, // LATIN SMALL LETTER A WITH OGONEK (8859_2) { 0x0106, 0xc6, 1 }, // LATIN CAPITAL LETTER C WITH ACUTE (8859_2) { 0x0107, 0xe6, 1 }, // LATIN SMALL LETTER C WITH ACUTE (8859_2) { 0x010c, 0xc8, 1 }, // LATIN CAPITAL LETTER C WITH CARON (8859_2) { 0x010d, 0xe8, 1 }, // LATIN SMALL LETTER C WITH CARON (8859_2) { 0x010e, 0xcf, 1 }, // LATIN CAPITAL LETTER D WITH CARON (8859_2) { 0x010f, 0xef, 1 }, // LATIN SMALL LETTER D WITH CARON (8859_2) { 0x0110, 0xd0, 1 }, // LATIN CAPITAL LETTER D WITH STROKE (8859_2) { 0x0111, 0xf0, 1 }, // LATIN SMALL LETTER D WITH STROKE (8859_2) { 0x0118, 0xca, 1 }, // LATIN CAPITAL LETTER E WITH OGONEK (8859_2) { 0x0119, 0xea, 1 }, // LATIN SMALL LETTER E WITH OGONEK (8859_2) { 0x011a, 0xcc, 1 }, // LATIN CAPITAL LETTER E WITH CARON (8859_2) { 0x011b, 0xec, 1 }, // LATIN SMALL LETTER E WITH CARON (8859_2) { 0x011e, 0xd0, 2 }, // LATIN CAPITAL LETTER G WITH BREVE (8859_9) { 0x011f, 0xf0, 2 }, // LATIN SMALL LETTER G WITH BREVE (8859_9) { 0x0130, 0xdd, 2 }, // LATIN CAPITAL LETTER I WITH DOT ABOVE (8859_9) { 0x0131, 0xfd, 2 }, // LATIN SMALL LETTER DOTLESS I (8859_9) { 0x0139, 0xc5, 1 }, // LATIN CAPITAL LETTER L WITH ACUTE (8859_2) { 0x013a, 0xe5, 1 }, // LATIN SMALL LETTER L WITH ACUTE (8859_2) { 0x013d, 0xa5, 1 }, // LATIN CAPITAL LETTER L WITH CARON (8859_2) { 0x013e, 0xb5, 1 }, // LATIN SMALL LETTER L WITH CARON (8859_2) { 0x0141, 0xa3, 1 }, // LATIN CAPITAL LETTER L WITH STROKE (8859_2) { 0x0142, 0xb3, 1 }, // LATIN SMALL LETTER L WITH STROKE (8859_2) { 0x0143, 0xd1, 1 }, // LATIN CAPITAL LETTER N WITH ACUTE (8859_2) { 0x0144, 0xf1, 1 }, // LATIN SMALL LETTER N WITH ACUTE (8859_2) { 0x0147, 0xd2, 1 }, // LATIN CAPITAL LETTER N WITH CARON (8859_2) { 0x0148, 0xf2, 1 }, // LATIN SMALL LETTER N WITH CARON (8859_2) { 0x0150, 0xd5, 1 }, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE (8859_2) { 0x0151, 0xf5, 1 }, // LATIN SMALL LETTER O WITH DOUBLE ACUTE (8859_2) { 0x0152, 0xea, 4 }, // LATIN CAPITAL LIGATURE OE (stdenc) { 0x0153, 0xfa, 4 }, // LATIN SMALL LIGATURE OE (stdenc) { 0x0154, 0xc0, 1 }, // LATIN CAPITAL LETTER R WITH ACUTE (8859_2) { 0x0155, 0xe0, 1 }, // LATIN SMALL LETTER R WITH ACUTE (8859_2) { 0x0158, 0xd8, 1 }, // LATIN CAPITAL LETTER R WITH CARON (8859_2) { 0x0159, 0xf8, 1 }, // LATIN SMALL LETTER R WITH CARON (8859_2) { 0x015a, 0xa6, 1 }, // LATIN CAPITAL LETTER S WITH ACUTE (8859_2) { 0x015b, 0xb6, 1 }, // LATIN SMALL LETTER S WITH ACUTE (8859_2) { 0x015e, 0xaa, 1 }, // LATIN CAPITAL LETTER S WITH CEDILLA (8859_2) { 0x015f, 0xba, 1 }, // LATIN SMALL LETTER S WITH CEDILLA (8859_2) { 0x0160, 0xa9, 1 }, // LATIN CAPITAL LETTER S WITH CARON (8859_2) { 0x0161, 0xb9, 1 }, // LATIN SMALL LETTER S WITH CARON (8859_2) { 0x0162, 0xde, 1 }, // LATIN CAPITAL LETTER T WITH CEDILLA (8859_2) { 0x0163, 0xfe, 1 }, // LATIN SMALL LETTER T WITH CEDILLA (8859_2) { 0x0164, 0xab, 1 }, // LATIN CAPITAL LETTER T WITH CARON (8859_2) { 0x0165, 0xbb, 1 }, // LATIN SMALL LETTER T WITH CARON (8859_2) { 0x016e, 0xd9, 1 }, // LATIN CAPITAL LETTER U WITH RING ABOVE (8859_2) { 0x016f, 0xf9, 1 }, // LATIN SMALL LETTER U WITH RING ABOVE (8859_2) { 0x0170, 0xdb, 1 }, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE (8859_2) { 0x0171, 0xfb, 1 }, // LATIN SMALL LETTER U WITH DOUBLE ACUTE (8859_2) { 0x0178, 0x9f, 6 }, // LATIN CAPITAL LETTER Y WITH DIAERESIS (CP1252) { 0x0179, 0xac, 1 }, // LATIN CAPITAL LETTER Z WITH ACUTE (8859_2) { 0x017a, 0xbc, 1 }, // LATIN SMALL LETTER Z WITH ACUTE (8859_2) { 0x017b, 0xaf, 1 }, // LATIN CAPITAL LETTER Z WITH DOT ABOVE (8859_2) { 0x017c, 0xbf, 1 }, // LATIN SMALL LETTER Z WITH DOT ABOVE (8859_2) { 0x017d, 0xae, 1 }, // LATIN CAPITAL LETTER Z WITH CARON (8859_2) { 0x017e, 0xbe, 1 }, // LATIN SMALL LETTER Z WITH CARON (8859_2) { 0x0192, 0x9f, 3 }, // LATIN SMALL LETTER F WITH HOOK (CP437) { 0x02c6, 0xc3, 4 }, // MODIFIER LETTER CIRCUMFLEX ACCENT (stdenc) { 0x02c7, 0xb7, 1 }, // CARON (8859_2) { 0x02c9, 0xc5, 4 }, // MODIFIER LETTER MACRON (stdenc) { 0x02d8, 0xa2, 1 }, // BREVE (8859_2) { 0x02d9, 0xff, 1 }, // DOT ABOVE (8859_2) { 0x02da, 0xca, 4 }, // RING ABOVE (stdenc) { 0x02db, 0xb2, 1 }, // OGONEK (8859_2) { 0x02dc, 0xc4, 4 }, // SMALL TILDE (stdenc) { 0x02dd, 0xbd, 1 }, // DOUBLE ACUTE ACCENT (8859_2) { 0x0391, 0x41, 5 }, // GREEK CAPITAL LETTER ALPHA (symbol) { 0x0392, 0x42, 5 }, // GREEK CAPITAL LETTER BETA (symbol) { 0x0393, 0xe2, 3 }, // GREEK CAPITAL LETTER GAMMA (CP437) { 0x0394, 0x44, 5 }, // GREEK CAPITAL LETTER DELTA (symbol) { 0x0395, 0x45, 5 }, // GREEK CAPITAL LETTER EPSILON (symbol) { 0x0396, 0x5a, 5 }, // GREEK CAPITAL LETTER ZETA (symbol) { 0x0397, 0x48, 5 }, // GREEK CAPITAL LETTER ETA (symbol) { 0x0398, 0xe9, 3 }, // GREEK CAPITAL LETTER THETA (CP437) { 0x0399, 0x49, 5 }, // GREEK CAPITAL LETTER IOTA (symbol) { 0x039a, 0x4b, 5 }, // GREEK CAPITAL LETTER KAPPA (symbol) { 0x039b, 0x4c, 5 }, // GREEK CAPITAL LETTER LAMDA (symbol) { 0x039c, 0x4d, 5 }, // GREEK CAPITAL LETTER MU (symbol) { 0x039d, 0x4e, 5 }, // GREEK CAPITAL LETTER NU (symbol) { 0x039e, 0x58, 5 }, // GREEK CAPITAL LETTER XI (symbol) { 0x039f, 0x4f, 5 }, // GREEK CAPITAL LETTER OMICRON (symbol) { 0x03a0, 0x50, 5 }, // GREEK CAPITAL LETTER PI (symbol) { 0x03a1, 0x52, 5 }, // GREEK CAPITAL LETTER RHO (symbol) { 0x03a3, 0xe4, 3 }, // GREEK CAPITAL LETTER SIGMA (CP437) { 0x03a4, 0x54, 5 }, // GREEK CAPITAL LETTER TAU (symbol) { 0x03a5, 0x55, 5 }, // GREEK CAPITAL LETTER UPSILON (symbol) { 0x03a6, 0xe8, 3 }, // GREEK CAPITAL LETTER PHI (CP437) { 0x03a7, 0x43, 5 }, // GREEK CAPITAL LETTER CHI (symbol) { 0x03a8, 0x59, 5 }, // GREEK CAPITAL LETTER PSI (symbol) { 0x03a9, 0xea, 3 }, // GREEK CAPITAL LETTER OMEGA (CP437) { 0x03b1, 0xe0, 3 }, // GREEK SMALL LETTER ALPHA (CP437) { 0x03b2, 0x62, 5 }, // GREEK SMALL LETTER BETA (symbol) { 0x03b3, 0x67, 5 }, // GREEK SMALL LETTER GAMMA (symbol) { 0x03b4, 0xeb, 3 }, // GREEK SMALL LETTER DELTA (CP437) { 0x03b5, 0xee, 3 }, // GREEK SMALL LETTER EPSILON (CP437) { 0x03b6, 0x7a, 5 }, // GREEK SMALL LETTER ZETA (symbol) { 0x03b7, 0x68, 5 }, // GREEK SMALL LETTER ETA (symbol) { 0x03b8, 0x71, 5 }, // GREEK SMALL LETTER THETA (symbol) { 0x03b9, 0x69, 5 }, // GREEK SMALL LETTER IOTA (symbol) { 0x03ba, 0x6b, 5 }, // GREEK SMALL LETTER KAPPA (symbol) { 0x03bb, 0x6c, 5 }, // GREEK SMALL LETTER LAMDA (symbol) { 0x03bc, 0x6d, 5 }, // GREEK SMALL LETTER MU (symbol) { 0x03bd, 0x6e, 5 }, // GREEK SMALL LETTER NU (symbol) { 0x03be, 0x78, 5 }, // GREEK SMALL LETTER XI (symbol) { 0x03bf, 0x6f, 5 }, // GREEK SMALL LETTER OMICRON (symbol) { 0x03c0, 0xe3, 3 }, // GREEK SMALL LETTER PI (CP437) { 0x03c1, 0x72, 5 }, // GREEK SMALL LETTER RHO (symbol) { 0x03c2, 0x56, 5 }, // GREEK SMALL LETTER FINAL SIGMA (symbol) { 0x03c3, 0xe5, 3 }, // GREEK SMALL LETTER SIGMA (CP437) { 0x03c4, 0xe7, 3 }, // GREEK SMALL LETTER TAU (CP437) { 0x03c5, 0x75, 5 }, // GREEK SMALL LETTER UPSILON (symbol) { 0x03c6, 0x6a, 5 }, // GREEK SMALL LETTER PHI (symbol) { 0x03c7, 0x63, 5 }, // GREEK SMALL LETTER CHI (symbol) { 0x03c8, 0x79, 5 }, // GREEK SMALL LETTER PSI (symbol) { 0x03c9, 0x77, 5 }, // GREEK SMALL LETTER OMEGA (symbol) { 0x03d1, 0x4a, 5 }, // GREEK THETA SYMBOL (symbol) { 0x03d2, 0xa1, 5 }, // GREEK UPSILON WITH HOOK SYMBOL (symbol) { 0x03d5, 0xed, 3 }, // GREEK PHI SYMBOL (CP437) { 0x03d6, 0x76, 5 }, // GREEK PI SYMBOL (symbol) { 0x2010, 0x2d, 0 }, // HYPHEN (mapped to 8859-1) { 0x2011, 0x2d, 0 }, // NON-BREAKING (mapped to 8859-1) { 0x2012, 0xb1, 4 }, // FIGURE DASH (mapped to stdenc) { 0x2013, 0xb1, 4 }, // EN DASH (stdenc) { 0x2014, 0xd0, 4 }, // EM DASH (stdenc) { 0x2017, 0xf2, 7 }, // DOUBLE LOW LINE (CP850) { 0x2018, 0x60, 4 }, // LEFT SINGLE QUOTATION MARK (stdenc) { 0x2019, 0x27, 4 }, // RIGHT SINGLE QUOTATION MARK (stdenc) { 0x201a, 0xb8, 4 }, // SINGLE LOW-9 QUOTATION MARK (stdenc) { 0x201c, 0xaa, 4 }, // LEFT DOUBLE QUOTATION MARK (stdenc) { 0x201d, 0xba, 4 }, // RIGHT DOUBLE QUOTATION MARK (stdenc) { 0x201e, 0xb9, 4 }, // DOUBLE LOW-9 QUOTATION MARK (stdenc) { 0x2020, 0xb2, 4 }, // DAGGER (stdenc) { 0x2021, 0xb3, 4 }, // DOUBLE DAGGER (stdenc) { 0x2022, 0xb7, 4 }, // BULLET (stdenc) { 0x2026, 0xbc, 4 }, // HORIZONTAL ELLIPSIS (stdenc) { 0x2030, 0xbd, 4 }, // PER MILLE SIGN (stdenc) { 0x2032, 0xa2, 5 }, // PRIME (symbol) { 0x2033, 0xb2, 5 }, // DOUBLE PRIME (symbol) { 0x2039, 0xac, 4 }, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (stdenc) { 0x203a, 0xad, 4 }, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (stdenc) { 0x2044, 0xa4, 4 }, // FRACTION SLASH (stdenc) { 0x207f, 0xfc, 3 }, // SUPERSCRIPT LATIN SMALL LETTER N (CP437) { 0x20a7, 0x9e, 3 }, // PESETA SIGN (CP437) { 0x20ac, 0x80, 6 }, // EURO SIGN (CP1252) { 0x2111, 0xc1, 5 }, // BLACK-LETTER CAPITAL I (symbol) { 0x2118, 0xc3, 5 }, // SCRIPT CAPITAL P (symbol) { 0x211c, 0xc2, 5 }, // BLACK-LETTER CAPITAL R (symbol) { 0x2122, 0x99, 6 }, // TRADE MARK SIGN (CP1252) { 0x2126, 0x57, 5 }, // OHM SIGN (symbol) { 0x2135, 0xc0, 5 }, // ALEF SYMBOL (symbol) { 0x2190, 0xac, 5 }, // LEFTWARDS ARROW (symbol) { 0x2191, 0xad, 5 }, // UPWARDS ARROW (symbol) { 0x2192, 0xae, 5 }, // RIGHTWARDS ARROW (symbol) { 0x2193, 0xaf, 5 }, // DOWNWARDS ARROW (symbol) { 0x2194, 0xab, 5 }, // LEFT RIGHT ARROW (symbol) { 0x21b5, 0xbf, 5 }, // DOWNWARDS ARROW WITH CORNER LEFTWARDS (symbol) { 0x21d0, 0xdc, 5 }, // LEFTWARDS DOUBLE ARROW (symbol) { 0x21d1, 0xdd, 5 }, // UPWARDS DOUBLE ARROW (symbol) { 0x21d2, 0xde, 5 }, // RIGHTWARDS DOUBLE ARROW (symbol) { 0x21d3, 0xdf, 5 }, // DOWNWARDS DOUBLE ARROW (symbol) { 0x21d4, 0xdb, 5 }, // LEFT RIGHT DOUBLE ARROW (symbol) { 0x2200, 0x22, 5 }, // FOR ALL (symbol) { 0x2202, 0xb6, 5 }, // PARTIAL DIFFERENTIAL (symbol) { 0x2203, 0x24, 5 }, // THERE EXISTS (symbol) { 0x2205, 0xc6, 5 }, // EMPTY SET (symbol) { 0x2206, 0x44, 5 }, // INCREMENT (symbol) { 0x2207, 0xd1, 5 }, // NABLA (symbol) { 0x2208, 0xce, 5 }, // ELEMENT OF (symbol) { 0x2209, 0xcf, 5 }, // NOT AN ELEMENT OF (symbol) { 0x220b, 0x27, 5 }, // CONTAINS AS MEMBER (symbol) { 0x220f, 0xd5, 5 }, // N-ARY PRODUCT (symbol) { 0x2211, 0xe5, 5 }, // N-ARY SUMMATION (symbol) { 0x2212, 0x2d, 5 }, // MINUS SIGN (symbol) { 0x2215, 0xa4, 4 }, // DIVISION SLASH (stdenc) { 0x2217, 0x2a, 5 }, // ASTERISK OPERATOR (symbol) { 0x2219, 0xf9, 3 }, // BULLET OPERATOR (CP437) { 0x221a, 0xfb, 3 }, // SQUARE ROOT (CP437) { 0x221d, 0xb5, 5 }, // PROPORTIONAL TO (symbol) { 0x221e, 0xec, 3 }, // INFINITY (CP437) { 0x2220, 0xd0, 5 }, // ANGLE (symbol) { 0x2227, 0xd9, 5 }, // LOGICAL AND (symbol) { 0x2228, 0xda, 5 }, // LOGICAL OR (symbol) { 0x2229, 0xef, 3 }, // INTERSECTION (CP437) { 0x222a, 0xc8, 5 }, // UNION (symbol) { 0x222b, 0xf2, 5 }, // INTEGRAL (symbol) { 0x2234, 0x5c, 5 }, // THEREFORE (symbol) { 0x223c, 0x7e, 5 }, // TILDE OPERATOR (symbol) { 0x2245, 0x40, 5 }, // APPROXIMATELY EQUAL TO (symbol) { 0x2248, 0xf7, 3 }, // ALMOST EQUAL TO (CP437) { 0x2260, 0xb9, 5 }, // NOT EQUAL TO (symbol) { 0x2261, 0xf0, 3 }, // IDENTICAL TO (CP437) { 0x2264, 0xf3, 3 }, // LESS-THAN OR EQUAL TO (CP437) { 0x2265, 0xf2, 3 }, // GREATER-THAN OR EQUAL TO (CP437) { 0x2282, 0xcc, 5 }, // SUBSET OF (symbol) { 0x2283, 0xc9, 5 }, // SUPERSET OF (symbol) { 0x2284, 0xcb, 5 }, // NOT A SUBSET OF (symbol) { 0x2286, 0xcd, 5 }, // SUBSET OF OR EQUAL TO (symbol) { 0x2287, 0xca, 5 }, // SUPERSET OF OR EQUAL TO (symbol) { 0x2295, 0xc5, 5 }, // CIRCLED PLUS (symbol) { 0x2297, 0xc4, 5 }, // CIRCLED TIMES (symbol) { 0x22a5, 0x5e, 5 }, // UP TACK (symbol) { 0x22c5, 0xd7, 5 }, // DOT OPERATOR (symbol) { 0x2310, 0xa9, 3 }, // REVERSED NOT SIGN (CP437) { 0x2320, 0xf4, 3 }, // TOP HALF INTEGRAL (CP437) { 0x2321, 0xf5, 3 }, // BOTTOM HALF INTEGRAL (CP437) { 0x2329, 0xe1, 5 }, // LEFT-POINTING ANGLE BRACKET (symbol) { 0x232a, 0xf1, 5 }, // RIGHT-POINTING ANGLE BRACKET (symbol) { 0x239b, 0xe6, 5 }, // LEFT PARENTHESIS UPPER HOOK (symbol) { 0x239c, 0xe7, 5 }, // LEFT PARENTHESIS EXTENSION (symbol) { 0x239d, 0xe8, 5 }, // LEFT PARENTHESIS LOWER HOOK (symbol) { 0x239e, 0xf6, 5 }, // RIGHT PARENTHESIS UPPER HOOK (symbol) { 0x239f, 0xf7, 5 }, // RIGHT PARENTHESIS EXTENSION (symbol) { 0x23a0, 0xf8, 5 }, // RIGHT PARENTHESIS LOWER HOOK (symbol) { 0x23a1, 0xe9, 5 }, // LEFT SQUARE BRACKET UPPER CORNER (symbol) { 0x23a2, 0xea, 5 }, // LEFT SQUARE BRACKET EXTENSION (symbol) { 0x23a3, 0xeb, 5 }, // LEFT SQUARE BRACKET LOWER CORNER (symbol) { 0x23a4, 0xf9, 5 }, // RIGHT SQUARE BRACKET UPPER CORNER (symbol) { 0x23a5, 0xfa, 5 }, // RIGHT SQUARE BRACKET EXTENSION (symbol) { 0x23a6, 0xfb, 5 }, // RIGHT SQUARE BRACKET LOWER CORNER (symbol) { 0x23a7, 0xec, 5 }, // LEFT CURLY BRACKET UPPER HOOK (symbol) { 0x23a8, 0xed, 5 }, // LEFT CURLY BRACKET MIDDLE PIECE (symbol) { 0x23a9, 0xee, 5 }, // LEFT CURLY BRACKET LOWER HOOK (symbol) { 0x23aa, 0xef, 5 }, // CURLY BRACKET EXTENSION (symbol) { 0x23ab, 0xfc, 5 }, // RIGHT CURLY BRACKET UPPER HOOK (symbol) { 0x23ac, 0xfd, 5 }, // RIGHT CURLY BRACKET MIDDLE PIECE (symbol) { 0x23ad, 0xfe, 5 }, // RIGHT CURLY BRACKET LOWER HOOK (symbol) { 0x23ae, 0xf4, 5 }, // INTEGRAL EXTENSION (symbol) { 0x23af, 0xbe, 5 }, // HORIZONTAL LINE EXTENSION (symbol) { 0x2500, 0xc4, 3 }, // BOX DRAWINGS LIGHT HORIZONTAL (CP437) { 0x2502, 0xb3, 3 }, // BOX DRAWINGS LIGHT VERTICAL (CP437) { 0x250c, 0xda, 3 }, // BOX DRAWINGS LIGHT DOWN AND RIGHT (CP437) { 0x2510, 0xbf, 3 }, // BOX DRAWINGS LIGHT DOWN AND LEFT (CP437) { 0x2514, 0xc0, 3 }, // BOX DRAWINGS LIGHT UP AND RIGHT (CP437) { 0x2518, 0xd9, 3 }, // BOX DRAWINGS LIGHT UP AND LEFT (CP437) { 0x251c, 0xc3, 3 }, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT (CP437) { 0x2524, 0xb4, 3 }, // BOX DRAWINGS LIGHT VERTICAL AND LEFT (CP437) { 0x252c, 0xc2, 3 }, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL (CP437) { 0x2534, 0xc1, 3 }, // BOX DRAWINGS LIGHT UP AND HORIZONTAL (CP437) { 0x253c, 0xc5, 3 }, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL (CP437) { 0x2550, 0xcd, 3 }, // BOX DRAWINGS DOUBLE HORIZONTAL (CP437) { 0x2551, 0xba, 3 }, // BOX DRAWINGS DOUBLE VERTICAL (CP437) { 0x2552, 0xd5, 3 }, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE (CP437) { 0x2553, 0xd6, 3 }, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE (CP437) { 0x2554, 0xc9, 3 }, // BOX DRAWINGS DOUBLE DOWN AND RIGHT (CP437) { 0x2555, 0xb8, 3 }, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE (CP437) { 0x2556, 0xb7, 3 }, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE (CP437) { 0x2557, 0xbb, 3 }, // BOX DRAWINGS DOUBLE DOWN AND LEFT (CP437) { 0x2558, 0xd4, 3 }, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE (CP437) { 0x2559, 0xd3, 3 }, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE (CP437) { 0x255a, 0xc8, 3 }, // BOX DRAWINGS DOUBLE UP AND RIGHT (CP437) { 0x255b, 0xbe, 3 }, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE (CP437) { 0x255c, 0xbd, 3 }, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE (CP437) { 0x255d, 0xbc, 3 }, // BOX DRAWINGS DOUBLE UP AND LEFT (CP437) { 0x255e, 0xc6, 3 }, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE (CP437) { 0x255f, 0xc7, 3 }, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE (CP437) { 0x2560, 0xcc, 3 }, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT (CP437) { 0x2561, 0xb5, 3 }, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE (CP437) { 0x2562, 0xb6, 3 }, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE (CP437) { 0x2563, 0xb9, 3 }, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT (CP437) { 0x2564, 0xd1, 3 }, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE (CP437) { 0x2565, 0xd2, 3 }, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE (CP437) { 0x2566, 0xcb, 3 }, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL (CP437) { 0x2567, 0xcf, 3 }, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE (CP437) { 0x2568, 0xd0, 3 }, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE (CP437) { 0x2569, 0xca, 3 }, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL (CP437) { 0x256a, 0xd8, 3 }, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE (CP437) { 0x256b, 0xd7, 3 }, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE (CP437) { 0x256c, 0xce, 3 }, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL (CP437) { 0x2580, 0xdf, 3 }, // UPPER HALF BLOCK (CP437) { 0x2584, 0xdc, 3 }, // LOWER HALF BLOCK (CP437) { 0x2588, 0xdb, 3 }, // FULL BLOCK (CP437) { 0x258c, 0xdd, 3 }, // LEFT HALF BLOCK (CP437) { 0x2590, 0xde, 3 }, // RIGHT HALF BLOCK (CP437) { 0x2591, 0xb0, 3 }, // LIGHT SHADE (CP437) { 0x2592, 0xb1, 3 }, // MEDIUM SHADE (CP437) { 0x2593, 0xb2, 3 }, // DARK SHADE (CP437) { 0x25a0, 0xfe, 3 }, // BLACK SQUARE (CP437) { 0x25ca, 0xe0, 5 }, // LOZENGE (symbol) { 0x2660, 0xaa, 5 }, // BLACK SPADE SUIT (symbol) { 0x2663, 0xa7, 5 }, // BLACK CLUB SUIT (symbol) { 0x2665, 0xa9, 5 }, // BLACK HEART SUIT (symbol) { 0x2666, 0xa8, 5 }, // BLACK DIAMOND SUIT (symbol) { 0x27e8, 0xe1, 5 }, // MATHEMATICAL LEFT ANGLE BRACKET (symbol) { 0x27e9, 0xf1, 5 }, // MATHEMATICAL RIGHT ANGLE BRACKET (symbol) { 0xfb01, 0xae, 4 }, // LATIN SMALL LIGATURE FI (stdenc) { 0xfb02, 0xaf, 4 } // LATIN SMALL LIGATURE FL (stdenc) }; struct codepair *findcode(wchar_t ucs) { int min = 0; int max = sizeof(codemap) / sizeof(struct codepair) - 1; int mid; /* binary search in table */ while (max >= min) { mid = (min + max) / 2; if (codemap[mid].ucs < ucs) min = mid + 1; else if (codemap[mid].ucs > ucs) max = mid - 1; else { /* found it */ return codemap + mid; } } /* no matching Unicode value found */ return NULL; } #define HP_WORST_LEN 11 /* * Transform wide character string to hp character set. In the worst case, * the string hp can be HP_WORST_LEN times longer than the string wc. */ void wcstohps(char *hp, const wchar_t *wc) { struct codepair *cp; for (;*wc; wc++) if (*wc < 0x100) { /* plain Latin-1 is just copied */ *(hp++) = *wc; } else if (*wc == 0xfffd) { /* default character */ strcpy(hp, "\x1b(s1S?\x1b(s0S"); hp += 11; } else { cp = findcode(*wc); if (cp) { strcpy(hp, charset[(int)cp->set]); hp += strlen(charset[(int)cp->set]); *(hp++) = cp->c; strcpy(hp, "\x1b(0N"); hp += 4; } else { /* unavailable character */ strcpy(hp, "\x1b(s1S\xbf\x1b(s0S"); hp += 11; } } *hp = 0; return; } int main(int argc, char **argv) { FILE *fin = NULL; char *fnin = ""; char *title = NULL; #define FN_MAX 200 wchar_t wtitle[FN_MAX]; char hp_title[FN_MAX * HP_WORST_LEN]; int page, ppos, xpos, page_length; char character[HP_WORST_LEN + 1]; int c, i, j, again; size_t k; wchar_t wbuf[2]; char cbuf[2]; int all_args = 0; int double_page = 0; int headline = 1; int landscape = 0; int left_margin = 8; int page_width = 80; int no_margin = 0; mbstate_t mbs; size_t r; /* set locale */ if (!setlocale(LC_CTYPE, "")) { fprintf(stderr, "Can't set the specified locale! " "Check LANG, LC_CTYPE, LC_ALL.\n"); exit(1); } /* parse command line arguments */ for (i = 1; i < argc; i++) { if (!all_args && argv[i][0] == '-') { if (argv[i][1] == '\0') { if (!fin) { fin = stdin; fnin = ""; } else { fprintf(stderr, usage, argv[0]); exit(1); } } else { for (j = 1; j < 10000 && argv[i][j]; j++) switch(tolower(argv[i][j])) { case '-' : all_args = 1; break; case 'd': double_page = 1; landscape = 0; break; case 'l': double_page = 0; landscape = 1; break; case 'h': headline = 0; break; case 'm': no_margin = 1; break; case 't': j = 10000; if (++i < argc) title = argv[i]; else { fprintf(stderr, usage, argv[0]); exit(1); } break; case 'r': for (k = 0; k < sizeof(codemap) / sizeof(struct codepair); k++) printf("%04lX\n", (unsigned long) codemap[k].ucs); exit(1); default: fprintf(stderr, usage, argv[0]); exit(1); } } } else { if (!fin) { fnin = argv[i]; fin = fopen(fnin, "r"); if (!fin) { fprintf(stderr, "Can't open input file '%s", fnin); perror("'"); exit(1); } } else { fprintf(stderr, usage, argv[0]); exit(1); } } } if (!fin) { fprintf(stderr, usage, argv[0]); exit(1); } if (no_margin) { page_width += left_margin + 4; left_margin = 0; } /* initialize printer */ printf("\x1b\x45"); /* reset printer */ printf("\x1b(0N"); /* character set: Latin 1 */ printf("\x1b&l26A"); /* ISO A4 paper format */ page_length = 63; if (double_page) { printf("\x1b&l1O"); /* landscape format */ printf("\x1b&k2S"); /* character width: condensed (12 cpi) */ printf("\x1b&l%dC", 6); /* vertical motion index x/48 inch */ page_length = 58; } else if (landscape) { printf("\x1b&l1O"); /* landscape format */ printf("\x1b&k4S"); /* character width: elite (12 cpi) */ page_length = 43; page_width += 40; } else { printf("\x1b&k4S"); /* character width: elite (12 cpi) */ } if (!title) title = fnin; mbstowcs(wtitle, title, FN_MAX); assert(page_width - 5 < FN_MAX); wtitle[page_width - 5] = 0; wcstohps(hp_title, wtitle); page = 0; ppos = 0; xpos = 0; again = 0; wbuf[1] = 0; cbuf[1] = 0; memset(&mbs, 0, sizeof(mbs)); /* initialize multi-byte state */ while (again || !feof(fin)) { if (!again) { c = fgetc(fin); if (feof(fin)) break; if (c == EOF) { wbuf[0] = 0xfffd; } else { cbuf[0] = c; r = mbrtowc(wbuf, cbuf, 1, &mbs); if (r == (size_t)(-2)) continue; if (r == (size_t)(-1)) { wbuf[0] = 0xfffd; memset(&mbs, 0, sizeof(mbs)); /* reset multi-byte state */ if (mbrtowc(NULL, cbuf, 1, &mbs) != (size_t)(-1)) { /* this character can perhaps still be rescued */ ungetc(c, fin); } memset(&mbs, 0, sizeof(mbs)); /* reset multi-byte state */ } } wcstohps(character, wbuf); } again = 0; if (ppos > page_length) { if (double_page && (page & 1) == 1) { printf("\x1b&f1S"); /* restore cursor position */ printf("\x1b&a%dL", 92); /* set left margin */ } else { if (double_page) printf("\x1b&a%dL", 0); /* set left margin */ putchar('\f'); } putchar('\r'); ppos = 0; xpos = 0; } if (ppos == 0) { page++; if (double_page && (page & 1) == 1) printf("\x1b&f0S"); /* save cursor position */ ppos = 1; if (headline) { printf("%*s\x1b(s3B%-*s%5d\x1b(s0B\r\n\n", left_margin, "", page_width - 5, hp_title, page); ppos += 2; } } switch (character[0]) { case '\n': putchar('\r'); xpos = 0; if (++ppos <= page_length) putchar('\n'); break; case '\r': putchar('\r'); xpos = 0; break; case '\f': ppos = 1000; break; case '\0': /* ignore */ break; case '\t': if (xpos == 0) printf("%*s", left_margin, ""); if (xpos >= page_width - 8) { if (xpos < page_width) putchar('\t'); printf("\x1b(12U\x10\x1b(0N\r"); if (++ppos <= page_length) putchar('\n'); xpos = 0; } else { putchar('\t'); xpos = ((xpos - 1) | 7) + 1; } break; default: if (xpos >= page_width) { printf("\x1b(12U\x10\x1b(0N\r"); if (++ppos <= page_length) putchar('\n'); xpos = 0; again = 1; } else { if (xpos == 0) printf("%*s", left_margin, ""); printf("%s", character); ++xpos; } } } #ifdef FINAL_FF /* in case, the printing system doesn't append its own form feed */ printf("\r\f"); printf("\x1b\x45"); /* reset printer */ #endif return 0; }