3 # Read the source-form of the NASM manual and generate the various
8 # Ellipsis support would be nice.
10 # Source-form features:
11 # ---------------------
14 # Bullets the paragraph. Rest of paragraph is indented to cope. In
15 # HTML, consecutive groups of bulleted paragraphs become unordered
19 # produces `_foobar_' in text and italics in HTML, PS, RTF
21 # Inline code \c{foobar}
22 # produces ``foobar'' in text, and fixed-pitch font in HTML, PS, RTF
27 # produces fixed-pitch font where appropriate, and doesn't break
28 # pages except sufficiently far into the middle of a display.
30 # Chapter, header and subheader
31 # \C{intro} Introduction
32 # \H{whatsnasm} What is NASM?
33 # \S{free} NASM Is Free
34 # dealt with as appropriate. Chapters begin on new sides, possibly
35 # even new _pages_. (Sub)?headers are good places to begin new
36 # pages. Just _after_ a (sub)?header isn't.
37 # The keywords can be substituted with \K and \k.
39 # Keyword \K{cintro} \k{cintro}
40 # Expands to `Chapter 1', `Section 1.1', `Section 1.1.1'. \K has an
41 # initial capital whereas \k doesn't. In HTML, will produce
44 # Web link \W{http://foobar/}{text} or \W{mailto:me@here}\c{me@here}
45 # the \W prefix is ignored except in HTML; in HTML the last part
46 # becomes a hyperlink to the first part.
49 # In case it's necessary, they expand to the real versions.
51 # Nonbreaking hyphen \-
55 # Causes everything after it on the line to be ignored by the
56 # source-form processor.
58 # Indexable word \i{foobar} (or \i\e{foobar} or \i\c{foobar}, equally)
59 # makes word appear in index, referenced to that point
60 # \i\c comes up in code style even in the index; \i\e doesn't come
61 # up in emphasised style.
63 # Indexable non-displayed word \I{foobar} or \I\c{foobar}
64 # just as \i{foobar} except that nothing is displayed for it
67 # \IR{foobar} \c{foobar} operator, uses of
68 # tidies up the appearance in the index of something the \i or \I
69 # operator was applied to
72 # \IA{foobar}{bazquux}
73 # aliases one index tag (as might be supplied to \i or \I) to
74 # another, so that \I{foobar} has the effect of \I{bazquux}, and
75 # \i{foobar} has the effect of \I{bazquux}foobar
79 # defines document metadata, such as authorship, title and copyright;
80 # different output formats use this differently.
83 $diag = 1, shift @ARGV if $ARGV[0] eq "-d";
87 $tstruct_previtem = $node = "Top";
89 $tstruct_level{$tstruct_previtem} = 0;
90 $tstruct_last[$tstruct_level{$tstruct_previtem}] = $tstruct_previtem;
91 $MAXLEVEL = 10; # really 3, but play safe ;-)
93 # Read the file; pass a paragraph at a time to the paragraph processor.
94 print "Reading input...";
95 $pname = "para000000";
96 @pnames = @pflags = ();
100 if (!/\S/ || /^\\(IA|IR|M)/) { # special case: \IA \IR \M imply new-paragraph
105 s/\\#.*$//; # strip comments
112 # Now we've read in the entire document and we know what all the
113 # heading keywords refer to. Go through and fix up the \k references.
114 print "Fixing up cross-references...";
118 # Sort the index tags, according to the slightly odd order I've decided on.
119 print "Sorting index tags...";
124 print "Writing index-diagnostic file...";
129 # OK. Write out the various output files.
130 print "Producing text output: ";
133 print "Producing HTML output: ";
136 print "Producing PostScript output: ";
139 print "Producing Texinfo output: ";
142 print "Producing WinHelp output: ";
148 my $pflags = "", $i, $w, $l, $t;
153 # Strip off _leading_ spaces, then determine type of paragraph.
157 # A code paragraph. The paragraph-array will contain the simple
158 # strings which form each line of the paragraph.
160 while (/^\\c (([^\\]|\\[^c])*)(.*)$/) {
168 $_ = ''; # suppress word-by-word code
170 # A chapter heading. Define the keyword and allocate a chapter
175 $xref = "chapter-$cnum";
176 $pflags = "chap $cnum :$xref";
177 die "badly formatted chapter heading: $_\n" if !/^\\C{([^}]*)}\s*(.*)$/;
178 $refs{$1} = "chapter $cnum";
179 $node = "Chapter $cnum";
181 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
184 # the standard word-by-word code will happen next
186 # An appendix heading. Define the keyword and allocate an appendix
189 $cnum = 'A' if $cnum =~ /[0-9]+/;
192 $xref = "appendix-$cnum";
193 $pflags = "appn $cnum :$xref";
194 die "badly formatted appendix heading: $_\n" if !/^\\A{([^}]*)}\s*(.*)$/;
195 $refs{$1} = "appendix $cnum";
196 $node = "Appendix $cnum";
198 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
201 # the standard word-by-word code will happen next
203 # A major heading. Define the keyword and allocate a section number.
206 $xref = "section-$cnum.$hnum";
207 $pflags = "head $cnum.$hnum :$xref";
208 die "badly formatted heading: $_\n" if !/^\\[HP]{([^}]*)}\s*(.*)$/;
209 $refs{$1} = "section $cnum.$hnum";
210 $node = "Section $cnum.$hnum";
212 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
215 # the standard word-by-word code will happen next
217 # A sub-heading. Define the keyword and allocate a section number.
219 $xref = "section-$cnum.$hnum.$snum";
220 $pflags = "subh $cnum.$hnum.$snum :$xref";
221 die "badly formatted subheading: $_\n" if !/^\\S{([^}]*)}\s*(.*)$/;
222 $refs{$1} = "section $cnum.$hnum.$snum";
223 $node = "Section $cnum.$hnum.$snum";
225 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
228 # the standard word-by-word code will happen next
231 die "badly formatted index rewrite: $_\n" if !/^\\IR{([^}]*)}\s*(.*)$/;
234 # the standard word-by-word code will happen next
237 die "badly formatted index alias: $_\n" if !/^\\IA{([^}]*)}{([^}]*)}\s*$/;
239 return; # avoid word-by-word code
242 die "badly formed metadata: $_\n" if !/^\\M{([^}]*)}{([^}]*)}\s*$/;
244 return; # avoid word-by-word code
246 # A bulleted paragraph. Strip off the initial \b and let the
247 # word-by-word code take care of the rest.
251 # A normal paragraph. Just set $pflags: the word-by-word code does
256 # The word-by-word code: unless @$pname is already defined (which it
257 # will be in the case of a code paragraph), split the paragraph up
258 # into words and push each on @$pname.
260 # Each thing pushed on @$pname should have a two-character type
261 # code followed by the text.
266 # "es" for first emphasised word in emphasised bit
267 # "e " for emphasised in mid-emphasised-bit
268 # "ee" for last emphasised word in emphasised bit
269 # "eo" for single (only) emphasised word
272 # "kK" for capitalised cross-ref
274 # "wc" for code-type Web link
275 # "x " for beginning of resolved cross-ref; generates no visible output,
276 # and the text is the cross-reference code
277 # "xe" for end of resolved cross-ref; text is same as for "x ".
278 # "i " for point to be indexed: the text is the internal index into the
282 s/^\s*//, push @$pname, "sp" if /^\s/;
283 $indexing = $qindex = 0;
284 if (/^(\\[iI])?\\c/) {
285 $qindex = 1 if $1 eq "\\I";
286 $indexing = 1, s/^\\[iI]// if $1;
288 die "badly formatted \\c: \\c$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
295 (push @$pname,"i"),$lastp = $#$pname if $indexing;
296 push @$pname,"c $w" if !$qindex;
297 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
298 } elsif (/^\\[iIe]/) {
301 $qindex = 1 if $1 eq "\\I";
302 $indexing = 1, $type = "\\i" if $1;
303 $emph = 1, $type = "\\e" if $2;
304 s/^(\\[iI])?(\\e?)//;
305 die "badly formatted $type: $type$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
312 $t = $emph ? "es" : "n ";
314 (push @$pname,"i"),$lastp = $#$pname if $indexing;
315 foreach $i (split /\s+/,$w) { # \e and \i can be multiple words
316 push @$pname,"$t$i","sp" if !$qindex;
317 ($ii=$i) =~ tr/A-Z/a-z/, push @ientry,"n $ii","sp" if $indexing;
318 $t = $emph ? "e " : "n ";
320 $w =~ tr/A-Z/a-z/, pop @ientry if $indexing;
321 $$pname[$lastp] = &addidx($node, $w, @ientry) if $indexing;
322 pop @$pname if !$qindex; # remove final space
323 if (substr($$pname[$#$pname],0,2) eq "es" && !$qindex) {
324 substr($$pname[$#$pname],0,2) = "eo";
325 } elsif ($emph && !$qindex) {
326 substr($$pname[$#$pname],0,2) = "ee";
328 } elsif (/^\\[kK]/) {
332 die "badly formatted \\k: \\c$_\n" if !/{([^}]*)}(.*)$/;
337 die "badly formatted \\W: \\W$_\n"
338 if !/{([^}]*)}(\\i)?(\\c)?{(([^\\}]|\\.)*)}(.*)$/;
343 $t = "wc" if $3 eq "\\c";
349 (push @$pname,"i"),$lastp = $#$pname if $indexing;
350 push @$pname,"$t<$l>$w";
351 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
353 die "what the hell? $_\n" if !/^(([^\s\\\-]|\\[\\{}\-])*-?)(.*)$/;
354 die "painful death! $_\n" if !length $1;
368 if ($irewrite ne undef) {
369 &addidx(undef, $irewrite, @$pname);
372 push @pnames, $pname;
373 push @pflags, $pflags;
379 my ($node, $text, @ientry) = @_;
380 $text = $idxalias{$text} || $text;
381 if ($node eq undef || !$idxmap{$text}) {
383 $idxmap{$text} = $ientry;
387 $idxnodes{$node,$text} = 1;
393 my $iitem, $ientry, $i, $piitem, $pcval, $cval, $clrcval;
395 @itags = map { # get back the original data as the 1st elt of each list
397 } sort { # compare auxiliary (non-first) elements of lists
398 $a->[1] cmp $b->[1] ||
399 $a->[2] cmp $b->[2] ||
401 } map { # transform array into list of 3-element lists
402 my $ientry = $idxmap{$_};
403 my $a = substr($$ientry[0],2);
405 [$_, uc($a), substr($$ientry[0],0,2)]
408 # Having done that, check for comma-hood.
410 foreach $iitem (@itags) {
411 $ientry = $idxmap{$iitem};
414 FL:for ($i=0; $i <= $#$ientry; $i++) {
415 if ($$ientry[$i] =~ /^(n .*,)(.*)/) {
417 splice @$ientry,$i+1,0,"n $2" if length $2;
418 $commapos{$iitem} = $i+1;
419 $cval = join("\002", @$ientry[0..$i]);
424 $cval = undef if $clrcval;
425 $commanext{$iitem} = $commaafter{$piitem} = 1
426 if $cval and ($cval eq $pcval);
432 my $iitem,$ientry,$w,$ww,$foo,$node;
433 open INDEXDIAG,">index.diag";
434 foreach $iitem (@itags) {
435 $ientry = $idxmap{$iitem};
436 print INDEXDIAG "<$iitem> ";
437 foreach $w (@$ientry) {
439 print INDEXDIAG $ww unless $ww eq "\001";
443 foreach $node (@nodes) {
444 (print INDEXDIAG $foo,$node), $foo = ", " if $idxnodes{$node,$iitem};
446 print INDEXDIAG "\n";
452 my $pname, $p, $i, $j, $k, $caps, @repl;
454 for ($p=0; $p<=$#pnames; $p++) {
455 next if $pflags[$p] eq "code";
456 $pname = $pnames[$p];
457 for ($i=$#$pname; $i >= 0; $i--) {
458 if ($$pname[$i] =~ /^k/) {
460 $caps = ($k =~ /^kK/);
463 die "undefined keyword `$k'\n" unless $repl;
464 substr($repl,0,1) =~ tr/a-z/A-Z/ if $caps;
466 push @repl,"x $xrefs{$k}";
467 foreach $j (split /\s+/,$repl) {
471 pop @repl; # remove final space
472 push @repl,"xe$xrefs{$k}";
473 splice @$pname,$i,1,@repl;
480 # This is called from the top level, so I won't bother using
484 print "writing file...";
485 open TEXT,">nasmdoc.txt";
489 $title = "The Netwide Assembler: NASM";
490 $spaces = ' ' x ((75-(length $title))/2);
491 ($underscore = $title) =~ s/./=/g;
492 print "$spaces$title\n$spaces$underscore\n";
494 for ($para = 0; $para <= $#pnames; $para++) {
495 $pname = $pnames[$para];
496 $pflags = $pflags[$para];
497 $ptype = substr($pflags,0,4);
499 print "\n"; # always one of these before a new paragraph
501 if ($ptype eq "chap") {
502 # Chapter heading. "Chapter N: Title" followed by a line of
504 $pflags =~ /chap (.*) :(.*)/;
505 $title = "Chapter $1: ";
506 foreach $i (@$pname) {
508 $title .= $ww unless $ww eq "\001";
513 } elsif ($ptype eq "appn") {
514 # Appendix heading. "Appendix N: Title" followed by a line of
516 $pflags =~ /appn (.*) :(.*)/;
517 $title = "Appendix $1: ";
518 foreach $i (@$pname) {
520 $title .= $ww unless $ww eq "\001";
525 } elsif ($ptype eq "head" || $ptype eq "subh") {
526 # Heading or subheading. Just a number and some text.
527 $pflags =~ /.... (.*) :(.*)/;
528 $title = sprintf "%6s ", $1;
529 foreach $i (@$pname) {
531 $title .= $ww unless $ww eq "\001";
534 } elsif ($ptype eq "code") {
535 # Code paragraph. Emit each line with a seven character indent.
536 foreach $i (@$pname) {
537 warn "code line longer than 68 chars: $i\n" if length $i > 68;
538 print ' 'x7, $i, "\n";
540 } elsif ($ptype eq "bull" || $ptype eq "norm") {
541 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
542 # 75-char right margin and either 7 or 11 char left margin
543 # depending on bullets.
544 if ($ptype eq "bull") {
545 $line = ' 'x7 . '(*) ';
548 $line = $next = ' 'x7;
553 do { $w = &word_txt(shift @a) } while $w eq "\001"; # nasty hack
555 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
556 if (length ($line . $wd) > 75) {
557 $line =~ s/\s*$//; # trim trailing spaces
560 $wd =~ s/^\s*//; # trim leading spaces
566 } while ($w ne '' && $w ne undef);
568 $line =~ s/\s*$//; # trim trailing spaces
583 return undef if $w eq '' || $w eq undef;
584 $wtype = substr($w,0,2);
585 $wmajt = substr($wtype,0,1);
587 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
588 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
590 } elsif ($wtype eq "sp") {
592 } elsif ($wtype eq "da") {
594 } elsif ($wmajt eq "c" || $wtype eq "wc") {
596 } elsif ($wtype eq "es") {
598 } elsif ($wtype eq "ee") {
600 } elsif ($wtype eq "eo") {
602 } elsif ($wmajt eq "x" || $wmajt eq "i") {
605 die "panic in word_txt: $wtype$w\n";
610 # This is called from the top level, so I won't bother using
613 # Write contents file. Just the preamble, then a menu of links to the
614 # separate chapter files and the nodes therein.
615 print "writing contents file...";
616 open TEXT,">nasmdoc0.html";
619 print "<p>This manual documents NASM, the Netwide Assembler: an assembler\n";
620 print "targetting the Intel x86 series of processors, with portable source.\n";
622 for ($node = $tstruct_next{'Top'}; $node; $node = $tstruct_next{$node}) {
623 if ($tstruct_level{$node} == 1) {
624 # Invent a file name.
625 ($number = lc($xrefnodes{$node})) =~ s/.*-//;
626 $fname="nasmdocx.html";
627 substr($fname,8 - length $number, length $number) = $number;
628 $html_fnames{$node} = $fname;
632 # Use the preceding filename plus a marker point.
633 $link = $fname . "#$xrefnodes{$node}";
636 $pname = $tstruct_pname{$node};
637 foreach $i (@$pname) {
638 $ww = &word_html($i);
639 $title .= $ww unless $ww eq "\001";
641 print "<a href=\"$link\">$title</a><br>\n";
643 print "<p><a href=\"nasmdoci.html\">Index</a>\n";
644 print "</body></html>\n";
648 # Open a null file, to ensure output (eg random &html_jumppoints calls)
650 print "writing chapter files...";
651 open TEXT,">/dev/null";
657 for ($para = 0; $para <= $#pnames; $para++) {
658 $pname = $pnames[$para];
659 $pflags = $pflags[$para];
660 $ptype = substr($pflags,0,4);
662 $in_list = 0, print "</ul>\n" if $in_list && $ptype ne "bull";
663 if ($ptype eq "chap") {
664 # Chapter heading. Begin a new file.
665 $pflags =~ /chap (.*) :(.*)/;
666 $title = "Chapter $1: ";
668 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
669 $html_lastf = $html_fnames{$chapternode};
670 $chapternode = $nodexrefs{$xref};
671 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
672 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
673 foreach $i (@$pname) {
674 $ww = &word_html($i);
675 $title .= $ww unless $ww eq "\001";
677 $h = "<h2><a name=\"$xref\">$title</a></h2>\n";
678 print $h; print FULL $h;
679 } elsif ($ptype eq "appn") {
680 # Appendix heading. Begin a new file.
681 $pflags =~ /appn (.*) :(.*)/;
682 $title = "Appendix $1: ";
684 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
685 $html_lastf = $html_fnames{$chapternode};
686 $chapternode = $nodexrefs{$xref};
687 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
688 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
689 foreach $i (@$pname) {
690 $ww = &word_html($i);
691 $title .= $ww unless $ww eq "\001";
693 print "<h2><a name=\"$xref\">$title</a></h2>\n";
694 } elsif ($ptype eq "head" || $ptype eq "subh") {
695 # Heading or subheading.
696 $pflags =~ /.... (.*) :(.*)/;
697 $hdr = ($ptype eq "subh" ? "h4" : "h3");
700 foreach $i (@$pname) {
701 $ww = &word_html($i);
702 $title .= $ww unless $ww eq "\001";
704 print "<$hdr><a name=\"$xref\">$title</a></$hdr>\n";
705 } elsif ($ptype eq "code") {
708 foreach $i (@$pname) {
716 } elsif ($ptype eq "bull" || $ptype eq "norm") {
717 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
718 # 75-char right margin and either 7 or 11 char left margin
719 # depending on bullets.
720 if ($ptype eq "bull") {
721 $in_list = 1, print "<ul>\n" unless $in_list;
729 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
731 if ($w eq ' ' || $w eq '' || $w eq undef) {
732 if (length ($line . $wd) > 75) {
733 $line =~ s/\s*$//; # trim trailing spaces
736 $wd =~ s/^\s*//; # trim leading spaces
742 } while ($w ne '' && $w ne undef);
744 $line =~ s/\s*$//; # trim trailing spaces
750 # Close whichever file was open.
752 print "</body></html>\n";
756 print "\n writing index file...";
757 open TEXT,">nasmdoci.html";
760 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
763 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
764 print "</body></html>\n";
770 print "<html><head><title>NASM Manual</title></head>\n";
771 print "<body><h1 align=center>The Netwide Assembler: NASM</h1>\n\n";
772 &html_jumppoints if $_[0];
775 sub html_jumppoints {
776 print "<p align=center>";
777 print "<a href=\"$html_nextf\">Next Chapter</a> |\n" if $html_nextf;
778 print "<a href=\"$html_lastf\">Previous Chapter</a> |\n" if $html_lastf;
779 print "<a href=\"nasmdoc0.html\">Contents</a> |\n";
780 print "<a href=\"nasmdoci.html\">Index</a>\n";
784 my $itag, $a, @ientry, $sep, $w, $wd, $wprev, $line;
787 foreach $itag (@itags) {
788 $ientry = $idxmap{$itag};
792 foreach $node (@nodes) {
793 next if !$idxnodes{$node,$itag};
794 push @a, "n ," if $sep;
795 push @a, "sp", "x $xrefnodes{$node}", "n $node", "xe$xrefnodes{$node}";
800 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
802 if ($w eq ' ' || $w eq '' || $w eq undef) {
803 if (length ($line . $wd) > 75) {
804 $line =~ s/\s*$//; # trim trailing spaces
807 $wd =~ s/^\s*//; # trim leading spaces
813 } while ($w ne '' && $w ne undef);
815 $line =~ s/\s*$//; # trim trailing spaces
824 my $wtype, $wmajt, $pfx, $sfx;
826 return undef if $w eq '' || $w eq undef;
828 $wtype = substr($w,0,2);
829 $wmajt = substr($wtype,0,1);
832 $pfx = "<a href=\"$1\">", $sfx = "</a>", $w = $2
833 if $wmajt eq "w" && $w =~ /^<(.*)>(.*)$/;
837 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
838 return $pfx . $w . $sfx;
839 } elsif ($wtype eq "sp") {
841 } elsif ($wtype eq "da") {
842 return '-'; # sadly, en-dashes are non-standard in HTML
843 } elsif ($wmajt eq "c" || $wtype eq "wc") {
844 return $pfx . "<code><nobr>${w}</nobr></code>" . $sfx;
845 } elsif ($wtype eq "es") {
847 } elsif ($wtype eq "ee") {
849 } elsif ($wtype eq "eo") {
850 return "<em>${w}</em>";
851 } elsif ($wtype eq "x ") {
852 # Magic: we must resolve the cross reference into file and marker
853 # parts, then dispose of the file part if it's us, and dispose of
854 # the marker part if the cross reference describes the top node of
856 my $node = $nodexrefs{$w}; # find the node we're aiming at
857 my $level = $tstruct_level{$node}; # and its level
858 my $up = $node, $uplev = $level-1;
859 $up = $tstruct_up{$up} while $uplev--; # get top node of containing file
860 my $file = ($up ne $chapternode) ? $html_fnames{$up} : "";
861 my $marker = ($level == 1 and $file) ? "" : "#$w";
862 return "<a href=\"$file$marker\">";
863 } elsif ($wtype eq "xe") {
865 } elsif ($wmajt eq "i") {
868 die "panic in word_html: $wtype$w\n";
878 sub ps_write_bookmarks {
883 my $ref, $pref, $i, $title;
885 for ($para = 0; $para <= $#pnames; $para++) {
886 my $pname = $pnames[$para];
887 my $pflags = $pflags[$para];
888 my $ptype = substr($pflags,0,4);
890 if ($ptype eq "chap" || $ptype eq "appn") {
891 # Chapter/appendix heading. "Chapter N: Title" followed by a line of
894 $pflags =~ /(chap|appn) (.*) :(.*)/;
897 foreach $i (@$pname) {
898 $title .= &word_ps_title($i);
900 $titles{$ref} = $title;
902 } elsif ($ptype eq "head" || $ptype eq "subh") {
903 # Heading/subheading. Just a number and some text.
904 $pflags =~ /.... (.*) :(.*)/;
906 $ref =~ /^(n[0-9A-Za-z_]+)\_[0-9A-Za-z]+$/;
910 foreach $i (@$pname) {
911 $title .= &word_ps_title($i);
913 $titles{$ref} = $title;
919 # Now we should have enough data to generate the bookmarks
920 print "[/Title (Contents) /Dest /nContents /OUT pdfmark";
921 foreach $i ( @reflist ) {
922 print '[/Title (', $titles{$i}, ")\n";
923 print '/Count -', $nchildren{$i}, ' ' if ( $nchildren{$i} );
924 print "/Dest /$i /OUT pdfmark\n";
926 print "[/Title (Index) /Dest /nIndex /OUT pdfmark\n";
930 # This is called from the top level, so I won't bother using
933 # First, set up the font metric arrays.
936 # First stage: reprocess the source arrays into a list of
937 # lines, each of which is a list of word-strings, each of
938 # which has a single-letter font code followed by text.
939 # Each line also has an associated type, which will be
940 # used for final alignment and font selection and things.
946 # ' ' == space (no following text required)
947 # '-' == dash (no following text required)
950 # chap == Chapter or appendix heading.
951 # head == Major heading.
952 # subh == Sub-heading.
953 # Ccha == Contents entry for a chapter.
954 # Chea == Contents entry for a heading.
955 # Csub == Contents entry for a subheading.
956 # cone == Code paragraph with just this one line on it.
957 # cbeg == First line of multi-line code paragraph.
958 # cbdy == Interior line of multi-line code paragraph.
959 # cend == Final line of multi-line code paragraph.
960 # none == Normal paragraph with just this one line on it.
961 # nbeg == First line of multi-line normal paragraph.
962 # nbdy == Interior line of multi-line normal paragraph.
963 # nend == Final line of multi-line normal paragraph.
964 # bone == Bulleted paragraph with just this one line on it.
965 # bbeg == First line of multi-line bulleted paragraph.
966 # bbdy == Interior line of multi-line bulleted paragraph.
967 # bend == Final line of multi-line bulleted paragraph.
968 print "line-breaks...";
969 $lname = "psline000000";
970 $lnamei = "idx" . $lname;
971 @lnames = @ltypes = ();
973 $linewidth = 468; # ADJUSTABLE: width of a normal text line
974 $bulletadj = 12; # ADJUSTABLE: space for a bullet
976 for ($para = 0; $para <= $#pnames; $para++) {
977 $pname = $pnames[$para];
978 $pflags = $pflags[$para];
979 $ptype = substr($pflags,0,4);
981 # New paragraph _ergo_ new line.
983 @lindex = (); # list of index tags referenced to this line
985 if ($ptype eq "chap") {
986 # Chapter heading. "Chapter N: Title" followed by a line of
988 $pflags =~ /chap (.*) :(.*)/;
989 push @line, "B".&ref_ps($1), "nChapter", " ", "n$1:", " ";
990 foreach $i (@$pname) {
992 push @line, $ww unless $ww eq "x";
994 @$lname = @line; @$lnamei = @lindex;
995 push @lnames, $lname++;
996 $lnamei = "idx" . $lname;
997 push @ltypes, "chap";
998 } elsif ($ptype eq "appn") {
999 # Appendix heading. "Appendix N: Title" followed by a line of
1001 $pflags =~ /appn (.*) :(.*)/;
1002 push @line, "B".&ref_ps($1), "nAppendix", " ", "n$1:", " ";
1003 foreach $i (@$pname) {
1005 push @line, $ww unless $ww eq "x";
1007 @$lname = @line; @$lnamei = @lindex;
1008 push @lnames, $lname++;
1009 $lnamei = "idx" . $lname;
1010 push @ltypes, "chap";
1011 } elsif ($ptype eq "head") {
1012 # Heading. Just a number and some text.
1013 $pflags =~ /.... (.*) :(.*)/;
1014 push @line, "B".&ref_ps($1), "n$1";
1015 foreach $i (@$pname) {
1017 push @line, $ww unless $ww eq "x";
1019 @$lname = @line; @$lnamei = @lindex;
1020 push @lnames, $lname++;
1021 $lnamei = "idx" . $lname;
1022 push @ltypes, $ptype;
1023 } elsif ($ptype eq "subh") {
1024 # Subheading. Just a number and some text.
1025 $pflags =~ /subh (.*) :(.*)/;
1026 push @line, "B".&ref_ps($1), "n$1";
1027 foreach $i (@$pname) {
1028 push @line, &word_ps($i);
1030 @$lname = @line; @$lnamei = @lindex;
1031 push @lnames, $lname++;
1032 $lnamei = "idx" . $lname;
1033 push @ltypes, "subh";
1034 } elsif ($ptype eq "code") {
1035 # Code paragraph. Emit lines one at a time.
1037 foreach $i (@$pname) {
1039 push @lnames, $lname++;
1040 $lnamei = "idx" . $lname;
1041 push @ltypes, $type;
1044 $ltypes[$#ltypes] = ($ltypes[$#ltypes] eq "cbeg" ? "cone" : "cend");
1045 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1046 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
1047 # 75-char right margin and either 7 or 11 char left margin
1048 # depending on bullets.
1049 if ($ptype eq "bull") {
1050 $width = $linewidth - $bulletadj;
1051 $type = $begtype = "bbeg";
1056 $width = $linewidth;
1057 $type = $begtype = "nbeg";
1067 do { $w = &word_ps(shift @a) } while ($w eq "x");
1068 push @wd, $wprev if $wprev;
1069 if ($wprev =~ /^n.*-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1070 $wdlen = &len_ps(@wd);
1071 if ($linelen + $wdlen > $width) {
1072 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1073 @$lname = @line; @$lnamei = @lindex;
1074 push @lnames, $lname++;
1075 $lnamei = "idx" . $lname;
1076 push @ltypes, $type;
1078 @line = @lindex = ();
1080 shift @wd while $wd[0] eq ' '; # trim leading spaces
1087 } while ($w ne '' && $w ne undef);
1089 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1090 @$lname = @line; @$lnamei = @lindex;
1091 push @lnames, $lname++;
1092 $lnamei = "idx" . $lname;
1093 push @ltypes, $type;
1097 ($ltypes[$#ltypes] eq $begtype ? $onetype : $endtype);
1101 # We've now processed the document source into lines. Before we
1102 # go on and do the page breaking, we'll fabricate a table of contents,
1103 # line by line, and then after doing page breaks we'll go back and
1104 # insert the page numbers into the contents entries.
1105 print "building contents...";
1106 @clnames = @cltypes = ();
1107 $clname = "pscont000000";
1108 @$clname = ("BnContents", "nContents"); # "chapter heading" for TOC
1109 push @clnames,$clname++;
1110 push @cltypes,"chap";
1111 for ($i=0; $i<=$#lnames; $i++) {
1112 $lname = $lnames[$i];
1113 if ($ltypes[$i] =~ /^(chap|head|subh)/) {
1115 splice @$clname,2,0," " if ($ltypes[$i] !~ /chap/);
1116 push @$clname,$i; # placeholder for page number
1117 push @clnames,$clname++;
1118 push @cltypes,"C" . substr($ltypes[$i],0,3);
1121 @$clname = ("BnIndex", "nIndex"); # contents entry for Index
1122 push @$clname,$i; # placeholder for page number
1123 $idx_clname = $clname;
1124 push @clnames,$clname++;
1125 push @cltypes,"Ccha";
1126 $contlen = $#clnames + 1;
1127 unshift @lnames,@clnames;
1128 unshift @ltypes,@cltypes;
1130 # Second stage: now we have a list of lines, break them into pages.
1131 # We do this by means of adding a third array in parallel with
1132 # @lnames and @ltypes, called @lpages, in which we store the page
1133 # number that each line resides on. We also add @ycoord which
1134 # stores the vertical position of each line on the page.
1136 # Page breaks may not come after line-types:
1137 # chap head subh cbeg nbeg bbeg
1138 # and may not come before line-types:
1140 # They are forced before line-types:
1142 print "page-breaks...";
1143 $pmax = 600; # ADJUSTABLE: maximum length of a page in points
1144 $textht = 11; # ADJUSTABLE: height of a normal line in points
1145 $spacing = 6; # ADJUSTABLE: space between paragraphs, in points
1146 $headht = 14; # ADJUSTABLE: height of a major heading in points
1147 $subht = 12; # ADJUSTABLE: height of a sub-heading in points
1148 $pstart = 0; # start line of current page
1149 $plen = 0; # current length of current page
1150 $pnum = 1; # number of current page
1151 $bpt = -1; # last feasible break point
1152 $i = 0; # line number
1153 while ($i <= $#lnames) {
1154 $lname = $lnames[$i];
1155 # Add the height of this line (computed the last time we went round
1156 # the loop, unless we're a chapter heading in which case we do it
1157 # now) to the length of the current page. Also, _put_ this line on
1158 # the current page, and allocate it a y-coordinate.
1159 if ($ltypes[$i] =~ /^chap$/) {
1160 $pnum += 1 - ($pnum & 1); # advance to odd numbered page if necessary
1161 $plen = 100; # ADJUSTABLE: space taken up by a chapter heading
1162 $ycoord[$i] = 0; # chapter heading: y-coord doesn't matter
1164 $ycoord[$i] = $plen + $space;
1165 $plen += $space + $ht;
1167 # See if we can break after this line.
1168 $bpt = $i if $ltypes[$i] !~ /^chap|head|subh|cbeg|nbeg|bbeg$/ &&
1169 $ltypes[$i+1] !~ /^cend|nend|bend$/;
1170 # Assume, to start with, that we don't break after this line.
1172 # See if a break is forced.
1173 $break = 1, $bpt = $i if $ltypes[$i+1] eq "chap" || !$ltypes[$i+1];
1174 # Otherwise, compute the height of the next line, and break if
1175 # it would make this page too long.
1176 $ht = $textht, $space = 0 if $ltypes[$i+1] =~ /^[nbc](bdy|end)$/;
1177 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^[nbc](one|beg)$/;
1178 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^C/;
1179 $ht = $subht, $space = $spacing if $ltypes[$i+1] eq "subh";
1180 $ht = $headht, $space = $spacing if $ltypes[$i+1] eq "head";
1181 $break = 1 if $plen + $space + $ht > $pmax;
1182 # Now, if we're breaking, assign page number $pnum to all lines up
1183 # to $bpt, set $i == $bpt+1, and zero $space since we are at the
1184 # start of a new page and don't want leading space.
1186 die "no feasible break point at all on page $pnum\n" if $bpt == -1;
1187 for ($j = $pstart; $j <= $bpt; $j++) {
1188 $lnamei = "idx" . $lnames[$j];
1189 foreach $k (@$lnamei) {
1190 ${$psidxpp{$k}}{$pnum} = 1;
1192 $lpages[$j] = $pnum;
1204 # Now fix up the TOC with page numbers.
1205 print "\n fixing up contents...";
1206 for ($i=0; $i<=$#lnames; $i++) {
1207 $lname = $lnames[$i];
1208 if ($ltypes[$i] =~ /^C/) {
1210 push @$lname, "n" . $lpages[$j+$contlen];
1214 # Having got page numbers for most stuff, generate an index.
1215 print "building index...";
1219 foreach $k (@itags) {
1222 @idxentry = @{$idxmap{$k}};
1223 if ($commaafter{$k} and !$commanext{$k}) {
1224 # This line is a null line beginning a multiple entry. We must
1225 # output the prefix on a line by itself.
1227 @idxhead = splice @idxentry,0,$commapos{$k};
1229 foreach $i (@idxhead) {
1231 push @line, $ww unless $ww eq "x";
1233 &ps_idxout("index",\@line,[]);
1237 $cmd = "iindex", splice @idxentry,0,$commapos{$k} if $commanext{$k};
1238 foreach $i (@idxentry) {
1240 push @line, $ww unless $ww eq "x";
1242 $len = $iwid - $sep - &len_ps(@line);
1243 warn "text for index tag `%s' is longer than one index line!\n"
1246 $inums = join(',',sort { $a <=> $b } keys %{$psidxpp{$k}});
1247 while (length $inums) {
1248 $inums =~ /^([^,]+)(,?)(.*)$/;
1249 $inums = $3, $inumc = $2; $inum = $1;
1250 @pnum = (" ", "Bp$inum", "n$inum", "E");
1251 push(@pnum, "n$inumc") if ( $inumc ne '' );
1252 $pnumlen = &len_ps(@pnum);
1253 if ($pnumlen > $len) {
1254 &ps_idxout($cmd,\@line,\@pp);
1258 $len = $iwid - $sep;
1263 &ps_idxout($cmd,\@line,\@pp) if (length @pp);
1264 $l1 = &len_ps(@line);
1267 $$idx_clname[$#$idx_clname] = "n" . $pnum; # fix up TOC entry for index
1269 print "writing file...";
1270 open PS,">nasmdoc.ps";
1274 &ps_write_bookmarks;
1275 for ($i=0; $i<=$#lnames; $i++) {
1276 &ps_throw_pg($page,$lpages[$i]) if $page != $lpages[$i];
1277 $page = $lpages[$i];
1278 &ps_out_line($ycoord[$i],$ltypes[$i],$lnames[$i]);
1281 while ($i <= $#psindex) {
1282 &ps_throw_pg($page, $pnum) if $page != $pnum;
1285 $ypos = 100, &ps_out_line(0, "chap", ["BnIndex", "nIndex"]) if !$i;
1286 $lines = ($pmax - $ypos) / $textht;
1287 my $col; # ps_out_line hits this variable
1288 PAGE:for ($col = 1; $col <= 2; $col++) {
1289 $y = $ypos; $l = $lines;
1290 COL: while ($l > 0) {
1292 $j++ while $psindex[$j] and ($psindex[$j][3] == 0); # find next break
1293 last COL if $j-$i > $l or $i > $#psindex;
1295 &ps_out_line($y, $psindex[$i][0] eq "index" ? "idl$col" : "ldl$col",
1297 &ps_out_line($y,"idr$col",$psindex[$i][2]);
1303 last PAGE if $i > $#psindex;
1312 my ($cmd, $left, $right) = @_;
1315 if ($#psindex >= 0) and ( ($#$left < 0) or ($cmd eq "iindex") );
1316 push @psindex,[$cmd,[@$left],[@$right],$break];
1322 /nf /Times-Roman findfont 11 scalefont def
1323 /ef /Times-Italic findfont 11 scalefont def
1324 /cf /Courier findfont 11 scalefont def
1325 /nc /Helvetica-Bold findfont 18 scalefont def
1326 /ec /Helvetica-Oblique findfont 18 scalefont def
1327 /cc /Courier-Bold findfont 18 scalefont def
1328 /nh /Helvetica-Bold findfont 14 scalefont def
1329 /eh /Helvetica-Oblique findfont 14 scalefont def
1330 /ch /Courier-Bold findfont 14 scalefont def
1331 /ns /Helvetica-Bold findfont 12 scalefont def
1332 /es /Helvetica-Oblique findfont 12 scalefont def
1333 /cs /Courier-Bold findfont 12 scalefont def
1334 /n 16#6E def /e 16#65 def /c 16#63 def
1335 /B 16#42 def /E 16#45 def /D 16#44 def
1336 /min { 2 copy gt { exch } if pop } def
1337 /max { 2 copy lt { exch } if pop } def
1346 /lktarget exch cvn def
1350 gsave dup true charpath pathbbox grestore
1358 lkury max /lkury exch def
1359 lkurx max /lkurx exch def
1360 lklly min /lklly exch def
1361 lkllx min /lkllx exch def
1367 [/Rect [ lkllx lklly lkurx lkury ]
1368 /Color [ 1.0 0.0 0.0 ]
1376 /lkdest exch cvn def
1378 /View [ /XYZ currentpoint 0 ]
1384 pop dup length 1 sub 1 exch getinterval linkbegin
1389 dup length 1 sub 1 exch getinterval linkdest
1394 550 50 moveto ns setfont dup stringwidth pop neg 0 rmoveto show
1396 /pageeven { 50 50 moveto ns setfont show } def
1398 dup length 1 sub 1 exch getinterval linkdest
1403 dup length 1 sub 1 exch getinterval
1406 dup n eq {pop nc setfont} {
1407 e eq {ec setfont} {cc setfont} ifelse
1409 dup length 1 sub 1 exch getinterval show
1411 0 setlinecap 3 setlinewidth
1412 newpath 100 610 moveto 468 0 rlineto stroke
1415 686 exch sub /y exch def /a exch def
1418 a 1 get dup length 1 sub 1 exch getinterval
1419 nh setfont dup stringwidth pop neg 0 rmoveto show
1421 a dup length 2 sub 2 exch getinterval {
1424 dup n eq {pop nh setfont} {
1425 e eq {eh setfont} {ch setfont} ifelse
1427 s s length 1 sub 1 exch getinterval show
1431 688 exch sub /y exch def /a exch def
1434 a 1 get dup length 1 sub 1 exch getinterval
1435 ns setfont dup stringwidth pop neg 0 rmoveto show
1437 a dup length 2 sub 2 exch getinterval {
1440 dup n eq {pop ns setfont} {
1441 e eq {es setfont} {cs setfont} ifelse
1443 s s length 1 sub 1 exch getinterval show
1447 568 exch sub exch 689 exch sub moveto
1454 dup n eq {pop nf setfont} {
1455 e eq {ef setfont} {cf setfont} ifelse
1457 s s length 1 sub 1 exch getinterval linkshow
1458 s sp eq {j 0 rmoveto} if
1462 /contents { /w exch def /y exch def /a exch def
1464 a a length 1 sub get dup length 1 sub 1 exch getinterval
1466 nf setfont 568 ss stringwidth pop sub /ex exch def
1467 a 0 a length 1 sub getinterval y w 0 disp
1468 /sx currentpoint pop def nf setfont
1469 100 10 568 { /i exch def
1470 i 5 sub sx gt i 5 add ex lt and {
1471 i yy moveto (.) linkshow
1474 ex yy moveto ss linkshow
1477 /just { /w exch def /y exch def /a exch def
1478 /jj w def /spaces 0 def
1482 dup n eq {pop nf setfont} {
1483 e eq {ef setfont} {cf setfont} ifelse
1485 s s length 1 sub 1 exch getinterval stringwidth pop
1486 jj exch sub /jj exch def
1487 s sp eq {/spaces spaces 1 add def} if
1489 a y w jj spaces spaces 0 eq {pop pop 0} {div} ifelse disp
1491 /idl { 468 exch sub 0 disp } def
1492 /ldl { 436 exch sub 0 disp } def
1493 /idr { 222 add 468 exch sub /x exch def /y exch def /a exch def
1500 dup n eq {pop nf setfont} {
1501 e eq {ef setfont} {cf setfont} ifelse
1503 s s length 1 sub 1 exch getinterval stringwidth pop
1511 nf setfont dup 100 exch 689 exch sub moveto (\267) show
1513 [/PageMode /UseOutlines /DOCVIEW pdfmark
1515 print "%!PS-Adobe-3.0\n";
1516 print "%%BoundingBox: 95 95 590 705\n";
1517 print "%%Creator: a nasty Perl script\n";
1518 print "%%DocumentData: Clean7Bit\n";
1519 print "%%Orientation: Portrait\n";
1520 print "%%Pages: $lpages[$#lpages]\n";
1521 print "%%DocumentNeededResources: font Times-Roman Times-Italic\n";
1522 print "%%+ font Helvetica-Bold Courier Courier-Bold\n";
1523 print "%%EndComments\n";
1524 print "%%BeginProlog\n";
1525 # This makes sure non-PDF PostScript interpreters don't choke on
1526 # pdfmarks in the output
1527 print "/pdfmark where\n";
1528 print "{pop} {userdict /pdfmark /cleartomark load put} ifelse\n";
1529 print "%%EndProlog\n";
1530 print "%%BeginSetup\n";
1532 $pshdr =~ s/\s+/ /g;
1533 while ($pshdr =~ /\S/) {
1534 last if length($pshdr) < 72 || $pshdr !~ /^(.{0,72}\S)\s(.*)$/;
1538 print "$pshdr\n" if $pshdr =~ /\S/;
1539 print "%%EndSetup\n";
1540 &ps_initpg($lpages[0]);
1546 print "%%Trailer\nrestore\n%%EOF\n";
1550 my ($oldpg, $newpg) = @_;
1551 while ($oldpg < $newpg) {
1560 print "%%Page: $pgnum $pgnum\n";
1561 print "%%BeginPageSetup\nsave\n%%EndPageSetup\n";
1562 print "95 705 moveto (p$pgnum) linkdest\n";
1568 print "%%PageTrailer\n($pgnum)pageodd restore showpage\n";
1570 print "%%PageTrailer\n($pgnum)pageeven restore showpage\n";
1575 my ($ypos,$ltype,$lname) = @_;
1580 foreach $c (@$lname) {#
1581 $c= "n " if $c eq " ";
1582 $c = "n\261" if $c eq "-";
1585 $d .= $1, $c = $2 while $c =~ /^([ -\'\*-\[\]-~]+)(.*)$/;
1587 $d .= "\\$1", $c = $2, next if $c =~ /^([\\\(\)])(.*)$/;
1588 ($d .= sprintf "\\%3o",unpack("C",$1)), $c = $2, next
1589 if $c =~ /^([^ -~])(.*)$/;
1594 $col = 0, print "\n" if $col>0 && $col+length $d > 77;
1598 print "\n" if $col > 60;
1600 if ($ltype =~ /^[nb](beg|bdy)$/) {
1601 printf "%d %s%d just\n",
1602 $ypos, ($ltype eq "bbeg" ? "bullet " : ""),
1603 ($ltype =~ /^b/ ? 456 : 468);
1604 } elsif ($ltype =~ /^[nb](one|end)$/) {
1605 printf "%d %s%d left\n",
1606 $ypos, ($ltype eq "bone" ? "bullet " : ""),
1607 ($ltype =~ /^b/ ? 456 : 468);
1608 } elsif ($ltype =~ /^c(one|beg|bdy|end)$/) {
1609 printf "$ypos 468 left\n";
1610 } elsif ($ltype =~ /^C/) {
1612 $wid = 456 if $ltype eq "Chea";
1613 $wid = 444 if $ltype eq "Csub";
1614 printf "$ypos $wid contents\n";
1615 } elsif ($ltype eq "chap") {
1617 } elsif ($ltype eq "head") {
1618 printf "$ypos heading\n";
1619 } elsif ($ltype eq "subh") {
1620 printf "$ypos subhead\n";
1621 } elsif ($ltype =~ /([il]d[lr])([12])/) {
1622 $left = ($2 eq "2" ? 468-222 : 0);
1623 printf "$ypos $left $1\n";
1631 return undef if $w eq '' || $w eq undef;
1633 $wtype = substr($w,0,2);
1634 $wmajt = substr($wtype,0,1);
1636 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1637 if ($wmajt eq "n" || $wtype eq "w ") {
1639 } elsif ($wtype eq "sp") {
1641 } elsif ($wtype eq "da") {
1643 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1645 } elsif ($wmajt eq "e") {
1647 } elsif ($wmajt eq "x") {
1649 } elsif ($wtype eq "i ") {
1653 die "panic in word_ps: $wtype$w\n";
1661 return undef if $w eq '' || $w eq undef;
1663 $wtype = substr($w,0,2);
1664 $wmajt = substr($wtype,0,1);
1666 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1667 if ($wmajt eq "n" || $wtype eq "w ") {
1669 } elsif ($wtype eq "sp") {
1671 } elsif ($wtype eq "da") {
1673 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1675 } elsif ($wmajt eq "e") {
1677 } elsif ($wmajt eq "x") {
1679 } elsif ($wtype eq "i ") {
1682 die "panic in word_ps_title: $wtype$w\n";
1691 $size = 11/1000; # used only for length calculations
1692 while ($w = shift @line) {
1693 $w = "n " if $w eq " ";
1694 $w = "n\261" if $w eq "-";
1695 $f = substr($w,0,1);
1696 if ( $f !~ /^[BDE]$/ ) {
1697 $f = "timesr" if $f eq "n";
1698 $f = "timesi" if $f eq "e";
1699 $f = "courr" if $f eq "c";
1700 foreach $c (unpack 'C*',substr($w,1)) {
1701 $l += $size * $$f[$c];
1709 # This is called from the top level, so I won't bother using
1713 print "writing file...";
1714 open TEXT,">nasmdoc.texi";
1718 print "\\input texinfo \@c -*-texinfo-*-\n";
1719 print "\@c \%**start of header\n";
1720 print "\@setfilename ",$metadata{'infofile'},".info\n";
1721 print "\@dircategory ",$metadata{'category'},"\n";
1722 print "\@direntry\n";
1723 printf "* %-28s %s.\n",
1724 sprintf('%s: (%s).', $metadata{'infoname'}, $metadata{'infofile'}),
1725 $metadata{'infotitle'};
1726 print "\@end direntry\n";
1727 print "\@settitle ",$metadata{'title'},"\n";
1728 print "\@setchapternewpage odd\n";
1729 print "\@c \%**end of header\n";
1732 print $metadata{'summary'}, "\n";
1734 print "Copyright ",$metadata{'year'}," ",$metadata{'author'},"\n";
1736 print $metadata{'license'}, "\n";
1737 print "\@end ifinfo\n";
1739 print "\@titlepage\n";
1740 print "\@title ",$metadata{'title'},"\n";
1741 print "\@author ",$metadata{'author'},"\n";
1744 print "\@vskip 0pt plus 1filll\n";
1745 print "Copyright \@copyright{} ",$metadata{'year'},' ',$metadata{'author'},"\n";
1747 print $metadata{'license'}, "\n";
1748 print "\@end titlepage\n";
1750 print "\@node Top, $tstruct_next{'Top'}, (dir), (dir)\n";
1751 print "\@top ",$metadata{'infotitle'},"\n";
1754 print $metadata{'summary'}, "\n";
1755 print "\@end ifinfo\n";
1760 for ($para = 0; $para <= $#pnames; $para++) {
1761 $pname = $pnames[$para];
1762 $pflags = $pflags[$para];
1763 $ptype = substr($pflags,0,4);
1765 $bulleting = 0, print "\@end itemize\n" if $bulleting && $ptype ne "bull";
1766 print "\n"; # always one of these before a new paragraph
1768 if ($ptype eq "chap") {
1769 # Chapter heading. Begin a new node.
1771 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1772 $pflags =~ /chap (.*) :(.*)/;
1773 $node = "Chapter $1";
1774 $title = "Chapter $1: ";
1775 foreach $i (@$pname) {
1776 $ww = &word_texi($i);
1777 $title .= $ww unless $ww eq "\001";
1779 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1780 print " $tstruct_up{$node}\n\@unnumbered $title\n";
1781 } elsif ($ptype eq "appn") {
1782 # Appendix heading. Begin a new node.
1784 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1785 $pflags =~ /appn (.*) :(.*)/;
1786 $node = "Appendix $1";
1787 $title = "Appendix $1: ";
1788 foreach $i (@$pname) {
1789 $ww = &word_texi($i);
1790 $title .= $ww unless $ww eq "\001";
1792 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1793 print " $tstruct_up{$node}\n\@unnumbered $title\n";
1794 } elsif ($ptype eq "head" || $ptype eq "subh") {
1795 # Heading or subheading. Begin a new node.
1797 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1798 $pflags =~ /.... (.*) :(.*)/;
1799 $node = "Section $1";
1801 foreach $i (@$pname) {
1802 $ww = &word_texi($i);
1803 $title .= $ww unless $ww eq "\001";
1805 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1806 print " $tstruct_up{$node}\n";
1807 $hdr = ($ptype eq "subh" ? "\@unnumberedsubsec" : "\@unnumberedsec");
1808 print "$hdr $title\n";
1809 } elsif ($ptype eq "code") {
1810 # Code paragraph. Surround with @example / @end example.
1811 print "\@example\n";
1812 foreach $i (@$pname) {
1813 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1819 print "\@end example\n";
1820 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1821 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1822 if ($ptype eq "bull") {
1823 $bulleting = 1, print "\@itemize \@bullet\n" if !$bulleting;
1830 do { $w = &word_texi(shift @a); } while $w eq "\001"; # hack
1832 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1833 if (length ($line . $wd) > 75) {
1834 $line =~ s/\s*$//; # trim trailing spaces
1837 $wd =~ s/^\s*//; # trim leading spaces
1843 } while ($w ne '' && $w ne undef);
1844 if ($line =~ /\S/) {
1845 $line =~ s/\s*$//; # trim trailing spaces
1855 print "\n\@contents\n\@bye\n";
1860 # Side effect of this procedure: update global `texiwdlen' to be the length
1861 # in chars of the formatted version of the word.
1866 return undef if $w eq '' || $w eq undef;
1867 $wtype = substr($w,0,2);
1868 $wmajt = substr($wtype,0,1);
1874 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1875 substr($w,0,1) =~ tr/a-z/A-Z/, $capital = 0 if $capital;
1876 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1879 } elsif ($wtype eq "sp") {
1882 } elsif ($wtype eq "da") {
1885 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1886 $texiwdlen = 2 + $wlen;
1887 return "\@code\{$w\}";
1888 } elsif ($wtype eq "es") {
1889 $texiwdlen = 1 + $wlen;
1890 return "\@emph\{${w}";
1891 } elsif ($wtype eq "ee") {
1892 $texiwdlen = 1 + $wlen;
1894 } elsif ($wtype eq "eo") {
1895 $texiwdlen = 2 + $wlen;
1896 return "\@emph\{${w}\}";
1897 } elsif ($wtype eq "x ") {
1898 $texiwdlen = 0; # we don't need it in this case
1899 $capital = 1; # hack
1901 } elsif ($wtype eq "xe") {
1902 $texiwdlen = 0; # we don't need it in this case
1904 } elsif ($wmajt eq "i") {
1905 $texiwdlen = 0; # we don't need it in this case
1908 die "panic in word_texi: $wtype$w\n";
1914 my $item, $i, $mpname, $title, $wd;
1916 $item = $tstruct_next{$topitem};
1920 $mpname = $tstruct_pname{$item};
1921 foreach $i (@$mpname) {
1922 $wd = &word_texi($i);
1923 $title .= $wd unless $wd eq "\001";
1925 print "* ${item}:: $title\n";
1926 $item = $tstruct_mnext{$item};
1928 print "* Index::\n" if $topitem eq "Top";
1929 print "\@end menu\n";
1933 my $itag, $ientry, @a, $wd, $item, $len;
1934 my $subnums = "123456789ABCDEFGHIJKLMNOPQRSTU" .
1935 "VWXYZabcdefghijklmnopqrstuvwxyz";
1937 print "\@ifinfo\n\@node Index, , $FIXMElastnode, Top\n";
1938 print "\@unnumbered Index\n\n\@menu\n";
1940 foreach $itag (@itags) {
1941 $ientry = $idxmap{$itag};
1946 $wd = &word_texi($i);
1947 $item .= $wd, $len += $texiwdlen unless $wd eq "\001";
1950 foreach $node (@nodes) {
1951 next if !$idxnodes{$node,$itag};
1952 printf "* %s%s (%s): %s.\n",
1953 $item, " " x (40-$len), substr($subnums,$i++,1), $node;
1956 print "\@end menu\n\@end ifinfo\n";
1960 # This is called from the top level, so I won't bother using
1963 # Build the index-tag text forms.
1964 print "building index entries...";
1967 my $ientry = $idxmap{$_};
1969 foreach $i (@$ientry) {
1970 $ww = &word_hlp($i,0);
1971 $title .= $ww unless $ww eq "\001";
1976 # Write the HPJ project-description file.
1977 print "writing .hpj file...";
1978 open HPJ,">nasmdoc.hpj";
1979 print HPJ "[OPTIONS]\ncompress=true\n";
1980 print HPJ "title=NASM: The Netwide Assembler\noldkeyphrase=no\n\n";
1981 print HPJ "[FILES]\nnasmdoc.rtf\n\n";
1982 print HPJ "[CONFIG]\n";
1983 print HPJ 'CreateButton("btn_up", "&Up",'.
1984 ' "JumpContents(`nasmdoc.hlp'."'".')")';
1985 print HPJ "\nBrowseButtons()\n";
1989 print "\n writing .rtf file...";
1990 open TEXT,">nasmdoc.rtf";
1994 print "{\\rtf1\\ansi{\\fonttbl\n";
1995 print "\\f0\\froman Times New Roman;\\f1\\fmodern Courier New;\n";
1996 print "\\f2\\fswiss Arial;\\f3\\ftech Wingdings}\\deff0\n";
1997 print "#{\\footnote Top}\n";
1998 print "\${\\footnote Contents}\n";
1999 print "+{\\footnote browse:00000}\n";
2000 print "!{\\footnote DisableButton(\"btn_up\")}\n";
2001 print "\\keepn\\f2\\b\\fs30\\sb0\n";
2002 print "NASM: The Netwide Assembler\n";
2003 print "\\par\\pard\\plain\\sb120\n";
2004 print "This file documents NASM, the Netwide Assembler: an assembler \n";
2005 print "targetting the Intel x86 series of processors, with portable source.\n";
2010 $newpar = "\\par\\sb120\n";
2011 for ($para = 0; $para <= $#pnames; $para++) {
2012 $pname = $pnames[$para];
2013 $pflags = $pflags[$para];
2014 $ptype = substr($pflags,0,4);
2017 $newpar = "\\par\\sb120\n";
2019 if ($ptype eq "chap") {
2020 # Chapter heading. Begin a new node.
2022 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
2023 $pflags =~ /chap (.*) :(.*)/;
2024 $node = "Chapter $1";
2025 $title = $footnotetitle = "Chapter $1: ";
2026 foreach $i (@$pname) {
2027 $ww = &word_hlp($i,1);
2028 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
2031 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
2032 print "\${\\footnote $footnotetitle}\n";
2033 printf "+{\\footnote browse:%05d}\n", ++$browse;
2034 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
2035 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
2036 &hlp_sectkw($tstruct_up{$node});
2037 print "EnableButton(\"btn_up\")}\n";
2038 &hlp_keywords($node);
2039 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
2041 $newpar = "\\par\\pard\\plain\\sb120\n";
2042 } elsif ($ptype eq "appn") {
2043 # Appendix heading. Begin a new node.
2045 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
2046 $pflags =~ /appn (.*) :(.*)/;
2047 $node = "Appendix $1";
2048 $title = $footnotetitle = "Appendix $1: ";
2049 foreach $i (@$pname) {
2050 $ww = &word_hlp($i,1);
2051 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
2054 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
2055 print "\${\\footnote $footnotetitle}\n";
2056 printf "+{\\footnote browse:%05d}\n", ++$browse;
2057 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
2058 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
2059 &hlp_sectkw($tstruct_up{$node});
2060 print "EnableButton(\"btn_up\")}\n";
2061 &hlp_keywords($node);
2062 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
2064 $newpar = "\\par\\pard\\plain\\sb120\n";
2065 } elsif ($ptype eq "head" || $ptype eq "subh") {
2066 # Heading or subheading. Begin a new node.
2068 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
2069 $pflags =~ /.... (.*) :(.*)/;
2070 $node = "Section $1";
2071 $title = $footnotetitle = "$1. ";
2072 foreach $i (@$pname) {
2073 $ww = &word_hlp($i,1);
2074 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
2077 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
2078 print "\${\\footnote $footnotetitle}\n";
2079 printf "+{\\footnote browse:%05d}\n", ++$browse;
2080 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
2081 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
2082 &hlp_sectkw($tstruct_up{$node});
2083 print "EnableButton(\"btn_up\")}\n";
2084 &hlp_keywords($node);
2085 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
2087 $newpar = "\\par\\pard\\plain\\sb120\n";
2088 } elsif ($ptype eq "code") {
2090 print "\\keep\\f1\\sb120\n";
2091 foreach $i (@$pname) {
2092 warn "code line longer than 68 chars: $i\n" if length $i > 68;
2096 print "$i\\par\\sb0\n";
2098 $newpar = "\\pard\\f0\\sb120\n";
2099 } elsif ($ptype eq "bull" || $ptype eq "norm") {
2100 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
2101 if ($ptype eq "bull") {
2102 print "\\tx360\\li360\\fi-360{\\f3\\'9F}\\tab\n";
2103 $newpar = "\\par\\pard\\sb120\n";
2105 $newpar = "\\par\\sb120\n";
2111 do { $w = &word_hlp((shift @a),1); } while $w eq "\001"; # hack
2113 if ($w eq ' ' || $w eq '' || $w eq undef) {
2114 if (length ($line . $wd) > 75) {
2115 $line =~ s/\s*$//; # trim trailing spaces
2116 print "$line \n"; # and put one back
2118 $wd =~ s/^\s*//; # trim leading spaces
2124 } while ($w ne '' && $w ne undef);
2125 if ($line =~ /\S/) {
2126 $line =~ s/\s*$//; # trim trailing spaces
2139 my ($w, $docode) = @_;
2142 return undef if $w eq '' || $w eq undef;
2143 $wtype = substr($w,0,2);
2144 $wmajt = substr($wtype,0,1);
2149 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
2150 substr($w,0,length($w)-1) =~ s/-/\\\'AD/g if $wmajt ne "x"; #nonbreakhyphens
2151 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
2153 } elsif ($wtype eq "sp") {
2155 } elsif ($wtype eq "da") {
2157 } elsif ($wmajt eq "c" || $wtype eq "wc") {
2158 $w =~ s/ /\\\'A0/g; # make spaces non-breaking
2159 return $docode ? "{\\f1 ${w}}" : $w;
2160 } elsif ($wtype eq "es") {
2162 } elsif ($wtype eq "ee") {
2164 } elsif ($wtype eq "eo") {
2165 return "{\\i ${w}}";
2166 } elsif ($wtype eq "x ") {
2168 } elsif ($wtype eq "xe") {
2169 $w = &hlp_sectkw($w);
2170 return "}{\\v ${w}}";
2171 } elsif ($wmajt eq "i") {
2174 die "panic in word_hlp: $wtype$w\n";
2180 my $item, $kword, $i, $mpname, $title;
2182 $item = $tstruct_next{$topitem};
2183 print "\\li360\\fi-360\n";
2186 $mpname = $tstruct_pname{$item};
2187 foreach $i (@$mpname) {
2188 $ww = &word_hlp($i, 0);
2189 $title .= $ww unless $ww eq "\001";
2191 $kword = &hlp_sectkw($item);
2192 print "{\\uldb ${item}: $title}{\\v $kword}\\par\\sb0\n";
2193 $item = $tstruct_mnext{$item};
2195 print "\\pard\\sb120\n";
2200 $node =~ tr/A-Z/a-z/;
2201 $node =~ tr/- ./___/;
2207 my $pfx = "K{\\footnote ";
2209 foreach $i (0..$#itags) {
2210 (print $pfx,$hlp_index[$i]), $pfx = ";\n", $done++
2211 if $idxnodes{$node,$itags[$i]};
2213 print "}\n" if $done;
2216 # Make tree structures. $tstruct_* is top-level and global.
2218 my ($item, $level) = @_;
2221 $tstruct_pname{$item} = $pname;
2222 $tstruct_next{$tstruct_previtem} = $item;
2223 $tstruct_prev{$item} = $tstruct_previtem;
2224 $tstruct_level{$item} = $level;
2225 $tstruct_up{$item} = $tstruct_last[$level-1];
2226 $tstruct_mnext{$tstruct_last[$level]} = $item;
2227 $tstruct_last[$level] = $item;
2228 for ($i=$level+1; $i<$MAXLEVEL; $i++) { $tstruct_last[$i] = undef; }
2229 $tstruct_previtem = $item;
2233 # PostScript font metric data. Used for line breaking.
2236 250, 0, 0, 0, 0, 0, 0, 0,
2237 0, 0, 0, 0, 0, 0, 0, 0,
2238 0, 0, 0, 0, 0, 0, 0, 0,
2239 0, 0, 0, 0, 0, 0, 0, 0,
2240 250, 333, 408, 500, 500, 833, 778, 333,
2241 333, 333, 500, 564, 250, 333, 250, 278,
2242 500, 500, 500, 500, 500, 500, 500, 500,
2243 500, 500, 278, 278, 564, 564, 564, 444,
2244 921, 722, 667, 667, 722, 611, 556, 722,
2245 722, 333, 389, 722, 611, 889, 722, 722,
2246 556, 722, 667, 556, 611, 722, 722, 944,
2247 722, 722, 611, 333, 278, 333, 469, 500,
2248 333, 444, 500, 444, 500, 444, 333, 500,
2249 500, 278, 278, 500, 278, 778, 500, 500,
2250 500, 500, 333, 389, 278, 500, 500, 722,
2251 500, 500, 444, 480, 200, 480, 541, 0,
2252 0, 0, 0, 0, 0, 0, 0, 0,
2253 0, 0, 0, 0, 0, 0, 0, 0,
2254 0, 0, 0, 0, 0, 0, 0, 0,
2255 0, 0, 0, 0, 0, 0, 0, 0,
2256 0, 333, 500, 500, 167, 500, 500, 500,
2257 500, 180, 444, 500, 333, 333, 556, 556,
2258 0, 500, 500, 500, 250, 0, 453, 350,
2259 333, 444, 444, 500,1000,1000, 0, 444,
2260 0, 333, 333, 333, 333, 333, 333, 333,
2261 333, 0, 333, 333, 0, 333, 333, 333,
2262 1000, 0, 0, 0, 0, 0, 0, 0,
2263 0, 0, 0, 0, 0, 0, 0, 0,
2264 0, 889, 0, 276, 0, 0, 0, 0,
2265 611, 722, 889, 310, 0, 0, 0, 0,
2266 0, 667, 0, 0, 0, 278, 0, 0,
2267 278, 500, 722, 500, 0, 0, 0, 0
2270 250, 0, 0, 0, 0, 0, 0, 0,
2271 0, 0, 0, 0, 0, 0, 0, 0,
2272 0, 0, 0, 0, 0, 0, 0, 0,
2273 0, 0, 0, 0, 0, 0, 0, 0,
2274 250, 333, 420, 500, 500, 833, 778, 333,
2275 333, 333, 500, 675, 250, 333, 250, 278,
2276 500, 500, 500, 500, 500, 500, 500, 500,
2277 500, 500, 333, 333, 675, 675, 675, 500,
2278 920, 611, 611, 667, 722, 611, 611, 722,
2279 722, 333, 444, 667, 556, 833, 667, 722,
2280 611, 722, 611, 500, 556, 722, 611, 833,
2281 611, 556, 556, 389, 278, 389, 422, 500,
2282 333, 500, 500, 444, 500, 444, 278, 500,
2283 500, 278, 278, 444, 278, 722, 500, 500,
2284 500, 500, 389, 389, 278, 500, 444, 667,
2285 444, 444, 389, 400, 275, 400, 541, 0,
2286 0, 0, 0, 0, 0, 0, 0, 0,
2287 0, 0, 0, 0, 0, 0, 0, 0,
2288 0, 0, 0, 0, 0, 0, 0, 0,
2289 0, 0, 0, 0, 0, 0, 0, 0,
2290 0, 389, 500, 500, 167, 500, 500, 500,
2291 500, 214, 556, 500, 333, 333, 500, 500,
2292 0, 500, 500, 500, 250, 0, 523, 350,
2293 333, 556, 556, 500, 889,1000, 0, 500,
2294 0, 333, 333, 333, 333, 333, 333, 333,
2295 333, 0, 333, 333, 0, 333, 333, 333,
2296 889, 0, 0, 0, 0, 0, 0, 0,
2297 0, 0, 0, 0, 0, 0, 0, 0,
2298 0, 889, 0, 276, 0, 0, 0, 0,
2299 556, 722, 944, 310, 0, 0, 0, 0,
2300 0, 667, 0, 0, 0, 278, 0, 0,
2301 278, 500, 667, 500, 0, 0, 0, 0
2304 600, 0, 0, 0, 0, 0, 0, 0,
2305 0, 0, 0, 0, 0, 0, 0, 0,
2306 0, 0, 0, 0, 0, 0, 0, 0,
2307 0, 0, 0, 0, 0, 0, 0, 0,
2308 600, 600, 600, 600, 600, 600, 600, 600,
2309 600, 600, 600, 600, 600, 600, 600, 600,
2310 600, 600, 600, 600, 600, 600, 600, 600,
2311 600, 600, 600, 600, 600, 600, 600, 600,
2312 600, 600, 600, 600, 600, 600, 600, 600,
2313 600, 600, 600, 600, 600, 600, 600, 600,
2314 600, 600, 600, 600, 600, 600, 600, 600,
2315 600, 600, 600, 600, 600, 600, 600, 600,
2316 600, 600, 600, 600, 600, 600, 600, 600,
2317 600, 600, 600, 600, 600, 600, 600, 600,
2318 600, 600, 600, 600, 600, 600, 600, 600,
2319 600, 600, 600, 600, 600, 600, 600, 0,
2320 0, 0, 0, 0, 0, 0, 0, 0,
2321 0, 0, 0, 0, 0, 0, 0, 0,
2322 0, 0, 0, 0, 0, 0, 0, 0,
2323 0, 0, 0, 0, 0, 0, 0, 0,
2324 0, 600, 600, 600, 600, 600, 600, 600,
2325 600, 600, 600, 600, 600, 600, 600, 600,
2326 0, 600, 600, 600, 600, 0, 600, 600,
2327 600, 600, 600, 600, 600, 600, 0, 600,
2328 0, 600, 600, 600, 600, 600, 600, 600,
2329 600, 0, 600, 600, 0, 600, 600, 600,
2330 600, 0, 0, 0, 0, 0, 0, 0,
2331 0, 0, 0, 0, 0, 0, 0, 0,
2332 0, 600, 0, 600, 0, 0, 0, 0,
2333 600, 600, 600, 600, 0, 0, 0, 0,
2334 0, 600, 0, 0, 0, 600, 0, 0,
2335 600, 600, 600, 600, 0, 0, 0, 0