home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1967 / i2ps
Encoding:
Text File  |  1990-12-28  |  15.8 KB  |  491 lines

  1. #!/usr/local/bin/perl
  2. 'di';
  3. 'ig00';
  4.  
  5. # "i2ps" text to PostScript filter written in perl by Gisle Aas, NCC 1990
  6. # $Id: i2ps,v 1.5 90/10/18 10:26:45 aas Exp $
  7. #
  8. # Whish list:  (this may become a feature some time)
  9. #     Marking (by some funny char) truncation and wrapping of lines
  10. #     Faster execution (rewrite the hole thing in C?)
  11. #     Parsing of backspace to produce bold and underlined fonts.
  12.  
  13. #
  14. # $Log:    i2ps,v $
  15. # Revision 1.5  90/10/18  10:26:45  aas
  16. # Changed the name from a2ps to i2ps. Merged the manual-page with the
  17. # program. I2ps now rejects garbage files. I2ps was confused about what
  18. # to put in the header when some of the specified files did not exist.
  19. # Some minor spelling corrections.
  20. # Revision 1.4  90/10/01  15:57:46  aas
  21. # Simplify reencoding to ISO-Latin1. (newencode)
  22. # Fixed problem with showpage after page level restore. Graphic state
  23. # initialized on each page. Included the ISOLatin1Encoding-vector
  24. # in the script. Linenumber on last line when the -l option is used.
  25. # Linenumbers are moved to the left margin.
  26. # Revision 1.3  90/09/27  14:05:31  aas
  27. # Cleaned up the use of A4 variables.
  28. # Revision 1.2  90/09/27  13:18:31  aas
  29. # Removed sccs-stuff, replaced it with rcs-stuff.
  30.  
  31. # Some configuration constants, meassured in points (1/72 inch)
  32. sub page_top        { 841; }    # A4 = 297mm x 210mm = 841pt x 595pt
  33. sub page_right_edge { 595; }
  34. # Uncomment next line if your printer doesn't have iso encoding builtin.
  35. #$isoencoding_not_builtin = 1; #true
  36.  
  37. # The next few entries are from the AFM file for Adobe's font Courier
  38. sub cour_char_width     { 600; }   # The width of each char in 1000x1000 square
  39. #sub underline_position  { -82; }   # Where underline goes relative to baseline
  40. #sub underline_thickness {  40; }   # and it's thickness
  41.  
  42. # Parse command line for options and flags
  43. $prog = substr(__FILE__,rindex(__FILE__,"/")+1,999);
  44. require 'getopts.pl';
  45. unless (&Getopts('nrth123s:b:lg')) {
  46.    print STDERR "Usage: $prog [-<options>] [file]...\n";
  47.    print STDERR "Options: -l       print with line numbers\n";
  48.    print STDERR "         -r       rotated, landscape orientation\n";
  49.    print STDERR "         -t       truncate long lines, " . 
  50.                                   "default is to wrap lines\n";
  51.    print STDERR "         -b\"text\" replaces the text in the page header\n";
  52.    print STDERR "         -h       no page headers\n";
  53.    print STDERR "         -2       set text in two columns format\n";
  54.    print STDERR "         -3       set text in three columns format\n";
  55.    print STDERR "         -s<size> select new text fontsize, default 10pt\n";
  56.    print STDERR "         -g       don't reject garbage files\n";
  57.    print STDERR "         -n       norwegian 7bit-ascii encoding\n";
  58.    exit(1);
  59. }
  60.  
  61. # Set default values, some based on command line options
  62. $left_margin  = 80;
  63. $right_margin = 40;
  64. $tb_margin    = 45;
  65. $font         = "Courier";
  66. $font_size    = 10;        $font_size = $opt_s if ($opt_s > 0);
  67. $header_font  = "Helvetica-Bold";
  68. $header_font_size = 12;
  69. $line_number_font = "Helvetica";
  70. $line_number_size = 5;
  71.  
  72. $line_height = $font_size * 1.08;
  73. $no_columns = defined($opt_2) ? 2 : defined($opt_3) ? 3 : 1;
  74. $col_separation = 30;
  75. $sep_bars = 0;  # false
  76. $landscape = defined($opt_r);
  77. $header_height = 30;
  78. $show_header = !defined($opt_h);
  79. $wrap_lines = !defined($opt_t);
  80. $truncate_lines = !$wrap_lines; # don't change this
  81. $norsk_ascii = defined($opt_n);
  82.  
  83. # Some initial values
  84. $opt_b = &ps_string($opt_b) if ($opt_b);
  85. $form_feed = 0; # false;
  86. $page_no  = 0;
  87. $line_no = 0;
  88. if ($landscape) {
  89.     $top = &page_right_edge;
  90.     $right_edge = &page_top;
  91.     $left_margin = $right_margin; # this is a dirty one
  92. } else {
  93.     $top = &page_top;
  94.     $right_edge = &page_right_edge;
  95. }
  96. $home_pos = $top - $tb_margin - ($show_header ? $header_height : 0);
  97. $col_width = ($right_edge - $left_margin - $right_margin
  98.               - ($no_columns - 1) * $col_separation) / $no_columns;
  99. $char_width = &cour_char_width * $font_size / 1000;
  100. $chars_per_line = int ($col_width / $char_width + 1);
  101.  
  102. &prolog;
  103.  
  104. unshift(@ARGV,'-') if $#ARGV < $[;
  105. FILE:
  106. while ($FILEHAND = shift) {
  107.     unless (open(FILEHAND)) {
  108.         print STDERR "Can't open \"$FILEHAND\"\n";
  109.         next FILE;
  110.     }
  111.     if (!defined($opt_g) && -B FILEHAND) {
  112.         print STDERR "Skipping binary file \"$FILEHAND\"\n";
  113.         close(FILEHAND);
  114.         next FILE;
  115.     }
  116.     $file_name = &ps_string($FILEHAND);
  117.     $cur_pos = -1;     # this will force a new column next time
  118.     $cur_col = 100;    # this will force a new page next time
  119.     $line_no = 0;
  120.     LINE:
  121.     while (<FILEHAND>) {
  122.         chop;
  123.         $line_no++;
  124.         if (ord == 014) {        # form feed
  125.             s/.//;    # chop off first char
  126.             $cur_pos = -1; 
  127.             next LINE if (length == 0);
  128.         }
  129.         while (s/\t/' ' x (8 - length($`) % 8)/e) {}   # expand tabs
  130.         do {
  131.             if ($cur_pos < $tb_margin) {
  132.                 $cur_pos = $home_pos;
  133.                 if ($cur_col < $no_columns) {
  134.                      $cur_col++;
  135.                 } else {
  136.                      $cur_col = 1;
  137.                      &new_page;
  138.                 }
  139.             }
  140.             $text = substr($_,0,$chars_per_line);
  141.             $_ = $truncate_lines ? '' : substr($_,$chars_per_line,10000);
  142.             if ($text =~ s/^ +//) {        # suppress leading blanks
  143.                 $indent = $char_width * length($&);
  144.             } else {
  145.                 $indent = 0;
  146.             }
  147.             # Make suitable as a postscript string, same as calling
  148.             # "ps_string", but the overhead of calling a function is
  149.             # not acceptable here.
  150.             $text =~ s/[\\\(\)]/\\$&/g;
  151.             $text =~ s/[\000-\037\177-\377]/sprintf("\\%03o",ord($&))/ge;
  152.             # Calculate position
  153.             $x = $left_margin +
  154.          ($cur_col - 1) * ($col_width + $col_separation);
  155.             $cur_pos -= $line_height;
  156.             printf "(%s)%.1f %.1f S\n", $text, $x + $indent, $cur_pos 
  157.                 if (length($text));
  158.             if ($opt_l && (($line_no % 5) == 0 || eof)) { # print line numbers
  159.                  printf "F2 SF($line_no)%.1f %.1f S F1 SF\n",
  160.                         $x + $col_width + 5, $cur_pos;
  161.             }
  162.         } while (length($_));
  163.     } # while (each line)
  164. } # while (each file)
  165. &end_page;
  166. print "%%Trailer\n";
  167. print "%%Pages: $page_no\n";
  168. # printf "($prog: $page_no page%s for $user\n) print\n",
  169. #     $page_no != 1 ? "s" : "";
  170.  
  171. #--end of main-------------------------------------------------------
  172.  
  173.  
  174. sub prolog {
  175.    $user = getlogin || "(unknown)";
  176.    local($sec,$min,$hour,$mday,$mon,$year) = localtime;
  177.    $date = sprintf("(%s %d, %d) (%2d:%02d)",
  178.                     ('January','February','March','April','May','June',
  179.                      'July','August','October','November','Desember')[$mon],
  180.                      $mday, $year+1900, $hour,$min);
  181.    print "%!PS-Adobe-2.0\n";
  182.    print "%%Title: @ARGV\n" if (@ARGV);
  183.    print <<"EOT";
  184. %%Creator: $prog, Text to PostScript filter in perl, (C) 1990 Gisle Aas, NCC
  185. %%CreationDate: $date
  186. %%For: $user
  187. %%Pages: (atend)
  188. EOT
  189.    print "%%DocumentFonts: $font";
  190.    print " $line_number_font" if ($opt_l);
  191.    print " $header_font" if ($show_header);
  192.    print "\n";
  193.    print <<"EOT";
  194. %%EndComments
  195. /S{moveto show}bind def
  196. /M/moveto load def
  197. /L/lineto load def
  198. /SF/setfont load def
  199. EOT
  200.     print <<"EOT" if ($isoencoding_not_builtin && !$norsk_ascii);
  201. ISOLatin1Encoding where { pop } { ISOLatin1Encoding
  202. [/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
  203. /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
  204. /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
  205. /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
  206. /exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright
  207. /parenleft/parenright/asterisk/plus/comma/minus/period/slash/zero/one
  208. /two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal
  209. /greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S
  210. /T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum
  211. /underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s
  212. /t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde/.notdef/.notdef
  213. /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
  214. /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/dotlessi/grave
  215. /acute/circumflex/tilde/macron/breve/dotaccent/dieresis/.notdef/ring
  216. /cedilla/.notdef/hungarumlaut/ogonek/caron/space/exclamdown/cent
  217. /sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine
  218. /guillemotleft/logicalnot/hyphen/registered/macron/degree/plusminus
  219. /twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla
  220. /onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters
  221. /questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
  222. /Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
  223. /Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
  224. /multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
  225. /germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae
  226. /ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex
  227. /idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide
  228. /oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]
  229. def %ISOLatin1Encoding
  230. } ifelse
  231. EOT
  232.     print <<"EOT" if ($norsk_ascii);
  233. %%BeginProcSet: reencode 1.0 0
  234. /RE { %def
  235.    findfont begin
  236.    currentdict dup length dict begin
  237.       { %forall
  238.          1 index/FID ne {def} {pop pop} ifelse
  239.       } forall
  240.       /FontName exch def
  241.       dup length 0 ne { %if
  242.          /Encoding Encoding 256 array copy def
  243.          0 exch { %forall
  244.             dup type /nametype eq { %ifelse
  245.                Encoding 2 index 2 index put
  246.                pop 1 add
  247.             }{%else
  248.                exch pop
  249.             } ifelse
  250.          } forall
  251.       } if pop
  252.       currentdict dup
  253.    end
  254.    end
  255.    /FontName get exch definefont pop
  256. } bind def
  257. %%EndProcSet: reencode 1.0 0
  258. EOT
  259.    print <<"EOT" if (!$norsk_ascii);
  260. %%BeginProcSet: newencode 1.0 0
  261. /NE { %def
  262.    findfont begin
  263.       currentdict dup length dict begin
  264.          { %forall
  265.             1 index/FID ne {def} {pop pop} ifelse
  266.          } forall
  267.          /FontName exch def
  268.          /Encoding exch def
  269.          currentdict dup
  270.       end
  271.    end
  272.    /FontName get exch definefont pop
  273. } bind def
  274. %%EndProcSet: newencode 1.0 0
  275. EOT
  276.    print "%%EndProlog\n%%BeginSetup\n";
  277.    if ($norsk_ascii) {
  278.       print "[8#133 /AE/Oslash/Aring 8#173 /ae/oslash/aring] dup\n";
  279.       print "/$font-ISO/$font RE\n";
  280.       print "/$header_font-ISO/$header_font RE\n" if ($show_header);
  281.    } else {
  282.       print "ISOLatin1Encoding /$font-ISO/$font NE\n";
  283.       print "ISOLatin1Encoding /$header_font-ISO/$header_font NE\n"
  284.          if ($show_header);
  285.    }
  286.    print "/F1/$font-ISO findfont $font_size scalefont def\n";
  287.    print "/F2/$line_number_font findfont $line_number_size scalefont def\n"
  288.         if ($opt_l);
  289.    print "/F3/$header_font-ISO findfont $header_font_size scalefont def\n"
  290.         if ($show_header);
  291.    print "F1 SF\n";
  292.    print "%%EndSetup\n";
  293. }
  294.  
  295.  
  296.  
  297. sub new_page {
  298.    &end_page unless ($page_no == 0);
  299.    $page_no++;
  300.    print "%%Page: $page_no $page_no\n";
  301.    print "%%BeginPageSetup\n";
  302.    print "/page_save save def\n";
  303.    printf "90 rotate 0 -%d translate %% landscape mode\n",&page_right_edge
  304.       if ($landscape);
  305.    print "0.15 setlinewidth\n" if ($show_header);
  306.    print "%%EndPageSetup\n";
  307.    if ($show_header) {
  308.       # First print a box
  309.       local($llx,$lly,$urx,$ury) = ($left_margin - 10,
  310.             $top - $tb_margin - $header_font_size * 1.3,
  311.             $right_edge - $right_margin + 10, $top - $tb_margin);
  312.       printf "%.1f %.1f M %.1f %.1f L %.1f %.1f L ",
  313.              $llx,$lly, $urx,$lly, $urx, $ury;
  314.       printf "%.1f %.1f L closepath \n",$llx,$ury;
  315.       print  "gsave .95 setgray fill grestore stroke\n";
  316.       # Then the banner or the filename
  317.       print "F3 SF\n";
  318.       if ($opt_b) {
  319.          printf "($opt_b)%.1f %.1f S\n",
  320.                 $left_margin,$top - $tb_margin - $header_font_size;
  321.       }
  322.       elsif ($file_name) {
  323.          printf "(%s)%.1f %.1f S\n", $file_name, 
  324.                       $left_margin,
  325.                       $top - $tb_margin - $header_font_size;
  326.       }
  327.       # Then print page number
  328.       printf "%.1f %.1f M($page_no)dup stringwidth pop neg 0 rmoveto show\n",
  329.                  $right_edge - $right_margin, 
  330.                  $top - $tb_margin - $header_font_size;
  331.       print  "F1 SF\n";
  332.    }
  333.    if ($sep_bars) {
  334.       print "% Some postscript code to draw horizontal bars.\n";
  335.       print "% Not implemented yet\n";
  336.    }
  337. }
  338.  
  339. sub end_page {
  340.    unless ($page_no == 0) {
  341.       print "page_save restore\n";
  342.       print "showpage\n";
  343.    }
  344. }
  345.  
  346. sub ps_string
  347. {
  348.    # Prepare text for printing
  349.    local($_) = shift;
  350.    s/[\\\(\)]/\\$&/g;
  351.    s/[\001-\037\177-\377]/sprintf("\\%03o",ord($&))/ge;
  352.    $_;    # return string
  353. }
  354.  
  355.  
  356. ###########################################################################
  357.     # These next few lines are legal in both Perl and nroff.
  358.  
  359. .00;            # finish .ig
  360.  
  361. 'di            \" finish diversion--previous line must be blank
  362. .nr nl 0-1        \" fake up transition to first page again
  363. .nr % 0            \" start at page 1
  364. ';<<'.ex'; #__END__ #### From here on it's a standard manual page #########
  365. .TH I2PS 1 "October 1990"
  366. .SH NAME
  367. i2ps \- convert ISO Latin1 text to PostScript
  368. .SH SYNOPSIS
  369. .B i2ps
  370. [
  371. .B \-nlrth23g
  372. ] [
  373. .B \-b
  374. .I "text"
  375. ] [
  376. .B \-s
  377. .I size
  378. ] [
  379. .I filename
  380. \&.\|.\|.
  381. ]
  382. .SH DESCRIPTION
  383. The
  384. .B i2ps
  385. program is used to print simple
  386. text files (e.g. program listings) on a PostScript\*R device. 
  387. The name
  388. .B i2ps
  389. stands for iso-to-postscript.  The program handles the whole
  390. ISO Latin1 (ISO 8859/1) character set. 
  391. Efforts have been made to ensure that 
  392. .B i2ps
  393. produces good looking and effective PostScript code.
  394. The output conforms to Adobe's
  395. document structuring conventions (version 2.1). The 
  396. .B i2ps 
  397. program
  398. assumes that the page format on the output device is A4. 
  399. (Change the definitions of &page_top and &page_right_edge if you
  400. want something else.)
  401. The meaning of form feed (^L) characters in the input stream is understood.
  402. .PP
  403. The
  404. .B i2ps
  405. program is written in
  406. .I perl.
  407. So if there is something you don't like about how
  408. .B i2ps
  409. works, you can "easily" fix it yourself.
  410. .SH OPTIONS
  411. .TP 5
  412. .B \-n
  413. use the norwegian version of ISO 646 (7-bit ascii) to encode the text.
  414. Norwegian letters will replace the left/right braces, left/right
  415. brackets, backslash and horizontal bar characters.
  416. .TP 5
  417. .B \-l
  418. produces line numbers on each 5'th and the last line.
  419. Nice for program listings.
  420. .TP 5
  421. .B \-t
  422. truncate lines that are to long. The default is to wrap
  423. long lines so that they continue on the next line on the printed output.
  424. .TP 5
  425. .B \-r
  426. rotate the output page 90 degrees. This is called
  427. .I landscape
  428. mode by some people.
  429. .TP 5
  430. .B \-h
  431. suppress generation of page headers.
  432. .TP 5
  433. .B \-2
  434. use two column format.
  435. .TP 5
  436. .B \-3
  437. use three column format.
  438. .TP 5
  439. .BI \-b " text"
  440. the 
  441. .I text
  442. parameter replaces the default text in the header of the pages.
  443. The default text is the filename of the file to be printed. There is no
  444. default if the text comes from standard input.
  445. .TP 5
  446. .BI \-s " size"
  447. specifies a new font size for the body text. The default is 10 point.
  448. .TP 5
  449. .B \-g
  450. eat garbage. 
  451. .B I2ps 
  452. normally skips binary files. This option means "print it anyway".
  453. .SH EXAMPLES
  454. To print files on a PostScript printer:
  455. .nf
  456.     i2ps -l *.[ch] | lpr
  457. .fi
  458. .PP
  459. To find out how many pages i2ps will produce for a given file:
  460. .nf
  461.     i2ps file.txt | tail -1
  462. .fi
  463. .PP
  464. Our printer stacks the pages the wrong way. To fix it try:
  465. .nf
  466.     cat file.txt | i2ps -b "some text" | psrev | lpr
  467. .fi
  468. .SH SEE ALSO
  469. .BR perl (1),
  470. .BR enscript (1),
  471. .BR psrev (1),
  472. .BR ISO8859 (7),
  473. .BR PostScript (7)
  474. .SH BUGS
  475. There is no easy way to change the margins or the fonts that
  476. .B i2ps
  477. insists on using.
  478. The
  479. .B i2ps
  480. filter ought to understand the meaning of the backspace character. It is used
  481. to produce boldfaced and underlined text by programs like 
  482. .BR nroff (1).
  483. .SH AUTHOR
  484. Gisle Aas, Norwegian Computing Center (NR), Oslo, Norway.
  485. <Gisle.Aas@nr.no>
  486. .ex
  487.