home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / old / ckermit70 / textps.c < prev   
C/C++ Source or Header  |  1996-05-20  |  39KB  |  1,093 lines

  1. char *version = "0.998 21-May-96";
  2. char *copyright = "Copyright (C) 1991, 1996, Trustees of Columbia University";
  3. /*
  4.   textps - Convert plain text to Postscript.
  5.  
  6.   DESCRIPTION:
  7.     Converts text files to PostScript Courier-11, 66 lines to the page, 80
  8.     characters to the line.  Handles pagination, tabs, line wrap, overstruck
  9.     characters (via BS) and overstruck lines (via CR).  Swallows and ignores
  10.     (rather than printing) ANSI escape sequences.  If the input file is
  11.     already Postscript (i.e. if its first line starts with "%!"), it is simply
  12.     copied to the output without alteration.  No special effects like page
  13.     headings, landscape, 2-up, etc.
  14.  
  15.     Unlike other "enscriptors", textps handles 8-bit character sets.  The
  16.     default file character set is CP437 on PCs, the NeXT character set on the
  17.     NeXT, and ISO 8859-1 Latin Alphabet 1 elsewhere.  CP850, DEC MCS, and
  18.     Apple QuickDraw are also supported.  Override the default character set
  19.     with the -c command-line option.  Shift-In/Shift-Out codes within the text
  20.     are handled, so 8-bit characters can be encoded by ^N<char-128>^O in the
  21.     7-bit environment (e.g. e-mail) and still print correctly.
  22.  
  23.   USAGE:
  24.     textps [ -h ] [ -v ] [ -c charset ] < input > output
  25.  
  26.     The input file character set is translated from the default character set
  27.     or the one given on the command line to ISO Latin Alphabet 1, and the
  28.     result is converted to Level-1 Postscript.  The -h command line option
  29.     prints a help message and exits immediately.  The -v option includes a
  30.     page showing the textps and PostScript version numbers.  The -c option
  31.     specifies the file's character set; charset may be latin1, cp437, cp850,
  32.     decmcs, apple, or next.
  33.  
  34.     UNIX example:   textps < file | lpr
  35.     MS-DOS example: textps < file > prn
  36.  
  37.     Suggestion for use with DOS.  Make a batch file called PSPRINT.BAT:
  38.       @echo off
  39.       textps < %1 > prn
  40.  
  41.     This assumes PRN is a Postscript printer.  Works with both Postscript
  42.     and non-Postscript files.  Works with Novell CAPTURE.  In VMS, make a
  43.     DCL procedure similar to this batch file.  In UNIX, use this program
  44.     as a print filter (in /etc/printcap, or alias lpr='textps | lpr').
  45.  
  46.   ERRORS:
  47.     Returns status code of 0 on success, 1 on failure.
  48.     Only fails if it is invoked with invalid command line arguments,
  49.     in which case an error and usage message is printed on stderr.
  50.  
  51.   BUGS:
  52.     Sometimes a spurious blank page is produced.
  53.  
  54.     Not all the characters print on early model laserwriters or other very
  55.     old PostScript printers: broken bar, copyright, trade mark, not sign,
  56.     fractions, Y/y-acute and Icelandic Thorn/thorn and Eth/eth, etc.  This
  57.     is because these characters were not present in early PostScript releases.
  58.  
  59.     8-bit characters are translated into an internal character set, which is
  60.     ISO Latin Alphabet 1 with a few extensions, so any file characters that
  61.     don't don't appear in this character set, such as PC line- and box-
  62.     drawing characters, are approximated with characters like '+', '-', and
  63.     '|'.  Alphabetic or punctuation characters that have no equivalents in
  64.     Latin-1 are shown as '?'.
  65.  
  66.   TO BUILD:
  67.     Just compile it.  If compiled under DOS with Microsoft C (and probably
  68.     also under Xenix?), the default character set is CP437, on the NeXT
  69.     it's the NeXT character set, otherwise it's Latin-1.
  70.  
  71.     For OS/2, use the Makefile textps.os2 ("make -f textps.os2 <object>").
  72.     See textps.os2 for a list of objects.
  73.  
  74.     For Windows NT and Windows 95, the default character set is CP437.
  75.  
  76.     To build with a particular default character set, include -DCHARSET=x
  77.     on the cc command line, where x = 0 for Latin1, 1 for CP437, 2 for
  78.     CP850, 3 for NeXT, 4 for DEC MCS, 5 for Apple QuickDraw.
  79.  
  80.     To disable ANSI-escape-sequence elimination, add -DNOESCSEQ.
  81.  
  82.   UPDATES:
  83.     0.95 5 Aug 91 
  84.       Add L procedure to output n blank lines, and don't bother to output
  85.       blank lines after last text on page.
  86.     0.96 6 Aug 91
  87.       Make sure a file that starts with Ctrl-L still outputs the PostScript
  88.       prolog.
  89.     0.97 8 Aug 91
  90.       Totally rewrite so we don't have to use backspacefont, which doesn't
  91.       work if used too much.  This also allows backspace overstriking to work
  92.       across line wrap boundaries.
  93.     0.98 1 Oct 91
  94.       Fix a few translation table entries.
  95.     0.99 7 Oct 91
  96.       Fix the top and bottom margins so 66th line doesn't sometimes have
  97.       descenders cut off.
  98.     0.995 18 Apr 93
  99.       Fix output of already-PS files to not contain an unnecessary
  100.       bufferful of blanks.  Add #ifdef for default OS/2 character set.
  101.       Remove compiler complaint about buf in printf.
  102.       Reported by Darrel Hankerson at Auburn University.
  103.     0.996 16 Jan 94
  104.       From Darrel Hankerson at Auburn University.  Improved OS/2 and MS-DOS
  105.       support: get the current PC code page from the operating system rather
  106.       than using a hardwired default.  New makefile for OS/2 and DOS.
  107.       Print usage() message if stdin isatty().
  108.     0.997 23 Feb 96
  109.       Added support for Windows NT and Windows 95.
  110.     0.998 21 May 96
  111.       Added page-length support.
  112.  
  113.   TO DO:
  114.     Add support for 7-bit national ISO 646 character sets so we can
  115.     print e-mail from Sweden, France, etc.
  116.  
  117.     Add support for other PC code pages that could be translated into
  118.     Latin-1, such as CP860, CP861, CP863, etc.
  119.  
  120.     Incorporate CP437 font from pc2ps program? (Box drawing chars, etc)
  121.  
  122.   Author: Frank da Cruz, Columbia University (fdc@columbia.edu), July 1991.
  123.   Acks:   For help with reencoding bugs: Bur Davis, Adobe.
  124.           For OS/2 and DOS improvements, Darrel Hankerson, Auburn University.
  125.  
  126.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  127.   York.  Permission is granted to any individual or institution to use this
  128.   software as long as it is not sold for profit.  This copyright notice must be
  129.   retained.  This software may not be included in commercial products without
  130.   written permission of the Office of Kermit Development and Distribution,
  131.   Academic Information Systems, Columbia University.
  132.  
  133. /* Defines and Includes... */
  134.  
  135. /* For portability, we can't use logical operators in the preprocessor. */
  136. /* Here we define OS2NTDOS if either OS2, MSDOS, or NT is defined, for items */
  137. /* common to OS/2, MS-DOS, and Windows NT/95 ... */
  138.  
  139. #ifdef __EMX__
  140. #ifndef OS2
  141. #define OS2
  142. #endif /* OS2 */
  143. #endif /* __EMX__ */
  144.  
  145. #ifdef OS2
  146. #ifndef OS2NTDOS
  147. #define OS2NTDOS
  148. #endif /* OS2NTDOS */
  149. #endif /* OS2 */
  150.  
  151. #ifdef NT
  152. #include <windows.h>
  153. #ifndef OS2NTDOS
  154. #define OS2NTDOS
  155. #endif
  156. #endif
  157.  
  158. #ifdef MSDOS
  159. #ifndef OS2NTDOS
  160. #define OS2NTDOS
  161. #endif /* OS2NTDOS */
  162. #endif /* MSDOS */
  163.  
  164. #ifndef NOESCSEQ    /* Swallow ANSI escape and control sequences */
  165. #define ESCSEQ        /* unless -DNOESCSEQ given on cc command line. */
  166. #endif /* NOESCSEQ */
  167.  
  168. #define WIDTH 80    /* Portrait printer line width, characters */
  169. #define LENGTH 66    /* Portrait printer page length, lines */
  170. #define MAXLENGTH 256
  171.  
  172. /* Character set translations */
  173.  
  174. #define UNK '?'      /* What to translate an untranslatable character into */
  175. #define SP ' '                /* Space character */
  176. #define DEL 0177            /* DEL character */
  177.  
  178. /* Character set symbols */
  179.  
  180. #define LATIN1 0            /* ISO Latin Alphabet 1 */
  181. #define CP437  1            /* IBM code page 437 */
  182. #define CP850  2            /* IBM code page 850 */
  183. #define NEXT   3            /* NeXT character set */
  184. #define DECMCS 4            /* DEC multinational character set */
  185. #define APPLE  5            /* Apple QuickDraw character set */
  186.  
  187. /* Default character set depends on where we're being compiled. */
  188.  
  189. #ifndef CHARSET                /* If default not already defined */
  190. #ifdef NT
  191. #define CHARSET CP437
  192. #else /* NT */
  193. #ifdef OS2                /* See also the Dos call in main() */
  194. #define CHARSET CP850            /* A little more modern for OS/2 */
  195. #else
  196. #ifdef MSDOS                /* Symbol predefined by Microsoft C */
  197. #define CHARSET CP437            /* Default character set for PCs */
  198. #else
  199. #ifdef NeXT                /* Predefined by NeXT compiler */
  200. #define CHARSET NEXT
  201. #else
  202. #define CHARSET LATIN1            /* Default character set for others */
  203. #endif /* NeXT */
  204. #endif /* OS2 */
  205. #endif /* MSDOS */
  206. #endif /* NT */
  207. #endif /* CHARSET */
  208.  
  209. #include <stdio.h>            /* For EOF definition */
  210. #ifdef OS2NTDOS
  211. #include <io.h>                /* For isatty() */
  212. #include <string.h>
  213. #endif /* OS2NTDOS */
  214.  
  215. /*
  216.   Postscript Prolog, to be inserted at the beginning of the output file.
  217.   The %% Comments are to make the file conformant with Adobe's "Postscript 
  218.   File Structuring Conventions", which allow page-oriented operations in
  219.   Postscript previewers, page pickers, etc.
  220. */
  221. char *prolog[] = {            /* Standard prolog */
  222.     "%!PS-Adobe-1.0",            /* Works with Postscript 1.0 */
  223.     "%%Title: oofa",
  224.     "%%DocumentFonts: Courier CourierLatin1", 
  225.     "%%Creator: textps",
  226.     "%%Pages: (atend)",
  227.     "%%EndComments",
  228. /*
  229.   Postscript font reencoding.  The standard encoding does not have the
  230.   characters needed for Latin-1.
  231.  
  232.   Unfortunately, the font reencoding methods listed in the Postscript
  233.   Cookbook simply do not work with the Apple Laserwriter (even though they
  234.   did work with other Postscript devices).  The method described in the
  235.   Adobe PostScript Language Reference Manual (2nd Ed) to change from the
  236.   StandardEncoding vector to the ISOLatin1Encoding vector works only with
  237.   the LaserWriter-II, but not older LaserWriters.
  238.  
  239.   This method, suggested by Bur Davis at Adobe, works around the fact that
  240.   Courier was a "stroke font" in pre-version-47.0 Postscript, in which many of
  241.   the accented characters are composed from other characters (e.g. i-grave =
  242.   dotless i + grave).  It is probably not the most efficient possible solution
  243.   (an iterative method might be better), but it works.
  244. */
  245.     "/CourierLatin1 /Courier findfont dup dup maxlength dict begin",
  246.     "{",
  247.     "    1 index /FID ne { def } { pop pop } ifelse", 
  248.     "} forall",
  249.     "/Encoding exch 1 index get 256 array copy def", 
  250. /*
  251.   The following characters are added at the C1 positions 128-153, for printing
  252.   non-Latin1 character sets such as IBM code pages, DEC MCS, NeXT, etc.  Note
  253.   that we cannot use characters from the Symbol font.  Characters from
  254.   different fonts cannot be mixed.  Anyway, the Symbol font is not fixed-width.
  255. */
  256.     "Encoding 128 /quotesingle put",
  257.     "Encoding 129 /quotedblleft put",
  258.     "Encoding 131 /fi put",
  259.     "Encoding 132 /endash put",
  260.     "Encoding 133 /dagger put",
  261.     "Encoding 134 /periodcentered put",
  262.     "Encoding 135 /bullet put",
  263.     "Encoding 136 /quotesinglbase put",
  264.     "Encoding 137 /quotedblbase put",
  265.     "Encoding 138 /quotedblright put",
  266.     "Encoding 139 /ellipsis put",
  267.     "Encoding 140 /perthousand put",
  268.     "Encoding 141 /dotaccent put",
  269.     "Encoding 142 /hungarumlaut put",
  270.     "Encoding 143 /ogonek put",
  271.     "Encoding 144 /caron put",
  272.     "Encoding 145 /fl put",
  273.     "Encoding 146 /emdash put",
  274.     "Encoding 147 /Lslash put",
  275.     "Encoding 148 /OE put",
  276.     "Encoding 149 /lslash put",
  277.     "Encoding 150 /oe put",
  278.     "Encoding 151 /florin put",
  279.     "Encoding 152 /fraction put",
  280.     "Encoding 153 /daggerdbl put",
  281. /*
  282.   The following six characters are required for pre-47.0 PostScript versions,
  283.   which compose accented Courier characters by putting together the base
  284.   character and the accent.
  285. */
  286.     "Encoding 154 /dotlessi put",
  287.     "Encoding 155 /grave put",
  288.     "Encoding 156 /circumflex put",
  289.     "Encoding 157 /tilde put",
  290.     "Encoding 158 /breve put",
  291.     "Encoding 159 /ring put",
  292. /*
  293.   The remainder follow the normal ISO 8859-1 encoding.
  294. */
  295.     "Encoding 160 /space put",
  296.     "Encoding 161 /exclamdown put",
  297.     "Encoding 162 /cent put", 
  298.     "Encoding 163 /sterling put", 
  299.     "Encoding 164 /currency put", 
  300.     "Encoding 165 /yen put", 
  301.     "Encoding 166 /brokenbar put", 
  302.     "Encoding 167 /section put", 
  303.     "Encoding 168 /dieresis put", 
  304.     "Encoding 169 /copyright put", 
  305.     "Encoding 170 /ordfeminine put", 
  306.     "Encoding 171 /guillemotleft put", 
  307.     "Encoding 172 /logicalnot put", 
  308.     "Encoding 173 /hyphen put", 
  309.     "Encoding 174 /registered put", 
  310.     "Encoding 175 /macron put", 
  311.     "Encoding 176 /degree put", 
  312.     "Encoding 177 /plusminus put", 
  313.     "Encoding 178 /twosuperior put", 
  314.     "Encoding 179 /threesuperior put", 
  315.     "Encoding 180 /acute put", 
  316.     "Encoding 181 /mu put", 
  317.     "Encoding 182 /paragraph put", 
  318.     "Encoding 183 /bullet put", 
  319.     "Encoding 184 /cedilla put", 
  320.     "Encoding 185 /onesuperior put", 
  321.     "Encoding 186 /ordmasculine put", 
  322.     "Encoding 187 /guillemotright put", 
  323.     "Encoding 188 /onequarter put", 
  324.     "Encoding 189 /onehalf put", 
  325.     "Encoding 190 /threequarters put", 
  326.     "Encoding 191 /questiondown put", 
  327.     "Encoding 192 /Agrave put", 
  328.     "Encoding 193 /Aacute put", 
  329.     "Encoding 194 /Acircumflex put", 
  330.     "Encoding 195 /Atilde put", 
  331.     "Encoding 196 /Adieresis put", 
  332.     "Encoding 197 /Aring put", 
  333.     "Encoding 198 /AE put", 
  334.     "Encoding 199 /Ccedilla put", 
  335.     "Encoding 200 /Egrave put", 
  336.     "Encoding 201 /Eacute put", 
  337.     "Encoding 202 /Ecircumflex put", 
  338.     "Encoding 203 /Edieresis put", 
  339.     "Encoding 204 /Igrave put", 
  340.     "Encoding 205 /Iacute put", 
  341.     "Encoding 206 /Icircumflex put", 
  342.     "Encoding 207 /Idieresis put", 
  343.     "Encoding 208 /Eth put", 
  344.     "Encoding 209 /Ntilde put", 
  345.     "Encoding 210 /Ograve put", 
  346.     "Encoding 211 /Oacute put", 
  347.     "Encoding 212 /Ocircumflex put", 
  348.     "Encoding 213 /Otilde put", 
  349.     "Encoding 214 /Odieresis put", 
  350.     "Encoding 215 /multiply put", 
  351.     "Encoding 216 /Oslash put", 
  352.     "Encoding 217 /Ugrave put", 
  353.     "Encoding 218 /Uacute put", 
  354.     "Encoding 219 /Ucircumflex put", 
  355.     "Encoding 220 /Udieresis put", 
  356.     "Encoding 221 /Yacute put", 
  357.     "Encoding 222 /Thorn put", 
  358.     "Encoding 223 /germandbls put", 
  359.     "Encoding 224 /agrave put", 
  360.     "Encoding 225 /aacute put", 
  361.     "Encoding 226 /acircumflex put", 
  362.     "Encoding 227 /atilde put", 
  363.     "Encoding 228 /adieresis put", 
  364.     "Encoding 229 /aring put", 
  365.     "Encoding 230 /ae put", 
  366.     "Encoding 231 /ccedilla put", 
  367.     "Encoding 232 /egrave put", 
  368.     "Encoding 233 /eacute put", 
  369.     "Encoding 234 /ecircumflex put", 
  370.     "Encoding 235 /edieresis put", 
  371.     "Encoding 236 /igrave put", 
  372.     "Encoding 237 /iacute put", 
  373.     "Encoding 238 /icircumflex put", 
  374.     "Encoding 239 /idieresis put", 
  375.     "Encoding 240 /eth put", 
  376.     "Encoding 241 /ntilde put", 
  377.     "Encoding 242 /ograve put", 
  378.     "Encoding 243 /oacute put", 
  379.     "Encoding 244 /ocircumflex put", 
  380.     "Encoding 245 /otilde put", 
  381.     "Encoding 246 /odieresis put", 
  382.     "Encoding 247 /divide put", 
  383.     "Encoding 248 /oslash put", 
  384.     "Encoding 249 /ugrave put", 
  385.     "Encoding 250 /uacute put", 
  386.     "Encoding 251 /ucircumflex put", 
  387.     "Encoding 252 /udieresis put", 
  388.     "Encoding 253 /yacute put", 
  389.     "Encoding 254 /thorn put", 
  390.     "Encoding 255 /ydieresis put", 
  391.     "currentdict end definefont", 
  392. /*
  393.   Set the font and define functions for adding lines and printing pages.
  394. */
  395.     "/CourierLatin1 findfont 11 scalefont setfont",
  396.     "/StartPage{/sv save def 48 765 moveto}def",
  397.     "/ld -11.4 def",            /* Line spacing */
  398.     "/yline 765 def",            /* Position of top line */
  399.     "/U{show",                /* Show line, don't advance */
  400.     "  48 yline moveto}def",
  401.     "/S{show",                /* Show line, move to next line */
  402.     "  /yline yline ld add def",
  403.     "  48 yline moveto}def",
  404.     "/L{ld mul yline add /yline exch def", /* Move down n lines  */
  405.     "  48 yline moveto}def",
  406.     "/EndPage{showpage sv restore}def",
  407.     "%%EndProlog",            /* End of prolog. */
  408.     "%%Page: 1 1",            /* Number the first page. */
  409.     "StartPage",            /* And start it. */
  410.     ""                    /* Empty string = end of array. */
  411. };
  412.  
  413. /*
  414.   Translation tables from local character sets into CourierLatin1.
  415. */
  416.  
  417. /*
  418.   IBM Code Page 437.  Line- and box-drawing characters are simulated with
  419.   dashes, bars, and plus signs.  Black and gray blobs (fill characters)
  420.   are replaced by X's.  Peseta is shown as P.  Greek letters that don't
  421.   exist in CourierLatin1 are shown as ?.  Untranslatable math symbols are
  422.   shown as ?.
  423. */
  424. unsigned char
  425. y43l1[] = {
  426.   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
  427.  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
  428.  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
  429.  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
  430.  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
  431.  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
  432.  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  433. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  434. 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197,
  435. 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 162, 163, 165, 'P', 151,
  436. 225, 237, 243, 250, 241, 209, 170, 186, 191, '+', 172, 189, 188, 161, 171, 187,
  437. 'X', 'X', 'X', '|', '+', '+', '+', '+', '+', '+', '|', '+', '+', '+', '+', '+',
  438. '+', '+', '+', '+', '-', '+', '+', '+', '+', '+', '+', '+', '+', '-', '+', '+',
  439. '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', 'X', 'X', 'X', 'X', 'X',
  440. UNK, 223, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK,
  441. UNK, 177, UNK, UNK, UNK, UNK, UNK, UNK, 176, 134, 135, UNK, 'n', 178, 'X', 160
  442. };
  443.  
  444. /*
  445.   IBM Code Page 850.  Line- and box-drawing characters are simulated with 
  446.   dashes, bars, and plus signs.  Black blobs are replaced by X's.
  447. */
  448. unsigned char
  449. y85l1[] = {
  450.   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
  451.  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
  452.  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
  453.  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
  454.  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
  455.  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
  456.  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  457. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  458. 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, 239, 238, 236, 196, 197,
  459. 201, 230, 198, 244, 246, 242, 251, 249, 255, 214, 220, 248, 163, 216, 215, 151,
  460. 225, 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, 188, 161, 171, 187,
  461. 'X', 'X', 'X', '|', '+', 193, 194, 192, 169, '+', '|', '+', '+', 162, 165, '+',
  462. '+', '+', '+', '+', '-', '+', 227, 195, '+', '+', '+', '+', '+', '-', '+', 164,
  463. 240, 208, 202, 203, 200, 154, 205, 206, 207, '+', '+', 'X', 'X', 166, 204, 'X',
  464. 211, 223, 212, 210, 245, 213, 181, 254, 222, 218, 219, 217, 253, 221, 175, 180,
  465. 173, 177, '=', 190, 182, 167, 247, 184, 176, 168, 134, 185, 179, 178, 'X', 160
  466. };
  467.  
  468. /*
  469.   NeXT character set.  Here we have a full translation.
  470. */
  471. unsigned char
  472. ynel1[] = {
  473.   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
  474.  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
  475.  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
  476.  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
  477.  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
  478.  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
  479.  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  480. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  481. 160, 192, 193, 194, 195, 196, 197, 199, 200, 201, 202, 203, 204, 205, 206, 207,
  482. 208, 209, 210, 211, 212, 213, 214, 217, 218, 219, 220, 221, 222, 181, 215, 247,
  483. 169, 161, 162, 163, 152, 165, 151, 167, 164, 128, 129, 171, '<', '>', 131, 145,
  484. 174, 132, 133, 153, 134, 166, 182, 135, 136, 137, 138, 187, 139, 140, 172, 191,
  485. 185,  96, 180,  94, 126, 175, 158, 141, 168, 178, 176, 184, 179, 142, 143, 144,
  486. 146, 177, 188, 189, 190, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234, 235,
  487. 236, 198, 237, 170, 238, 239, 240, 241, 147, 216, 148, 186, 242, 243, 244, 245,
  488. 246, 230, 249, 250, 251, 154, 252, 253, 149, 248, 150, 223, 254, 255, ' ', ' '
  489. };
  490.  
  491. /*
  492.   DEC Multinational Character Set (MCS).
  493. */
  494. unsigned char
  495. ydml1[] = {
  496.   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
  497.  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
  498.  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
  499.  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
  500.  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
  501.  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
  502.  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  503. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  504. 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
  505. 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
  506. 160, 161, 162, 163, ' ', 165, ' ', 167, 164, 169, 170, 171, ' ', ' ', ' ', ' ',
  507. 176, 177, 178, 179, ' ', 181, 182, 134, ' ', 185, 186, 187, 188, 189, ' ', 191,
  508. 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
  509. ' ', 209, 210, 211, 212, 213, 214, 148, 216, 217, 218, 219, 220, 221, ' ', 223,
  510. 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
  511. ' ', 241, 242, 243, 244, 245, 246, 150, 248, 249, 250, 251, 252, 255, ' ', ' ',
  512. };
  513.  
  514. /*
  515.   Apple QuickDraw character set.
  516. */
  517. unsigned char
  518. yaql1[] = {
  519.   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
  520.  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
  521.  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
  522.  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
  523.  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
  524.  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
  525.  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  526. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  527. 196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 228, 227, 229, 231, 233, 232,
  528. 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, 250, 249, 251, 252,
  529. 133, 176, 162, 163, 167, 135, 182, 223, 174, 169, UNK, 180, 168, UNK, 198, 216,
  530. UNK, 177, UNK, UNK, 165, 181, UNK, UNK, UNK, UNK, UNK, 170, 186, UNK, 230, 248,
  531. 191, 161, 172, UNK, 151, UNK, UNK, 171, 187, 139, ' ', 193, 195, 213, 148, 150,
  532. 132, 146, 129, 138,  47,  47, 247, UNK, 255, UNK, 152, 164, '<', '>', 131, 145,
  533. 153, 134, 136, 137, 140, 194, 202, 192, 203, 200, 205, 206, 207, 204, 211, 212,
  534. UNK, 210, 218, 219, 217, 154, 156, 157, 175, 158, 141, 176, 184, 142, 143, 144
  535. };
  536.  
  537. /*
  538.   Data structures and functions for parsing and displaying character set name.
  539. */
  540. struct keytab {                /* Keyword table template */
  541.     char *kwd;                /* Pointer to keyword string */
  542.     int kwval;                /* Associated value */
  543. };
  544.  
  545. struct keytab csets[] = {        /* Character sets, alphabetical */
  546.     "apple",   APPLE,            /* Apple QuickDraw */
  547.     "cp437",   CP437,            /* IBM Code Page 437 */
  548.     "cp850",   CP850,            /* IBM Code Page 850 */
  549.     "decmcs",  DECMCS,            /* DEC Multinational Character Set */
  550.     "latin1",  LATIN1,            /* ISO 8859-1 Latin Alphabet 1 */
  551.     "next",    NEXT            /* NeXT character set */
  552. };
  553. int ncsets = (sizeof(csets) / sizeof(struct keytab));
  554.  
  555. int
  556. lower(s) char *s; {            /* Lowercase the string */
  557.     int n = 0;                /* return its length */
  558.     while (*s) {
  559.     if (*s >= 'A' && *s <= 'Z')
  560.       *s += ('A' - 'a');
  561.         s++, n++;
  562.     }
  563.     return(n);
  564. }
  565.  
  566. /* Look up keyword, return value */
  567.  
  568. int
  569. lookup(table,cmd,n,x) char *cmd; struct keytab table[]; int n, *x; {
  570.  
  571.     int i, v, cmdlen;
  572.  
  573. /* Lowercase & get length of target, if it's null return code -3. */
  574.  
  575.     if ((((cmdlen = lower(cmd))) == 0) || (n < 1)) return(-3);
  576.  
  577. /* Not null, look it up */
  578.  
  579.     for (i = 0; i < n-1; i++) {
  580.         if (!strcmp(table[i].kwd,cmd) ||
  581.            ((v = !strncmp(table[i].kwd,cmd,cmdlen)) &&
  582.              strncmp(table[i+1].kwd,cmd,cmdlen))) {
  583.                 *x = i;
  584.                 return(table[i].kwval);
  585.              }
  586.         if (v) return(-2);
  587.     }   
  588.  
  589. /* Last (or only) element */
  590.  
  591.     if (!strncmp(table[n-1].kwd,cmd,cmdlen)) {
  592.         *x = n-1;
  593.         return(table[n-1].kwval);
  594.     } else return(-1);
  595. }
  596.  
  597. /* Look up value, return keyword */
  598.  
  599. char *
  600. getname(x,table,n) int x, n; struct keytab table[]; {
  601.     int i;
  602.     for (i = 0; i < n; i++)
  603.       if (table[i].kwval == x)
  604.     return(table[i].kwd);
  605.     return("");
  606. }
  607.  
  608. /* Global data */
  609.  
  610. int charset = CHARSET,            /* Character set */
  611.   hpos = 0,                /* Character number in line buffer */
  612.   maxhpos = 0,                /* Longest line in buffer */
  613.   page = 0,                /* Page number */
  614.   line = 0,                /* Line number */
  615.   blank = 0,                /* Blank line count */
  616.   pagefull = 0,                /* Flag for page overflow */
  617.   psflag = 0,                /* Flag for file already postscript */
  618.   proflg = 0,                /* Prolog done */
  619.   shift = 0;                /* Shift state */
  620.  
  621. int width = WIDTH;            /* Paper width, characters */
  622. int length = LENGTH;            /* Paper length, characters */
  623.  
  624. /* Data structures */
  625.  
  626. /*
  627.   buf is the line buffer.  columns (indexed by hpos) are the characters
  628.   in the line, rows are overstruck lines.  At display time (see addline),
  629.   buf is treated as a 3-dimensional array, with the extra dimension being
  630.   for wraparound.  The total size of the buffer is 80 chars per line times
  631.   66 lines per page times 10 levels of overstriking = 52,800.  This allows
  632.   files that contain absolutely no linefeeds to still print correctly.
  633. */
  634. #define BUFNUM 10            /* Number of overstrike buffers */
  635. #define BUFWID 5280            /* Max characters per line */
  636.  
  637. unsigned char buf[BUFNUM][BUFWID];    /* Line buffers */
  638. unsigned char outbuf[400];        /* Output buffer */
  639. int linesize[BUFNUM];            /* Size of each line in buffer */
  640. int bufs[MAXLENGTH];            /* # overstrike buffers per line */
  641.  
  642. /* Line and page display routines */
  643.  
  644. /* Forward declarations */
  645.  
  646. void addline();                /* Add line to page */
  647. void addchar();                /* Add character to line */
  648. void newpage();                /* New page */
  649. void usage();                /* Usage message */
  650.  
  651. void
  652. clearbuf() {                /* Clear line buffer */
  653.     int i;
  654. /*
  655.   Note: if a loop is used instead of memset, this program runs
  656.   veeeery slooooooowly.
  657. */
  658.     memset(buf,SP,BUFNUM * BUFWID);    /* Clear buffers and counts */
  659.     for (i = 0; i < BUFNUM; linesize[i++] = -1) ;
  660.     for (i = 0; i < length; bufs[i++] = 0) ;
  661.     hpos = 0;                /* Reset line buffer pointer */
  662.     maxhpos = 0;            /* And maximum line length */
  663. }
  664.  
  665. void
  666. doprolog() {                /* Output the PostScript prolog */
  667.     int i;
  668.     for (i = 0; *prolog[i]; i++) {
  669.     printf("%s\n",prolog[i]);
  670.     proflg++;
  671.     }
  672. }
  673.  
  674. void
  675. addchar(c) unsigned char c; {        /* Add character to line buffer */
  676.     int i, m;
  677.     
  678.     if (c < SP || c == DEL) c = SP;    /* ASCII controls become spaces. */
  679.  
  680.     if (c > 127) {            /* 8-bit values are translated */
  681.     switch (charset) {        /* according to character set. */
  682.       case LATIN1:
  683.         if (c > 127 && c < 161)    /* C1 characters are controls */
  684.           c = SP;            /* in Latin-1. */
  685.         break;
  686.       case CP437:  c = y43l1[c]; break;
  687.       case CP850:  c = y85l1[c]; break;
  688.       case NEXT:   c = ynel1[c]; break;
  689.       case DECMCS: c = ydml1[c]; break;
  690.       case APPLE:  c = yaql1[c]; break;
  691.     }
  692.     }
  693.     for (i = 0; i < BUFNUM; i++) {    /* Find first */
  694.     if (hpos > linesize[i]) {    /* available overstrike buffer */
  695.         buf[i][hpos] = c;        /* Deposit character */
  696.         linesize[i] = hpos;        /* Remember size of this buffer. */
  697.         m = hpos / width;        /* Line-wrap segment number. */
  698.         if (i > bufs[m]) bufs[m] = i; /* Highest overstrike buffer used */
  699.         break;            /*   for this line-wrap segment. */
  700.     }
  701.     }
  702.     if (hpos > maxhpos) maxhpos = hpos;    /* Remember maximum line position. */
  703.     if (++hpos >= BUFWID)        /* Increment line position. */
  704.       addline();            /* If buffer full, dump it. */
  705. }
  706.  
  707. void
  708. addline() {                /* Add a line to the current page */
  709.     int i, j, k, m, n, y, wraps;
  710.     unsigned char *p, *q, c;
  711.  
  712.     if (line == 0 && page == 1) {    /* First line of file? */
  713.     if (!strncmp(buf[0],"%!",2)) {    /* Already Postscript? */
  714.         psflag++;            /* Yes, set this flag & just copy */
  715.         buf[0][hpos] = '\0';    /* Trim trailing blanks */
  716.         printf("%s\n",buf[0]);    /* Send this line to stdout */
  717.         return;
  718.     } else if (!proflg) {        /* Not Postscript, print prolog. */
  719.         doprolog();
  720.     }
  721.     }
  722.     if (linesize[0] < 0) {        /* If line is empty, */
  723.     blank++;            /* just count it. */
  724.     return;
  725.     }
  726.     if (blank > 0) {            /* Any previous blank lines? */
  727.     if (blank == 1)            /* One */
  728.       printf("()S\n");
  729.     else                /* Many */
  730.       printf("%d L\n",blank);
  731.     }
  732.     line += blank;            /* Count the blank lines */
  733.     blank = 0;                /* Reset blank line counter */
  734.  
  735.     wraps = maxhpos / width;        /* Number of times line will wrap */
  736.     if (wraps > length) wraps = length;    /* (within reason) */
  737.  
  738.     for (k = 0; k <= wraps; k++) {    /* For each wrapped line */
  739.     m = k * width;            /* Starting position in buffer */
  740.     for (i = 0; i <= bufs[k]; i++) { /* For each overstrike buffer */
  741.         y = linesize[i] + 1;    /* Actual character count */
  742.         if (y <= m)            /* Nothing there, next buffer. */
  743.           continue;
  744.         /* Ending position of this wrap region in buffer. */
  745.         n = (y < m + width) ? y : m + width;
  746.         q = outbuf;
  747.         *q++ = '(';            /* Start text arg */
  748.         for (j = m, p = buf[i]+m; j < n; j++) { /* For each character */
  749.         c = *p++;
  750.         if (c == '(' || c == ')' || c =='\\') /* Quote specials */
  751.           *q++ = '\\';        /*  with backslash. */
  752.         if ((int) c < 128)    /* Insert 7-bit character literally */
  753.           *q++ = c;
  754.         else {            /* Insert 8-bit character */
  755.             *q++ = '\\';    /* as octal backslash escape */
  756.             *q++ = (c >> 6) + '0'; /* (this avoids call to sprintf) */
  757.             *q++ = ((c >> 3) & 07) + '0';
  758.             *q++ = (c & 07) + '0';
  759.         }
  760.         }
  761.         *q = '\0';
  762.         printf("%s%s",outbuf, (i == bufs[k]) ? ")S\n" : ")U\n");
  763.     }
  764.     }
  765.     clearbuf();                /* Clear line buffer */
  766.     line += wraps + 1;            /* Increment line number */
  767.     if (line > (length - 1)) {        /* If page is full */
  768.     newpage();            /* print it and start new one */
  769.     pagefull = 1;
  770.     }
  771. }
  772.  
  773. void
  774. newpage() {                /* Print current page, start new one */
  775.     if (pagefull) {            /* If we just overflowed onto a */
  776.     pagefull = 0;            /* new page, but then got a formfeed */
  777.     return;                /* immediately after... */
  778.     }
  779.     if (!proflg)            /* Do prolog if not done already */
  780.       doprolog();            /*  (in case file starts with ^L) */
  781.     if (hpos)                /* Add any partial line */
  782.       addline();
  783.     line = hpos = 0;            /* Reset line, advance page */
  784.     page++;
  785.     printf("EndPage\n%%%%Page: %d %d\nStartPage\n",page,page);
  786.     blank = 0;
  787. }
  788.  
  789. void            /* Show program & PostScript version numbers */
  790. showver() {
  791.     printf("%%!\n/Courier findfont 11 scalefont setfont\n");
  792.     printf("/EndPage{version (PostScript version )\n");
  793.     printf("48 720 moveto show show showpage sv restore}def\n");
  794.     printf("/sv save def 48 740 moveto\n");
  795.     printf("(textps version %s) show\n",version);
  796.     printf("/sv save def 48 700 moveto\n");
  797.     printf("(textps %s) show\n",copyright);
  798.     printf("EndPage\n");
  799. }
  800.  
  801. /*
  802.    gcharset  -  Set the default character set.
  803.  
  804.    Under OS/2, use the DosQueryCp() or DosGetCp() call;
  805.    under MSDOS, use int 21h; on others just return CHARSET.
  806.  
  807.    Note that in an MSC bound program, DosGetCp() will return the
  808.    current code page and no more than one prepared code page.
  809.  
  810.    INT 21 - DOS 3.3+ - GET GLOBAL CODE PAGE TABLE
  811.               AX = 6601h
  812.    Return: CF set on error
  813.               AX = error code (see AH=59h)
  814.            CF clear if successful
  815.               BX = active code page (see AX=6602h)
  816.           DX = system code page
  817.  
  818.    Values for code page:
  819.      437 US (hardware code page on most PCs)
  820.      850 Multilingual (OS/2 default)
  821.  
  822.    The following are similar to CP437, and are treated like CP437:
  823.      857 Turkish         
  824.      860 Portugal
  825.      861 Iceland
  826.      863 Canada (French)
  827.      865 Norway/Denmark
  828.  
  829.    The following are not supported by textps,
  830.    because Courier does not have the needed characters:
  831.      852 Slavic/Latin-2 (DOS 5+)
  832.      862 Hebrew
  833.      866 Cyrillic
  834.      982 Japanese Shift-JIS
  835.      etc etc.
  836. */
  837. int
  838. gcharset() {
  839.  
  840. /* Note that charset=CHARSET is initialized above */
  841.  
  842. #ifdef OS2NTDOS
  843.     int i;
  844. #ifdef NT
  845.    i = GetConsoleCP() ;
  846. #else /* NT */
  847. #ifdef OS2                /* Then get the code page... */
  848. #define INCL_DOSNLS
  849. #include <os2.h>
  850. /*
  851.   Get the current code page and the first two prepared code pages.
  852.   Only the current code page is used in the following.
  853. */
  854. #ifdef __EMX__
  855.     ULONG CpList[3], CpSize, rc;
  856.     rc = DosQueryCp(sizeof(CpList), CpList, &CpSize);
  857. #else /* MSC */
  858.     USHORT CpList[3], CpSize, rc;
  859.     rc = DosGetCp(sizeof(CpList), CpList, &CpSize);
  860. #endif /* __EMX__ */
  861.     i = (int) CpList[0];
  862. #else /* MSDOS */
  863. #include <dos.h>
  864.     union REGS regs;
  865.  
  866.     regs.x.ax = 0x6601;
  867.     intdos(®s, ®s);
  868.     i = regs.x.bx;
  869. #endif /* OS2 */
  870. #endif /* NT */
  871.     switch (i) {
  872.       case 437: /* CP437 */
  873.       case 860: /* Portugal */
  874.       case 857: /* Turkey */
  875.       case 861: /* Iceland */
  876.       case 863: /* Canadian French */
  877.       case 865: /*  Norway and Denmark */
  878.     charset = CP437;
  879.     break;
  880.       case 850: /* Multilingual (West European) code page */
  881.     charset = CP850;
  882.     break;
  883.     }
  884. #endif /* OS2NTDOS */
  885.  
  886.     return (charset);
  887. }
  888.  
  889.  
  890. /* Main program */
  891.  
  892. void
  893. main(argc, argv) int argc; char *argv[]; {
  894.  
  895.     int i, j,                /* Worker ints */
  896.       escape;                /* Flag when Esc seen. */
  897.     unsigned char c;            /* Input character */
  898.  
  899.     gcharset();                /* Get the default character set */
  900.     while (--argc > 0) {        /* argv/argc "User interface"... */
  901.     argv++;
  902.     if (**argv == '-') {        /* Look for '-' */
  903.         c = *(*argv+1);        /* Get option letter */
  904.         switch (c) {
  905.           case 'l': case 'L':    /* Paper length */
  906.         argv++, argc--;
  907.         length = atol(*argv);
  908.         break;
  909.           case 'w': case 'W':    /* Paper width */
  910.         argv++, argc--;
  911.         width = atol(*argv);
  912.         break;
  913.           case 'h': case 'H': case '?': /* Help */
  914.         usage(-1);
  915.           case 'c': case 'C':    /* Character set */
  916.         argv++, argc--;
  917.         if (argc < 1) usage(4);
  918.         i = lookup(csets,*argv,ncsets,&j);
  919.         if (i < 0) usage(-i);
  920.         charset = i;
  921.         break;
  922.           case 'v': case 'V':    /* Show version numbers */
  923.         showver();
  924.         break;
  925.           default:
  926.         usage(5);
  927.         }
  928.     } else {            /* Options must begin with '-' */
  929.         usage(0);
  930.     }
  931.     }
  932. #ifdef OS2NTDOS
  933. #ifndef NT
  934.    if (isatty(fileno(stdin)))
  935. #endif /* NT */
  936.       usage(-1);
  937. #endif /* OS2NTDOS */
  938.     hpos = line = psflag = 0;        /* Initialize these... */ 
  939.     escape = blank = 0;
  940.     page = 1;
  941.  
  942.     clearbuf();                /* Clear line buffer. */
  943.  
  944.     while ((i = getchar()) != EOF) {    /* Read a file character */
  945.     c = i;                /* Convert to unsigned char */
  946.     if (psflag) {            /* File already postscript? */
  947.         putchar(c);            /* Just copy the bytes. */
  948.         continue;
  949.     }
  950. #ifdef ESCSEQ
  951.     if (escape) {            /* Swallow ANSI escape sequences */
  952.         switch (escape) {
  953.           case 1:            /* ESC */
  954.         if (c < 040 || c > 057) /* Not intermediate character */
  955.           escape = 0;
  956.         continue;
  957.           case 2:            /* CSI */
  958.         if (c < 040 || c > 077)    /* Not parameter or intermediate */
  959.           escape = 0;
  960.         continue;
  961.           default:            /* Bad escape value, */
  962.         escape = 0;        /* shouldn't happen. */
  963.         break;
  964.         }
  965.     }
  966. #endif /* ESCSEQ */
  967.  
  968.     if (shift && c > 31 && c < 127) 
  969.       c |= 0200;            /* Handle shift state. */
  970.  
  971.     if (pagefull && c != 014)    /* Spurious blank page suppression */
  972.       pagefull = 0;
  973.  
  974.     switch (c) {            /* Handle the input character */
  975.  
  976.       case 010:            /* Backspace */
  977.         hpos--;
  978.         if (hpos < 0) hpos = 0;
  979.         continue;
  980.  
  981.       case 011:             /* Tab */
  982.         hpos = (hpos | 7) + 1;
  983.         continue;
  984.  
  985.       case 012:            /* Linefeed */
  986.         addline();            /* Add the line to the page */
  987.         continue;
  988.  
  989.       case 014:            /* Formfeed */
  990.         newpage();            /* Print current page */
  991.         continue;
  992.  
  993.       case 015:            /* Carriage return */
  994.         hpos = 0;            /* Back to left margin */
  995.         continue;
  996.  
  997.       case 016:            /* Shift-Out */
  998.         shift = 1;            /* Set shift state */
  999.         continue;
  1000.  
  1001.       case 017:            /* Shift-In */
  1002.         shift = 0;            /* Reset shift state */
  1003.         continue;
  1004.  
  1005. #ifdef ESCSEQ                /* Swallow ANSI escape sequences */
  1006. /*
  1007.   1 = ANSI escape sequence
  1008.   2 = ANSI control sequence
  1009. */
  1010.       case 033:            /* ESC or 7-bit CSI */
  1011.         escape = ((c = getchar()) == 0133) ? 2 : 1;
  1012.         if (c != 033 && c != 0133 && c != 233) /* Not ANSI after all */
  1013.           ungetc(c,stdin);        /* put it back, avoid loops */
  1014.         continue;
  1015.  
  1016.       case 0233:            /* 8-bit CSI */
  1017.         if (charset == LATIN1) {
  1018.         escape = 2;        /* 0233 is graphic char on PC, etc */
  1019.         continue;
  1020.         }                /* Otherwise fall thru & print it */
  1021. #endif /* ESCSEQ */
  1022.  
  1023.       default:
  1024.         addchar(c);
  1025.     }
  1026.     }
  1027.     if (!psflag) {            /* Done. If not postscript already, */
  1028.     if (hpos)            /* if last line was not empty, */
  1029.       addline();            /* add it to the page. */
  1030.     if (page != 1 || line != 0) {    /* Add trailer. */
  1031.         printf("EndPage\n%%%%Trailer\n%%%%Pages: %d\n",page);
  1032.     }
  1033.     }
  1034.     exit(0);                /* Done, return success code. */
  1035. }
  1036.  
  1037. void
  1038. usage(x) int x; {            /* Give usage message and quit. */
  1039.     int i;
  1040.     switch (x) {
  1041.       case 0:
  1042.     fprintf(stderr,"textps: only options, not filenames, allowed;");
  1043.     fprintf(stderr," use standard input.\n");
  1044.     break;
  1045.       case 1:
  1046.     fprintf(stderr,"textps: invalid character set name\n");
  1047.     break;
  1048.       case 2:
  1049.     fprintf(stderr,"textps: ambiguous option\n");
  1050.     break;
  1051.       case 3:
  1052.     fprintf(stderr,"textps: option required after -\n");
  1053.     break;
  1054.       case 4:
  1055.     fprintf(stderr,"textps: option requires an argument\n");
  1056.     break;
  1057.       case 5:
  1058.     fprintf(stderr,"textps: invalid option\n");
  1059.     break;    
  1060.       default:
  1061.     break;
  1062.     }
  1063.     fprintf(stderr,
  1064. "textps converts standard input to PostScript on standard output.\n");
  1065.     fprintf(stderr,
  1066. "if standard input is already in PostScript format, it is simply copied.\n");
  1067.     fprintf(stderr,
  1068. "usage:  textps -h -v -c charset -l number -w number < infile > outfile\n");
  1069.     fprintf(stderr,"  -h displays this usage message.\n");
  1070.  
  1071.     fprintf(stderr,
  1072. "  -v produces a page showing textps and PostScript version numbers.\n");
  1073.     fprintf(stderr,
  1074. "  -c specifies the file's character set, one of the following:\n");
  1075.     for (i = 0; i < ncsets; i++)
  1076.       fprintf(stderr,"      %s\n",csets[i].kwd);
  1077.     gcharset();
  1078.     fprintf(stderr,"  the default character set is %s.\n",
  1079.         getname(charset,csets,ncsets));
  1080.     fprintf(stderr,"  -l number is paper length in lines (default 66).\n");
  1081.     fprintf(stderr,"  -w number is paper width in characters (default 80).\n");
  1082.     fprintf(stderr,"examples:\n");
  1083.     fprintf(stderr,"  textps < infile > outfile\n");
  1084.     fprintf(stderr,"  textps -v < infile > outfile\n");
  1085.     fprintf(stderr,"  textps -c cp850 < infile > outfile\n");
  1086.     fprintf(stderr,"  textps -v -c next < infile > outfile\n");
  1087.     fprintf(stderr,"  textps < infile | lpr (UNIX)\n");
  1088.     fprintf(stderr,"  textps < infile > prn (DOS)\n");
  1089.     fprintf(stderr,"textps version: %s.\n",version);
  1090.     fprintf(stderr,"%s\n",copyright);
  1091.     exit(1);
  1092. }
  1093.