home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / vbdatabs / pscript.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-14  |  28.8 KB  |  915 lines

  1. // ------------------------------- //
  2. // -------- Start of File -------- //
  3. // ------------------------------- //
  4. // ----------------------------------------------------------- // 
  5. // C++ Source Code File Name: pscript.cpp
  6. // Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
  7. // Produced By: Doug Gaer 
  8. // File Creation Date: 12/17/1997  
  9. // Date Last Modified: 03/15/1999
  10. // Copyright (c) 1997 Douglas M. Gaer
  11. // ----------------------------------------------------------- // 
  12. // ------------- Program Description aond Details ------------- // 
  13. // ----------------------------------------------------------- // 
  14. /*
  15. The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
  16. All those who put this code or its derivatives in a commercial
  17. product MUST mention this copyright in their documentation for
  18. users of the products in which this code or its derivative
  19. classes are used. Otherwise, you have the freedom to redistribute
  20. verbatim copies of this source code, adapt it to your specific
  21. needs, or improve the code and release your improvements to the
  22. public provided that the modified files carry prominent notices
  23. stating that you changed the files and the date of any change.
  24.  
  25. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
  26. THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
  27. IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
  28. YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
  29. CORRECTION.
  30.  
  31. The PostScriptDrv class is used to create postscript documents.
  32. This version prints postscript documents to a file.
  33. */
  34. // ----------------------------------------------------------- // 
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38. #include <time.h>
  39. #include <math.h> // For ceil() function
  40. #include "pscript.h"
  41.  
  42. // PostScript fonts
  43. const char *PostScriptFonts[NumberOfFonts] = {
  44.   // Courier fonts
  45.   "Courier",             // COURIER
  46.   "Courier-Bold",        // COURIER_BOLD
  47.   "Courier-Oblique",     // COURIER_OBLIQUE
  48.   "Courier-BoldOblique", // COURIER_BOLD_OBLIQUE
  49.  
  50.   // Times-Roman fonts
  51.   "Times-Roman",      // TIMES
  52.   "Times-Bold",       // TIMES_BOLD
  53.   "Times-Italic",     // TIMES_ITALIC
  54.   "Times-BoldItalic", // TIMES_BOLD_ITALIC
  55.  
  56.   // Helvetica fonts
  57.   "Helvetica",             // HELV
  58.   "Helvetica-Bold",        // HELV_BOLD
  59.   "Helvetica-Oblique",     // HELV_OBLIUQE
  60.   "Helvetica-BoldOblique", // HELV_BOLD_OBLIQUE
  61.  
  62.   // Symbol font
  63.   "Symbol" // SYMBOL                     
  64. };
  65.  
  66. // PostScript command strings defined in the postscript prologue
  67. const char *BACKSPACE  = "B";
  68. const char *ENDPAGE    = "EP";
  69. const char *LINETO     = "L";
  70. const char *MOVETO     = "M";
  71. const char *NEWPATH    = "NP";
  72. const char *SHOW       = "S";
  73. const char *STARTPAGE  = "SP";
  74. const char *STROKE     = "ST";
  75. const char *TAB        = "T";
  76.  
  77. void GetSystemTime(char *s, int full_month_name)
  78. // Stand alone function use to create a custom time string for
  79. // PostScript headers.
  80. {
  81.   time_t STime;
  82.   struct tm *TimeBuffer;
  83.   char month[25]; char day[25]; char year[25];
  84.   char hour[25]; char minutes[25]; char seconds[25];
  85.   time(&STime);
  86.   TimeBuffer = localtime(&STime);
  87.   if(full_month_name)
  88.     strftime(month, 25, "%B", TimeBuffer);
  89.   else
  90.     strftime(month, 25, "%b", TimeBuffer);
  91.   strftime(day, 25, "%d", TimeBuffer);
  92.   strftime(year, 25, "%Y", TimeBuffer);
  93.   strftime(hour, 25, "%H", TimeBuffer);
  94.   strftime(minutes, 25, "%M", TimeBuffer);
  95.   strftime(seconds, 25, "%S", TimeBuffer);
  96.  
  97.   // Weekday Name Month Day, Year HH:MM:SS
  98.   sprintf(s, "%s %s, %s %s:%s:%s", month, day, year, hour, minutes, seconds);
  99. }
  100.  
  101. PostScriptDrv::PostScriptDrv()
  102. {
  103.   ncopies = 1;          // Print at least one copy of this document
  104.   landscape = 0;        // Use portrait mode by default
  105.   use_header = 0;       // Do not use headers and trailers by default
  106.   use_lr_margin = 0;    // Do not use left and right margins by default  
  107.   use_tb_margin = 0;    // Do not use top and bottom margins by default
  108.   document_name = 0;    // Name of this document
  109.   date_string = 0;      // Time and date this document was printed
  110.   draw_header_line = 0; // Do not draw line between header and document 
  111.  
  112.   tabstop = DEFAULT_TAB_SIZE;
  113.   page_count = 0;
  114.   SetFont(COURIER, 10);
  115.   DocumentSetup();
  116.   row = start_y;
  117.   line_count = lines_per_page;
  118.   SetHeaderFont(COURIER_BOLD, 15);
  119. }
  120.  
  121. PostScriptDrv::PostScriptDrv(const PostScriptDrv &ob)
  122. {
  123.   ncopies = ob.ncopies;        
  124.   landscape = ob.landscape;      
  125.   lines_per_page = ob.lines_per_page;
  126.   columns = ob.columns;
  127.   tabstop = ob.tabstop;
  128.   row = ob.row;
  129.   start_x = ob.start_x;
  130.   start_y = ob.start_y;
  131.   page_count = ob.page_count;
  132.   font_size = ob.font_size;
  133.   page_width = ob.page_width; 
  134.   page_height = ob.page_height;
  135.   chars_per_inch = ob.chars_per_inch;
  136.   char_width = ob.char_width;
  137.   text_font = ob.text_font;
  138.   use_lr_margin = ob.use_lr_margin;
  139.   use_tb_margin = ob.use_tb_margin;
  140.   use_header = ob.use_header;
  141.   header_font = ob.header_font;
  142.   header_font_size = ob.header_font_size;
  143.   document_name = ob.document_name;
  144.   date_string = ob.date_string;
  145.   draw_header_line = ob.draw_header_line;
  146.   line_count = ob.line_count;
  147. }
  148.   
  149. PostScriptDrv &PostScriptDrv::operator=(const PostScriptDrv &ob)
  150. {
  151.   ncopies = ob.ncopies;        
  152.   landscape = ob.landscape;      
  153.   lines_per_page = ob.lines_per_page;
  154.   columns = ob.columns;
  155.   tabstop = ob.tabstop;
  156.   row = ob.row;
  157.   start_x = ob.start_x;
  158.   start_y = ob.start_y;
  159.   page_count = ob.page_count;
  160.   font_size = ob.font_size;
  161.   page_width = ob.page_width; 
  162.   page_height = ob.page_height;
  163.   text_font = ob.text_font;
  164.   chars_per_inch = ob.chars_per_inch;
  165.   char_width = ob.char_width;
  166.   use_lr_margin = ob.use_lr_margin;
  167.   use_tb_margin = ob.use_tb_margin;
  168.   use_header = ob.use_header;
  169.   header_font = ob.header_font;
  170.   header_font_size = ob.header_font_size;
  171.   document_name = ob.document_name;
  172.   date_string = ob.date_string;
  173.   draw_header_line = ob.draw_header_line;
  174.   line_count = ob.line_count;
  175.   
  176.   return *this;
  177. }
  178.  
  179. void PostScriptDrv::SetFont(PSFonts font, double size)
  180. {
  181.   switch(font){
  182.     case COURIER:              
  183.       font_size = size;
  184.       char_width = 0.6 * font_size; // Width of each character
  185.       break;
  186.       
  187.     case COURIER_BOLD:         
  188.       font_size = size;
  189.       char_width = 0.6 * font_size; // Width of each character
  190.       break;
  191.       
  192.     case COURIER_OBLIQUE:      
  193.       font_size = size;
  194.       char_width = 0.6 * font_size; // Width of each character
  195.       break;
  196.       
  197.     case COURIER_BOLD_OBLIQUE: 
  198.       font_size = size;
  199.       char_width = 0.6 * font_size; // Width of each character
  200.       break;
  201.       
  202.     case TIMES:             
  203.       font_size = size;
  204.       char_width = 0.57 * font_size; // Width of each character
  205.       break;
  206.       
  207.     case TIMES_BOLD:        
  208.       font_size = size;
  209.       char_width = 0.6 * font_size; // Width of each character
  210.       break;
  211.       
  212.     case TIMES_ITALIC:      
  213.       font_size = size;
  214.       char_width = 0.55 * font_size; // Width of each character
  215.       break;
  216.       
  217.     case TIMES_BOLD_ITALIC: 
  218.       font_size = size;
  219.       char_width = 0.58 * font_size; // Width of each character
  220.       break;
  221.       
  222.     case HELV:             
  223.       font_size = size;
  224.       char_width = 0.6 * font_size; // Width of each character
  225.       break;
  226.       
  227.     case HELV_BOLD:        
  228.       font_size = size;
  229.       char_width = 0.6 * font_size; // Width of each character
  230.       break;
  231.       
  232.     case HELV_OBLIQUE:     
  233.       font_size = size;
  234.       char_width = 0.6 * font_size; // Width of each character
  235.       break;
  236.       
  237.     case HELV_BOLD_OBLIQUE:
  238.       font_size = size;
  239.       char_width = 0.6 * font_size; // Width of each character
  240.       break;
  241.       
  242.     case SYMBOL:
  243.       font_size = size;
  244.       char_width = 0.57 * font_size; // Width of each character
  245.       break;
  246.  
  247.     default: // COURIER              
  248.       font_size = DEFAULT_POINT_SIZE;
  249.       char_width = 0.6 * font_size; // Width of each character
  250.       break;
  251.   }
  252.  
  253.   // Set font name
  254.   text_font = (char *)PostScriptFonts[font];
  255.  
  256.   // Calculate the number of characters per inch
  257.   chars_per_inch = PIXELS_PER_INCH / char_width; 
  258. }
  259.  
  260. void PostScriptDrv::SetHeaderFont(PSFonts font, double size)
  261. {
  262.   header_font_size = size;
  263.   header_font = (char *)PostScriptFonts[font];
  264. }
  265.  
  266. void PostScriptDrv::SetPaperSize(PSPaperSizes size)
  267. // Calculates the x and y positions for landscape and portrait modes
  268. // for different paper sizes. There are 72 points per inch, with the
  269. // origin (0,0) in the lower left corner of the page. By default,
  270. // distances are specified in PostScript points (1/72 of an inch). 
  271.  
  272. {
  273.   switch(size) {
  274.     case LETTER_SIZE: // 8.5 X 11 inches 
  275.       page_width = int(8.5 * PIXELS_PER_INCH); // 612 points per inch 
  276.       page_height = int(11 * PIXELS_PER_INCH); // 729 points per inch 
  277.       break;
  278.  
  279.     case LEGAL_SIZE: // 8.5 x 14 inches 
  280.       page_width = int(8.5 * PIXELS_PER_INCH); // 612 points per inch 
  281.       page_height = int(14 * PIXELS_PER_INCH); // 1008 points per inch 
  282.       break;
  283.       
  284.     case TABLOID_SIZE: // 11 x 17 inches  
  285.       page_width = int(11 * PIXELS_PER_INCH);  // 792 points per inch 
  286.       page_height = int(17 * PIXELS_PER_INCH); // 1224 points per inch 
  287.       break;
  288.  
  289.     case A3_SIZE: // 297mm x 420mm (11.70" X 16.55")
  290.       page_width = int(11.70 * PIXELS_PER_INCH);  // 842.4 points per inch 
  291.       page_height = int(16.55 * PIXELS_PER_INCH); // 1191.6 points per inch 
  292.       break;
  293.  
  294.     case A4_SIZE: // 210mm x 297mm (8.27" X 11.70") 
  295.       page_width = int(8.27 * PIXELS_PER_INCH);   // 595.44 points per inch 
  296.       page_height = int(11.70 * PIXELS_PER_INCH); // 842.4 points per inch 
  297.       break;
  298.       
  299.     default: // Default value is letter size: 8.5 X 11 inches 
  300.       page_width = int(8.5 * PIXELS_PER_INCH); // 612 points per inch 
  301.       page_height = int(11 * PIXELS_PER_INCH); // 729 points per inch 
  302.       break;
  303.   }
  304. }
  305.  
  306. void PostScriptDrv::DocumentSetup(double LR_margin, double TB_margin, int man)
  307. // Calculates the x and y positions, lines per page and columns for
  308. // landscape and portrait modes. The left/right and top/bottom margin
  309. // offsets will not be used if left/right or top/bottom margins are
  310. // not enabled. If man if true the line per page will be set to max
  311. // lines per page for UNIX man pages produced by nroff. nroff is used
  312. // to format man pages under most variants of UNIX.
  313. {
  314.   start_x = (int)PRINTABLE_OFFSET_X;
  315.   
  316.    // If using page headers set the Top, Bottom, Left and Right margins
  317.   if(use_header) {
  318.     if(landscape && use_lr_margin == 0)
  319.       use_tb_margin = 1;
  320.     else
  321.       use_lr_margin = use_tb_margin = 1;
  322.     
  323.     LR_margin = TB_margin = HEADER_OFFSET;
  324.   }
  325.   
  326.   if(landscape) {
  327.     start_y = int(page_width - (PRINTABLE_OFFSET_Y + font_size));
  328.     
  329.     // Account for the printable areas at the top and bottom of the page
  330.     lines_per_page = (int)ceil((start_y - PRINTABLE_OFFSET_Y) / font_size);
  331.  
  332.     if(man == 1 && lines_per_page > UNIX_MAN_PAGE_LINES) 
  333.       lines_per_page = UNIX_MAN_PAGE_LINES;
  334.     
  335.     if(use_lr_margin) { // Calculate the left and right margins offsets
  336.       double right_margin = LR_margin * 2;
  337.       double new_page_width = page_height - (right_margin * PIXELS_PER_INCH);
  338.       columns = (int)ceil(new_page_width / char_width);
  339.       start_x = int(LR_margin * PIXELS_PER_INCH);
  340.     }
  341.     else {
  342.       double width = page_height - (PRINTABLE_OFFSET_Y * 2);
  343.       columns = (int)ceil((width / char_width) - 1);
  344.     }
  345.  
  346.     if(use_tb_margin) { // Calculate the top and bottom margins
  347.       int nlines = (int)ceil((TB_margin * PIXELS_PER_INCH) / font_size);
  348.       start_y = int(page_width - (nlines * font_size));
  349.       double bottom_margin = page_width - ((TB_margin *2 ) * PIXELS_PER_INCH);
  350.       lines_per_page = (int)ceil(bottom_margin / font_size);
  351.       if(man == 1 && lines_per_page > UNIX_MAN_PAGE_LINES)
  352.     lines_per_page = UNIX_MAN_PAGE_LINES;
  353.     }
  354.   }
  355.   else { 
  356.     start_y = int(page_height - (PRINTABLE_OFFSET_Y + font_size));
  357.     lines_per_page = (int)ceil(start_y / font_size) - 1;
  358.  
  359.     if(man == 1 && lines_per_page > UNIX_MAN_PAGE_LINES)
  360.       lines_per_page = UNIX_MAN_PAGE_LINES;
  361.  
  362.     if(use_lr_margin) { // Calculate the left and right margins offsets
  363.       double right_margin = LR_margin * 2;
  364.       double new_page_width = page_width - (right_margin * PIXELS_PER_INCH);
  365.       columns = (int)ceil(new_page_width / char_width);
  366.       start_x = int(LR_margin * PIXELS_PER_INCH);
  367.     }
  368.     else {
  369.       double width = page_width - (PRINTABLE_OFFSET_X * 2);
  370.       columns = (int)ceil((width / char_width) - 1);
  371.     }
  372.     
  373.     if(use_tb_margin) { // Calculate the top and bottom margins
  374.       int nlines = (int)ceil((TB_margin * PIXELS_PER_INCH) / font_size);
  375.       start_y = int(page_height - (nlines * font_size));
  376.       double bottom_margin = page_height - ((TB_margin * 2) * PIXELS_PER_INCH);
  377.       lines_per_page = (int)ceil(bottom_margin / font_size);
  378.       if(man == 1 && lines_per_page > UNIX_MAN_PAGE_LINES)
  379.     lines_per_page = UNIX_MAN_PAGE_LINES;
  380.     }
  381.   }
  382. }
  383.  
  384. void PostScriptDrv::Prologue(ostream &stream, char *pn, char *hn,
  385.                  char *cd, char *un)
  386. // Generates the PostScript header and includes the prologue.
  387. // Arguments are: pn - Program Name, hn - Hostname,
  388. // cd - Creation Date, un - Username.
  389. {
  390.   stream << "%!PS-Adobe-2.0" << endl;
  391.   if(pn) {
  392.     stream << "%%Produced By: " <<  pn;
  393.     if(hn) stream << " on " << hn << endl; else  stream << endl;
  394.   }
  395.  
  396.   if(cd) stream << "%%Creation Date: " << cd << endl;
  397.   if(un) stream << "%%For: " << un << endl;
  398.   if(text_font) stream << "%%DocumentFont: " << text_font << endl;
  399.   stream << "%%Pages: (atend)" << endl;
  400.   stream << "%%EndComments" << endl;
  401.  
  402.   stream << "% PostScript Prologue for ASCII to PostScript converter" << endl;
  403.   stream << "%%BeginProlog" << endl;
  404.   
  405.   // PostScript command strings 
  406.   stream << "/B {NW 0 rmoveto}bind def" << endl;
  407.   stream << "/EP {SV restore /#copies exch def showpage}bind def" << endl;
  408.   stream << "/L /lineto load def" << endl;
  409.   stream << "/M /moveto load def" << endl;
  410.   stream << "/NP /newpath load def" << endl;
  411.   stream << "/S /show load def" << endl;
  412.   stream << "/SP {/SV save def findfont exch scalefont setfont ( )" << endl;
  413.   stream << "  stringwidth pop dup /W exch def neg /NW exch def}bind def"
  414.      << endl;
  415.   stream << "/ST /stroke load def" << endl;
  416.   stream << "/T {W mul 0 rmoveto}bind def" << endl;
  417.  
  418.   // PostScript procedures 
  419.   stream << "/drawLine { " << endl;
  420.   stream << "gsave " << LINE_WIDTH
  421.      << " setlinewidth 0 setgray moveto 0 rlineto stroke grestore"
  422.      << endl;
  423.   stream << "} bind def" << endl;
  424.   
  425.   stream << "/drawThickLine { " << endl;
  426.   stream << "gsave " << THICK_LINE_WIDTH
  427.      << " setlinewidth 0 setgray moveto 0 rlineto stroke grestore" 
  428.      << endl;
  429.   stream << "} bind def" << endl;
  430.  
  431.   stream << "%%EndProlog" << endl;
  432. }
  433.  
  434. void PostScriptDrv::drawLine(ostream &stream, int points,
  435.                        int xpos, int ypos)
  436. {
  437.   stream << points << " " << xpos << " " << ypos << " drawLine"
  438.      << endl;
  439. }
  440.  
  441. void PostScriptDrv::drawThickLine(ostream &stream, int points,
  442.                   int xpos, int ypos)
  443. {
  444.   stream << points << " " << xpos << " " << ypos << " drawThickLine"
  445.      << endl;
  446. }
  447.  
  448. int PostScriptDrv::ProcessText(char *in, ostream &stream, int cut, int filter)
  449. // Process a line of text before printing it. If cut is true the line
  450. // will be truncated to match the number of columns for this line. If
  451. // filter is true each line will be filtered for escape seqences and
  452. // non-printable characters before the line is truncated. Retuns true 
  453. // if successful.
  454. {
  455.   int len = strlen(in);
  456.  
  457.   // Truncate the line if it exceeds the maximum number of columns
  458.   if(len >= columns && filter == 1) { 
  459.     int word_count = 0;
  460.  
  461.     // Filter escape seqences and non-printable chars before truncating line
  462.     for(int pos = 0; pos < len; pos++) { 
  463.       if(in[pos] == ' ') word_count = 0; else word_count++;
  464.  
  465.       // Filter bold sequences produced by nroff
  466.       // nroff is used to format man pages under most variants of UNIX
  467.       char c = in[pos++];
  468.       if(c == in[pos+1] && in[pos] == in[pos+2] &&
  469.      c == in[pos+3] &&  in[pos] == in[pos+4] &&
  470.      c == in[pos+5]) {
  471.     int bold_offset = (word_count * 7) - word_count;
  472.     len -= bold_offset; 
  473.     word_count = 0;
  474.       }
  475.       
  476.       // Filter underline sequences produced by nroff 
  477.       // nroff is used to format man pages under most variants of UNIX
  478.       if(in[pos] == '\b') len--;
  479.     } 
  480.   }
  481.  
  482.   // Truncate if necessary after filtering line 
  483.   if(len >= columns && cut == 1) { 
  484.     char *buf = new char[columns];
  485.     buf[columns] = '\0';
  486.     memmove(buf, in, columns);
  487.     stream << start_x << " "  << row << " " << MOVETO << endl;
  488.     int rv = PrintLine(buf, stream);
  489.     delete [] buf;
  490.     return rv;
  491.   }
  492.   else {
  493.     stream << start_x << " "  << row << " " << MOVETO << endl;
  494.     return PrintLine(in, stream);
  495.   }
  496. }
  497.  
  498. int PostScriptDrv::PrintLine(char *in, ostream &stream)
  499. // Print a line of PostScript text, escaping characters when
  500. // necessary and handling tabs.
  501. {
  502.   char bufout[BUFOUT];
  503.   char *p, *q, *savep;
  504.   int currentp, instr, tabc, tabto, i, colskip, ncols;
  505.   int seen_sep = 0;
  506.   
  507.   currentp = instr = tabto = 0;
  508.   char *last = bufout + MAX_LINE - 20; // Subtract error factor 
  509.  
  510.   q = bufout;
  511.   *q = '\0';
  512.   for(p = in; *p != '\0'; p++) {
  513.     switch (*p) {
  514.       case SEP_CHAR: // Column separator character 
  515.     // This assumes that the input buffer contains the entire line,
  516.     // otherwise the column count will be offset.
  517.     if (!seen_sep) { // Discern number of columns 
  518.       seen_sep = 1;
  519.       ncols = 2; // There are at least two columns
  520.       savep = p++;
  521.       while (*p != '\0') {
  522.         if (*p++ == SEP_CHAR)
  523.           ncols++;
  524.       }
  525.       p = savep;
  526.       colskip = columns / ncols;
  527.     }
  528.     if(instr) {
  529.       sprintf(q, ")%s ", SHOW);
  530.       q += strlen(q);
  531.       instr = 0;
  532.     }
  533.     tabto += (colskip - currentp);
  534.     currentp = 0;
  535.     break;
  536.  
  537.       case '\t': // Tab
  538.     // Count the number of tabs that immediately follow this one
  539.     tabc = 0;
  540.     while (*(p + 1) == '\t') {
  541.       p++;
  542.       tabc++;
  543.     }
  544.     if (currentp > 0) { // Not beginning of line 
  545.       i = tabstop - (currentp % tabstop) + tabc * tabstop;
  546.       if (instr) {
  547.         (void) sprintf(q, ")%s ", SHOW);
  548.         q += strlen(q);
  549.         instr = 0;
  550.       }
  551.     }
  552.     else
  553.       i = (tabc + 1) * tabstop;
  554.     tabto += i;
  555.     currentp += i;
  556.     break;
  557.  
  558.       case '\b': // Back Space
  559.     *q = '\0';
  560.     stream << bufout << ")" << SHOW << endl;
  561.     // backspacing over tabs doesn't work
  562.     if (tabto != 0) return 0; // Attempt to backspace over a tab
  563.     p++;
  564.     for (i = 1; *p == '\b'; p++)
  565.       i++;
  566.     if (currentp - i < 0) return 0; // Too many backspaces
  567.     if (!instr) return 0; // Bad Back Spacing
  568.  
  569.     // Handle consecutive backspace seqences produced by nroff 
  570.     // nroff is used to format man pages under most variants of UNIX
  571.     if (i == 1)  
  572.       sprintf(bufout, "%s (", BACKSPACE);
  573.     else
  574.       sprintf(bufout, "-%d %s (", i, TAB);
  575.     currentp -= i;
  576.     q = bufout + strlen(bufout);
  577.     p--;
  578.     break;
  579.  
  580.       case '\f': // Form Feed
  581.     tabto = 0; // Optimizes 
  582.     *q = '\0';
  583.     if(instr)
  584.       stream << bufout << ")" << SHOW << endl;
  585.     else
  586.       stream << bufout << endl;
  587.     EndPage(stream);
  588.     StartPage(page_count + 1, stream);
  589.     row = start_y;
  590.     stream << start_x << " " << row << " " << MOVETO << endl;
  591.     q = bufout;
  592.     currentp = 0;
  593.     instr = 0;
  594.     break;
  595.  
  596.       case '\r': // Hard Return
  597.     tabto = 0; // optimizes 
  598.     if (instr) {
  599.       *q = '\0';
  600.       stream << bufout << ")" << SHOW << endl;
  601.       instr = 0;
  602.       q = bufout;
  603.     }
  604.     stream << start_x << " " << row << " " << MOVETO << endl;
  605.     currentp = 0;
  606.     break;
  607.  
  608.       case '\\': case '(': case ')':
  609.     if (!instr) {
  610.       if (tabto) {
  611.         sprintf(q, "%d %s ", tabto, TAB);
  612.         q += strlen(q);
  613.         tabto = 0;
  614.       }
  615.       *q++ = '(';
  616.       instr = 1;
  617.     }
  618.     *q++ = '\\';
  619.     *q++ = *p;
  620.     currentp++;
  621.     break;
  622.  
  623.       default:
  624.     // PostScript files can contain only the printable subset
  625.     // of the ASCII character set (plus the newline marker).
  626.     if (!isascii(*p) || !isprint(*p)) return 0; // Bad character in input
  627.     if (!instr) {
  628.       if (tabto) {
  629.         sprintf(q, "%d %s ", tabto, TAB);
  630.         q += strlen(q);
  631.         tabto = 0;
  632.       }
  633.       *q++ = '(';
  634.       instr = 1;
  635.     }
  636.     *q++ = *p;
  637.     currentp++;
  638.     break;
  639.     }
  640.  
  641.     if (q >= last) {
  642.       *q = '\0';
  643.       if (instr)
  644.     stream << bufout << ")" << SHOW << endl;
  645.       else
  646.     stream << bufout << endl;
  647.       q = bufout;
  648.       instr = 0;
  649.     }
  650.   }
  651.  
  652.   if (instr) {
  653.     sprintf(q, ")%s", SHOW);
  654.     q += strlen(q);
  655.   }
  656.   else
  657.     *q = '\0';
  658.  
  659.   if(q >= last) return 0; // Output buffer overflow
  660.   if(bufout[0] != '\0') stream << bufout << endl;
  661.   return 1;
  662. }
  663.  
  664. void PostScriptDrv::EndPage(ostream &stream)
  665. // Terminate the page and indicate the start of the next
  666. {
  667.   if (page_count == MAXPAGES) return; // pagelimit reached;
  668.   stream << ncopies << " " << ENDPAGE << endl;
  669.   page_count++;
  670. }
  671.  
  672. void PostScriptDrv::ChangeFont(ostream &stream, PSFonts font, double size)
  673. // Change the font before printing
  674. {
  675.   stream << size << " /" <<  PostScriptFonts[font] << " ";
  676.   stream << "findfont " << size << " scalefont setfont" << endl; 
  677. }
  678.  
  679. void PostScriptDrv::StartPage(int n, ostream &stream)
  680. // Start a new page
  681. {
  682.   stream << "%%Page: ? " << n << endl; 
  683.  
  684.   if(use_header) // Set the header font
  685.     stream << header_font_size << " /" << header_font << " ";
  686.   else
  687.     stream << font_size << " /" << text_font << " ";
  688.   
  689.   if(landscape) {
  690.     stream << STARTPAGE << " " << page_width << " 0 translate " << endl;
  691.     stream << "90 rotate" << endl;
  692.   }
  693.   else
  694.     stream << STARTPAGE << endl;
  695.  
  696.   if(use_header) { // Print the header info and reset the font
  697.     int hpoints = int(HEADER_OFFSET * PIXELS_PER_INCH);
  698.     int header_char_width = int(header_font_size * .6);
  699.     int line_width, width, len, line_points, ypos, xpos = start_x; 
  700.     int hoffset = hpoints / 2; // Offsets the header from text
  701.     
  702.     if(landscape) {
  703.       // Leave some room for three hole punch margin at top of page
  704.       ypos = page_width - (hpoints - 20);
  705.  
  706.       if(use_lr_margin == 0)
  707.     line_points = int(page_height - (PRINTABLE_OFFSET_X * 2));
  708.       else
  709.     line_points = page_height - (hpoints * 2);
  710.  
  711.       width = page_height;
  712.     }
  713.     else {
  714.       ypos = page_height - hoffset;
  715.       line_points = page_width - (hpoints * 2);
  716.       width = page_width;
  717.     }
  718.  
  719.     if(draw_header_line) { // Draw the top and bottom lines
  720.       drawThickLine(stream, line_points, xpos, ypos);
  721.       drawThickLine(stream, line_points, xpos, hoffset);
  722.       line_width = THICK_LINE_WIDTH * 2; // Offset the line from header text
  723.     }
  724.     else
  725.       line_width = 0;
  726.     
  727.     ypos += line_width;
  728.     if(date_string != 0 && document_name != 0) {
  729.       // Left justify the document_name
  730.       stream << xpos << " " << ypos << " " << MOVETO << endl;
  731.       stream << "(" << document_name << ")" << " " << SHOW << endl;
  732.  
  733.       // Right justify the date string
  734.       len = strlen(date_string) * header_char_width;
  735.       if(use_lr_margin == 0)
  736.     xpos = int((width - PRINTABLE_OFFSET_X) - len);
  737.       else
  738.     xpos = (line_points + hpoints) - len;
  739.       stream << xpos << " " << ypos << " " << MOVETO << endl;
  740.       stream << "(" << date_string << ")" << " " << SHOW << endl;
  741.     }
  742.     else { // Center the doucuments name
  743.       if(document_name == 0) document_name = "PostScript Document";
  744.       len = strlen(document_name) * header_char_width;
  745.       xpos = (width / 2) - (len / 2);
  746.       stream << xpos << " " << ypos << " " << MOVETO << endl;
  747.       stream << "(" << document_name << ")" << " " << SHOW << endl;
  748.       xpos = start_x;
  749.     }
  750.  
  751.     // Draw the page numbers
  752.     char page_number_string[255];
  753.     sprintf(page_number_string, "PAGE %d", n);
  754.     len = strlen(page_number_string) * header_char_width;
  755.     xpos = (width / 2) - (len / 2);
  756.     ypos = int(hoffset - (header_font_size + line_width));
  757.     stream << xpos << " " << ypos << " " << MOVETO << endl;
  758.     stream << "(" << page_number_string << ")" << " " << SHOW << endl;
  759.     
  760.     // Reset the text font
  761.     stream << font_size << " /" << text_font << " " << STARTPAGE << endl;
  762.   }
  763. }
  764.  
  765. int PostScriptDrv::ConvertTextFile(ifstream &infile, ostream &stream,
  766.                    int wrap, int cut)
  767. // Convert the ASCII document to postcript. Returns 1 if successful.
  768. // If wrap is true the line will wrap around the page if the number
  769. // of columns are exceeded. If cut is true the line will be truncated
  770. // to match the number of columns.
  771. {
  772.   if(!infile) return 0; 
  773.   char bufin[BUFIN];
  774.  
  775.   // Read in text file line by line until EOF
  776.   while(!infile.eof()) {
  777.     StartPage(page_count + 1, stream);
  778.     row = start_y;
  779.     line_count = lines_per_page;
  780.     // Process the next page 
  781.     for (int lineno = 0; lineno < line_count; lineno++) {
  782.       infile.getline(bufin, MAX_LINE);
  783.       if (bufin[0] == '\f') break;
  784.       if (bufin[0] != '\0') {
  785.     int len = strlen(bufin);
  786.     
  787.     if(wrap == 1 && len >= columns) { // Wrap text lines 
  788.       int i = 0, j = 0, x = 0;
  789.       char *temp_buf = new char[columns];
  790.       temp_buf[columns] = '\0';
  791.     
  792.       while(len >= columns) { // Loop until length is less then columns
  793.         len = len - columns;
  794.         for(j = 0; j < columns; j++, i++) temp_buf[j] = bufin[i];
  795.         stream << start_x << " "  << row << " " << MOVETO << endl;
  796.         if(PrintLine(temp_buf, stream) == 0) return 0;
  797.         for(x = 0; x < columns; x++) temp_buf[x] = '\0';
  798.         row -= (int)font_size; // Update the y position after wrap
  799.  
  800.         if(row < font_size) { // Start a new page
  801.           EndPage(stream);
  802.           StartPage(page_count + 1, stream);
  803.           row = start_y;
  804.           line_count = lines_per_page;
  805.           lineno = 0;
  806.         }
  807.         line_count--;
  808.         if(len < columns) break;
  809.       }
  810.  
  811.       if(len > 0) { // Print the remaining characters
  812.         for(j = 0; j < len; j++, i++) temp_buf[j] = bufin[i];
  813.         stream << start_x << " "  << row << " " << MOVETO << endl;
  814.         if(PrintLine(temp_buf, stream) == 0) return 0;
  815.       }
  816.     }
  817.     else 
  818.       if(ProcessText(bufin, stream, cut) == 0) return 0;
  819.     
  820.     for(int i = 0; i < BUFIN; i++) bufin[i] = 0;  // Clear the buffer
  821.       }
  822.       row -= (int)font_size;
  823.     }
  824.     EndPage(stream);
  825.   } 
  826.   return 1;
  827. }
  828.  
  829. void PostScriptDrv::Epilogue(ostream &stream, int page_count)
  830. {
  831.   stream << "%%Trailer" << endl;
  832.   stream << "%%Pages: " << page_count << endl;
  833. }
  834.  
  835.  
  836. void PostScriptDrv::MediaSetup(ostream &stream, int duplex, int manualfeed,
  837.                    int use_tray, int tray_number)
  838. // Sets the physical sources and physical destinations for the media
  839. // source and destination to be used in the printer. These settings
  840. // are device dependent. 
  841. {
  842.   stream << "%%BeginSetup" << endl;
  843.  
  844.   if(duplex) {
  845.     // Enable duplex printing if a duplex device is attached to the
  846.     // printer. Each pair of consecutive pages will be printed on
  847.     // opposite sides of a single sheet of paper.
  848.     stream << "%%BeginFeature: *Duplex" << endl;
  849.     stream << "<</Duplex true>>setpagedevice" << endl;
  850.     stream << "%%EndFeature" << endl;
  851.   }
  852.  
  853.   if(manualfeed) {
  854.     // Feed paper from the manual feed position.
  855.     stream << "%%BeginFeature: *ManualFeed" << endl;
  856.     stream << "<</ManualFeed true>>setpagedevice" << endl;
  857.     stream << "%%EndFeature" << endl;
  858.   }
  859.  
  860.   if(use_tray) {
  861.     // Select a specific paper tray to print from. The number following
  862.     // "MediaPosition" indicates the actual tray. The correspondence
  863.     // between tray numbers and the actual positions is specific to
  864.     // each printer.
  865.  
  866.     // Example: The HP LaserJet 5Si/5Si MX printer uses the following
  867.     // numbers to represent the actual paper trays:
  868.     // 0 = Tray 2, 1 = Tray 3, 2 = Envelope Feeder, 3 = Tray 1, 4 = Tray 4
  869.     
  870.     stream << "%%BeginFeature: *MediaPosition" << endl;
  871.     stream << "<</MediaPosition " << tray_number << ">> setpagedevice"
  872.        << endl;
  873.     stream << "%%EndFeature" << endl;
  874.   }
  875.   
  876.   stream << "%%EndSetup" << endl;
  877. }
  878.  
  879. void PostScriptDrv::MoveTo(ostream &stream, int x, int y)
  880. {
  881.  stream << x << " "  << y << " " << MOVETO << endl;
  882. }
  883.  
  884. int PostScriptDrv::StringLen(char *s, int charWidth)
  885. // Convert string lenght to PostScript points
  886. {
  887.   return strlen(s) * charWidth;
  888. }
  889.  
  890. int PostScriptDrv::StringLen(const char *s, int charWidth)
  891. // Convert string lenght to PostScript points
  892. {
  893.   return strlen(s) * charWidth;
  894. }
  895.  
  896. int PostScriptDrv::PrintLine(char *s, unsigned max_len, ofstream &stream)
  897. {
  898.   if(s == 0 || max_len <= 0) return 0;
  899.   
  900.   if(strlen(s) > max_len) {
  901.     char *buf = new char[max_len];
  902.     buf[max_len] = '\0';
  903.     memmove(buf, s, max_len);
  904.     int rv = PrintLine(buf, stream);
  905.     delete [] buf;
  906.     return rv;
  907.   }
  908.   else
  909.     return PrintLine(s, stream);
  910. }
  911. // ----------------------------------------------------------- //
  912. // ------------------------------- //
  913. // --------- End of File --------- //
  914. // ------------------------------- //
  915.