Clean up the character set handling somewhat.
[platform/upstream/nasm.git] / doc / genps.pl
index 1af10b8..d406ebb 100755 (executable)
@@ -22,12 +22,14 @@ use Fcntl;
           plmarg => 50,        # Page number position relative to left margin
           prmarg => 0,         # Page number position relative to right margin
           pymarg => 50,        # Page number position relative to bot margin
+          startcopyright => 75, # How much above the bottom margin is the
+                                # copyright notice stuff
           bulladj => 12,       # How much to indent a bullet paragraph
           tocind => 12,        # TOC indentation per level
           tocpnz => 24,        # Width of TOC page number only zone
           tocdots => 8,        # Spacing between TOC dots
           idxspace => 24,      # Minimum space between index title and pg#
-          idxindent => 32,     # How much to indent a subindex entry
+          idxindent => 24,     # How much to indent a subindex entry
           idxgutter => 24,     # Space between index columns
           idxcolumns => 2,     # Number of index columns
           );
@@ -38,6 +40,8 @@ use Fcntl;
 
 # Known paper sizes
 %papersizes = (
+              'a5'     => [421, 595], # ISO half paper size
+              'b5'     => [501, 709], # ISO small paper size
               'a4'     => [595, 842], # ISO standard paper size
               'letter' => [612, 792], # US common paper size
               'pa4'    => [595, 792], # Compromise ("portable a4")
@@ -52,8 +56,8 @@ use Fcntl;
 #
 undef $input;
 while ( $arg = shift(@ARGV) ) {
-    if ( $arg =~ /^\-(|no\-)/ ) {
-       $parm = $';
+    if ( $arg =~ /^\-(|no\-)(.*)$/ ) {
+       $parm = $2;
        $true = ($1 eq '') ? 1 : 0;
        if ( $true && defined($papersizes{$parm}) ) {
            $psconf{pagewidth}  = $papersizes{$parm}->[0];
@@ -62,6 +66,8 @@ while ( $arg = shift(@ARGV) ) {
            $psbool{$parm} = $true;
        } elsif ( $true && defined($psconf{$parm}) ) {
            $psconf{$parm} = shift(@ARGV);
+       } elsif ( $parm =~ /^(title|subtitle|year|author|license)$/ ) {
+           $metadata{$parm} = shift(@ARGV);
        } else {
            die "$0: Unknown option: $arg\n";
        }
@@ -85,6 +91,62 @@ $tocskip = 6;                        # Space between TOC entries
              'code' => $paraskip, 'toc0' => $tocskip,
              'toc1' => $tocskip,  'toc2' => $tocskip);
 
+# Custom encoding vector.  This is basically the same as
+# ISOLatin1Encoding (a level 2 feature, so we dont want to use it),
+# but with the "naked" accents at \200-\237 moved to the \000-\037
+# range (ASCII control characters), and a few extra characters thrown
+# in.  It is basically a modified Windows 1252 codepage, minus, for
+# now, the euro sign (\200 is reserved for euro.)
+
+@NASMEncoding =
+(
+ undef, undef, undef, undef, undef, undef, undef, undef, undef, undef,
+ undef, undef, undef, undef, undef, undef, 'dotlessi', 'grave',
+ 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent',
+ 'dieresis', undef, 'ring', 'cedilla', undef, 'hungarumlaut',
+ 'ogonek', 'caron', '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', undef, undef, undef, 'quotesinglbase', 'florin',
+ 'quotedblbase', 'ellipsis', 'dagger', 'dbldagger', 'circumflex',
+ 'perthousand', 'Scaron', 'guilsinglleft', 'OE', undef, 'Zcaron',
+ undef, undef, 'grave', 'quotesingle', 'quotedblleft',
+ 'quotedblright', 'bullet', 'endash', 'emdash', 'tilde', 'trademark',
+ 'scaron', 'guilsignlright', 'oe', undef, 'zcaron', 'Ydieresis',
+ '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'
+);
+
+# Name-to-byte lookup hash
+%charcode = ();
+for ( $i = 0 ; $i < 256 ; $i++ ) {
+    $charcode{$NASMEncoding[$i]} = chr($i);
+}
+
 #
 # First, format the stuff coming from the front end into
 # a cleaner representation
@@ -99,22 +161,26 @@ while ( defined($line = <PARAS>) ) {
     chomp $line;
     $data = <PARAS>;
     chomp $data;
-    if ( $line =~ /^meta :/ ) {
-       $metakey = $';
+    if ( $line =~ /^meta :(.*)$/ ) {
+       $metakey = $1;
        $metadata{$metakey} = $data;
-    } elsif ( $line =~ /^indx :/ ) {
-       $ixentry = $';
+    } elsif ( $line =~ /^indx :(.*)$/ ) {
+       $ixentry = $1;
        push(@ixentries, $ixentry);
        $ixterms{$ixentry} = [split(/\037/, $data)];
        # Look for commas.  This is easier done on the string
        # representation, so do it now.
-       if ( $line =~ /^(.*\,)\037sp\037/ ) {
+       if ( $data =~ /^(.*)\,\037sp\037/ ) {
            $ixprefix = $1;
+           $ixprefix =~ s/\037n $//; # Discard possible font change at end
            $ixhasprefix{$ixentry} = $ixprefix;
            if ( !$ixprefixes{$ixprefix} ) {
                $ixcommafirst{$ixentry}++;
            }
            $ixprefixes{$ixprefix}++;
+       } else {
+           # A complete term can also be used as a prefix
+           $ixprefixes{$data}++;
        }
     } else {
        push(@ptypes, $line);
@@ -141,6 +207,24 @@ sub int2base($$) {
 }    
 
 #
+# Convert a string to a rendering array
+#
+sub string2array($)
+{
+    my($s) = @_;
+    my(@a) = ();
+    
+    $s =~ s/ \- / $charcode{'endash'} /g;      # Replace " - " with en dash
+
+    while ( $s =~ /^(\s+|\S+)(.*)$/ ) {
+       push(@a, [0,$1]);
+       $s = $2;
+    }
+
+    return @a;
+}
+
+#
 # Take a crossreference name and generate the PostScript name for it.
 #
 # This hack produces a somewhat smaller PDF...
@@ -207,11 +291,13 @@ sub ps_flow_lines($$$@) {
                push(@xd, $e);
            }
        } else {
-           my $ew = ps_width($$e[1], $fontset->{fonts}->[$$e[0]][1]) *
+           my $ew = ps_width($$e[1], $fontset->{fonts}->[$$e[0]][1],
+                             \@NASMEncoding) *
                ($fontset->{fonts}->[$$e[0]][0]/1000);
            my $sp = $$e[1];
            $sp =~ tr/[^ ]//d;  # Delete nonspaces
-           my $esw = ps_width($sp, $fontset->{fonts}->[$$e[0]][1]) *
+           my $esw = ps_width($sp, $fontset->{fonts}->[$$e[0]][1],
+                              \@NASMEncoding) *
                ($fontset->{fonts}->[$$e[0]][0]/1000);
            
            if ( ($w+$ew) - $ps_space_squeeze*($sw+$esw) > $wid ) {
@@ -268,11 +354,15 @@ sub ps_flow_lines($$$@) {
                # Compute the width of the remainder array
                for my $le ( @l ) {
                    if ( $$le[0] >= 0 ) {
-                       my $xew = ps_width($$le[1], $fontset->{fonts}->[$$le[0]][1]) *
+                       my $xew = ps_width($$le[1],
+                                          $fontset->{fonts}->[$$le[0]][1],
+                                          \@NASMEncoding) *
                            ($fontset->{fonts}->[$$le[0]][0]/1000);
                        my $xsp = $$le[1];
                        $xsp =~ tr/[^ ]//d;     # Delete nonspaces
-                       my $xsw = ps_width($xsp, $fontset->{fonts}->[$$le[0]][1]) *
+                       my $xsw = ps_width($xsp,
+                                          $fontset->{fonts}->[$$le[0]][1],
+                                          \@NASMEncoding) *
                            ($fontset->{fonts}->[$$le[0]][0]/1000);
                        $w += $xew;  $sw += $xsw;
                    }
@@ -286,7 +376,7 @@ sub ps_flow_lines($$$@) {
            }
        }
     }
-    push(@l,@wd);
+    push(@l,@xd);
     if ( scalar(@l) ) {
        push(@ls, [[$type,0,undef,$fontset,0,0],[@l]]); # Final line
     }
@@ -358,8 +448,7 @@ sub mkparaarray($@) {
            if ( $type eq 'sp' ) {
                push(@para, [$in_e?1:0, ' ']);
            } elsif ( $type eq 'da' ) {
-               # \261 is en dash in Adobe StandardEncoding
-               push(@para, [$in_e?1:0, "\261"]);
+               push(@para, [$in_e?1:0, $charcode{'endash'}]);
            } elsif ( $type eq 'n ' ) {
                push(@para, [0, $text]);
                $in_e = 0;
@@ -423,12 +512,28 @@ sub ps_dup_para(@) {
 }
 
 #
+# This generates a duplicate of a paragraph, stripping anchor
+# tags (-4 and -5)
+#
+sub ps_dup_para_noanchor(@) {
+    my(@i) = @_;
+    my(@o) = ();
+    my($c);
+
+    foreach $c ( @i ) {
+       my @cc = @{$c};
+       push(@o, [@cc]) unless ( $cc[0] == -4 || $cc[0] == -5 );
+    }
+    return @o;
+}
+
+#
 # Scan for header paragraphs and fix up their contents;
 # also generate table of contents and PDF bookmarks.
 #
 @tocparas = ([[-5, 'contents'], [0,'Contents']]);
 @tocptypes = ('chap');
-@bookmarks = (['title', 0, 'Title Page'], ['contents', 0, 'Contents']);
+@bookmarks = (['title', 0, 'Title'], ['contents', 0, 'Contents']);
 %bookref = ();
 for ( $i = 0 ; $i < $npara ; $i++ ) {
     my $xtype = $ptypes[$i];
@@ -449,7 +554,7 @@ for ( $i = 0 ; $i < $npara ; $i++ ) {
        push(@bookmarks, $book);
        $bookref{$secn} = $book;
 
-       push(@tocparas, [ps_dup_para(@{$paras[$i]})]);
+       push(@tocparas, [ps_dup_para_noanchor(@{$paras[$i]})]);
        push(@tocptypes, 'toc0'.' :'.$sech.':'.$chap.' '.$secn.':');
 
        unshift(@{$paras[$i]},
@@ -469,7 +574,7 @@ for ( $i = 0 ; $i < $npara ; $i++ ) {
        $bookref{$secn} = $book;
        $bookref{$pref}->[1]--; # Adjust count for parent node
 
-       push(@tocparas, [ps_dup_para(@{$paras[$i]})]);
+       push(@tocparas, [ps_dup_para_noanchor(@{$paras[$i]})]);
        push(@tocptypes,
             (($ptype eq 'subh') ? 'toc2':'toc1').' :'.$sech.':'.$secn);
 
@@ -482,6 +587,16 @@ for ( $i = 0 ; $i < $npara ; $i++ ) {
 #
 unshift(@paras,  @tocparas);  undef @tocparas;
 unshift(@ptypes, @tocptypes); undef @tocptypes;
+
+#
+# Add copyright notice to the beginning
+#
+unshift(@paras,
+       [[0, $charcode{'copyright'}], [0, ' '], [0,$metadata{'year'}],
+        [0, ' '], string2array($metadata{'author'})],
+       [string2array($metadata{'license'})]);
+unshift(@ptypes, 'norm', 'norm');
+
 $npara = scalar(@paras);
 
 #
@@ -522,7 +637,7 @@ sub ps_break_lines($$) {
            my $p;
            # Code paragraph; each chunk is a line
            foreach $p ( @data ) {
-               push(@ls, [[$ptype,0,undef,\%TextFont,0,0],[$p]]);
+               push(@ls, [[$ptype,0,undef,\%BodyFont,0,0],[$p]]);
            }
            $ls[0]->[0]->[1] |= 1;           # First in para
            $ls[-1]->[0]->[1] |= 2;      # Last in para
@@ -540,9 +655,9 @@ sub ps_break_lines($$) {
            # We need the heading number as auxillary data
            $ls[0]->[0]->[2] = [[$AuxStr,$secn]];
        } elsif ( $ptype eq 'norm' ) {
-           @ls = ps_flow_lines($linewidth, \%TextFont, $ptype, @data);
+           @ls = ps_flow_lines($linewidth, \%BodyFont, $ptype, @data);
        } elsif ( $ptype eq 'bull' ) {
-           @ls = ps_flow_lines($bullwidth, \%TextFont, $ptype, @data);
+           @ls = ps_flow_lines($bullwidth, \%BodyFont, $ptype, @data);
        } elsif ( $ptype =~ /^toc/ ) {
            unless ( $xtype =~/^\S+ :([^:]*):(.*)$/ ) {
                die "Bad para";
@@ -550,12 +665,13 @@ sub ps_break_lines($$) {
            my $xref = $1;
            my $refname = $2.' ';
            my $ntoc = substr($ptype,3,1)+0;
-           my $refwidth = ps_width($refname, $TextFont{fonts}->[0][1]) *
-               ($TextFont{fonts}->[0][0]/1000);
+           my $refwidth = ps_width($refname, $BodyFont{fonts}->[0][1],
+                                   \@NASMEncoding) *
+               ($BodyFont{fonts}->[0][0]/1000);
            
            @ls = ps_flow_lines($linewidth-$ntoc*$psconf{tocind}-
                                $psconf{tocpnz}-$refwidth,
-                               \%TextFont, $ptype, @data);
+                               \%BodyFont, $ptype, @data);
            
            # Auxilliary data: for the first line, the cross reference symbol
            # and the reference name; for all lines but the first, the
@@ -571,7 +687,7 @@ sub ps_break_lines($$) {
            my $lvl = substr($ptype,3,1)+0;
 
            @ls = ps_flow_lines($indxwidth-$lvl*$psconf{idxindent},
-                               \%TextFont, $ptype, @data);
+                               \%BodyFont, $ptype, @data);
        } else {
            die "Unknown para type: $ptype";
        }
@@ -590,8 +706,10 @@ ps_break_lines(\@paras, \@ptypes);
 # Break lines in to pages
 #
 
-$curpage = 3;                  # First text page is page 3
-$curypos = 0;                  # Space used on this page
+# Where to start on page 2, the copyright page
+$curpage = 2;                  # Start on page 2
+$curypos = $psconf{pageheight}-$psconf{topmarg}-$psconf{botmarg}-
+    $psconf{startcopyright};
 undef $columnstart;            # Not outputting columnar text
 undef $curcolumn;              # Current column
 $nlines = scalar(@pslines);
@@ -610,7 +728,9 @@ sub ps_break_pages($$) {
     my $nobreakregexp = "^(chap|appn|head|subh|toc.|idx.)\$";
     # Paragraph types which are heading (meaning they should not be broken
     # immediately after)
-    my $headingregexp = "^(chap|appn|head|subh)\$";
+    my $nobreakafter = "^(chap|appn|head|subh)\$";
+    # Paragraph types which should never be broken *before*
+    my $nobreakbefore = "^idx[1-9]\$";
     # Paragraph types which are set in columnar format
     my $columnregexp = "^idx.\$";
 
@@ -657,7 +777,8 @@ sub ps_break_pages($$) {
                } elsif ( $$linfo[1] & 1 ) {
                    # Sole line or start of paragraph.  Break unless
                    # the previous line was part of a heading.
-                   $broken = 1 if ( $$pinfo[0] !~ /$headingregexp/o );
+                   $broken = 1 if ( $$pinfo[0] !~ /$nobreakafter/o &&
+                                    $$linfo[0] !~ /$nobreakbefore/o );
                } else {
                    # Middle of paragraph.  Break unless we're in a
                    # no-break paragraph, or the previous line would
@@ -725,7 +846,41 @@ $startofindex = scalar(@pslines);
 foreach $k ( @ixentries ) {
     my $n,$i;
     my $ixptype = 'idx0';
-    my @ixpara = mkparaarray('idx0',@{$ixterms{$k}});
+    my $prefix = $ixhasprefix{$k};
+    my @ixpara = mkparaarray($ixptype,@{$ixterms{$k}});
+    my $commapos = undef;
+
+    if ( defined($prefix) && $ixprefixes{$prefix} > 1 ) {
+       # This entry has a "hanging comma"
+       for ( $i = 0 ; $i < scalar(@ixpara)-1 ; $i++ ) {
+           if ( substr($ixpara[$i]->[1],-1,1) eq ',' &&
+                $ixpara[$i+1]->[1] eq ' ' ) {
+               $commapos = $i;
+               last;
+           }
+       }
+    }
+    if ( defined($commapos) ) {
+       if ( $ixcommafirst{$k} ) {
+           # This is the first entry; generate the
+           # "hanging comma" entry
+           my @precomma = splice(@ixpara,0,$commapos);
+           if ( $ixpara[0]->[1] eq ',' ) {
+               shift(@ixpara); # Discard lone comma
+           } else {
+               # Discard attached comma
+               $ixpara[0]->[1] =~ s/\,$//;
+               push(@precomma,shift(@ixpara));
+           }
+           push(@precomma, [-6,undef]);
+           push(@ixparas, [@precomma]);
+           push(@ixptypes, $ixptype);
+           shift(@ixpara);     # Remove space
+       } else {
+           splice(@ixpara,0,$commapos+2);
+       }
+       $ixptype = 'idx1';
+    }
 
     push(@ixpara, [-6,undef]); # Left/right marker
     $i = 1;  $n = scalar(@{$ps_index_pages{$k}});
@@ -769,7 +924,7 @@ foreach $fset ( @AllFonts ) {
 print "%!PS-Adobe-3.0\n";
 print "%%Pages: $curpage\n";
 print "%%BoundingBox: 0 0 ", $psconf{pagewidth}, ' ', $psconf{pageheight}, "\n";
-print "%%Creator: NASM psflow.pl\n";
+print "%%Creator: (NASM psflow.pl)\n";
 print "%%DocumentData: Clean7Bit\n";
 print "%%DocumentFonts: ", join(' ', keys(%ps_all_fonts)), "\n";
 print "%%DocumentNeededFonts: ", join(' ', keys(%ps_all_fonts)), "\n";
@@ -786,13 +941,40 @@ foreach $c ( keys(%psbool) ) {
     print "/$c ", ($psbool{$c}?'true':'false'), " def\n";
 }
 
+# Emit custom encoding vector
+$zstr = '/NASMEncoding [ ';
+foreach $c ( @NASMEncoding ) {
+    my $z = '/'.(defined($c)?$c:'.notdef ').' ';
+    if ( length($zstr)+length($z) > 72 ) {
+       print $zstr,"\n";
+       $zstr = ' ';
+    }
+    $zstr .= $z;
+}
+print $zstr, "] def\n";
+
+# Font recoding routine
+# newname fontname --
+print "/nasmenc {\n";
+print "  findfont dup length dict begin\n";
+print "    { 1 index /FID ne {def}{pop pop} ifelse } forall\n";
+print "    /Encoding NASMEncoding def\n";
+print "    currentdict\n";
+print "  end\n";
+print "  definefont pop\n";
+print "} def\n";
+
 # Emit fontset definitions
+foreach $font ( keys(%ps_all_fonts) ) {
+    print '/',$font,'-NASM /',$font," nasmenc\n";
+}
+
 foreach $fset ( @AllFonts ) {
     my $i = 0;
     my @zfonts = ();
     foreach $font ( @{$fset->{fonts}} ) {
        print '/', $fset->{name}, $i, ' ',
-       '/', $font->[1]->{name}, ' findfont ',
+       '/', $font->[1]->{name}, '-NASM findfont ',
        $font->[0], " scalefont def\n";
        push(@zfonts, $fset->{name}.$i);
        $i++;
@@ -800,7 +982,10 @@ foreach $fset ( @AllFonts ) {
     print '/', $fset->{name}, ' [', join(' ',@zfonts), "] def\n";
 }
 
-# Emit the result as PostScript.  This is *NOT* correct code yet!
+# This is used by the bullet-paragraph PostScript methods
+print "/bullet [",ps_string($charcode{'bullet'}),"] def\n";
+
+# Emit the canned PostScript prologue
 open(PSHEAD, "< head.ps");
 while ( defined($line = <PSHEAD>) ) {
     print $line;
@@ -860,54 +1045,92 @@ sub ps_end_page($) {
 
 $ps_page = 0;
 
-# Title page and inner cover
-ps_start_page();
-# FIX THIS: This shouldn't be hard-coded like this
-$title = $metadata{'title'};
-$title =~ s/ \- / \320 /;      # \320 = em dash
-$pstitle = ps_string($title);
-print <<EOF;
-lmarg pageheight 2 mul 3 div moveto
-/Helvetica-Bold findfont 20 scalefont setfont
-/title linkdest ${pstitle} show
-lmarg pageheight 2 mul 3 div 10 sub moveto
-0 setlinecap 3 setlinewidth
-pagewidth lmarg sub rmarg sub 0 rlineto stroke
-/nasmlogo {
-gsave 1 dict begin
-/sz exch def
-/Courier-Bold findfont sz scalefont setfont
-moveto
-0.85 1.22 scale
-[(-~~..~:\#;L       .-:\#;L,.-   .~:\#:;.T  -~~.~:;. .~:;. )
-( E8+U    *T     +U\'   *T\#  .97     *L   E8+\'  *;T\'  *;, )
-( D97     \`*L  .97     \'*L   \"T;E+:,     D9     *L    *L )
-( H7       I\#  T7       I\#        \"*:.   H7     I\#    I\# )
-( U:       :8  *\#+    , :8  T,      79   U:     :8    :8 )
-(,\#B.     .IE,  \"T;E*  .IE, J *+;\#:T*\"  ,\#B.   .IE,  .IE,)] {
-currentpoint 3 -1 roll
-sz -0.10 mul 0 3 -1 roll ashow
-sz 0.72 mul sub moveto
-} forall
-end grestore
-} def
-0.6 setgray
-pagewidth 2 div 143 sub
-pageheight 2 div 33 add
-12 nasmlogo
-EOF
-ps_end_page(0);
+# Title page
 ps_start_page();
-print "% Inner cover goes here\n";
+$title = $metadata{'title'} || '';
+$title =~ s/ \- / $emdash /;
+
+$subtitle = $metadata{'subtitle'} || '';
+$subtitle =~ s/ \- / $emdash /;
+
+# Print title
+print "/ti ", ps_string($title), " def\n";
+print "/sti ", ps_string($subtitle), " def\n";
+print "lmarg pageheight 2 mul 3 div moveto\n";
+print "tfont0 setfont\n";
+print "/title linkdest ti show\n";
+print "lmarg pageheight 2 mul 3 div 10 sub moveto\n";
+print "0 setlinecap 3 setlinewidth\n";
+print "pagewidth lmarg sub rmarg sub 0 rlineto currentpoint stroke moveto\n";
+print "hfont1 setfont sti stringwidth pop neg ",
+    -$HeadFont{leading}, " rmoveto\n";
+print "sti show\n";
+
+# Print logo, if there is one
+# FIX: To be 100% correct, this should look for DocumentNeeded*
+# and DocumentFonts in the header of the EPSF and add those to the
+# global header.
+if ( defined($metadata{epslogo}) &&
+     sysopen(EPS, $metadata{epslogo}, O_RDONLY) ) {
+    my @eps = ();
+    my ($bbllx,$bblly,$bburx,$bbury) = (undef,undef,undef,undef);
+    my $line;
+    my $scale = 1;
+    my $maxwidth = $psconf{pagewidth}-$psconf{lmarg}-$psconf{rmarg};
+    my $maxheight = $psconf{pageheight}/3-40;
+    my $width, $height;
+    my $x, $y;
+
+    while ( defined($line = <EPS>) ) {
+       last if ( $line =~ /^%%EOF/ );
+       if ( !defined($bbllx) &&
+            $line =~ /^\%\%BoundingBox\:\s*([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)/i ) {
+           $bbllx = $1+0; $bblly = $2+0;
+           $bburx = $3+0; $bbury = $4+0;
+       }
+       push(@eps,$line);
+    }
+    close(EPS);
+
+    if ( defined($bbllx) ) {
+       $width = $bburx-$bbllx;
+       $height = $bbury-$bblly;
+
+       if ( $width > $maxwidth ) {
+           $scale = $maxwidth/$width;
+       }
+       if ( $height*$scale > $maxheight ) {
+           $scale = $maxheight/$height;
+       }
+
+       $x = ($psconf{pagewidth}-$width*$scale)/2;
+       $y = ($psconf{pageheight}-$height*$scale)/2;
+
+       print "BeginEPSF\n";
+       print $x, ' ', $y, " translate\n";
+       print $scale, " dup scale\n" unless ( $scale == 1 );
+       print -$bbllx, ' ', -$bblly, " translate\n";
+       print "$bbllx $bblly moveto\n";
+       print "$bburx $bblly lineto\n";
+       print "$bburx $bbury lineto\n";
+       print "$bbllx $bbury lineto\n";
+       print "$bbllx $bblly lineto clip newpath\n";
+       print "%%BeginDocument: ",ps_string($metadata{epslogo}),"\n";
+       print @eps;
+       print "%%EndDocument\n";
+       print "EndEPSF\n";
+    }
+}
 ps_end_page(0);
 
-$curpage = 3;
+# Emit the rest of the document (page 2 and on)
+$curpage = 2;
 ps_start_page();
 foreach $line ( @pslines ) {
     my $linfo = $line->[0];
     
     if ( $$linfo[4] != $curpage ) {
-        ps_end_page(1);
+        ps_end_page($curpage > 2);
         ps_start_page();
         $curpage = $$linfo[4];
     }