doc: document packed BCD constants
[nasm.git] / doc / rdsrc.pl
blobc4069b1e843f433d252d9ea8a4dfb27f4a1cdf60
1 #!/usr/bin/perl
3 # Read the source-form of the NASM manual and generate the various
4 # output forms.
6 # TODO:
8 # Ellipsis support would be nice.
10 # Source-form features:
11 # ---------------------
13 # Bullet \b
14 # Bullets the paragraph. Rest of paragraph is indented to cope. In
15 # HTML, consecutive groups of bulleted paragraphs become unordered
16 # lists.
18 # Emphasis \e{foobar}
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
24 # Display code
25 # \c line one
26 # \c line two
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
42 # hyperlinks.
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.
48 # Literals \{ \} \\
49 # In case it's necessary, they expand to the real versions.
51 # Nonbreaking hyphen \-
52 # Need more be said?
54 # Source comment \#
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
66 # Index rewrite
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
71 # Index alias
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 # Metadata
78 # \M{key}{something}
79 # defines document metadata, such as authorship, title and copyright;
80 # different output formats use this differently.
82 # Include subfile
83 # \&{filename}
84 # Includes filename. Recursion is allowed.
87 use IO::File;
89 $diag = 1, shift @ARGV if $ARGV[0] eq "-d";
91 ($out_format) = @ARGV;
93 $| = 1;
95 $tstruct_previtem = $node = "Top";
96 $nodes = ($node);
97 $tstruct_level{$tstruct_previtem} = 0;
98 $tstruct_last[$tstruct_level{$tstruct_previtem}] = $tstruct_previtem;
99 $MAXLEVEL = 10; # really 3, but play safe ;-)
101 # Read the file; pass a paragraph at a time to the paragraph processor.
102 print "Reading input...";
103 $pname = "para000000";
104 @pnames = @pflags = ();
105 $para = undef;
106 while (defined($_ = <STDIN>)) {
107 &check_include($_);
109 &got_para($para);
110 print "done.\n";
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...";
115 &fixup_xrefs;
116 print "done.\n";
118 # Sort the index tags, according to the slightly odd order I've decided on.
119 print "Sorting index tags...";
120 &indexsort;
121 print "done.\n";
123 if ($diag) {
124 print "Writing index-diagnostic file...";
125 &indexdiag;
126 print "done.\n";
129 # OK. Write out the various output files.
130 if ($out_format eq 'txt') {
131 print "Producing text output: ";
132 &write_txt;
133 print "done.\n";
134 } elsif ($out_format eq 'html') {
135 print "Producing HTML output: ";
136 &write_html;
137 print "done.\n";
138 } elsif ($out_format eq 'texi') {
139 print "Producing Texinfo output: ";
140 &write_texi;
141 print "done.\n";
142 } elsif ($out_format eq 'hlp') {
143 print "Producing WinHelp output: ";
144 &write_hlp;
145 print "done.\n";
146 } elsif ($out_format eq 'dip') {
147 print "Producing Documentation Intermediate Paragraphs: ";
148 &write_dip;
149 print "done.\n";
150 } else {
151 die "$0: unknown output format: $out_format\n";
154 sub check_include {
155 local $_ = shift;
156 if (/\\& (\S+)/) {
157 &include($1);
158 } else {
159 &get_para($_);
162 sub get_para($_) {
163 chomp;
164 if (!/\S/ || /^\\(IA|IR|M)/) { # special case: \IA \IR \M imply new-paragraph
165 &got_para($para);
166 $para = undef;
168 if (/\S/) {
169 s/\\#.*$//; # strip comments
170 $para .= " " . $_;
173 sub include {
174 my $name = shift;
175 my $F = IO::File->new($name)
176 or die "Cannot open $name: $!";
177 while (<$F>) {
178 &check_include($_);
181 sub got_para {
182 local ($_) = @_;
183 my $pflags = "", $i, $w, $l, $t;
184 return if !/\S/;
186 @$pname = ();
188 # Strip off _leading_ spaces, then determine type of paragraph.
189 s/^\s*//;
190 $irewrite = undef;
191 if (/^\\c[^{]/) {
192 # A code paragraph. The paragraph-array will contain the simple
193 # strings which form each line of the paragraph.
194 $pflags = "code";
195 while (/^\\c (([^\\]|\\[^c])*)(.*)$/) {
196 $l = $1;
197 $_ = $3;
198 $l =~ s/\\{/{/g;
199 $l =~ s/\\}/}/g;
200 $l =~ s/\\\\/\\/g;
201 push @$pname, $l;
203 $_ = ''; # suppress word-by-word code
204 } elsif (/^\\C/) {
205 # A chapter heading. Define the keyword and allocate a chapter
206 # number.
207 $cnum++;
208 $hnum = 0;
209 $snum = 0;
210 $xref = "chapter-$cnum";
211 $pflags = "chap $cnum :$xref";
212 die "badly formatted chapter heading: $_\n" if !/^\\C{([^}]*)}\s*(.*)$/;
213 $refs{$1} = "chapter $cnum";
214 $node = "Chapter $cnum";
215 &add_item($node, 1);
216 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
217 $xrefs{$1} = $xref;
218 $_ = $2;
219 # the standard word-by-word code will happen next
220 } elsif (/^\\A/) {
221 # An appendix heading. Define the keyword and allocate an appendix
222 # letter.
223 $cnum++;
224 $cnum = 'A' if $cnum =~ /[0-9]+/;
225 $hnum = 0;
226 $snum = 0;
227 $xref = "appendix-$cnum";
228 $pflags = "appn $cnum :$xref";
229 die "badly formatted appendix heading: $_\n" if !/^\\A{([^}]*)}\s*(.*)$/;
230 $refs{$1} = "appendix $cnum";
231 $node = "Appendix $cnum";
232 &add_item($node, 1);
233 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
234 $xrefs{$1} = $xref;
235 $_ = $2;
236 # the standard word-by-word code will happen next
237 } elsif (/^\\H/) {
238 # A major heading. Define the keyword and allocate a section number.
239 $hnum++;
240 $snum = 0;
241 $xref = "section-$cnum.$hnum";
242 $pflags = "head $cnum.$hnum :$xref";
243 die "badly formatted heading: $_\n" if !/^\\[HP]{([^}]*)}\s*(.*)$/;
244 $refs{$1} = "section $cnum.$hnum";
245 $node = "Section $cnum.$hnum";
246 &add_item($node, 2);
247 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
248 $xrefs{$1} = $xref;
249 $_ = $2;
250 # the standard word-by-word code will happen next
251 } elsif (/^\\S/) {
252 # A sub-heading. Define the keyword and allocate a section number.
253 $snum++;
254 $xref = "section-$cnum.$hnum.$snum";
255 $pflags = "subh $cnum.$hnum.$snum :$xref";
256 die "badly formatted subheading: $_\n" if !/^\\S{([^}]*)}\s*(.*)$/;
257 $refs{$1} = "section $cnum.$hnum.$snum";
258 $node = "Section $cnum.$hnum.$snum";
259 &add_item($node, 3);
260 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
261 $xrefs{$1} = $xref;
262 $_ = $2;
263 # the standard word-by-word code will happen next
264 } elsif (/^\\IR/) {
265 # An index-rewrite.
266 die "badly formatted index rewrite: $_\n" if !/^\\IR{([^}]*)}\s*(.*)$/;
267 $irewrite = $1;
268 $_ = $2;
269 # the standard word-by-word code will happen next
270 } elsif (/^\\IA/) {
271 # An index-alias.
272 die "badly formatted index alias: $_\n" if !/^\\IA{([^}]*)}{([^}]*)}\s*$/;
273 $idxalias{$1} = $2;
274 return; # avoid word-by-word code
275 } elsif (/^\\M/) {
276 # Metadata
277 die "badly formed metadata: $_\n" if !/^\\M{([^}]*)}{([^}]*)}\s*$/;
278 $metadata{$1} = $2;
279 return; # avoid word-by-word code
280 } elsif (/^\\b/) {
281 # A bulleted paragraph. Strip off the initial \b and let the
282 # word-by-word code take care of the rest.
283 $pflags = "bull";
284 s/^\\b\s*//;
285 } else {
286 # A normal paragraph. Just set $pflags: the word-by-word code does
287 # the rest.
288 $pflags = "norm";
291 # The word-by-word code: unless @$pname is already defined (which it
292 # will be in the case of a code paragraph), split the paragraph up
293 # into words and push each on @$pname.
295 # Each thing pushed on @$pname should have a two-character type
296 # code followed by the text.
298 # Type codes are:
299 # "n " for normal
300 # "da" for a dash
301 # "es" for first emphasised word in emphasised bit
302 # "e " for emphasised in mid-emphasised-bit
303 # "ee" for last emphasised word in emphasised bit
304 # "eo" for single (only) emphasised word
305 # "c " for code
306 # "k " for cross-ref
307 # "kK" for capitalised cross-ref
308 # "w " for Web link
309 # "wc" for code-type Web link
310 # "x " for beginning of resolved cross-ref; generates no visible output,
311 # and the text is the cross-reference code
312 # "xe" for end of resolved cross-ref; text is same as for "x ".
313 # "i " for point to be indexed: the text is the internal index into the
314 # index-items arrays
315 # "sp" for space
316 while (/\S/) {
317 s/^\s*//, push @$pname, "sp" if /^\s/;
318 $indexing = $qindex = 0;
319 if (/^(\\[iI])?\\c/) {
320 $qindex = 1 if $1 eq "\\I";
321 $indexing = 1, s/^\\[iI]// if $1;
322 s/^\\c//;
323 die "badly formatted \\c: \\c$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
324 $w = $1;
325 $_ = $3;
326 $w =~ s/\\{/{/g;
327 $w =~ s/\\}/}/g;
328 $w =~ s/\\-/-/g;
329 $w =~ s/\\\\/\\/g;
330 (push @$pname,"i"),$lastp = $#$pname if $indexing;
331 push @$pname,"c $w" if !$qindex;
332 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
333 } elsif (/^\\[iIe]/) {
334 /^(\\[iI])?(\\e)?/;
335 $emph = 0;
336 $qindex = 1 if $1 eq "\\I";
337 $indexing = 1, $type = "\\i" if $1;
338 $emph = 1, $type = "\\e" if $2;
339 s/^(\\[iI])?(\\e?)//;
340 die "badly formatted $type: $type$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
341 $w = $1;
342 $_ = $3;
343 $w =~ s/\\{/{/g;
344 $w =~ s/\\}/}/g;
345 $w =~ s/\\-/-/g;
346 $w =~ s/\\\\/\\/g;
347 $t = $emph ? "es" : "n ";
348 @ientry = ();
349 (push @$pname,"i"),$lastp = $#$pname if $indexing;
350 foreach $i (split /\s+/,$w) { # \e and \i can be multiple words
351 push @$pname,"$t$i","sp" if !$qindex;
352 ($ii=$i) =~ tr/A-Z/a-z/, push @ientry,"n $ii","sp" if $indexing;
353 $t = $emph ? "e " : "n ";
355 $w =~ tr/A-Z/a-z/, pop @ientry if $indexing;
356 $$pname[$lastp] = &addidx($node, $w, @ientry) if $indexing;
357 pop @$pname if !$qindex; # remove final space
358 if (substr($$pname[$#$pname],0,2) eq "es" && !$qindex) {
359 substr($$pname[$#$pname],0,2) = "eo";
360 } elsif ($emph && !$qindex) {
361 substr($$pname[$#$pname],0,2) = "ee";
363 } elsif (/^\\[kK]/) {
364 $t = "k ";
365 $t = "kK" if /^\\K/;
366 s/^\\[kK]//;
367 die "badly formatted \\k: \\c$_\n" if !/{([^}]*)}(.*)$/;
368 $_ = $2;
369 push @$pname,"$t$1";
370 } elsif (/^\\W/) {
371 s/^\\W//;
372 die "badly formatted \\W: \\W$_\n"
373 if !/{([^}]*)}(\\i)?(\\c)?{(([^\\}]|\\.)*)}(.*)$/;
374 $l = $1;
375 $w = $4;
376 $_ = $6;
377 $t = "w ";
378 $t = "wc" if $3 eq "\\c";
379 $indexing = 1 if $2;
380 $w =~ s/\\{/{/g;
381 $w =~ s/\\}/}/g;
382 $w =~ s/\\-/-/g;
383 $w =~ s/\\\\/\\/g;
384 (push @$pname,"i"),$lastp = $#$pname if $indexing;
385 push @$pname,"$t<$l>$w";
386 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
387 } else {
388 die "what the hell? $_\n" if !/^(([^\s\\\-]|\\[\\{}\-])*-?)(.*)$/;
389 die "painful death! $_\n" if !length $1;
390 $w = $1;
391 $_ = $3;
392 $w =~ s/\\{/{/g;
393 $w =~ s/\\}/}/g;
394 $w =~ s/\\-/-/g;
395 $w =~ s/\\\\/\\/g;
396 if ($w eq "-") {
397 push @$pname,"da";
398 } else {
399 push @$pname,"n $w";
403 if ($irewrite ne undef) {
404 &addidx(undef, $irewrite, @$pname);
405 @$pname = ();
406 } else {
407 push @pnames, $pname;
408 push @pflags, $pflags;
409 $pname++;
413 sub addidx {
414 my ($node, $text, @ientry) = @_;
415 $text = $idxalias{$text} || $text;
416 if ($node eq undef || !$idxmap{$text}) {
417 @$ientry = @ientry;
418 $idxmap{$text} = $ientry;
419 $ientry++;
421 if ($node) {
422 $idxnodes{$node,$text} = 1;
423 return "i $text";
427 sub indexsort {
428 my $iitem, $ientry, $i, $piitem, $pcval, $cval, $clrcval;
430 @itags = map { # get back the original data as the 1st elt of each list
431 $_->[0]
432 } sort { # compare auxiliary (non-first) elements of lists
433 $a->[1] cmp $b->[1] ||
434 $a->[2] cmp $b->[2] ||
435 $a->[0] cmp $b->[0]
436 } map { # transform array into list of 3-element lists
437 my $ientry = $idxmap{$_};
438 my $a = substr($$ientry[0],2);
439 $a =~ tr/A-Za-z0-9//cd;
440 [$_, uc($a), substr($$ientry[0],0,2)]
441 } keys %idxmap;
443 # Having done that, check for comma-hood.
444 $cval = 0;
445 foreach $iitem (@itags) {
446 $ientry = $idxmap{$iitem};
447 $clrcval = 1;
448 $pcval = $cval;
449 FL:for ($i=0; $i <= $#$ientry; $i++) {
450 if ($$ientry[$i] =~ /^(n .*,)(.*)/) {
451 $$ientry[$i] = $1;
452 splice @$ientry,$i+1,0,"n $2" if length $2;
453 $commapos{$iitem} = $i+1;
454 $cval = join("\002", @$ientry[0..$i]);
455 $clrcval = 0;
456 last FL;
459 $cval = undef if $clrcval;
460 $commanext{$iitem} = $commaafter{$piitem} = 1
461 if $cval and ($cval eq $pcval);
462 $piitem = $iitem;
466 sub indexdiag {
467 my $iitem,$ientry,$w,$ww,$foo,$node;
468 open INDEXDIAG,">index.diag";
469 foreach $iitem (@itags) {
470 $ientry = $idxmap{$iitem};
471 print INDEXDIAG "<$iitem> ";
472 foreach $w (@$ientry) {
473 $ww = &word_txt($w);
474 print INDEXDIAG $ww unless $ww eq "\001";
476 print INDEXDIAG ":";
477 $foo = " ";
478 foreach $node (@nodes) {
479 (print INDEXDIAG $foo,$node), $foo = ", " if $idxnodes{$node,$iitem};
481 print INDEXDIAG "\n";
483 close INDEXDIAG;
486 sub fixup_xrefs {
487 my $pname, $p, $i, $j, $k, $caps, @repl;
489 for ($p=0; $p<=$#pnames; $p++) {
490 next if $pflags[$p] eq "code";
491 $pname = $pnames[$p];
492 for ($i=$#$pname; $i >= 0; $i--) {
493 if ($$pname[$i] =~ /^k/) {
494 $k = $$pname[$i];
495 $caps = ($k =~ /^kK/);
496 $k = substr($k,2);
497 $repl = $refs{$k};
498 die "undefined keyword `$k'\n" unless $repl;
499 substr($repl,0,1) =~ tr/a-z/A-Z/ if $caps;
500 @repl = ();
501 push @repl,"x $xrefs{$k}";
502 foreach $j (split /\s+/,$repl) {
503 push @repl,"n $j";
504 push @repl,"sp";
506 pop @repl; # remove final space
507 push @repl,"xe$xrefs{$k}";
508 splice @$pname,$i,1,@repl;
514 sub write_txt {
515 # This is called from the top level, so I won't bother using
516 # my or local.
518 # Open file.
519 print "writing file...";
520 open TEXT,">nasmdoc.txt";
521 select TEXT;
523 # Preamble.
524 $title = "The Netwide Assembler: NASM";
525 $spaces = ' ' x ((75-(length $title))/2);
526 ($underscore = $title) =~ s/./=/g;
527 print "$spaces$title\n$spaces$underscore\n";
529 for ($para = 0; $para <= $#pnames; $para++) {
530 $pname = $pnames[$para];
531 $pflags = $pflags[$para];
532 $ptype = substr($pflags,0,4);
534 print "\n"; # always one of these before a new paragraph
536 if ($ptype eq "chap") {
537 # Chapter heading. "Chapter N: Title" followed by a line of
538 # minus signs.
539 $pflags =~ /chap (.*) :(.*)/;
540 $title = "Chapter $1: ";
541 foreach $i (@$pname) {
542 $ww = &word_txt($i);
543 $title .= $ww unless $ww eq "\001";
545 print "$title\n";
546 $title =~ s/./-/g;
547 print "$title\n";
548 } elsif ($ptype eq "appn") {
549 # Appendix heading. "Appendix N: Title" followed by a line of
550 # minus signs.
551 $pflags =~ /appn (.*) :(.*)/;
552 $title = "Appendix $1: ";
553 foreach $i (@$pname) {
554 $ww = &word_txt($i);
555 $title .= $ww unless $ww eq "\001";
557 print "$title\n";
558 $title =~ s/./-/g;
559 print "$title\n";
560 } elsif ($ptype eq "head" || $ptype eq "subh") {
561 # Heading or subheading. Just a number and some text.
562 $pflags =~ /.... (.*) :(.*)/;
563 $title = sprintf "%6s ", $1;
564 foreach $i (@$pname) {
565 $ww = &word_txt($i);
566 $title .= $ww unless $ww eq "\001";
568 print "$title\n";
569 } elsif ($ptype eq "code") {
570 # Code paragraph. Emit each line with a seven character indent.
571 foreach $i (@$pname) {
572 warn "code line longer than 68 chars: $i\n" if length $i > 68;
573 print ' 'x7, $i, "\n";
575 } elsif ($ptype eq "bull" || $ptype eq "norm") {
576 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
577 # 75-char right margin and either 7 or 11 char left margin
578 # depending on bullets.
579 if ($ptype eq "bull") {
580 $line = ' 'x7 . '(*) ';
581 $next = ' 'x11;
582 } else {
583 $line = $next = ' 'x7;
585 @a = @$pname;
586 $wd = $wprev = '';
587 do {
588 do { $w = &word_txt(shift @a) } while $w eq "\001"; # nasty hack
589 $wd .= $wprev;
590 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
591 if (length ($line . $wd) > 75) {
592 $line =~ s/\s*$//; # trim trailing spaces
593 print "$line\n";
594 $line = $next;
595 $wd =~ s/^\s*//; # trim leading spaces
597 $line .= $wd;
598 $wd = '';
600 $wprev = $w;
601 } while ($w ne '' && $w ne undef);
602 if ($line =~ /\S/) {
603 $line =~ s/\s*$//; # trim trailing spaces
604 print "$line\n";
609 # Close file.
610 select STDOUT;
611 close TEXT;
614 sub word_txt {
615 my ($w) = @_;
616 my $wtype, $wmajt;
618 return undef if $w eq '' || $w eq undef;
619 $wtype = substr($w,0,2);
620 $wmajt = substr($wtype,0,1);
621 $w = substr($w,2);
622 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
623 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
624 return $w;
625 } elsif ($wtype eq "sp") {
626 return ' ';
627 } elsif ($wtype eq "da") {
628 return '-';
629 } elsif ($wmajt eq "c" || $wtype eq "wc") {
630 return "`${w}'";
631 } elsif ($wtype eq "es") {
632 return "_${w}";
633 } elsif ($wtype eq "ee") {
634 return "${w}_";
635 } elsif ($wtype eq "eo") {
636 return "_${w}_";
637 } elsif ($wmajt eq "x" || $wmajt eq "i") {
638 return "\001";
639 } else {
640 die "panic in word_txt: $wtype$w\n";
644 sub write_html {
645 # This is called from the top level, so I won't bother using
646 # my or local.
648 # Write contents file. Just the preamble, then a menu of links to the
649 # separate chapter files and the nodes therein.
650 print "writing contents file...";
651 open TEXT,">nasmdoc0.html";
652 select TEXT;
653 &html_preamble(0);
654 print "<p>This manual documents NASM, the Netwide Assembler: an assembler\n";
655 print "targetting the Intel x86 series of processors, with portable source.\n";
656 print "<p>";
657 for ($node = $tstruct_next{'Top'}; $node; $node = $tstruct_next{$node}) {
658 if ($tstruct_level{$node} == 1) {
659 # Invent a file name.
660 ($number = lc($xrefnodes{$node})) =~ s/.*-//;
661 $fname="nasmdocx.html";
662 substr($fname,8 - length $number, length $number) = $number;
663 $html_fnames{$node} = $fname;
664 $link = $fname;
665 print "<p>";
666 } else {
667 # Use the preceding filename plus a marker point.
668 $link = $fname . "#$xrefnodes{$node}";
670 $title = "$node: ";
671 $pname = $tstruct_pname{$node};
672 foreach $i (@$pname) {
673 $ww = &word_html($i);
674 $title .= $ww unless $ww eq "\001";
676 print "<a href=\"$link\">$title</a><br>\n";
678 print "<p><a href=\"nasmdoci.html\">Index</a>\n";
679 print "</body></html>\n";
680 select STDOUT;
681 close TEXT;
683 # Open a null file, to ensure output (eg random &html_jumppoints calls)
684 # goes _somewhere_.
685 print "writing chapter files...";
686 open TEXT,">/dev/null";
687 select TEXT;
688 $html_lastf = '';
690 $in_list = 0;
692 for ($para = 0; $para <= $#pnames; $para++) {
693 $pname = $pnames[$para];
694 $pflags = $pflags[$para];
695 $ptype = substr($pflags,0,4);
697 $in_list = 0, print "</ul>\n" if $in_list && $ptype ne "bull";
698 if ($ptype eq "chap") {
699 # Chapter heading. Begin a new file.
700 $pflags =~ /chap (.*) :(.*)/;
701 $title = "Chapter $1: ";
702 $xref = $2;
703 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
704 $html_lastf = $html_fnames{$chapternode};
705 $chapternode = $nodexrefs{$xref};
706 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
707 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
708 foreach $i (@$pname) {
709 $ww = &word_html($i);
710 $title .= $ww unless $ww eq "\001";
712 $h = "<h2><a name=\"$xref\">$title</a></h2>\n";
713 print $h; print FULL $h;
714 } elsif ($ptype eq "appn") {
715 # Appendix heading. Begin a new file.
716 $pflags =~ /appn (.*) :(.*)/;
717 $title = "Appendix $1: ";
718 $xref = $2;
719 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
720 $html_lastf = $html_fnames{$chapternode};
721 $chapternode = $nodexrefs{$xref};
722 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
723 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
724 foreach $i (@$pname) {
725 $ww = &word_html($i);
726 $title .= $ww unless $ww eq "\001";
728 print "<h2><a name=\"$xref\">$title</a></h2>\n";
729 } elsif ($ptype eq "head" || $ptype eq "subh") {
730 # Heading or subheading.
731 $pflags =~ /.... (.*) :(.*)/;
732 $hdr = ($ptype eq "subh" ? "h4" : "h3");
733 $title = $1 . " ";
734 $xref = $2;
735 foreach $i (@$pname) {
736 $ww = &word_html($i);
737 $title .= $ww unless $ww eq "\001";
739 print "<$hdr><a name=\"$xref\">$title</a></$hdr>\n";
740 } elsif ($ptype eq "code") {
741 # Code paragraph.
742 print "<p><pre>\n";
743 foreach $i (@$pname) {
744 $w = $i;
745 $w =~ s/&/&amp;/g;
746 $w =~ s/</&lt;/g;
747 $w =~ s/>/&gt;/g;
748 print $w, "\n";
750 print "</pre>\n";
751 } elsif ($ptype eq "bull" || $ptype eq "norm") {
752 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
753 # 75-char right margin and either 7 or 11 char left margin
754 # depending on bullets.
755 if ($ptype eq "bull") {
756 $in_list = 1, print "<ul>\n" unless $in_list;
757 $line = '<li>';
758 } else {
759 $line = '<p>';
761 @a = @$pname;
762 $wd = $wprev = '';
763 do {
764 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
765 $wd .= $wprev;
766 if ($w eq ' ' || $w eq '' || $w eq undef) {
767 if (length ($line . $wd) > 75) {
768 $line =~ s/\s*$//; # trim trailing spaces
769 print "$line\n";
770 $line = '';
771 $wd =~ s/^\s*//; # trim leading spaces
773 $line .= $wd;
774 $wd = '';
776 $wprev = $w;
777 } while ($w ne '' && $w ne undef);
778 if ($line =~ /\S/) {
779 $line =~ s/\s*$//; # trim trailing spaces
780 print "$line\n";
785 # Close whichever file was open.
786 &html_jumppoints;
787 print "</body></html>\n";
788 select STDOUT;
789 close TEXT;
791 print "\n writing index file...";
792 open TEXT,">nasmdoci.html";
793 select TEXT;
794 &html_preamble(0);
795 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
796 print "<p>";
797 &html_index;
798 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
799 print "</body></html>\n";
800 select STDOUT;
801 close TEXT;
804 sub html_preamble {
805 print "<html><head><title>NASM Manual</title></head>\n";
806 print "<body><h1 align=center>The Netwide Assembler: NASM</h1>\n\n";
807 &html_jumppoints if $_[0];
810 sub html_jumppoints {
811 print "<p align=center>";
812 print "<a href=\"$html_nextf\">Next Chapter</a> |\n" if $html_nextf;
813 print "<a href=\"$html_lastf\">Previous Chapter</a> |\n" if $html_lastf;
814 print "<a href=\"nasmdoc0.html\">Contents</a> |\n";
815 print "<a href=\"nasmdoci.html\">Index</a>\n";
818 sub html_index {
819 my $itag, $a, @ientry, $sep, $w, $wd, $wprev, $line;
821 $chapternode = '';
822 foreach $itag (@itags) {
823 $ientry = $idxmap{$itag};
824 @a = @$ientry;
825 push @a, "n :";
826 $sep = 0;
827 foreach $node (@nodes) {
828 next if !$idxnodes{$node,$itag};
829 push @a, "n ," if $sep;
830 push @a, "sp", "x $xrefnodes{$node}", "n $node", "xe$xrefnodes{$node}";
831 $sep = 1;
833 $line = '';
834 do {
835 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
836 $wd .= $wprev;
837 if ($w eq ' ' || $w eq '' || $w eq undef) {
838 if (length ($line . $wd) > 75) {
839 $line =~ s/\s*$//; # trim trailing spaces
840 print "$line\n";
841 $line = '';
842 $wd =~ s/^\s*//; # trim leading spaces
844 $line .= $wd;
845 $wd = '';
847 $wprev = $w;
848 } while ($w ne '' && $w ne undef);
849 if ($line =~ /\S/) {
850 $line =~ s/\s*$//; # trim trailing spaces
851 print "$line\n";
853 print "<br>\n";
857 sub word_html {
858 my ($w) = @_;
859 my $wtype, $wmajt, $pfx, $sfx;
861 return undef if $w eq '' || $w eq undef;
863 $wtype = substr($w,0,2);
864 $wmajt = substr($wtype,0,1);
865 $w = substr($w,2);
866 $pfx = $sfx = '';
867 $pfx = "<a href=\"$1\">", $sfx = "</a>", $w = $2
868 if $wmajt eq "w" && $w =~ /^<(.*)>(.*)$/;
869 $w =~ s/&/&amp;/g;
870 $w =~ s/</&lt;/g;
871 $w =~ s/>/&gt;/g;
872 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
873 return $pfx . $w . $sfx;
874 } elsif ($wtype eq "sp") {
875 return ' ';
876 } elsif ($wtype eq "da") {
877 return '-'; # sadly, en-dashes are non-standard in HTML
878 } elsif ($wmajt eq "c" || $wtype eq "wc") {
879 return $pfx . "<code><nobr>${w}</nobr></code>" . $sfx;
880 } elsif ($wtype eq "es") {
881 return "<em>${w}";
882 } elsif ($wtype eq "ee") {
883 return "${w}</em>";
884 } elsif ($wtype eq "eo") {
885 return "<em>${w}</em>";
886 } elsif ($wtype eq "x ") {
887 # Magic: we must resolve the cross reference into file and marker
888 # parts, then dispose of the file part if it's us, and dispose of
889 # the marker part if the cross reference describes the top node of
890 # another file.
891 my $node = $nodexrefs{$w}; # find the node we're aiming at
892 my $level = $tstruct_level{$node}; # and its level
893 my $up = $node, $uplev = $level-1;
894 $up = $tstruct_up{$up} while $uplev--; # get top node of containing file
895 my $file = ($up ne $chapternode) ? $html_fnames{$up} : "";
896 my $marker = ($level == 1 and $file) ? "" : "#$w";
897 return "<a href=\"$file$marker\">";
898 } elsif ($wtype eq "xe") {
899 return "</a>";
900 } elsif ($wmajt eq "i") {
901 return "\001";
902 } else {
903 die "panic in word_html: $wtype$w\n";
907 sub write_texi {
908 # This is called from the top level, so I won't bother using
909 # my or local.
911 # Open file.
912 print "writing file...";
913 open TEXT,">nasmdoc.texi";
914 select TEXT;
916 # Preamble.
917 print "\\input texinfo \@c -*-texinfo-*-\n";
918 print "\@c \%**start of header\n";
919 print "\@setfilename ",$metadata{'infofile'},".info\n";
920 print "\@dircategory ",$metadata{'category'},"\n";
921 print "\@direntry\n";
922 printf "* %-28s %s.\n",
923 sprintf('%s: (%s).', $metadata{'infoname'}, $metadata{'infofile'}),
924 $metadata{'infotitle'};
925 print "\@end direntry\n";
926 print "\@settitle ", $metadata{'title'},"\n";
927 print "\@setchapternewpage odd\n";
928 print "\@c \%**end of header\n";
929 print "\n";
930 print "\@ifinfo\n";
931 print $metadata{'summary'}, "\n";
932 print "\n";
933 print "Copyright ",$metadata{'year'}," ",$metadata{'author'},"\n";
934 print "\n";
935 print $metadata{'license'}, "\n";
936 print "\@end ifinfo\n";
937 print "\n";
938 print "\@titlepage\n";
939 $title = $metadata{'title'};
940 $title =~ s/ - / --- /g;
941 print "\@title ${title}\n";
942 print "\@author ",$metadata{'author'},"\n";
943 print "\n";
944 print "\@page\n";
945 print "\@vskip 0pt plus 1filll\n";
946 print "Copyright \@copyright{} ",$metadata{'year'},' ',$metadata{'author'},"\n";
947 print "\n";
948 print $metadata{'license'}, "\n";
949 print "\@end titlepage\n";
950 print "\n";
951 print "\@node Top, $tstruct_next{'Top'}, (dir), (dir)\n";
952 print "\@top ",$metadata{'infotitle'},"\n";
953 print "\n";
954 print "\@ifinfo\n";
955 print $metadata{'summary'}, "\n";
956 print "\@end ifinfo\n";
958 $node = "Top";
960 $bulleting = 0;
961 for ($para = 0; $para <= $#pnames; $para++) {
962 $pname = $pnames[$para];
963 $pflags = $pflags[$para];
964 $ptype = substr($pflags,0,4);
966 $bulleting = 0, print "\@end itemize\n" if $bulleting && $ptype ne "bull";
967 print "\n"; # always one of these before a new paragraph
969 if ($ptype eq "chap") {
970 # Chapter heading. Begin a new node.
971 &texi_menu($node)
972 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
973 $pflags =~ /chap (.*) :(.*)/;
974 $node = "Chapter $1";
975 $title = "Chapter $1: ";
976 foreach $i (@$pname) {
977 $ww = &word_texi($i);
978 $title .= $ww unless $ww eq "\001";
980 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
981 print " $tstruct_up{$node}\n\@unnumbered $title\n";
982 } elsif ($ptype eq "appn") {
983 # Appendix heading. Begin a new node.
984 &texi_menu($node)
985 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
986 $pflags =~ /appn (.*) :(.*)/;
987 $node = "Appendix $1";
988 $title = "Appendix $1: ";
989 foreach $i (@$pname) {
990 $ww = &word_texi($i);
991 $title .= $ww unless $ww eq "\001";
993 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
994 print " $tstruct_up{$node}\n\@unnumbered $title\n";
995 } elsif ($ptype eq "head" || $ptype eq "subh") {
996 # Heading or subheading. Begin a new node.
997 &texi_menu($node)
998 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
999 $pflags =~ /.... (.*) :(.*)/;
1000 $node = "Section $1";
1001 $title = "$1. ";
1002 foreach $i (@$pname) {
1003 $ww = &word_texi($i);
1004 $title .= $ww unless $ww eq "\001";
1006 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1007 print " $tstruct_up{$node}\n";
1008 $hdr = ($ptype eq "subh" ? "\@unnumberedsubsec" : "\@unnumberedsec");
1009 print "$hdr $title\n";
1010 } elsif ($ptype eq "code") {
1011 # Code paragraph. Surround with @example / @end example.
1012 print "\@example\n";
1013 foreach $i (@$pname) {
1014 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1015 $i =~ s/\@/\@\@/g;
1016 $i =~ s/\{/\@\{/g;
1017 $i =~ s/\}/\@\}/g;
1018 print "$i\n";
1020 print "\@end example\n";
1021 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1022 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1023 if ($ptype eq "bull") {
1024 $bulleting = 1, print "\@itemize \@bullet\n" if !$bulleting;
1025 print "\@item\n";
1027 $line = '';
1028 @a = @$pname;
1029 $wd = $wprev = '';
1030 do {
1031 do { $w = &word_texi(shift @a); } while $w eq "\001"; # hack
1032 $wd .= $wprev;
1033 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1034 if (length ($line . $wd) > 75) {
1035 $line =~ s/\s*$//; # trim trailing spaces
1036 print "$line\n";
1037 $line = '';
1038 $wd =~ s/^\s*//; # trim leading spaces
1040 $line .= $wd;
1041 $wd = '';
1043 $wprev = $w;
1044 } while ($w ne '' && $w ne undef);
1045 if ($line =~ /\S/) {
1046 $line =~ s/\s*$//; # trim trailing spaces
1047 print "$line\n";
1052 # Write index.
1053 &texi_index;
1055 # Close file.
1056 print "\n\@contents\n\@bye\n";
1057 select STDOUT;
1058 close TEXT;
1061 # Side effect of this procedure: update global `texiwdlen' to be the length
1062 # in chars of the formatted version of the word.
1063 sub word_texi {
1064 my ($w) = @_;
1065 my $wtype, $wmajt;
1067 return undef if $w eq '' || $w eq undef;
1068 $wtype = substr($w,0,2);
1069 $wmajt = substr($wtype,0,1);
1070 $w = substr($w,2);
1071 $wlen = length $w;
1072 $w =~ s/\@/\@\@/g;
1073 $w =~ s/\{/\@\{/g;
1074 $w =~ s/\}/\@\}/g;
1075 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1076 substr($w,0,1) =~ tr/a-z/A-Z/, $capital = 0 if $capital;
1077 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1078 $texiwdlen = $wlen;
1079 return $w;
1080 } elsif ($wtype eq "sp") {
1081 $texiwdlen = 1;
1082 return ' ';
1083 } elsif ($wtype eq "da") {
1084 $texiwdlen = 2;
1085 return '--';
1086 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1087 $texiwdlen = 2 + $wlen;
1088 return "\@code\{$w\}";
1089 } elsif ($wtype eq "es") {
1090 $texiwdlen = 1 + $wlen;
1091 return "\@emph\{${w}";
1092 } elsif ($wtype eq "ee") {
1093 $texiwdlen = 1 + $wlen;
1094 return "${w}\}";
1095 } elsif ($wtype eq "eo") {
1096 $texiwdlen = 2 + $wlen;
1097 return "\@emph\{${w}\}";
1098 } elsif ($wtype eq "x ") {
1099 $texiwdlen = 0; # we don't need it in this case
1100 $capital = 1; # hack
1101 return "\@ref\{";
1102 } elsif ($wtype eq "xe") {
1103 $texiwdlen = 0; # we don't need it in this case
1104 return "\}";
1105 } elsif ($wmajt eq "i") {
1106 $texiwdlen = 0; # we don't need it in this case
1107 return "\001";
1108 } else {
1109 die "panic in word_texi: $wtype$w\n";
1113 sub texi_menu {
1114 my ($topitem) = @_;
1115 my $item, $i, $mpname, $title, $wd;
1117 $item = $tstruct_next{$topitem};
1118 print "\@menu\n";
1119 while ($item) {
1120 $title = "";
1121 $mpname = $tstruct_pname{$item};
1122 foreach $i (@$mpname) {
1123 $wd = &word_texi($i);
1124 $title .= $wd unless $wd eq "\001";
1126 print "* ${item}:: $title\n";
1127 $item = $tstruct_mnext{$item};
1129 print "* Index::\n" if $topitem eq "Top";
1130 print "\@end menu\n";
1133 sub texi_index {
1134 my $itag, $ientry, @a, $wd, $item, $len;
1135 my $subnums = "123456789ABCDEFGHIJKLMNOPQRSTU" .
1136 "VWXYZabcdefghijklmnopqrstuvwxyz";
1138 print "\@ifinfo\n\@node Index, , $FIXMElastnode, Top\n";
1139 print "\@unnumbered Index\n\n\@menu\n";
1141 foreach $itag (@itags) {
1142 $ientry = $idxmap{$itag};
1143 @a = @$ientry;
1144 $item = '';
1145 $len = 0;
1146 foreach $i (@a) {
1147 $wd = &word_texi($i);
1148 $item .= $wd, $len += $texiwdlen unless $wd eq "\001";
1150 $i = 0;
1151 foreach $node (@nodes) {
1152 next if !$idxnodes{$node,$itag};
1153 printf "* %s%s (%s): %s.\n",
1154 $item, " " x (40-$len), substr($subnums,$i++,1), $node;
1157 print "\@end menu\n\@end ifinfo\n";
1160 sub write_hlp {
1161 # This is called from the top level, so I won't bother using
1162 # my or local.
1164 # Build the index-tag text forms.
1165 print "building index entries...";
1166 @hlp_index = map {
1167 my $i,$ww;
1168 my $ientry = $idxmap{$_};
1169 my $title = "";
1170 foreach $i (@$ientry) {
1171 $ww = &word_hlp($i,0);
1172 $title .= $ww unless $ww eq "\001";
1174 $title;
1175 } @itags;
1177 # Write the HPJ project-description file.
1178 print "writing .hpj file...";
1179 open HPJ,">nasmdoc.hpj";
1180 print HPJ "[OPTIONS]\ncompress=true\n";
1181 print HPJ "title=NASM: The Netwide Assembler\noldkeyphrase=no\n\n";
1182 print HPJ "[FILES]\nnasmdoc.rtf\n\n";
1183 print HPJ "[CONFIG]\n";
1184 print HPJ 'CreateButton("btn_up", "&Up",'.
1185 ' "JumpContents(`nasmdoc.hlp'."'".')")';
1186 print HPJ "\nBrowseButtons()\n";
1187 close HPJ;
1189 # Open file.
1190 print "\n writing .rtf file...";
1191 open TEXT,">nasmdoc.rtf";
1192 select TEXT;
1194 # Preamble.
1195 print "{\\rtf1\\ansi{\\fonttbl\n";
1196 print "\\f0\\froman Times New Roman;\\f1\\fmodern Courier New;\n";
1197 print "\\f2\\fswiss Arial;\\f3\\ftech Wingdings}\\deff0\n";
1198 print "#{\\footnote Top}\n";
1199 print "\${\\footnote Contents}\n";
1200 print "+{\\footnote browse:00000}\n";
1201 print "!{\\footnote DisableButton(\"btn_up\")}\n";
1202 print "\\keepn\\f2\\b\\fs30\\sb0\n";
1203 print "NASM: The Netwide Assembler\n";
1204 print "\\par\\pard\\plain\\sb120\n";
1205 print "This file documents NASM, the Netwide Assembler: an assembler \n";
1206 print "targetting the Intel x86 series of processors, with portable source.\n";
1208 $node = "Top";
1209 $browse = 0;
1211 $newpar = "\\par\\sb120\n";
1212 for ($para = 0; $para <= $#pnames; $para++) {
1213 $pname = $pnames[$para];
1214 $pflags = $pflags[$para];
1215 $ptype = substr($pflags,0,4);
1217 print $newpar;
1218 $newpar = "\\par\\sb120\n";
1220 if ($ptype eq "chap") {
1221 # Chapter heading. Begin a new node.
1222 &hlp_menu($node)
1223 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1224 $pflags =~ /chap (.*) :(.*)/;
1225 $node = "Chapter $1";
1226 $title = $footnotetitle = "Chapter $1: ";
1227 foreach $i (@$pname) {
1228 $ww = &word_hlp($i,1);
1229 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1231 print "\\page\n";
1232 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1233 print "\${\\footnote $footnotetitle}\n";
1234 printf "+{\\footnote browse:%05d}\n", ++$browse;
1235 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1236 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1237 &hlp_sectkw($tstruct_up{$node});
1238 print "EnableButton(\"btn_up\")}\n";
1239 &hlp_keywords($node);
1240 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1241 print "$title\n";
1242 $newpar = "\\par\\pard\\plain\\sb120\n";
1243 } elsif ($ptype eq "appn") {
1244 # Appendix heading. Begin a new node.
1245 &hlp_menu($node)
1246 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1247 $pflags =~ /appn (.*) :(.*)/;
1248 $node = "Appendix $1";
1249 $title = $footnotetitle = "Appendix $1: ";
1250 foreach $i (@$pname) {
1251 $ww = &word_hlp($i,1);
1252 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1254 print "\\page\n";
1255 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1256 print "\${\\footnote $footnotetitle}\n";
1257 printf "+{\\footnote browse:%05d}\n", ++$browse;
1258 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1259 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1260 &hlp_sectkw($tstruct_up{$node});
1261 print "EnableButton(\"btn_up\")}\n";
1262 &hlp_keywords($node);
1263 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1264 print "$title\n";
1265 $newpar = "\\par\\pard\\plain\\sb120\n";
1266 } elsif ($ptype eq "head" || $ptype eq "subh") {
1267 # Heading or subheading. Begin a new node.
1268 &hlp_menu($node)
1269 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1270 $pflags =~ /.... (.*) :(.*)/;
1271 $node = "Section $1";
1272 $title = $footnotetitle = "$1. ";
1273 foreach $i (@$pname) {
1274 $ww = &word_hlp($i,1);
1275 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1277 print "\\page\n";
1278 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1279 print "\${\\footnote $footnotetitle}\n";
1280 printf "+{\\footnote browse:%05d}\n", ++$browse;
1281 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1282 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1283 &hlp_sectkw($tstruct_up{$node});
1284 print "EnableButton(\"btn_up\")}\n";
1285 &hlp_keywords($node);
1286 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1287 print "$title\n";
1288 $newpar = "\\par\\pard\\plain\\sb120\n";
1289 } elsif ($ptype eq "code") {
1290 # Code paragraph.
1291 print "\\keep\\f1\\sb120\n";
1292 foreach $i (@$pname) {
1293 my $x = $i;
1294 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1295 $x =~ s/\\/\\\\/g;
1296 $x =~ s/\{/\\\{/g;
1297 $x =~ s/\}/\\\}/g;
1298 print "$x\\par\\sb0\n";
1300 $newpar = "\\pard\\f0\\sb120\n";
1301 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1302 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1303 if ($ptype eq "bull") {
1304 print "\\tx360\\li360\\fi-360{\\f3\\'9F}\\tab\n";
1305 $newpar = "\\par\\pard\\sb120\n";
1306 } else {
1307 $newpar = "\\par\\sb120\n";
1309 $line = '';
1310 @a = @$pname;
1311 $wd = $wprev = '';
1312 do {
1313 do { $w = &word_hlp((shift @a),1); } while $w eq "\001"; # hack
1314 $wd .= $wprev;
1315 if ($w eq ' ' || $w eq '' || $w eq undef) {
1316 if (length ($line . $wd) > 75) {
1317 $line =~ s/\s*$//; # trim trailing spaces
1318 print "$line \n"; # and put one back
1319 $line = '';
1320 $wd =~ s/^\s*//; # trim leading spaces
1322 $line .= $wd;
1323 $wd = '';
1325 $wprev = $w;
1326 } while ($w ne '' && $w ne undef);
1327 if ($line =~ /\S/) {
1328 $line =~ s/\s*$//; # trim trailing spaces
1329 print "$line\n";
1334 # Close file.
1335 print "\\page}\n";
1336 select STDOUT;
1337 close TEXT;
1340 sub word_hlp {
1341 my ($w, $docode) = @_;
1342 my $wtype, $wmajt;
1344 return undef if $w eq '' || $w eq undef;
1345 $wtype = substr($w,0,2);
1346 $wmajt = substr($wtype,0,1);
1347 $w = substr($w,2);
1348 $w =~ s/\\/\\\\/g;
1349 $w =~ s/\{/\\\{/g;
1350 $w =~ s/\}/\\\}/g;
1351 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1352 substr($w,0,length($w)-1) =~ s/-/\\\'AD/g if $wmajt ne "x"; #nonbreakhyphens
1353 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1354 return $w;
1355 } elsif ($wtype eq "sp") {
1356 return ' ';
1357 } elsif ($wtype eq "da") {
1358 return "\\'96";
1359 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1360 $w =~ s/ /\\\'A0/g; # make spaces non-breaking
1361 return $docode ? "{\\f1 ${w}}" : $w;
1362 } elsif ($wtype eq "es") {
1363 return "{\\i ${w}";
1364 } elsif ($wtype eq "ee") {
1365 return "${w}}";
1366 } elsif ($wtype eq "eo") {
1367 return "{\\i ${w}}";
1368 } elsif ($wtype eq "x ") {
1369 return "{\\uldb ";
1370 } elsif ($wtype eq "xe") {
1371 $w = &hlp_sectkw($w);
1372 return "}{\\v ${w}}";
1373 } elsif ($wmajt eq "i") {
1374 return "\001";
1375 } else {
1376 die "panic in word_hlp: $wtype$w\n";
1380 sub hlp_menu {
1381 my ($topitem) = @_;
1382 my $item, $kword, $i, $mpname, $title;
1384 $item = $tstruct_next{$topitem};
1385 print "\\li360\\fi-360\n";
1386 while ($item) {
1387 $title = "";
1388 $mpname = $tstruct_pname{$item};
1389 foreach $i (@$mpname) {
1390 $ww = &word_hlp($i, 0);
1391 $title .= $ww unless $ww eq "\001";
1393 $kword = &hlp_sectkw($item);
1394 print "{\\uldb ${item}: $title}{\\v $kword}\\par\\sb0\n";
1395 $item = $tstruct_mnext{$item};
1397 print "\\pard\\sb120\n";
1400 sub hlp_sectkw {
1401 my ($node) = @_;
1402 $node =~ tr/A-Z/a-z/;
1403 $node =~ tr/- ./___/;
1404 $node;
1407 sub hlp_keywords {
1408 my ($node) = @_;
1409 my $pfx = "K{\\footnote ";
1410 my $done = 0;
1411 foreach $i (0..$#itags) {
1412 (print $pfx,$hlp_index[$i]), $pfx = ";\n", $done++
1413 if $idxnodes{$node,$itags[$i]};
1415 print "}\n" if $done;
1418 # Make tree structures. $tstruct_* is top-level and global.
1419 sub add_item {
1420 my ($item, $level) = @_;
1421 my $i;
1423 $tstruct_pname{$item} = $pname;
1424 $tstruct_next{$tstruct_previtem} = $item;
1425 $tstruct_prev{$item} = $tstruct_previtem;
1426 $tstruct_level{$item} = $level;
1427 $tstruct_up{$item} = $tstruct_last[$level-1];
1428 $tstruct_mnext{$tstruct_last[$level]} = $item;
1429 $tstruct_last[$level] = $item;
1430 for ($i=$level+1; $i<$MAXLEVEL; $i++) { $tstruct_last[$i] = undef; }
1431 $tstruct_previtem = $item;
1432 push @nodes, $item;
1436 # This produces documentation intermediate paragraph format; this is
1437 # basically the digested output of the front end. Intended for use
1438 # by future backends, instead of putting it all in the same script.
1440 sub write_dip {
1441 open(PARAS, "> nasmdoc.dip");
1442 foreach $k (keys(%metadata)) {
1443 print PARAS 'meta :', $k, "\n";
1444 print PARAS $metadata{$k},"\n";
1446 for ($para = 0; $para <= $#pnames; $para++) {
1447 print PARAS $pflags[$para], "\n";
1448 print PARAS join("\037", @{$pnames[$para]}, "\n");
1450 foreach $k (@itags) {
1451 print PARAS 'indx :', $k, "\n";
1452 print PARAS join("\037", @{$idxmap{$k}}), "\n";
1454 close(PARAS);