// t2psncol.C -- Ascii text to n-column Postscript. // MR Jul 2001. // // Output a PostScript script/program that displays the input ascii text // in n columns per page, in MONOSPACE (Courier) font. // // The only control characters are '\t' and '\n'; no backspace character. #include #include #include //--------------------------------------------------------------------------- // Paper size stuff //--------------------------------------------------------------------------- // Throughout we use the standard Postscript coordinates, which are in // "points" and have origin (0,0) in the bottom left corner of the paper. // All distances are in ''POINTS'': 72 points = 1 inch = 2.54 cm. class PrintPositionCoordinator { // // Settings passed to constructor // double xPaperwidth; // Everything in points double yPaperheight; double xLRMar; // Left & right horizontal margins double xMMar; // Middle horizontal margin between text-columns double yTBMar; // Top & bottom vertical margins int nchar_line; // # of characters in a line within a text-column int nCols; // # of text-columns in a page double fLineH_CharW; // { line height / char width } factor double fFontSz_CharW; // { font size / char width } factor // // Calculated settings // double xCharwid; // Width of character including inter-char spacing double yLinehigh; // Height of line including inter-line spacing double fontsize; double xColoffset; // Width of text-column plus inter-column margin double yLine0; // y print position of top line int nLines; // # of lines that fits in height of paper // // Variables // // NB: iline, icol: all 0-based. int iline; // Current line number within text column int icol; // Current text-column number within page public: PrintPositionCoordinator( double paperwidth0, // Everything in points double paperheight0, double lrMar0, double mMar0, double tbMar0, int nchar_line0, // # of chars on line int ncol0, double fLineH_CharW, // { line height / char width } factor double fFontSz_CharW ); // { font size / char width } factor double getfontsize( void ) { return fontsize; } int getnchar_line( void ) { return nchar_line; } double getXprintpos( void ); //Coords of start of current line double getYprintpos( void ); bool nextline( void ); // Update print position. // Return true if moved to new page, false if not. }; PrintPositionCoordinator::PrintPositionCoordinator( double paperwidth0, // Everything in points double paperheight0, double lrMar0, double mMar0, double tbMar0, int nchar_line0, int ncol0, double fLineH_CharW0, // { line height / char width } factor double fFontSz_CharW0 ) // { font size / char width } factor { assert ( ncol0 >= 1 ); // // Store constructor arguments // xPaperwidth = paperwidth0; yPaperheight = paperheight0; xLRMar = lrMar0; xMMar = mMar0; yTBMar = tbMar0; nchar_line = nchar_line0; nCols = ncol0; fLineH_CharW = fLineH_CharW0; fFontSz_CharW = fFontSz_CharW0; // // Calculate settings dependent on constructor arguments // double xColwid = ( xPaperwidth - 2.0*xLRMar - (nCols-1)*xMMar ) / nCols; if ( xColwid <= 0.0 ) { fprintf( stderr, "t2psncol ERROR: width of text columns <= 0\n" ); exit( -1 ); } xCharwid = xColwid / nchar_line; yLinehigh = fLineH_CharW * xCharwid; fontsize = fFontSz_CharW * xCharwid; xColoffset = xColwid + xMMar; yLine0 = yPaperheight - yTBMar; double yTexthigh = yPaperheight - 2.0*yTBMar; nLines = (int)( yTexthigh / yLinehigh ); // round down // // Initialize variables // iline = 0; icol = 0; } double PrintPositionCoordinator::getXprintpos( void ) // Return X-coord (printing position) of start of current line { return ( xLRMar + icol*xColoffset ); } double PrintPositionCoordinator::getYprintpos( void ) // Return Y-coord (printing position) of start of current line { return ( yLine0 - iline*yLinehigh ); } bool PrintPositionCoordinator::nextline( void ) // Update print position. // Return true if moved to new page, false if not. { iline++; if ( iline >= nLines ) { iline = 0; icol++; if ( icol >= nCols ) { // To new page icol = 0; return true; } } return false; } //--------------------------------------------------------------------------- // PS code output //--------------------------------------------------------------------------- void printBeginDocument( FILE * fp, double fontpointsize ) { fprintf( fp, "%%!PS-Adobe-3.0\n" ); fprintf( fp, "%%%%DocumentNeededResources: font Courier\n" ); fprintf( fp, "%%%%Pages: (atend)\n" ); fprintf( fp, "%%%%EndComments\n" ); //fprintf( fp, "%%%%BeginProlog\n" ); //fprintf( fp, "%%%%EndProlog\n" ); fprintf( fp, "%%%%BeginSetup\n" ); fprintf( fp, "%%%%IncludeResource: font Courier\n" ); fprintf( fp, "/Courier findfont\n" ); fprintf( fp, "%g scalefont setfont\n", fontpointsize ); fprintf( fp, "%%%%EndSetup\n" ); } int GLOB_pagenr = 0; void printBeginPage( FILE * fp ) { GLOB_pagenr++; fprintf( fp, "%%%%Page: %d %d\n", GLOB_pagenr, GLOB_pagenr ); } void printEndPage( FILE * fp ) { fprintf( fp, "showpage\n" ); } void printEndDocument( FILE * fp ) { fprintf( fp, "%%%%Trailer\n" ); fprintf( fp, "%%%%Pages: %d\n", GLOB_pagenr ); fprintf( fp, "%%%%EOF\n" ); } void printLine( FILE * fp, double x0, double y0, const char * buf, int n ) { int i; fprintf( fp, "%g %g moveto (", x0, y0 ); for ( i = 0; i < n; i++ ) { switch ( buf[i] ) { case '(': fprintf( fp, "\\050" ); break; case ')': fprintf( fp, "\\051" ); break; case '\\': fprintf( fp, "\\134" ); break; default: fprintf( fp, "%c", buf[i] ); break; }//switch } fprintf( fp, ") show\n" ); } //--------------------------------------------------------------------------- // LineBuffer //--------------------------------------------------------------------------- // // LineBuffer: Character buffer that automatically writes // its contents to output when buffer is full. // // Uses class PrintPositionCoordinator, and writes output // to file 'fp' as PostScript, using the Postscript output funcs // defined above. class LineBuffer { char * pbuf; int ibuf; // # of chars in pbuf[] int linesize; // Length of array pbuf[], and max. # of chars // on a line. Equal to return value of // 'pppc->getnchar_line()'. FILE * fp; PrintPositionCoordinator * pppc; public: LineBuffer( FILE * fp0, PrintPositionCoordinator * pppc0 ); ~LineBuffer( void ); int getlinesize( void ) { return linesize; } int getnchar( void ) { return ibuf; } // Return current # of chars in buffer from start of // line. The buffer always contains the chars on the // current line that still have to be written, te // buffer contains all the chars from the start of the line. void flush( void ); // Write out the contents of the line buffer and set // the buffer to empty. // Also always advance to the print position for the // next line (which may be on the next column, page). void outchar( char c ); // Append to buffer, flush when necessary. }; LineBuffer::LineBuffer( FILE * fp0, PrintPositionCoordinator * pppc0 ) { fp = fp0; pppc = pppc0; // Init buffer linesize = pppc->getnchar_line(); pbuf = new char[linesize]; ibuf = 0; // Initialize the output document printBeginDocument( fp, pppc->getfontsize() ); printBeginPage( fp ); } LineBuffer::~LineBuffer( void ) { // Print the rest of the buffer if ( ibuf > 0 ) { flush(); } // Finish the output document printEndPage( fp ); printEndDocument( fp ); // Deallocate buffer delete[] pbuf; } void LineBuffer::flush( void ) { printLine( fp, pppc->getXprintpos(), pppc->getYprintpos(), pbuf, ibuf ); ibuf = 0; bool newpage = pppc->nextline(); if ( newpage ) { printEndPage( fp ); printBeginPage( fp ); } } void LineBuffer::outchar( char c ) { if ( ibuf >= linesize ) { // Print buffered characters first flush(); } // Now append new character to buffer pbuf[ibuf++] = c; } //--------------------------------------------------------------------------- // main() //--------------------------------------------------------------------------- // // Cmd line arg (option) values: // // (All sizes are in "points") #define A4WIDE_PT 595.3 #define A4HIGH_PT 841.9 static double G_paperwidth = A4WIDE_PT; static double G_paperheight = A4HIGH_PT; static double G_lrMar_pt = 56.7; // Left & right margin = 2.0 cm static double G_mMar_pt = 42.5; // Left & right margin = 1.5 cm static double G_tbMar_pt = 56.7; // Top & bottom margin = 2.0 cm static int G_nchar_line = 80; // # of chars on one line static int G_ncol = 2; // # of text columns on page static double G_fLineH_CharW = 2.0; static double G_fFontSz_CharW = 1.8; static int G_ntab = 8; // Tab width in # of chars static bool G_v = false; // Verbose messages on stderr void usage( void ) { fprintf( stderr, "Usage: t2psncol [options] < txtfile > psfile\n" "Options are: (xx = real value, nn = int value)\n" " Lxx Set factor lineheight/charwidth (default %g)\n" " Fxx Set factor fontsize/charwidth (default %g)\n" " Mxx Use left & right margin of xx points (default %g)\n" " (NB: 72 points = 1 inch = 2.54 cm)\n" " wnn nn characters per line (default %d)\n" " cnn Print in nn columns (default %d)\n" " Tnn Use tab with of nn characters (default %d)\n" " v Verbose\n" "Note: No '-' before option letter, and no space between\n" "option letter and value.\n", G_fLineH_CharW, G_fFontSz_CharW, G_lrMar_pt, G_nchar_line, G_ncol, G_ntab ); } bool doArgs( int argc, char ** argv ) { int i; double a; int n; for ( i = 1; i < argc; i++ ) { switch ( argv[i][0] ) { case 'L': case 'F': case 'M': if ( sscanf( argv[i] + 1, "%le", &a ) != 1 || ! ( a > 0 ) ) { return 0; } switch ( argv[i][0] ) { case 'L': G_fLineH_CharW = a; break; case 'F': G_fFontSz_CharW = a; break; case 'M': G_lrMar_pt = a; break; } break; case 'w': case 'c': case 'T': if ( sscanf( argv[i] + 1, "%d", &n ) != 1 || ! ( n > 0 ) ) { return 0; } switch ( argv[i][0] ) { case 'w': G_nchar_line = n; break; case 'c': G_ncol = n; break; case 'T': G_ntab = n; break; } break; case 'v': G_v = true; break; default: return false; break; }//switch } return true; } int main( int argc, char ** argv ) { int ic; // // Cmd line args // if ( ! doArgs( argc, argv ) ) { usage(); return -1; } // // Initialize // PrintPositionCoordinator ppc( G_paperwidth, G_paperheight, G_lrMar_pt, //double lrMar0 G_mMar_pt, //double mMar0 G_tbMar_pt, //double tbMar0 G_nchar_line, //int nchar_line0 G_ncol, //int ncol0 G_fLineH_CharW, G_fFontSz_CharW ); if( G_v ) { fprintf( stderr, "fontsize = %g\n", ppc.getfontsize() ); } LineBuffer lbuf( stdout, &ppc ); // // Filter the input // while ( ic = fgetc(stdin), ic != EOF ) { switch( ic ) { case '\t': // Tab do { if ( lbuf.getnchar() >= lbuf.getlinesize() ) { break; } lbuf.outchar( ' ' ); } while ( lbuf.getnchar() % G_ntab != 0 ); break; case '\n': // Newline lbuf.flush(); break; default: // Normal character lbuf.outchar( ic ); break; }//switch }//while return 0; }