/*
* 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;
}