#! /client/bin/perl # "i2ps" text to PostScript filter written in perl by Gisle Aas, NCC 1990 'di'; 'ig00'; # $Id: i2ps,v 1.7 90/10/30 16:54:46 aas Exp $ # # Whish list: (this may become a feature some time) # Marking (by some funny char) truncation and wrapping of lines # Faster execution (rewrite the hole thing in C?) # Parsing of backspace to produce bold and underlined fonts. # # $Log: i2ps,v $ # Revision 1.7 90/10/30 16:54:46 aas # Options can be specified with the environment variable I2PS. # New option -w. Fixed bug which made -n option act like the -f # option. # # Revision 1.6 90/10/24 12:00:43 aas # Applied patch from Tor Lillqvist. I2ps now supports finnish/swedish # ISO-646. # # Revision 1.5 90/10/18 10:26:45 aas # Changed the name from a2ps to i2ps. Merged the manual-page with the # program. I2ps now rejects garbage files. I2ps was confused about what # to put in the header when some of the specified files did not exist. # Some minor spelling corrections. # # Revision 1.4 90/10/01 15:57:46 aas # Simplify reencoding to ISO-Latin1. (newencode) # Fixed problem with showpage after page level restore. Graphic state # initialized on each page. Included the ISOLatin1Encoding-vector # in the script. Linenumber on last line when the -l option is used. # Linenumbers are moved to the left margin. # # Revision 1.3 90/09/27 14:05:31 aas # Cleaned up the use of A4 variables. # # Revision 1.2 90/09/27 13:18:31 aas # Removed sccs-stuff, replaced it with rcs-stuff. # # Some configuration constants, meassured in points (1/72 inch) sub page_top { 841; } # A4 = 297mm x 210mm = 841pt x 595pt sub page_right_edge { 595; } # Uncomment next line if your printer doesn't have iso encoding builtin. #$isoencoding_not_builtin = 1; #true # The next few entries are from the AFM file for Adobe's font Courier sub cour_char_width { 600; } # The width of each char in 1000x1000 square #sub underline_position { -82; } # Where underline goes relative to baseline #sub underline_thickness { 40; } # and it's thickness # Parse command line for options and flags $prog_name = substr($0,rindex($0,"/")+1); ($upcase_name = $prog_name) =~ tr/a-z/A-Z/; unshift(@ARGV,$ENV{$upcase_name}) if defined($ENV{$upcase_name}); require 'getopts.pl'; unless (&Getopts('nfrth123s:b:lgw:')) { print STDERR "Usage: $prog_name [-] [file]...\n" . "Options: -l print with line numbers\n" . " -r rotated, landscape orientation\n" . " -t truncate long lines, default is to wrap lines\n" . " -b\"text\" replaces the text in the page header\n" . " -h no page headers\n" . " -2 set text in two columns format\n" . " -3 set text in three columns format\n" . " -s select new text fontsize, default 10pt\n" . " -w char positions per column\n" . " -g don't reject garbage files\n" . " -n norwegian 7bit-ascii encoding\n" . " -f finnish/swedish 7bit-ascii encoding\n"; exit(1); } if (defined($opt_s) && $opt_s <= 0) { printf STDERR "Illegal argument \"$opt_s\" to -s option\n"; exit(1); } if (defined($opt_w) && $opt_w <= 0) { printf STDERR "Illegal argument \"$opt_w\" to -w option\n"; exit(1); } # Set default values, some based on command line options $left_margin = 80; $right_margin = 40; $tb_margin = 45; $font = "Courier"; $header_font = "Helvetica-Bold"; $header_font_size = 12; $line_number_font = "Helvetica"; $line_number_size = 5; $no_columns = defined($opt_2) ? 2 : defined($opt_3) ? 3 : 1; $col_separation = 30; $sep_bars = 0; # false $landscape = defined($opt_r); $header_height = 30; $show_header = !defined($opt_h); $wrap_lines = !defined($opt_t); $truncate_lines = !$wrap_lines; # don't change this $norsk_ascii = defined($opt_n); $sw_fi_ascii = defined($opt_f); # Some initial values $opt_b = &ps_string($opt_b) if ($opt_b); $form_feed = 0; # false; $page_no = 0; $line_no = 0; if ($landscape) { $top = &page_right_edge; $right_edge = &page_top; $left_margin = $right_margin; # this is a dirty one } else { $top = &page_top; $right_edge = &page_right_edge; } $home_pos = $top - $tb_margin - ($show_header ? $header_height : 0); $col_width = ($right_edge - $left_margin - $right_margin - ($no_columns - 1) * $col_separation) / $no_columns; $font_size = $opt_s || 10; if (defined($opt_w)) { $font_size = ($col_width / $opt_w) / (&cour_char_width / 1000); printf STDERR "New font size is %.2g points\n", $font_size; } $line_height = $font_size * 1.08; $char_width = &cour_char_width * $font_size / 1000; $chars_per_line = int ($col_width / $char_width + 1); &prolog; unshift(@ARGV,'-') if $#ARGV < $[; FILE: while ($FILEHAND = shift) { unless (open(FILEHAND)) { print STDERR "Can't open \"$FILEHAND\"\n"; next FILE; } if (!defined($opt_g) && -B FILEHAND) { print STDERR "Skipping binary file \"$FILEHAND\"\n"; close(FILEHAND); next FILE; } $file_name = ($FILEHAND eq '-') ? '' : &ps_string($FILEHAND); $cur_pos = -1; # this will force a new column next time $cur_col = 100; # this will force a new page next time $line_no = 0; LINE: while () { chop; $line_no++; if (ord == 014) { # form feed s/.//; # chop off first char $cur_pos = -1; next LINE if (length == 0); } while (s/\t/' ' x (8 - length($`) % 8)/e) {} # expand tabs do { if ($cur_pos < $tb_margin) { $cur_pos = $home_pos; if ($cur_col < $no_columns) { $cur_col++; } else { $cur_col = 1; &new_page; } } $text = substr($_,0,$chars_per_line); $_ = $truncate_lines ? '' : substr($_,$chars_per_line,10000); if ($text =~ s/^ +//) { # suppress leading blanks $indent = $char_width * length($&); } else { $indent = 0; } # Make suitable as a postscript string, same as calling # "ps_string", but the overhead of calling a function is # not acceptable here. $text =~ s/[\\\(\)]/\\$&/g; $text =~ s/[\000-\037\177-\377]/sprintf("\\%03o",ord($&))/ge; # Calculate position $x = $left_margin + ($cur_col - 1) * ($col_width + $col_separation); $cur_pos -= $line_height; printf "(%s)%.1f %.1f S\n", $text, $x + $indent, $cur_pos if (length($text)); if ($opt_l && (($line_no % 5) == 0 || eof)) { # print line numbers printf "F2 SF($line_no)%.1f %.1f S F1 SF\n", $x + $col_width + 5, $cur_pos; } } while (length($_)); } # while (each line) } # while (each file) &end_page; print "%%Trailer\n"; print "%%Pages: $page_no\n"; # printf "($prog_name: $page_no page%s for $user\n) print\n", # $page_no != 1 ? "s" : ""; #--end of main------------------------------------------------------- sub prolog { $user = getlogin || "(unknown)"; local($sec,$min,$hour,$mday,$mon,$year) = localtime; $date = sprintf("(%s %d, %d) (%2d:%02d)", ('January','February','March','April','May','June', 'July','August','October','November','Desember')[$mon], $mday, $year+1900, $hour,$min); print "%!PS-Adobe-2.0\n"; print "%%Title: @ARGV\n" if (@ARGV); print <<"EOT"; %%Creator: $prog_name, Text to PostScript filter in perl, (C) 1990 Gisle Aas, NCC %%CreationDate: $date %%For: $user %%Pages: (atend) EOT print "%%DocumentFonts: $font"; print " $line_number_font" if ($opt_l); print " $header_font" if ($show_header); print "\n"; print <<"EOT"; %%EndComments /S{moveto show}bind def /M/moveto load def /L/lineto load def /SF/setfont load def EOT print <<"EOT" if ($isoencoding_not_builtin && !($norsk_ascii || $sw_fi_ascii)); ISOLatin1Encoding where { pop } { ISOLatin1Encoding [/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space /exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright /parenleft/parenright/asterisk/plus/comma/minus/period/slash/zero/one /two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal /greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S /T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum /underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s /t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/dotlessi/grave /acute/circumflex/tilde/macron/breve/dotaccent/dieresis/.notdef/ring /cedilla/.notdef/hungarumlaut/ogonek/caron/space/exclamdown/cent /sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine /guillemotleft/logicalnot/hyphen/registered/macron/degree/plusminus /twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla /onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters /questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE /Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex /Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis /multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn /germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae /ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex /idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide /oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis] def %ISOLatin1Encoding } ifelse EOT print <<"EOT" if ($norsk_ascii || $sw_fi_ascii); %%BeginProcSet: reencode 1.0 0 /RE { %def findfont begin currentdict dup length dict begin { %forall 1 index/FID ne {def} {pop pop} ifelse } forall /FontName exch def dup length 0 ne { %if /Encoding Encoding 256 array copy def 0 exch { %forall dup type /nametype eq { %ifelse Encoding 2 index 2 index put pop 1 add }{%else exch pop } ifelse } forall } if pop currentdict dup end end /FontName get exch definefont pop } bind def %%EndProcSet: reencode 1.0 0 EOT print <<"EOT" if (!($norsk_ascii || $sw_fi_ascii)); %%BeginProcSet: newencode 1.0 0 /NE { %def findfont begin currentdict dup length dict begin { %forall 1 index/FID ne {def} {pop pop} ifelse } forall /FontName exch def /Encoding exch def currentdict dup end end /FontName get exch definefont pop } bind def %%EndProcSet: newencode 1.0 0 EOT print "%%EndProlog\n%%BeginSetup\n"; if ($norsk_ascii || $sw_fi_ascii) { print "[8#133 /AE/Oslash/Aring 8#173 /ae/oslash/aring] dup\n" if ($norsk_ascii); print "[8#133 /Adieresis/Odieresis/Aring" . " 8#173 /adieresis/odieresis/aring] dup\n" if ($sw_fi_ascii); print "/$font-ISO/$font RE\n"; print "/$header_font-ISO/$header_font RE\n" if ($show_header); } else { print "ISOLatin1Encoding /$font-ISO/$font NE\n"; print "ISOLatin1Encoding /$header_font-ISO/$header_font NE\n" if ($show_header); } printf "/F1/$font-ISO findfont %.2g scalefont def\n", $font_size; print "/F2/$line_number_font findfont $line_number_size scalefont def\n" if ($opt_l); print "/F3/$header_font-ISO findfont $header_font_size scalefont def\n" if ($show_header); print "F1 SF\n"; print "%%EndSetup\n"; } sub new_page { &end_page unless ($page_no == 0); $page_no++; print "%%Page: $page_no $page_no\n"; print "%%BeginPageSetup\n"; print "/page_save save def\n"; printf "90 rotate 0 -%d translate %% landscape mode\n",&page_right_edge if ($landscape); print "0.15 setlinewidth\n" if ($show_header); print "%%EndPageSetup\n"; if ($show_header) { # First print a box local($llx,$lly,$urx,$ury) = ($left_margin - 10, $top - $tb_margin - $header_font_size * 1.3, $right_edge - $right_margin + 10, $top - $tb_margin); printf "%.1f %.1f M %.1f %.1f L %.1f %.1f L ", $llx,$lly, $urx,$lly, $urx, $ury; printf "%.1f %.1f L closepath \n",$llx,$ury; print "gsave .95 setgray fill grestore stroke\n"; # Then the banner or the filename print "F3 SF\n"; if ($opt_b) { printf "($opt_b)%.1f %.1f S\n", $left_margin,$top - $tb_margin - $header_font_size; } elsif ($file_name) { printf "(%s)%.1f %.1f S\n", $file_name, $left_margin, $top - $tb_margin - $header_font_size; } # Then print page number printf "%.1f %.1f M($page_no)dup stringwidth pop neg 0 rmoveto show\n", $right_edge - $right_margin, $top - $tb_margin - $header_font_size; print "F1 SF\n"; } if ($sep_bars) { print "% Some postscript code to draw horizontal bars.\n"; print "% Not implemented yet\n"; } } sub end_page { unless ($page_no == 0) { print "page_save restore\n"; print "showpage\n"; } } sub ps_string { # Prepare text for printing local($_) = shift; s/[\\\(\)]/\\$&/g; s/[\001-\037\177-\377]/sprintf("\\%03o",ord($&))/ge; $_; # return string }