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
77 $diag = 1, shift @ARGV if $ARGV[0] eq "-d";
81 $tstruct_previtem = $node = "Top";
83 $tstruct_level{$tstruct_previtem} = 0;
84 $tstruct_last[$tstruct_level{$tstruct_previtem}] = $tstruct_previtem;
85 $MAXLEVEL = 10; # really 3, but play safe ;-)
87 # Read the file; pass a paragraph at a time to the paragraph processor.
88 print "Reading input...";
89 $pname = "para000000";
90 @pnames = @pflags = ();
94 if (!/\S/ || /^\\I[AR]/) { # special case: \I[AR] implies new-paragraph
99 s/\\#.*$//; # strip comments
106 # Now we've read in the entire document and we know what all the
107 # heading keywords refer to. Go through and fix up the \k references.
108 print "Fixing up cross-references...";
112 # Sort the index tags, according to the slightly odd order I've decided on.
113 print "Sorting index tags...";
118 print "Writing index-diagnostic file...";
123 # OK. Write out the various output files.
124 print "Producing text output: ";
127 print "Producing HTML output: ";
130 print "Producing PostScript output: ";
133 print "Producing Texinfo output: ";
136 print "Producing WinHelp output: ";
142 my $pflags = "", $i, $w, $l, $t;
147 # Strip off _leading_ spaces, then determine type of paragraph.
151 # A code paragraph. The paragraph-array will contain the simple
152 # strings which form each line of the paragraph.
154 while (/^\\c (([^\\]|\\[^c])*)(.*)$/) {
162 $_ = ''; # suppress word-by-word code
164 # A chapter heading. Define the keyword and allocate a chapter
169 $xref = "chapter-$cnum";
170 $pflags = "chap $cnum :$xref";
171 die "badly formatted chapter heading: $_\n" if !/^\\C{([^}]*)}\s*(.*)$/;
172 $refs{$1} = "chapter $cnum";
173 $node = "Chapter $cnum";
175 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
178 # the standard word-by-word code will happen next
180 # An appendix heading. Define the keyword and allocate an appendix
183 $cnum = 'A' if $cnum =~ /[0-9]+/;
186 $xref = "appendix-$cnum";
187 $pflags = "appn $cnum :$xref";
188 die "badly formatted appendix heading: $_\n" if !/^\\A{([^}]*)}\s*(.*)$/;
189 $refs{$1} = "appendix $cnum";
190 $node = "Appendix $cnum";
192 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
195 # the standard word-by-word code will happen next
197 # A major heading. Define the keyword and allocate a section number.
200 $xref = "section-$cnum.$hnum";
201 $pflags = "head $cnum.$hnum :$xref";
202 die "badly formatted heading: $_\n" if !/^\\[HP]{([^}]*)}\s*(.*)$/;
203 $refs{$1} = "section $cnum.$hnum";
204 $node = "Section $cnum.$hnum";
206 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
209 # the standard word-by-word code will happen next
211 # A sub-heading. Define the keyword and allocate a section number.
213 $xref = "section-$cnum.$hnum.$snum";
214 $pflags = "subh $cnum.$hnum.$snum :$xref";
215 die "badly formatted subheading: $_\n" if !/^\\S{([^}]*)}\s*(.*)$/;
216 $refs{$1} = "section $cnum.$hnum.$snum";
217 $node = "Section $cnum.$hnum.$snum";
219 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
222 # the standard word-by-word code will happen next
225 die "badly formatted index rewrite: $_\n" if !/^\\IR{([^}]*)}\s*(.*)$/;
228 # the standard word-by-word code will happen next
231 die "badly formatted index alias: $_\n" if !/^\\IA{([^}]*)}{([^}]*)}\s*$/;
233 return; # avoid word-by-word code
235 # A bulleted paragraph. Strip off the initial \b and let the
236 # word-by-word code take care of the rest.
240 # A normal paragraph. Just set $pflags: the word-by-word code does
245 # The word-by-word code: unless @$pname is already defined (which it
246 # will be in the case of a code paragraph), split the paragraph up
247 # into words and push each on @$pname.
249 # Each thing pushed on @$pname should have a two-character type
250 # code followed by the text.
255 # "es" for first emphasised word in emphasised bit
256 # "e " for emphasised in mid-emphasised-bit
257 # "ee" for last emphasised word in emphasised bit
258 # "eo" for single (only) emphasised word
261 # "kK" for capitalised cross-ref
263 # "wc" for code-type Web link
264 # "x " for beginning of resolved cross-ref; generates no visible output,
265 # and the text is the cross-reference code
266 # "xe" for end of resolved cross-ref; text is same as for "x ".
267 # "i " for point to be indexed: the text is the internal index into the
271 s/^\s*//, push @$pname, "sp" if /^\s/;
272 $indexing = $qindex = 0;
273 if (/^(\\[iI])?\\c/) {
274 $qindex = 1 if $1 eq "\\I";
275 $indexing = 1, s/^\\[iI]// if $1;
277 die "badly formatted \\c: \\c$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
284 (push @$pname,"i"),$lastp = $#$pname if $indexing;
285 push @$pname,"c $w" if !$qindex;
286 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
287 } elsif (/^\\[iIe]/) {
290 $qindex = 1 if $1 eq "\\I";
291 $indexing = 1, $type = "\\i" if $1;
292 $emph = 1, $type = "\\e" if $2;
293 s/^(\\[iI])?(\\e?)//;
294 die "badly formatted $type: $type$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
301 $t = $emph ? "es" : "n ";
303 (push @$pname,"i"),$lastp = $#$pname if $indexing;
304 foreach $i (split /\s+/,$w) { # \e and \i can be multiple words
305 push @$pname,"$t$i","sp" if !$qindex;
306 ($ii=$i) =~ tr/A-Z/a-z/, push @ientry,"n $ii","sp" if $indexing;
307 $t = $emph ? "e " : "n ";
309 $w =~ tr/A-Z/a-z/, pop @ientry if $indexing;
310 $$pname[$lastp] = &addidx($node, $w, @ientry) if $indexing;
311 pop @$pname if !$qindex; # remove final space
312 if (substr($$pname[$#$pname],0,2) eq "es" && !$qindex) {
313 substr($$pname[$#$pname],0,2) = "eo";
314 } elsif ($emph && !$qindex) {
315 substr($$pname[$#$pname],0,2) = "ee";
317 } elsif (/^\\[kK]/) {
321 die "badly formatted \\k: \\c$_\n" if !/{([^}]*)}(.*)$/;
326 die "badly formatted \\W: \\W$_\n"
327 if !/{([^}]*)}(\\i)?(\\c)?{(([^\\}]|\\.)*)}(.*)$/;
332 $t = "wc" if $3 eq "\\c";
338 (push @$pname,"i"),$lastp = $#$pname if $indexing;
339 push @$pname,"$t<$l>$w";
340 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
342 die "what the hell? $_\n" if !/^(([^\s\\\-]|\\[\\{}\-])*-?)(.*)$/;
343 die "painful death! $_\n" if !length $1;
357 if ($irewrite ne undef) {
358 &addidx(undef, $irewrite, @$pname);
361 push @pnames, $pname;
362 push @pflags, $pflags;
368 my ($node, $text, @ientry) = @_;
369 $text = $idxalias{$text} || $text;
370 if ($node eq undef || !$idxmap{$text}) {
372 $idxmap{$text} = $ientry;
376 $idxnodes{$node,$text} = 1;
382 my $iitem, $ientry, $i, $piitem, $pcval, $cval, $clrcval;
384 @itags = map { # get back the original data as the 1st elt of each list
386 } sort { # compare auxiliary (non-first) elements of lists
387 $a->[1] cmp $b->[1] ||
388 $a->[2] cmp $b->[2] ||
390 } map { # transform array into list of 3-element lists
391 my $ientry = $idxmap{$_};
392 my $a = substr($$ientry[0],2);
394 [$_, uc($a), substr($$ientry[0],0,2)]
397 # Having done that, check for comma-hood.
399 foreach $iitem (@itags) {
400 $ientry = $idxmap{$iitem};
403 FL:for ($i=0; $i <= $#$ientry; $i++) {
404 if ($$ientry[$i] =~ /^(n .*,)(.*)/) {
406 splice @$ientry,$i+1,0,"n $2" if length $2;
407 $commapos{$iitem} = $i+1;
408 $cval = join("\002", @$ientry[0..$i]);
413 $cval = undef if $clrcval;
414 $commanext{$iitem} = $commaafter{$piitem} = 1
415 if $cval and ($cval eq $pcval);
421 my $iitem,$ientry,$w,$ww,$foo,$node;
422 open INDEXDIAG,">index.diag";
423 foreach $iitem (@itags) {
424 $ientry = $idxmap{$iitem};
425 print INDEXDIAG "<$iitem> ";
426 foreach $w (@$ientry) {
428 print INDEXDIAG $ww unless $ww eq "\001";
432 foreach $node (@nodes) {
433 (print INDEXDIAG $foo,$node), $foo = ", " if $idxnodes{$node,$iitem};
435 print INDEXDIAG "\n";
441 my $pname, $p, $i, $j, $k, $caps, @repl;
443 for ($p=0; $p<=$#pnames; $p++) {
444 next if $pflags[$p] eq "code";
445 $pname = $pnames[$p];
446 for ($i=$#$pname; $i >= 0; $i--) {
447 if ($$pname[$i] =~ /^k/) {
449 $caps = ($k =~ /^kK/);
452 die "undefined keyword `$k'\n" unless $repl;
453 substr($repl,0,1) =~ tr/a-z/A-Z/ if $caps;
455 push @repl,"x $xrefs{$k}";
456 foreach $j (split /\s+/,$repl) {
460 pop @repl; # remove final space
461 push @repl,"xe$xrefs{$k}";
462 splice @$pname,$i,1,@repl;
469 # This is called from the top level, so I won't bother using
473 print "writing file...";
474 open TEXT,">nasmdoc.txt";
478 $title = "The Netwide Assembler: NASM";
479 $spaces = ' ' x ((75-(length $title))/2);
480 ($underscore = $title) =~ s/./=/g;
481 print "$spaces$title\n$spaces$underscore\n";
483 for ($para = 0; $para <= $#pnames; $para++) {
484 $pname = $pnames[$para];
485 $pflags = $pflags[$para];
486 $ptype = substr($pflags,0,4);
488 print "\n"; # always one of these before a new paragraph
490 if ($ptype eq "chap") {
491 # Chapter heading. "Chapter N: Title" followed by a line of
493 $pflags =~ /chap (.*) :(.*)/;
494 $title = "Chapter $1: ";
495 foreach $i (@$pname) {
497 $title .= $ww unless $ww eq "\001";
502 } elsif ($ptype eq "appn") {
503 # Appendix heading. "Appendix N: Title" followed by a line of
505 $pflags =~ /appn (.*) :(.*)/;
506 $title = "Appendix $1: ";
507 foreach $i (@$pname) {
509 $title .= $ww unless $ww eq "\001";
514 } elsif ($ptype eq "head" || $ptype eq "subh") {
515 # Heading or subheading. Just a number and some text.
516 $pflags =~ /.... (.*) :(.*)/;
517 $title = sprintf "%6s ", $1;
518 foreach $i (@$pname) {
520 $title .= $ww unless $ww eq "\001";
523 } elsif ($ptype eq "code") {
524 # Code paragraph. Emit each line with a seven character indent.
525 foreach $i (@$pname) {
526 warn "code line longer than 68 chars: $i\n" if length $i > 68;
527 print ' 'x7, $i, "\n";
529 } elsif ($ptype eq "bull" || $ptype eq "norm") {
530 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
531 # 75-char right margin and either 7 or 11 char left margin
532 # depending on bullets.
533 if ($ptype eq "bull") {
534 $line = ' 'x7 . '(*) ';
537 $line = $next = ' 'x7;
542 do { $w = &word_txt(shift @a) } while $w eq "\001"; # nasty hack
544 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
545 if (length ($line . $wd) > 75) {
546 $line =~ s/\s*$//; # trim trailing spaces
549 $wd =~ s/^\s*//; # trim leading spaces
555 } while ($w ne '' && $w ne undef);
557 $line =~ s/\s*$//; # trim trailing spaces
572 return undef if $w eq '' || $w eq undef;
573 $wtype = substr($w,0,2);
574 $wmajt = substr($wtype,0,1);
576 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
577 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
579 } elsif ($wtype eq "sp") {
581 } elsif ($wtype eq "da") {
583 } elsif ($wmajt eq "c" || $wtype eq "wc") {
585 } elsif ($wtype eq "es") {
587 } elsif ($wtype eq "ee") {
589 } elsif ($wtype eq "eo") {
591 } elsif ($wmajt eq "x" || $wmajt eq "i") {
594 die "panic in word_txt: $wtype$w\n";
599 # This is called from the top level, so I won't bother using
602 # Write contents file. Just the preamble, then a menu of links to the
603 # separate chapter files and the nodes therein.
604 print "writing contents file...";
605 open TEXT,">nasmdoc0.html";
608 print "<p>This manual documents NASM, the Netwide Assembler: an assembler\n";
609 print "targetting the Intel x86 series of processors, with portable source.\n";
611 for ($node = $tstruct_next{'Top'}; $node; $node = $tstruct_next{$node}) {
612 if ($tstruct_level{$node} == 1) {
613 # Invent a file name.
614 ($number = lc($xrefnodes{$node})) =~ s/.*-//;
615 $fname="nasmdocx.html";
616 substr($fname,8 - length $number, length $number) = $number;
617 $html_fnames{$node} = $fname;
621 # Use the preceding filename plus a marker point.
622 $link = $fname . "#$xrefnodes{$node}";
625 $pname = $tstruct_pname{$node};
626 foreach $i (@$pname) {
627 $ww = &word_html($i);
628 $title .= $ww unless $ww eq "\001";
630 print "<a href=\"$link\">$title</a><br>\n";
632 print "<p><a href=\"nasmdoci.html\">Index</a>\n";
633 print "</body></html>\n";
637 # Open a null file, to ensure output (eg random &html_jumppoints calls)
639 print "writing chapter files...";
640 open TEXT,">/dev/null";
646 for ($para = 0; $para <= $#pnames; $para++) {
647 $pname = $pnames[$para];
648 $pflags = $pflags[$para];
649 $ptype = substr($pflags,0,4);
651 $in_list = 0, print "</ul>\n" if $in_list && $ptype ne "bull";
652 if ($ptype eq "chap") {
653 # Chapter heading. Begin a new file.
654 $pflags =~ /chap (.*) :(.*)/;
655 $title = "Chapter $1: ";
657 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
658 $html_lastf = $html_fnames{$chapternode};
659 $chapternode = $nodexrefs{$xref};
660 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
661 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
662 foreach $i (@$pname) {
663 $ww = &word_html($i);
664 $title .= $ww unless $ww eq "\001";
666 $h = "<h2><a name=\"$xref\">$title</a></h2>\n";
667 print $h; print FULL $h;
668 } elsif ($ptype eq "appn") {
669 # Appendix heading. Begin a new file.
670 $pflags =~ /appn (.*) :(.*)/;
671 $title = "Appendix $1: ";
673 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
674 $html_lastf = $html_fnames{$chapternode};
675 $chapternode = $nodexrefs{$xref};
676 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
677 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
678 foreach $i (@$pname) {
679 $ww = &word_html($i);
680 $title .= $ww unless $ww eq "\001";
682 print "<h2><a name=\"$xref\">$title</a></h2>\n";
683 } elsif ($ptype eq "head" || $ptype eq "subh") {
684 # Heading or subheading.
685 $pflags =~ /.... (.*) :(.*)/;
686 $hdr = ($ptype eq "subh" ? "h4" : "h3");
689 foreach $i (@$pname) {
690 $ww = &word_html($i);
691 $title .= $ww unless $ww eq "\001";
693 print "<$hdr><a name=\"$xref\">$title</a></$hdr>\n";
694 } elsif ($ptype eq "code") {
697 foreach $i (@$pname) {
705 } elsif ($ptype eq "bull" || $ptype eq "norm") {
706 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
707 # 75-char right margin and either 7 or 11 char left margin
708 # depending on bullets.
709 if ($ptype eq "bull") {
710 $in_list = 1, print "<ul>\n" unless $in_list;
718 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
720 if ($w eq ' ' || $w eq '' || $w eq undef) {
721 if (length ($line . $wd) > 75) {
722 $line =~ s/\s*$//; # trim trailing spaces
725 $wd =~ s/^\s*//; # trim leading spaces
731 } while ($w ne '' && $w ne undef);
733 $line =~ s/\s*$//; # trim trailing spaces
739 # Close whichever file was open.
741 print "</body></html>\n";
745 print "\n writing index file...";
746 open TEXT,">nasmdoci.html";
749 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
752 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
753 print "</body></html>\n";
759 print "<html><head><title>NASM Manual</title></head>\n";
760 print "<body><h1 align=center>The Netwide Assembler: NASM</h1>\n\n";
761 &html_jumppoints if $_[0];
764 sub html_jumppoints {
765 print "<p align=center>";
766 print "<a href=\"$html_nextf\">Next Chapter</a> |\n" if $html_nextf;
767 print "<a href=\"$html_lastf\">Previous Chapter</a> |\n" if $html_lastf;
768 print "<a href=\"nasmdoc0.html\">Contents</a> |\n";
769 print "<a href=\"nasmdoci.html\">Index</a>\n";
773 my $itag, $a, @ientry, $sep, $w, $wd, $wprev, $line;
776 foreach $itag (@itags) {
777 $ientry = $idxmap{$itag};
781 foreach $node (@nodes) {
782 next if !$idxnodes{$node,$itag};
783 push @a, "n ," if $sep;
784 push @a, "sp", "x $xrefnodes{$node}", "n $node", "xe$xrefnodes{$node}";
789 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
791 if ($w eq ' ' || $w eq '' || $w eq undef) {
792 if (length ($line . $wd) > 75) {
793 $line =~ s/\s*$//; # trim trailing spaces
796 $wd =~ s/^\s*//; # trim leading spaces
802 } while ($w ne '' && $w ne undef);
804 $line =~ s/\s*$//; # trim trailing spaces
813 my $wtype, $wmajt, $pfx, $sfx;
815 return undef if $w eq '' || $w eq undef;
817 $wtype = substr($w,0,2);
818 $wmajt = substr($wtype,0,1);
821 $pfx = "<a href=\"$1\">", $sfx = "</a>", $w = $2
822 if $wmajt eq "w" && $w =~ /^<(.*)>(.*)$/;
826 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
827 return $pfx . $w . $sfx;
828 } elsif ($wtype eq "sp") {
830 } elsif ($wtype eq "da") {
831 return '-'; # sadly, en-dashes are non-standard in HTML
832 } elsif ($wmajt eq "c" || $wtype eq "wc") {
833 return $pfx . "<code><nobr>${w}</nobr></code>" . $sfx;
834 } elsif ($wtype eq "es") {
836 } elsif ($wtype eq "ee") {
838 } elsif ($wtype eq "eo") {
839 return "<em>${w}</em>";
840 } elsif ($wtype eq "x ") {
841 # Magic: we must resolve the cross reference into file and marker
842 # parts, then dispose of the file part if it's us, and dispose of
843 # the marker part if the cross reference describes the top node of
845 my $node = $nodexrefs{$w}; # find the node we're aiming at
846 my $level = $tstruct_level{$node}; # and its level
847 my $up = $node, $uplev = $level-1;
848 $up = $tstruct_up{$up} while $uplev--; # get top node of containing file
849 my $file = ($up ne $chapternode) ? $html_fnames{$up} : "";
850 my $marker = ($level == 1 and $file) ? "" : "#$w";
851 return "<a href=\"$file$marker\">";
852 } elsif ($wtype eq "xe") {
854 } elsif ($wmajt eq "i") {
857 die "panic in word_html: $wtype$w\n";
867 sub ps_write_bookmarks {
872 my $ref, $pref, $i, $title;
874 for ($para = 0; $para <= $#pnames; $para++) {
875 my $pname = $pnames[$para];
876 my $pflags = $pflags[$para];
877 my $ptype = substr($pflags,0,4);
879 if ($ptype eq "chap" || $ptype eq "appn") {
880 # Chapter/appendix heading. "Chapter N: Title" followed by a line of
883 $pflags =~ /(chap|appn) (.*) :(.*)/;
886 foreach $i (@$pname) {
887 $title .= &word_ps_title($i);
889 $titles{$ref} = $title;
891 } elsif ($ptype eq "head" || $ptype eq "subh") {
892 # Heading/subheading. Just a number and some text.
893 $pflags =~ /.... (.*) :(.*)/;
895 $ref =~ /^(n[0-9A-Za-z_]+)\_[0-9A-Za-z]+$/;
899 foreach $i (@$pname) {
900 $title .= &word_ps_title($i);
902 $titles{$ref} = $title;
908 # Now we should have enough data to generate the bookmarks
909 print "[/Title (Contents) /Dest /nContents /OUT pdfmark";
910 foreach $i ( @reflist ) {
911 print '[/Title (', $titles{$i}, ")\n";
912 print '/Count -', $nchildren{$i}, ' ' if ( $nchildren{$i} );
913 print "/Dest /$i /OUT pdfmark\n";
915 print "[/Title (Index) /Dest /nIndex /OUT pdfmark\n";
919 # This is called from the top level, so I won't bother using
922 # First, set up the font metric arrays.
925 # First stage: reprocess the source arrays into a list of
926 # lines, each of which is a list of word-strings, each of
927 # which has a single-letter font code followed by text.
928 # Each line also has an associated type, which will be
929 # used for final alignment and font selection and things.
935 # ' ' == space (no following text required)
936 # '-' == dash (no following text required)
939 # chap == Chapter or appendix heading.
940 # head == Major heading.
941 # subh == Sub-heading.
942 # Ccha == Contents entry for a chapter.
943 # Chea == Contents entry for a heading.
944 # Csub == Contents entry for a subheading.
945 # cone == Code paragraph with just this one line on it.
946 # cbeg == First line of multi-line code paragraph.
947 # cbdy == Interior line of multi-line code paragraph.
948 # cend == Final line of multi-line code paragraph.
949 # none == Normal paragraph with just this one line on it.
950 # nbeg == First line of multi-line normal paragraph.
951 # nbdy == Interior line of multi-line normal paragraph.
952 # nend == Final line of multi-line normal paragraph.
953 # bone == Bulleted paragraph with just this one line on it.
954 # bbeg == First line of multi-line bulleted paragraph.
955 # bbdy == Interior line of multi-line bulleted paragraph.
956 # bend == Final line of multi-line bulleted paragraph.
957 print "line-breaks...";
958 $lname = "psline000000";
959 $lnamei = "idx" . $lname;
960 @lnames = @ltypes = ();
962 $linewidth = 468; # ADJUSTABLE: width of a normal text line
963 $bulletadj = 12; # ADJUSTABLE: space for a bullet
965 for ($para = 0; $para <= $#pnames; $para++) {
966 $pname = $pnames[$para];
967 $pflags = $pflags[$para];
968 $ptype = substr($pflags,0,4);
970 # New paragraph _ergo_ new line.
972 @lindex = (); # list of index tags referenced to this line
974 if ($ptype eq "chap") {
975 # Chapter heading. "Chapter N: Title" followed by a line of
977 $pflags =~ /chap (.*) :(.*)/;
978 push @line, "B".&ref_ps($1), "nChapter", " ", "n$1:", " ";
979 foreach $i (@$pname) {
981 push @line, $ww unless $ww eq "x";
983 @$lname = @line; @$lnamei = @lindex;
984 push @lnames, $lname++;
985 $lnamei = "idx" . $lname;
986 push @ltypes, "chap";
987 } elsif ($ptype eq "appn") {
988 # Appendix heading. "Appendix N: Title" followed by a line of
990 $pflags =~ /appn (.*) :(.*)/;
991 push @line, "B".&ref_ps($1), "nAppendix", " ", "n$1:", " ";
992 foreach $i (@$pname) {
994 push @line, $ww unless $ww eq "x";
996 @$lname = @line; @$lnamei = @lindex;
997 push @lnames, $lname++;
998 $lnamei = "idx" . $lname;
999 push @ltypes, "chap";
1000 } elsif ($ptype eq "head") {
1001 # Heading. Just a number and some text.
1002 $pflags =~ /.... (.*) :(.*)/;
1003 push @line, "B".&ref_ps($1), "n$1";
1004 foreach $i (@$pname) {
1006 push @line, $ww unless $ww eq "x";
1008 @$lname = @line; @$lnamei = @lindex;
1009 push @lnames, $lname++;
1010 $lnamei = "idx" . $lname;
1011 push @ltypes, $ptype;
1012 } elsif ($ptype eq "subh") {
1013 # Subheading. Just a number and some text.
1014 $pflags =~ /subh (.*) :(.*)/;
1015 push @line, "B".&ref_ps($1), "n$1";
1016 foreach $i (@$pname) {
1017 push @line, &word_ps($i);
1019 @$lname = @line; @$lnamei = @lindex;
1020 push @lnames, $lname++;
1021 $lnamei = "idx" . $lname;
1022 push @ltypes, "subh";
1023 } elsif ($ptype eq "code") {
1024 # Code paragraph. Emit lines one at a time.
1026 foreach $i (@$pname) {
1028 push @lnames, $lname++;
1029 $lnamei = "idx" . $lname;
1030 push @ltypes, $type;
1033 $ltypes[$#ltypes] = ($ltypes[$#ltypes] eq "cbeg" ? "cone" : "cend");
1034 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1035 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
1036 # 75-char right margin and either 7 or 11 char left margin
1037 # depending on bullets.
1038 if ($ptype eq "bull") {
1039 $width = $linewidth - $bulletadj;
1040 $type = $begtype = "bbeg";
1045 $width = $linewidth;
1046 $type = $begtype = "nbeg";
1056 do { $w = &word_ps(shift @a) } while ($w eq "x");
1057 push @wd, $wprev if $wprev;
1058 if ($wprev =~ /^n.*-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1059 $wdlen = &len_ps(@wd);
1060 if ($linelen + $wdlen > $width) {
1061 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1062 @$lname = @line; @$lnamei = @lindex;
1063 push @lnames, $lname++;
1064 $lnamei = "idx" . $lname;
1065 push @ltypes, $type;
1067 @line = @lindex = ();
1069 shift @wd while $wd[0] eq ' '; # trim leading spaces
1076 } while ($w ne '' && $w ne undef);
1078 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1079 @$lname = @line; @$lnamei = @lindex;
1080 push @lnames, $lname++;
1081 $lnamei = "idx" . $lname;
1082 push @ltypes, $type;
1086 ($ltypes[$#ltypes] eq $begtype ? $onetype : $endtype);
1090 # We've now processed the document source into lines. Before we
1091 # go on and do the page breaking, we'll fabricate a table of contents,
1092 # line by line, and then after doing page breaks we'll go back and
1093 # insert the page numbers into the contents entries.
1094 print "building contents...";
1095 @clnames = @cltypes = ();
1096 $clname = "pscont000000";
1097 @$clname = ("BnContents", "nContents"); # "chapter heading" for TOC
1098 push @clnames,$clname++;
1099 push @cltypes,"chap";
1100 for ($i=0; $i<=$#lnames; $i++) {
1101 $lname = $lnames[$i];
1102 if ($ltypes[$i] =~ /^(chap|head|subh)/) {
1104 splice @$clname,2,0," " if ($ltypes[$i] !~ /chap/);
1105 push @$clname,$i; # placeholder for page number
1106 push @clnames,$clname++;
1107 push @cltypes,"C" . substr($ltypes[$i],0,3);
1110 @$clname = ("BnIndex", "nIndex"); # contents entry for Index
1111 push @$clname,$i; # placeholder for page number
1112 $idx_clname = $clname;
1113 push @clnames,$clname++;
1114 push @cltypes,"Ccha";
1115 $contlen = $#clnames + 1;
1116 unshift @lnames,@clnames;
1117 unshift @ltypes,@cltypes;
1119 # Second stage: now we have a list of lines, break them into pages.
1120 # We do this by means of adding a third array in parallel with
1121 # @lnames and @ltypes, called @lpages, in which we store the page
1122 # number that each line resides on. We also add @ycoord which
1123 # stores the vertical position of each line on the page.
1125 # Page breaks may not come after line-types:
1126 # chap head subh cbeg nbeg bbeg
1127 # and may not come before line-types:
1129 # They are forced before line-types:
1131 print "page-breaks...";
1132 $pmax = 600; # ADJUSTABLE: maximum length of a page in points
1133 $textht = 11; # ADJUSTABLE: height of a normal line in points
1134 $spacing = 6; # ADJUSTABLE: space between paragraphs, in points
1135 $headht = 14; # ADJUSTABLE: height of a major heading in points
1136 $subht = 12; # ADJUSTABLE: height of a sub-heading in points
1137 $pstart = 0; # start line of current page
1138 $plen = 0; # current length of current page
1139 $pnum = 1; # number of current page
1140 $bpt = -1; # last feasible break point
1141 $i = 0; # line number
1142 while ($i <= $#lnames) {
1143 $lname = $lnames[$i];
1144 # Add the height of this line (computed the last time we went round
1145 # the loop, unless we're a chapter heading in which case we do it
1146 # now) to the length of the current page. Also, _put_ this line on
1147 # the current page, and allocate it a y-coordinate.
1148 if ($ltypes[$i] =~ /^chap$/) {
1149 $pnum += 1 - ($pnum & 1); # advance to odd numbered page if necessary
1150 $plen = 100; # ADJUSTABLE: space taken up by a chapter heading
1151 $ycoord[$i] = 0; # chapter heading: y-coord doesn't matter
1153 $ycoord[$i] = $plen + $space;
1154 $plen += $space + $ht;
1156 # See if we can break after this line.
1157 $bpt = $i if $ltypes[$i] !~ /^chap|head|subh|cbeg|nbeg|bbeg$/ &&
1158 $ltypes[$i+1] !~ /^cend|nend|bend$/;
1159 # Assume, to start with, that we don't break after this line.
1161 # See if a break is forced.
1162 $break = 1, $bpt = $i if $ltypes[$i+1] eq "chap" || !$ltypes[$i+1];
1163 # Otherwise, compute the height of the next line, and break if
1164 # it would make this page too long.
1165 $ht = $textht, $space = 0 if $ltypes[$i+1] =~ /^[nbc](bdy|end)$/;
1166 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^[nbc](one|beg)$/;
1167 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^C/;
1168 $ht = $subht, $space = $spacing if $ltypes[$i+1] eq "subh";
1169 $ht = $headht, $space = $spacing if $ltypes[$i+1] eq "head";
1170 $break = 1 if $plen + $space + $ht > $pmax;
1171 # Now, if we're breaking, assign page number $pnum to all lines up
1172 # to $bpt, set $i == $bpt+1, and zero $space since we are at the
1173 # start of a new page and don't want leading space.
1175 die "no feasible break point at all on page $pnum\n" if $bpt == -1;
1176 for ($j = $pstart; $j <= $bpt; $j++) {
1177 $lnamei = "idx" . $lnames[$j];
1178 foreach $k (@$lnamei) {
1179 ${$psidxpp{$k}}{$pnum} = 1;
1181 $lpages[$j] = $pnum;
1193 # Now fix up the TOC with page numbers.
1194 print "\n fixing up contents...";
1195 for ($i=0; $i<=$#lnames; $i++) {
1196 $lname = $lnames[$i];
1197 if ($ltypes[$i] =~ /^C/) {
1199 push @$lname, "n" . $lpages[$j+$contlen];
1203 # Having got page numbers for most stuff, generate an index.
1204 print "building index...";
1208 foreach $k (@itags) {
1211 @idxentry = @{$idxmap{$k}};
1212 if ($commaafter{$k} and !$commanext{$k}) {
1213 # This line is a null line beginning a multiple entry. We must
1214 # output the prefix on a line by itself.
1216 @idxhead = splice @idxentry,0,$commapos{$k};
1218 foreach $i (@idxhead) {
1220 push @line, $ww unless $ww eq "x";
1222 &ps_idxout("index",\@line,[]);
1226 $cmd = "iindex", splice @idxentry,0,$commapos{$k} if $commanext{$k};
1227 foreach $i (@idxentry) {
1229 push @line, $ww unless $ww eq "x";
1231 $len = $iwid - $sep - &len_ps(@line);
1232 warn "text for index tag `%s' is longer than one index line!\n"
1235 $inums = join(',',sort { $a <=> $b } keys %{$psidxpp{$k}});
1236 while (length $inums) {
1237 $inums =~ /^([^,]+)(,?)(.*)$/;
1238 $inums = $3, $inumc = $2; $inum = $1;
1239 @pnum = (" ", "Bp$inum", "n$inum", "E");
1240 push(@pnum, "n$inumc") if ( $inumc ne '' );
1241 $pnumlen = &len_ps(@pnum);
1242 if ($pnumlen > $len) {
1243 &ps_idxout($cmd,\@line,\@pp);
1247 $len = $iwid - $sep;
1252 &ps_idxout($cmd,\@line,\@pp) if (length @pp);
1253 $l1 = &len_ps(@line);
1256 $$idx_clname[$#$idx_clname] = "n" . $pnum; # fix up TOC entry for index
1258 print "writing file...";
1259 open PS,">nasmdoc.ps";
1263 &ps_write_bookmarks;
1264 for ($i=0; $i<=$#lnames; $i++) {
1265 &ps_throw_pg($page,$lpages[$i]) if $page != $lpages[$i];
1266 $page = $lpages[$i];
1267 &ps_out_line($ycoord[$i],$ltypes[$i],$lnames[$i]);
1270 while ($i <= $#psindex) {
1271 &ps_throw_pg($page, $pnum) if $page != $pnum;
1274 $ypos = 100, &ps_out_line(0, "chap", ["BnIndex", "nIndex"]) if !$i;
1275 $lines = ($pmax - $ypos) / $textht;
1276 my $col; # ps_out_line hits this variable
1277 PAGE:for ($col = 1; $col <= 2; $col++) {
1278 $y = $ypos; $l = $lines;
1279 COL: while ($l > 0) {
1281 $j++ while $psindex[$j] and ($psindex[$j][3] == 0); # find next break
1282 last COL if $j-$i > $l or $i > $#psindex;
1284 &ps_out_line($y, $psindex[$i][0] eq "index" ? "idl$col" : "ldl$col",
1286 &ps_out_line($y,"idr$col",$psindex[$i][2]);
1292 last PAGE if $i > $#psindex;
1301 my ($cmd, $left, $right) = @_;
1304 if ($#psindex >= 0) and ( ($#$left < 0) or ($cmd eq "iindex") );
1305 push @psindex,[$cmd,[@$left],[@$right],$break];
1311 /nf /Times-Roman findfont 11 scalefont def
1312 /ef /Times-Italic findfont 11 scalefont def
1313 /cf /Courier findfont 11 scalefont def
1314 /nc /Helvetica-Bold findfont 18 scalefont def
1315 /ec /Helvetica-Oblique findfont 18 scalefont def
1316 /cc /Courier-Bold findfont 18 scalefont def
1317 /nh /Helvetica-Bold findfont 14 scalefont def
1318 /eh /Helvetica-Oblique findfont 14 scalefont def
1319 /ch /Courier-Bold findfont 14 scalefont def
1320 /ns /Helvetica-Bold findfont 12 scalefont def
1321 /es /Helvetica-Oblique findfont 12 scalefont def
1322 /cs /Courier-Bold findfont 12 scalefont def
1323 /n 16#6E def /e 16#65 def /c 16#63 def
1324 /B 16#42 def /E 16#45 def /D 16#44 def
1325 /min { 2 copy gt { exch } if pop } def
1326 /max { 2 copy lt { exch } if pop } def
1335 /lktarget exch cvn def
1339 gsave dup true charpath pathbbox grestore
1347 lkury max /lkury exch def
1348 lkurx max /lkurx exch def
1349 lklly min /lklly exch def
1350 lkllx min /lkllx exch def
1356 [/Rect [ lkllx lklly lkurx lkury ]
1357 /Color [ 1.0 0.0 0.0 ]
1365 /lkdest exch cvn def
1367 /View [ /XYZ currentpoint 0 ]
1373 pop dup length 1 sub 1 exch getinterval linkbegin
1378 dup length 1 sub 1 exch getinterval linkdest
1383 550 50 moveto ns setfont dup stringwidth pop neg 0 rmoveto show
1385 /pageeven { 50 50 moveto ns setfont show } def
1387 dup length 1 sub 1 exch getinterval linkdest
1392 dup length 1 sub 1 exch getinterval
1395 dup n eq {pop nc setfont} {
1396 e eq {ec setfont} {cc setfont} ifelse
1398 dup length 1 sub 1 exch getinterval show
1400 0 setlinecap 3 setlinewidth
1401 newpath 100 610 moveto 468 0 rlineto stroke
1404 686 exch sub /y exch def /a exch def
1407 a 1 get dup length 1 sub 1 exch getinterval
1408 nh setfont dup stringwidth pop neg 0 rmoveto show
1410 a dup length 2 sub 2 exch getinterval {
1413 dup n eq {pop nh setfont} {
1414 e eq {eh setfont} {ch setfont} ifelse
1416 s s length 1 sub 1 exch getinterval show
1420 688 exch sub /y exch def /a exch def
1423 a 1 get dup length 1 sub 1 exch getinterval
1424 ns setfont dup stringwidth pop neg 0 rmoveto show
1426 a dup length 2 sub 2 exch getinterval {
1429 dup n eq {pop ns setfont} {
1430 e eq {es setfont} {cs setfont} ifelse
1432 s s length 1 sub 1 exch getinterval show
1436 568 exch sub exch 689 exch sub moveto
1443 dup n eq {pop nf setfont} {
1444 e eq {ef setfont} {cf setfont} ifelse
1446 s s length 1 sub 1 exch getinterval linkshow
1447 s sp eq {j 0 rmoveto} if
1451 /contents { /w exch def /y exch def /a exch def
1453 a a length 1 sub get dup length 1 sub 1 exch getinterval
1455 nf setfont 568 ss stringwidth pop sub /ex exch def
1456 a 0 a length 1 sub getinterval y w 0 disp
1457 /sx currentpoint pop def nf setfont
1458 100 10 568 { /i exch def
1459 i 5 sub sx gt i 5 add ex lt and {
1460 i yy moveto (.) linkshow
1463 ex yy moveto ss linkshow
1466 /just { /w exch def /y exch def /a exch def
1467 /jj w def /spaces 0 def
1471 dup n eq {pop nf setfont} {
1472 e eq {ef setfont} {cf setfont} ifelse
1474 s s length 1 sub 1 exch getinterval stringwidth pop
1475 jj exch sub /jj exch def
1476 s sp eq {/spaces spaces 1 add def} if
1478 a y w jj spaces spaces 0 eq {pop pop 0} {div} ifelse disp
1480 /idl { 468 exch sub 0 disp } def
1481 /ldl { 436 exch sub 0 disp } def
1482 /idr { 222 add 468 exch sub /x exch def /y exch def /a exch def
1489 dup n eq {pop nf setfont} {
1490 e eq {ef setfont} {cf setfont} ifelse
1492 s s length 1 sub 1 exch getinterval stringwidth pop
1500 nf setfont dup 100 exch 689 exch sub moveto (\267) show
1502 [/PageMode /UseOutlines /DOCVIEW pdfmark
1504 print "%!PS-Adobe-3.0\n";
1505 print "%%BoundingBox: 95 95 590 705\n";
1506 print "%%Creator: a nasty Perl script\n";
1507 print "%%DocumentData: Clean7Bit\n";
1508 print "%%Orientation: Portrait\n";
1509 print "%%Pages: $lpages[$#lpages]\n";
1510 print "%%DocumentNeededResources: font Times-Roman Times-Italic\n";
1511 print "%%+ font Helvetica-Bold Courier Courier-Bold\n";
1512 print "%%EndComments\n";
1513 print "%%BeginProlog\n";
1514 # This makes sure non-PDF PostScript interpreters don't choke on
1515 # pdfmarks in the output
1516 print "/pdfmark where\n";
1517 print "{pop} {userdict /pdfmark /cleartomark load put} ifelse\n";
1518 print "%%EndProlog\n";
1519 print "%%BeginSetup\n";
1521 $pshdr =~ s/\s+/ /g;
1522 while ($pshdr =~ /\S/) {
1523 last if length($pshdr) < 72 || $pshdr !~ /^(.{0,72}\S)\s(.*)$/;
1527 print "$pshdr\n" if $pshdr =~ /\S/;
1528 print "%%EndSetup\n";
1529 &ps_initpg($lpages[0]);
1535 print "%%Trailer\nrestore\n%%EOF\n";
1539 my ($oldpg, $newpg) = @_;
1540 while ($oldpg < $newpg) {
1549 print "%%Page: $pgnum $pgnum\n";
1550 print "%%BeginPageSetup\nsave\n%%EndPageSetup\n";
1551 print "95 705 moveto (p$pgnum) linkdest\n";
1557 print "%%PageTrailer\n($pgnum)pageodd restore showpage\n";
1559 print "%%PageTrailer\n($pgnum)pageeven restore showpage\n";
1564 my ($ypos,$ltype,$lname) = @_;
1569 foreach $c (@$lname) {#
1570 $c= "n " if $c eq " ";
1571 $c = "n\261" if $c eq "-";
1574 $d .= $1, $c = $2 while $c =~ /^([ -\'\*-\[\]-~]+)(.*)$/;
1576 $d .= "\\$1", $c = $2, next if $c =~ /^([\\\(\)])(.*)$/;
1577 ($d .= sprintf "\\%3o",unpack("C",$1)), $c = $2, next
1578 if $c =~ /^([^ -~])(.*)$/;
1583 $col = 0, print "\n" if $col>0 && $col+length $d > 77;
1587 print "\n" if $col > 60;
1589 if ($ltype =~ /^[nb](beg|bdy)$/) {
1590 printf "%d %s%d just\n",
1591 $ypos, ($ltype eq "bbeg" ? "bullet " : ""),
1592 ($ltype =~ /^b/ ? 456 : 468);
1593 } elsif ($ltype =~ /^[nb](one|end)$/) {
1594 printf "%d %s%d left\n",
1595 $ypos, ($ltype eq "bone" ? "bullet " : ""),
1596 ($ltype =~ /^b/ ? 456 : 468);
1597 } elsif ($ltype =~ /^c(one|beg|bdy|end)$/) {
1598 printf "$ypos 468 left\n";
1599 } elsif ($ltype =~ /^C/) {
1601 $wid = 456 if $ltype eq "Chea";
1602 $wid = 444 if $ltype eq "Csub";
1603 printf "$ypos $wid contents\n";
1604 } elsif ($ltype eq "chap") {
1606 } elsif ($ltype eq "head") {
1607 printf "$ypos heading\n";
1608 } elsif ($ltype eq "subh") {
1609 printf "$ypos subhead\n";
1610 } elsif ($ltype =~ /([il]d[lr])([12])/) {
1611 $left = ($2 eq "2" ? 468-222 : 0);
1612 printf "$ypos $left $1\n";
1620 return undef if $w eq '' || $w eq undef;
1622 $wtype = substr($w,0,2);
1623 $wmajt = substr($wtype,0,1);
1625 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1626 if ($wmajt eq "n" || $wtype eq "w ") {
1628 } elsif ($wtype eq "sp") {
1630 } elsif ($wtype eq "da") {
1632 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1634 } elsif ($wmajt eq "e") {
1636 } elsif ($wmajt eq "x") {
1638 } elsif ($wtype eq "i ") {
1642 die "panic in word_ps: $wtype$w\n";
1650 return undef if $w eq '' || $w eq undef;
1652 $wtype = substr($w,0,2);
1653 $wmajt = substr($wtype,0,1);
1655 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1656 if ($wmajt eq "n" || $wtype eq "w ") {
1658 } elsif ($wtype eq "sp") {
1660 } elsif ($wtype eq "da") {
1662 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1664 } elsif ($wmajt eq "e") {
1666 } elsif ($wmajt eq "x") {
1668 } elsif ($wtype eq "i ") {
1671 die "panic in word_ps_title: $wtype$w\n";
1680 $size = 11/1000; # used only for length calculations
1681 while ($w = shift @line) {
1682 $w = "n " if $w eq " ";
1683 $w = "n\261" if $w eq "-";
1684 $f = substr($w,0,1);
1685 if ( $f !~ /^[BDE]$/ ) {
1686 $f = "timesr" if $f eq "n";
1687 $f = "timesi" if $f eq "e";
1688 $f = "courr" if $f eq "c";
1689 foreach $c (unpack 'C*',substr($w,1)) {
1690 $l += $size * $$f[$c];
1698 # This is called from the top level, so I won't bother using
1702 print "writing file...";
1703 open TEXT,">nasmdoc.texi";
1707 print "\\input texinfo \@c -*-texinfo-*-\n";
1708 print "\@c \%**start of header\n";
1709 print "\@setfilename nasm.info\n";
1710 print "\@dircategory Programming\n";
1711 print "\@direntry\n";
1712 print "* NASM: (nasm). The Netwide Assembler for x86.\n";
1713 print "\@end direntry\n";
1714 print "\@settitle NASM: The Netwide Assembler\n";
1715 print "\@setchapternewpage odd\n";
1716 print "\@c \%**end of header\n";
1719 print "This file documents NASM, the Netwide Assembler: an assembler\n";
1720 print "targetting the Intel x86 series of processors, with portable source.\n";
1722 print "Copyright 1997 Simon Tatham\n";
1724 print "All rights reserved. This document is redistributable under the\n";
1725 print "licence given in the file \"Licence\" distributed in the NASM archive.\n";
1726 print "\@end ifinfo\n";
1728 print "\@titlepage\n";
1729 print "\@title NASM: The Netwide Assembler\n";
1730 print "\@author Simon Tatham\n";
1733 print "\@vskip 0pt plus 1filll\n";
1734 print "Copyright \@copyright{} 1997 Simon Tatham\n";
1736 print "All rights reserved. This document is redistributable under the\n";
1737 print "licence given in the file \"Licence\" distributed in the NASM archive.\n";
1738 print "\@end titlepage\n";
1740 print "\@node Top, $tstruct_next{'Top'}, (dir), (dir)\n";
1741 print "\@top Netwide Assembler\n";
1744 print "This file documents NASM, the Netwide Assembler: an assembler\n";
1745 print "targetting the Intel x86 series of processors, with portable source.\n";
1746 print "\@end ifinfo\n";
1751 for ($para = 0; $para <= $#pnames; $para++) {
1752 $pname = $pnames[$para];
1753 $pflags = $pflags[$para];
1754 $ptype = substr($pflags,0,4);
1756 $bulleting = 0, print "\@end itemize\n" if $bulleting && $ptype ne "bull";
1757 print "\n"; # always one of these before a new paragraph
1759 if ($ptype eq "chap") {
1760 # Chapter heading. Begin a new node.
1762 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1763 $pflags =~ /chap (.*) :(.*)/;
1764 $node = "Chapter $1";
1765 $title = "Chapter $1: ";
1766 foreach $i (@$pname) {
1767 $ww = &word_texi($i);
1768 $title .= $ww unless $ww eq "\001";
1770 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1771 print " $tstruct_up{$node}\n\@unnumbered $title\n";
1772 } elsif ($ptype eq "appn") {
1773 # Appendix heading. Begin a new node.
1775 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1776 $pflags =~ /appn (.*) :(.*)/;
1777 $node = "Appendix $1";
1778 $title = "Appendix $1: ";
1779 foreach $i (@$pname) {
1780 $ww = &word_texi($i);
1781 $title .= $ww unless $ww eq "\001";
1783 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1784 print " $tstruct_up{$node}\n\@unnumbered $title\n";
1785 } elsif ($ptype eq "head" || $ptype eq "subh") {
1786 # Heading or subheading. Begin a new node.
1788 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1789 $pflags =~ /.... (.*) :(.*)/;
1790 $node = "Section $1";
1792 foreach $i (@$pname) {
1793 $ww = &word_texi($i);
1794 $title .= $ww unless $ww eq "\001";
1796 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1797 print " $tstruct_up{$node}\n";
1798 $hdr = ($ptype eq "subh" ? "\@unnumberedsubsec" : "\@unnumberedsec");
1799 print "$hdr $title\n";
1800 } elsif ($ptype eq "code") {
1801 # Code paragraph. Surround with @example / @end example.
1802 print "\@example\n";
1803 foreach $i (@$pname) {
1804 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1810 print "\@end example\n";
1811 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1812 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1813 if ($ptype eq "bull") {
1814 $bulleting = 1, print "\@itemize \@bullet\n" if !$bulleting;
1821 do { $w = &word_texi(shift @a); } while $w eq "\001"; # hack
1823 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1824 if (length ($line . $wd) > 75) {
1825 $line =~ s/\s*$//; # trim trailing spaces
1828 $wd =~ s/^\s*//; # trim leading spaces
1834 } while ($w ne '' && $w ne undef);
1835 if ($line =~ /\S/) {
1836 $line =~ s/\s*$//; # trim trailing spaces
1846 print "\n\@contents\n\@bye\n";
1851 # Side effect of this procedure: update global `texiwdlen' to be the length
1852 # in chars of the formatted version of the word.
1857 return undef if $w eq '' || $w eq undef;
1858 $wtype = substr($w,0,2);
1859 $wmajt = substr($wtype,0,1);
1865 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1866 substr($w,0,1) =~ tr/a-z/A-Z/, $capital = 0 if $capital;
1867 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1870 } elsif ($wtype eq "sp") {
1873 } elsif ($wtype eq "da") {
1876 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1877 $texiwdlen = 2 + $wlen;
1878 return "\@code\{$w\}";
1879 } elsif ($wtype eq "es") {
1880 $texiwdlen = 1 + $wlen;
1881 return "\@emph\{${w}";
1882 } elsif ($wtype eq "ee") {
1883 $texiwdlen = 1 + $wlen;
1885 } elsif ($wtype eq "eo") {
1886 $texiwdlen = 2 + $wlen;
1887 return "\@emph\{${w}\}";
1888 } elsif ($wtype eq "x ") {
1889 $texiwdlen = 0; # we don't need it in this case
1890 $capital = 1; # hack
1892 } elsif ($wtype eq "xe") {
1893 $texiwdlen = 0; # we don't need it in this case
1895 } elsif ($wmajt eq "i") {
1896 $texiwdlen = 0; # we don't need it in this case
1899 die "panic in word_texi: $wtype$w\n";
1905 my $item, $i, $mpname, $title, $wd;
1907 $item = $tstruct_next{$topitem};
1911 $mpname = $tstruct_pname{$item};
1912 foreach $i (@$mpname) {
1913 $wd = &word_texi($i);
1914 $title .= $wd unless $wd eq "\001";
1916 print "* ${item}:: $title\n";
1917 $item = $tstruct_mnext{$item};
1919 print "* Index::\n" if $topitem eq "Top";
1920 print "\@end menu\n";
1924 my $itag, $ientry, @a, $wd, $item, $len;
1925 my $subnums = "123456789ABCDEFGHIJKLMNOPQRSTU" .
1926 "VWXYZabcdefghijklmnopqrstuvwxyz";
1928 print "\@ifinfo\n\@node Index, , $FIXMElastnode, Top\n";
1929 print "\@unnumbered Index\n\n\@menu\n";
1931 foreach $itag (@itags) {
1932 $ientry = $idxmap{$itag};
1937 $wd = &word_texi($i);
1938 $item .= $wd, $len += $texiwdlen unless $wd eq "\001";
1941 foreach $node (@nodes) {
1942 next if !$idxnodes{$node,$itag};
1943 printf "* %s%s (%s): %s.\n",
1944 $item, " " x (40-$len), substr($subnums,$i++,1), $node;
1947 print "\@end menu\n\@end ifinfo\n";
1951 # This is called from the top level, so I won't bother using
1954 # Build the index-tag text forms.
1955 print "building index entries...";
1958 my $ientry = $idxmap{$_};
1960 foreach $i (@$ientry) {
1961 $ww = &word_hlp($i,0);
1962 $title .= $ww unless $ww eq "\001";
1967 # Write the HPJ project-description file.
1968 print "writing .hpj file...";
1969 open HPJ,">nasmdoc.hpj";
1970 print HPJ "[OPTIONS]\ncompress=true\n";
1971 print HPJ "title=NASM: The Netwide Assembler\noldkeyphrase=no\n\n";
1972 print HPJ "[FILES]\nnasmdoc.rtf\n\n";
1973 print HPJ "[CONFIG]\n";
1974 print HPJ 'CreateButton("btn_up", "&Up",'.
1975 ' "JumpContents(`nasmdoc.hlp'."'".')")';
1976 print HPJ "\nBrowseButtons()\n";
1980 print "\n writing .rtf file...";
1981 open TEXT,">nasmdoc.rtf";
1985 print "{\\rtf1\\ansi{\\fonttbl\n";
1986 print "\\f0\\froman Times New Roman;\\f1\\fmodern Courier New;\n";
1987 print "\\f2\\fswiss Arial;\\f3\\ftech Wingdings}\\deff0\n";
1988 print "#{\\footnote Top}\n";
1989 print "\${\\footnote Contents}\n";
1990 print "+{\\footnote browse:00000}\n";
1991 print "!{\\footnote DisableButton(\"btn_up\")}\n";
1992 print "\\keepn\\f2\\b\\fs30\\sb0\n";
1993 print "NASM: The Netwide Assembler\n";
1994 print "\\par\\pard\\plain\\sb120\n";
1995 print "This file documents NASM, the Netwide Assembler: an assembler \n";
1996 print "targetting the Intel x86 series of processors, with portable source.\n";
2001 $newpar = "\\par\\sb120\n";
2002 for ($para = 0; $para <= $#pnames; $para++) {
2003 $pname = $pnames[$para];
2004 $pflags = $pflags[$para];
2005 $ptype = substr($pflags,0,4);
2008 $newpar = "\\par\\sb120\n";
2010 if ($ptype eq "chap") {
2011 # Chapter heading. Begin a new node.
2013 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
2014 $pflags =~ /chap (.*) :(.*)/;
2015 $node = "Chapter $1";
2016 $title = $footnotetitle = "Chapter $1: ";
2017 foreach $i (@$pname) {
2018 $ww = &word_hlp($i,1);
2019 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
2022 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
2023 print "\${\\footnote $footnotetitle}\n";
2024 printf "+{\\footnote browse:%05d}\n", ++$browse;
2025 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
2026 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
2027 &hlp_sectkw($tstruct_up{$node});
2028 print "EnableButton(\"btn_up\")}\n";
2029 &hlp_keywords($node);
2030 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
2032 $newpar = "\\par\\pard\\plain\\sb120\n";
2033 } elsif ($ptype eq "appn") {
2034 # Appendix heading. Begin a new node.
2036 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
2037 $pflags =~ /appn (.*) :(.*)/;
2038 $node = "Appendix $1";
2039 $title = $footnotetitle = "Appendix $1: ";
2040 foreach $i (@$pname) {
2041 $ww = &word_hlp($i,1);
2042 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
2045 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
2046 print "\${\\footnote $footnotetitle}\n";
2047 printf "+{\\footnote browse:%05d}\n", ++$browse;
2048 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
2049 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
2050 &hlp_sectkw($tstruct_up{$node});
2051 print "EnableButton(\"btn_up\")}\n";
2052 &hlp_keywords($node);
2053 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
2055 $newpar = "\\par\\pard\\plain\\sb120\n";
2056 } elsif ($ptype eq "head" || $ptype eq "subh") {
2057 # Heading or subheading. Begin a new node.
2059 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
2060 $pflags =~ /.... (.*) :(.*)/;
2061 $node = "Section $1";
2062 $title = $footnotetitle = "$1. ";
2063 foreach $i (@$pname) {
2064 $ww = &word_hlp($i,1);
2065 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
2068 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
2069 print "\${\\footnote $footnotetitle}\n";
2070 printf "+{\\footnote browse:%05d}\n", ++$browse;
2071 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
2072 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
2073 &hlp_sectkw($tstruct_up{$node});
2074 print "EnableButton(\"btn_up\")}\n";
2075 &hlp_keywords($node);
2076 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
2078 $newpar = "\\par\\pard\\plain\\sb120\n";
2079 } elsif ($ptype eq "code") {
2081 print "\\keep\\f1\\sb120\n";
2082 foreach $i (@$pname) {
2083 warn "code line longer than 68 chars: $i\n" if length $i > 68;
2087 print "$i\\par\\sb0\n";
2089 $newpar = "\\pard\\f0\\sb120\n";
2090 } elsif ($ptype eq "bull" || $ptype eq "norm") {
2091 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
2092 if ($ptype eq "bull") {
2093 print "\\tx360\\li360\\fi-360{\\f3\\'9F}\\tab\n";
2094 $newpar = "\\par\\pard\\sb120\n";
2096 $newpar = "\\par\\sb120\n";
2102 do { $w = &word_hlp((shift @a),1); } while $w eq "\001"; # hack
2104 if ($w eq ' ' || $w eq '' || $w eq undef) {
2105 if (length ($line . $wd) > 75) {
2106 $line =~ s/\s*$//; # trim trailing spaces
2107 print "$line \n"; # and put one back
2109 $wd =~ s/^\s*//; # trim leading spaces
2115 } while ($w ne '' && $w ne undef);
2116 if ($line =~ /\S/) {
2117 $line =~ s/\s*$//; # trim trailing spaces
2130 my ($w, $docode) = @_;
2133 return undef if $w eq '' || $w eq undef;
2134 $wtype = substr($w,0,2);
2135 $wmajt = substr($wtype,0,1);
2140 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
2141 substr($w,0,length($w)-1) =~ s/-/\\\'AD/g if $wmajt ne "x"; #nonbreakhyphens
2142 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
2144 } elsif ($wtype eq "sp") {
2146 } elsif ($wtype eq "da") {
2148 } elsif ($wmajt eq "c" || $wtype eq "wc") {
2149 $w =~ s/ /\\\'A0/g; # make spaces non-breaking
2150 return $docode ? "{\\f1 ${w}}" : $w;
2151 } elsif ($wtype eq "es") {
2153 } elsif ($wtype eq "ee") {
2155 } elsif ($wtype eq "eo") {
2156 return "{\\i ${w}}";
2157 } elsif ($wtype eq "x ") {
2159 } elsif ($wtype eq "xe") {
2160 $w = &hlp_sectkw($w);
2161 return "}{\\v ${w}}";
2162 } elsif ($wmajt eq "i") {
2165 die "panic in word_hlp: $wtype$w\n";
2171 my $item, $kword, $i, $mpname, $title;
2173 $item = $tstruct_next{$topitem};
2174 print "\\li360\\fi-360\n";
2177 $mpname = $tstruct_pname{$item};
2178 foreach $i (@$mpname) {
2179 $ww = &word_hlp($i, 0);
2180 $title .= $ww unless $ww eq "\001";
2182 $kword = &hlp_sectkw($item);
2183 print "{\\uldb ${item}: $title}{\\v $kword}\\par\\sb0\n";
2184 $item = $tstruct_mnext{$item};
2186 print "\\pard\\sb120\n";
2191 $node =~ tr/A-Z/a-z/;
2192 $node =~ tr/- ./___/;
2198 my $pfx = "K{\\footnote ";
2200 foreach $i (0..$#itags) {
2201 (print $pfx,$hlp_index[$i]), $pfx = ";\n", $done++
2202 if $idxnodes{$node,$itags[$i]};
2204 print "}\n" if $done;
2207 # Make tree structures. $tstruct_* is top-level and global.
2209 my ($item, $level) = @_;
2212 $tstruct_pname{$item} = $pname;
2213 $tstruct_next{$tstruct_previtem} = $item;
2214 $tstruct_prev{$item} = $tstruct_previtem;
2215 $tstruct_level{$item} = $level;
2216 $tstruct_up{$item} = $tstruct_last[$level-1];
2217 $tstruct_mnext{$tstruct_last[$level]} = $item;
2218 $tstruct_last[$level] = $item;
2219 for ($i=$level+1; $i<$MAXLEVEL; $i++) { $tstruct_last[$i] = undef; }
2220 $tstruct_previtem = $item;
2224 # PostScript font metric data. Used for line breaking.
2227 250, 0, 0, 0, 0, 0, 0, 0,
2228 0, 0, 0, 0, 0, 0, 0, 0,
2229 0, 0, 0, 0, 0, 0, 0, 0,
2230 0, 0, 0, 0, 0, 0, 0, 0,
2231 250, 333, 408, 500, 500, 833, 778, 333,
2232 333, 333, 500, 564, 250, 333, 250, 278,
2233 500, 500, 500, 500, 500, 500, 500, 500,
2234 500, 500, 278, 278, 564, 564, 564, 444,
2235 921, 722, 667, 667, 722, 611, 556, 722,
2236 722, 333, 389, 722, 611, 889, 722, 722,
2237 556, 722, 667, 556, 611, 722, 722, 944,
2238 722, 722, 611, 333, 278, 333, 469, 500,
2239 333, 444, 500, 444, 500, 444, 333, 500,
2240 500, 278, 278, 500, 278, 778, 500, 500,
2241 500, 500, 333, 389, 278, 500, 500, 722,
2242 500, 500, 444, 480, 200, 480, 541, 0,
2243 0, 0, 0, 0, 0, 0, 0, 0,
2244 0, 0, 0, 0, 0, 0, 0, 0,
2245 0, 0, 0, 0, 0, 0, 0, 0,
2246 0, 0, 0, 0, 0, 0, 0, 0,
2247 0, 333, 500, 500, 167, 500, 500, 500,
2248 500, 180, 444, 500, 333, 333, 556, 556,
2249 0, 500, 500, 500, 250, 0, 453, 350,
2250 333, 444, 444, 500,1000,1000, 0, 444,
2251 0, 333, 333, 333, 333, 333, 333, 333,
2252 333, 0, 333, 333, 0, 333, 333, 333,
2253 1000, 0, 0, 0, 0, 0, 0, 0,
2254 0, 0, 0, 0, 0, 0, 0, 0,
2255 0, 889, 0, 276, 0, 0, 0, 0,
2256 611, 722, 889, 310, 0, 0, 0, 0,
2257 0, 667, 0, 0, 0, 278, 0, 0,
2258 278, 500, 722, 500, 0, 0, 0, 0
2261 250, 0, 0, 0, 0, 0, 0, 0,
2262 0, 0, 0, 0, 0, 0, 0, 0,
2263 0, 0, 0, 0, 0, 0, 0, 0,
2264 0, 0, 0, 0, 0, 0, 0, 0,
2265 250, 333, 420, 500, 500, 833, 778, 333,
2266 333, 333, 500, 675, 250, 333, 250, 278,
2267 500, 500, 500, 500, 500, 500, 500, 500,
2268 500, 500, 333, 333, 675, 675, 675, 500,
2269 920, 611, 611, 667, 722, 611, 611, 722,
2270 722, 333, 444, 667, 556, 833, 667, 722,
2271 611, 722, 611, 500, 556, 722, 611, 833,
2272 611, 556, 556, 389, 278, 389, 422, 500,
2273 333, 500, 500, 444, 500, 444, 278, 500,
2274 500, 278, 278, 444, 278, 722, 500, 500,
2275 500, 500, 389, 389, 278, 500, 444, 667,
2276 444, 444, 389, 400, 275, 400, 541, 0,
2277 0, 0, 0, 0, 0, 0, 0, 0,
2278 0, 0, 0, 0, 0, 0, 0, 0,
2279 0, 0, 0, 0, 0, 0, 0, 0,
2280 0, 0, 0, 0, 0, 0, 0, 0,
2281 0, 389, 500, 500, 167, 500, 500, 500,
2282 500, 214, 556, 500, 333, 333, 500, 500,
2283 0, 500, 500, 500, 250, 0, 523, 350,
2284 333, 556, 556, 500, 889,1000, 0, 500,
2285 0, 333, 333, 333, 333, 333, 333, 333,
2286 333, 0, 333, 333, 0, 333, 333, 333,
2287 889, 0, 0, 0, 0, 0, 0, 0,
2288 0, 0, 0, 0, 0, 0, 0, 0,
2289 0, 889, 0, 276, 0, 0, 0, 0,
2290 556, 722, 944, 310, 0, 0, 0, 0,
2291 0, 667, 0, 0, 0, 278, 0, 0,
2292 278, 500, 667, 500, 0, 0, 0, 0
2295 600, 0, 0, 0, 0, 0, 0, 0,
2296 0, 0, 0, 0, 0, 0, 0, 0,
2297 0, 0, 0, 0, 0, 0, 0, 0,
2298 0, 0, 0, 0, 0, 0, 0, 0,
2299 600, 600, 600, 600, 600, 600, 600, 600,
2300 600, 600, 600, 600, 600, 600, 600, 600,
2301 600, 600, 600, 600, 600, 600, 600, 600,
2302 600, 600, 600, 600, 600, 600, 600, 600,
2303 600, 600, 600, 600, 600, 600, 600, 600,
2304 600, 600, 600, 600, 600, 600, 600, 600,
2305 600, 600, 600, 600, 600, 600, 600, 600,
2306 600, 600, 600, 600, 600, 600, 600, 600,
2307 600, 600, 600, 600, 600, 600, 600, 600,
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, 0,
2311 0, 0, 0, 0, 0, 0, 0, 0,
2312 0, 0, 0, 0, 0, 0, 0, 0,
2313 0, 0, 0, 0, 0, 0, 0, 0,
2314 0, 0, 0, 0, 0, 0, 0, 0,
2315 0, 600, 600, 600, 600, 600, 600, 600,
2316 600, 600, 600, 600, 600, 600, 600, 600,
2317 0, 600, 600, 600, 600, 0, 600, 600,
2318 600, 600, 600, 600, 600, 600, 0, 600,
2319 0, 600, 600, 600, 600, 600, 600, 600,
2320 600, 0, 600, 600, 0, 600, 600, 600,
2321 600, 0, 0, 0, 0, 0, 0, 0,
2322 0, 0, 0, 0, 0, 0, 0, 0,
2323 0, 600, 0, 600, 0, 0, 0, 0,
2324 600, 600, 600, 600, 0, 0, 0, 0,
2325 0, 600, 0, 0, 0, 600, 0, 0,
2326 600, 600, 600, 600, 0, 0, 0, 0