NASM 0.98p3.3
[nasm.git] / doc / rdsrc.pl
blob1a981287cc399f9fa76e9ab5e4efeef822efa5d7
1 #!/usr/bin/perl
3 # Read the source-form of the NASM manual and generate the various
4 # output forms.
6 # TODO:
8 # PS output:
9 # - show page numbers in printed output
10 # - think about double-sided support (start all chapters on RHS,
11 # ie odd-numbered, pages).
13 # Ellipsis support would be nice.
15 # Source-form features:
16 # ---------------------
18 # Bullet \b
19 # Bullets the paragraph. Rest of paragraph is indented to cope. In
20 # HTML, consecutive groups of bulleted paragraphs become unordered
21 # lists.
23 # Emphasis \e{foobar}
24 # produces `_foobar_' in text and italics in HTML, PS, RTF
26 # Inline code \c{foobar}
27 # produces ``foobar'' in text, and fixed-pitch font in HTML, PS, RTF
29 # Display code
30 # \c line one
31 # \c line two
32 # produces fixed-pitch font where appropriate, and doesn't break
33 # pages except sufficiently far into the middle of a display.
35 # Chapter, header and subheader
36 # \C{intro} Introduction
37 # \H{whatsnasm} What is NASM?
38 # \S{free} NASM Is Free
39 # dealt with as appropriate. Chapters begin on new sides, possibly
40 # even new _pages_. (Sub)?headers are good places to begin new
41 # pages. Just _after_ a (sub)?header isn't.
42 # The keywords can be substituted with \K and \k.
44 # Keyword \K{cintro} \k{cintro}
45 # Expands to `Chapter 1', `Section 1.1', `Section 1.1.1'. \K has an
46 # initial capital whereas \k doesn't. In HTML, will produce
47 # hyperlinks.
49 # Web link \W{http://foobar/}{text} or \W{mailto:me@here}\c{me@here}
50 # the \W prefix is ignored except in HTML; in HTML the last part
51 # becomes a hyperlink to the first part.
53 # Literals \{ \} \\
54 # In case it's necessary, they expand to the real versions.
56 # Nonbreaking hyphen \-
57 # Need more be said?
59 # Source comment \#
60 # Causes everything after it on the line to be ignored by the
61 # source-form processor.
63 # Indexable word \i{foobar} (or \i\e{foobar} or \i\c{foobar}, equally)
64 # makes word appear in index, referenced to that point
65 # \i\c comes up in code style even in the index; \i\e doesn't come
66 # up in emphasised style.
68 # Indexable non-displayed word \I{foobar} or \I\c{foobar}
69 # just as \i{foobar} except that nothing is displayed for it
71 # Index rewrite
72 # \IR{foobar} \c{foobar} operator, uses of
73 # tidies up the appearance in the index of something the \i or \I
74 # operator was applied to
76 # Index alias
77 # \IA{foobar}{bazquux}
78 # aliases one index tag (as might be supplied to \i or \I) to
79 # another, so that \I{foobar} has the effect of \I{bazquux}, and
80 # \i{foobar} has the effect of \I{bazquux}foobar
82 $diag = 1, shift @ARGV if $ARGV[0] eq "-d";
84 $| = 1;
86 $tstruct_previtem = $node = "Top";
87 $nodes = ($node);
88 $tstruct_level{$tstruct_previtem} = 0;
89 $tstruct_last[$tstruct_level{$tstruct_previtem}] = $tstruct_previtem;
90 $MAXLEVEL = 10; # really 3, but play safe ;-)
92 # Read the file; pass a paragraph at a time to the paragraph processor.
93 print "Reading input...";
94 $pname = "para000000";
95 @pnames = @pflags = ();
96 $para = undef;
97 while (<>) {
98 chomp;
99 if (!/\S/ || /^\\I[AR]/) { # special case: \I[AR] implies new-paragraph
100 &got_para($para);
101 $para = undef;
103 if (/\S/) {
104 s/\\#.*$//; # strip comments
105 $para .= " " . $_;
108 &got_para($para);
109 print "done.\n";
111 # Now we've read in the entire document and we know what all the
112 # heading keywords refer to. Go through and fix up the \k references.
113 print "Fixing up cross-references...";
114 &fixup_xrefs;
115 print "done.\n";
117 # Sort the index tags, according to the slightly odd order I've decided on.
118 print "Sorting index tags...";
119 &indexsort;
120 print "done.\n";
122 if ($diag) {
123 print "Writing index-diagnostic file...";
124 &indexdiag;
125 print "done.\n";
128 # OK. Write out the various output files.
129 print "Producing text output: ";
130 &write_txt;
131 print "done.\n";
132 print "Producing HTML output: ";
133 &write_html;
134 print "done.\n";
135 print "Producing PostScript output: ";
136 &write_ps;
137 print "done.\n";
138 print "Producing Texinfo output: ";
139 &write_texi;
140 print "done.\n";
141 print "Producing WinHelp output: ";
142 &write_hlp;
143 print "done.\n";
145 sub got_para {
146 local ($_) = @_;
147 my $pflags = "", $i, $w, $l, $t;
148 return if !/\S/;
150 @$pname = ();
152 # Strip off _leading_ spaces, then determine type of paragraph.
153 s/^\s*//;
154 $irewrite = undef;
155 if (/^\\c[^{]/) {
156 # A code paragraph. The paragraph-array will contain the simple
157 # strings which form each line of the paragraph.
158 $pflags = "code";
159 while (/^\\c (([^\\]|\\[^c])*)(.*)$/) {
160 $l = $1;
161 $_ = $3;
162 $l =~ s/\\{/{/g;
163 $l =~ s/\\}/}/g;
164 $l =~ s/\\\\/\\/g;
165 push @$pname, $l;
167 $_ = ''; # suppress word-by-word code
168 } elsif (/^\\C/) {
169 # A chapter heading. Define the keyword and allocate a chapter
170 # number.
171 $cnum++;
172 $hnum = 0;
173 $snum = 0;
174 $xref = "chapter-$cnum";
175 $pflags = "chap $cnum :$xref";
176 die "badly formatted chapter heading: $_\n" if !/^\\C{([^}]*)}\s*(.*)$/;
177 $refs{$1} = "chapter $cnum";
178 $node = "Chapter $cnum";
179 &add_item($node, 1);
180 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
181 $xrefs{$1} = $xref;
182 $_ = $2;
183 # the standard word-by-word code will happen next
184 } elsif (/^\\A/) {
185 # An appendix heading. Define the keyword and allocate an appendix
186 # letter.
187 $cnum++;
188 $cnum = 'A' if $cnum =~ /[0-9]+/;
189 $hnum = 0;
190 $snum = 0;
191 $xref = "appendix-$cnum";
192 $pflags = "appn $cnum :$xref";
193 die "badly formatted appendix heading: $_\n" if !/^\\A{([^}]*)}\s*(.*)$/;
194 $refs{$1} = "appendix $cnum";
195 $node = "Appendix $cnum";
196 &add_item($node, 1);
197 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
198 $xrefs{$1} = $xref;
199 $_ = $2;
200 # the standard word-by-word code will happen next
201 } elsif (/^\\H/) {
202 # A major heading. Define the keyword and allocate a section number.
203 $hnum++;
204 $snum = 0;
205 $xref = "section-$cnum.$hnum";
206 $pflags = "head $cnum.$hnum :$xref";
207 die "badly formatted heading: $_\n" if !/^\\[HP]{([^}]*)}\s*(.*)$/;
208 $refs{$1} = "section $cnum.$hnum";
209 $node = "Section $cnum.$hnum";
210 &add_item($node, 2);
211 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
212 $xrefs{$1} = $xref;
213 $_ = $2;
214 # the standard word-by-word code will happen next
215 } elsif (/^\\S/) {
216 # A sub-heading. Define the keyword and allocate a section number.
217 $snum++;
218 $xref = "section-$cnum.$hnum.$snum";
219 $pflags = "subh $cnum.$hnum.$snum :$xref";
220 die "badly formatted subheading: $_\n" if !/^\\S{([^}]*)}\s*(.*)$/;
221 $refs{$1} = "section $cnum.$hnum.$snum";
222 $node = "Section $cnum.$hnum.$snum";
223 &add_item($node, 3);
224 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
225 $xrefs{$1} = $xref;
226 $_ = $2;
227 # the standard word-by-word code will happen next
228 } elsif (/^\\IR/) {
229 # An index-rewrite.
230 die "badly formatted index rewrite: $_\n" if !/^\\IR{([^}]*)}\s*(.*)$/;
231 $irewrite = $1;
232 $_ = $2;
233 # the standard word-by-word code will happen next
234 } elsif (/^\\IA/) {
235 # An index-alias.
236 die "badly formatted index alias: $_\n" if !/^\\IA{([^}]*)}{([^}]*)}\s*$/;
237 $idxalias{$1} = $2;
238 return; # avoid word-by-word code
239 } elsif (/^\\b/) {
240 # A bulleted paragraph. Strip off the initial \b and let the
241 # word-by-word code take care of the rest.
242 $pflags = "bull";
243 s/^\\b\s*//;
244 } else {
245 # A normal paragraph. Just set $pflags: the word-by-word code does
246 # the rest.
247 $pflags = "norm";
250 # The word-by-word code: unless @$pname is already defined (which it
251 # will be in the case of a code paragraph), split the paragraph up
252 # into words and push each on @$pname.
254 # Each thing pushed on @$pname should have a two-character type
255 # code followed by the text.
257 # Type codes are:
258 # "n " for normal
259 # "da" for a dash
260 # "es" for first emphasised word in emphasised bit
261 # "e " for emphasised in mid-emphasised-bit
262 # "ee" for last emphasised word in emphasised bit
263 # "eo" for single (only) emphasised word
264 # "c " for code
265 # "k " for cross-ref
266 # "kK" for capitalised cross-ref
267 # "w " for Web link
268 # "wc" for code-type Web link
269 # "x " for beginning of resolved cross-ref; generates no visible output,
270 # and the text is the cross-reference code
271 # "xe" for end of resolved cross-ref; text is same as for "x ".
272 # "i " for point to be indexed: the text is the internal index into the
273 # index-items arrays
274 # "sp" for space
275 while (/\S/) {
276 s/^\s*//, push @$pname, "sp" if /^\s/;
277 $indexing = $qindex = 0;
278 if (/^(\\[iI])?\\c/) {
279 $qindex = 1 if $1 eq "\\I";
280 $indexing = 1, s/^\\[iI]// if $1;
281 s/^\\c//;
282 die "badly formatted \\c: \\c$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
283 $w = $1;
284 $_ = $3;
285 $w =~ s/\\{/{/g;
286 $w =~ s/\\}/}/g;
287 $w =~ s/\\-/-/g;
288 $w =~ s/\\\\/\\/g;
289 (push @$pname,"i"),$lastp = $#$pname if $indexing;
290 push @$pname,"c $w" if !$qindex;
291 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
292 } elsif (/^\\[iIe]/) {
293 /^(\\[iI])?(\\e)?/;
294 $emph = 0;
295 $qindex = 1 if $1 eq "\\I";
296 $indexing = 1, $type = "\\i" if $1;
297 $emph = 1, $type = "\\e" if $2;
298 s/^(\\[iI])?(\\e?)//;
299 die "badly formatted $type: $type$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
300 $w = $1;
301 $_ = $3;
302 $w =~ s/\\{/{/g;
303 $w =~ s/\\}/}/g;
304 $w =~ s/\\-/-/g;
305 $w =~ s/\\\\/\\/g;
306 $t = $emph ? "es" : "n ";
307 @ientry = ();
308 (push @$pname,"i"),$lastp = $#$pname if $indexing;
309 foreach $i (split /\s+/,$w) { # \e and \i can be multiple words
310 push @$pname,"$t$i","sp" if !$qindex;
311 ($ii=$i) =~ tr/A-Z/a-z/, push @ientry,"n $ii","sp" if $indexing;
312 $t = $emph ? "e " : "n ";
314 $w =~ tr/A-Z/a-z/, pop @ientry if $indexing;
315 $$pname[$lastp] = &addidx($node, $w, @ientry) if $indexing;
316 pop @$pname if !$qindex; # remove final space
317 if (substr($$pname[$#$pname],0,2) eq "es" && !$qindex) {
318 substr($$pname[$#$pname],0,2) = "eo";
319 } elsif ($emph && !$qindex) {
320 substr($$pname[$#$pname],0,2) = "ee";
322 } elsif (/^\\[kK]/) {
323 $t = "k ";
324 $t = "kK" if /^\\K/;
325 s/^\\[kK]//;
326 die "badly formatted \\k: \\c$_\n" if !/{([^}]*)}(.*)$/;
327 $_ = $2;
328 push @$pname,"$t$1";
329 } elsif (/^\\W/) {
330 s/^\\W//;
331 die "badly formatted \\W: \\W$_\n"
332 if !/{([^}]*)}(\\i)?(\\c)?{(([^\\}]|\\.)*)}(.*)$/;
333 $l = $1;
334 $w = $4;
335 $_ = $6;
336 $t = "w ";
337 $t = "wc" if $3 eq "\\c";
338 $indexing = 1 if $2;
339 $w =~ s/\\{/{/g;
340 $w =~ s/\\}/}/g;
341 $w =~ s/\\-/-/g;
342 $w =~ s/\\\\/\\/g;
343 (push @$pname,"i"),$lastp = $#$pname if $indexing;
344 push @$pname,"$t<$l>$w";
345 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
346 } else {
347 die "what the hell? $_\n" if !/^(([^\s\\\-]|\\[\\{}\-])*-?)(.*)$/;
348 die "painful death! $_\n" if !length $1;
349 $w = $1;
350 $_ = $3;
351 $w =~ s/\\{/{/g;
352 $w =~ s/\\}/}/g;
353 $w =~ s/\\-/-/g;
354 $w =~ s/\\\\/\\/g;
355 if ($w eq "-") {
356 push @$pname,"da";
357 } else {
358 push @$pname,"n $w";
362 if ($irewrite ne undef) {
363 &addidx(undef, $irewrite, @$pname);
364 @$pname = ();
365 } else {
366 push @pnames, $pname;
367 push @pflags, $pflags;
368 $pname++;
372 sub addidx {
373 my ($node, $text, @ientry) = @_;
374 $text = $idxalias{$text} || $text;
375 if ($node eq undef || !$idxmap{$text}) {
376 @$ientry = @ientry;
377 $idxmap{$text} = $ientry;
378 $ientry++;
380 if ($node) {
381 $idxnodes{$node,$text} = 1;
382 return "i $text";
386 sub indexsort {
387 my $iitem, $ientry, $i, $piitem, $pcval, $cval, $clrcval;
389 @itags = map { # get back the original data as the 1st elt of each list
390 $_->[0]
391 } sort { # compare auxiliary (non-first) elements of lists
392 $a->[1] cmp $b->[1] ||
393 $a->[2] cmp $b->[2] ||
394 $a->[0] cmp $b->[0]
395 } map { # transform array into list of 3-element lists
396 my $ientry = $idxmap{$_};
397 my $a = substr($$ientry[0],2);
398 $a =~ tr/A-Za-z//cd;
399 [$_, uc($a), substr($$ientry[0],0,2)]
400 } keys %idxmap;
402 # Having done that, check for comma-hood.
403 $cval = 0;
404 foreach $iitem (@itags) {
405 $ientry = $idxmap{$iitem};
406 $clrcval = 1;
407 $pcval = $cval;
408 FL:for ($i=0; $i <= $#$ientry; $i++) {
409 if ($$ientry[$i] =~ /^(n .*,)(.*)/) {
410 $$ientry[$i] = $1;
411 splice @$ientry,$i+1,0,"n $2" if length $2;
412 $commapos{$iitem} = $i+1;
413 $cval = join("\002", @$ientry[0..$i]);
414 $clrcval = 0;
415 last FL;
418 $cval = undef if $clrcval;
419 $commanext{$iitem} = $commaafter{$piitem} = 1
420 if $cval and ($cval eq $pcval);
421 $piitem = $iitem;
425 sub indexdiag {
426 my $iitem,$ientry,$w,$ww,$foo,$node;
427 open INDEXDIAG,">index.diag";
428 foreach $iitem (@itags) {
429 $ientry = $idxmap{$iitem};
430 print INDEXDIAG "<$iitem> ";
431 foreach $w (@$ientry) {
432 $ww = &word_txt($w);
433 print INDEXDIAG $ww unless $ww eq "\001";
435 print INDEXDIAG ":";
436 $foo = " ";
437 foreach $node (@nodes) {
438 (print INDEXDIAG $foo,$node), $foo = ", " if $idxnodes{$node,$iitem};
440 print INDEXDIAG "\n";
442 close INDEXDIAG;
445 sub fixup_xrefs {
446 my $pname, $p, $i, $j, $k, $caps, @repl;
448 for ($p=0; $p<=$#pnames; $p++) {
449 next if $pflags[$p] eq "code";
450 $pname = $pnames[$p];
451 for ($i=$#$pname; $i >= 0; $i--) {
452 if ($$pname[$i] =~ /^k/) {
453 $k = $$pname[$i];
454 $caps = ($k =~ /^kK/);
455 $k = substr($k,2);
456 $repl = $refs{$k};
457 die "undefined keyword `$k'\n" unless $repl;
458 substr($repl,0,1) =~ tr/a-z/A-Z/ if $caps;
459 @repl = ();
460 push @repl,"x $xrefs{$k}";
461 foreach $j (split /\s+/,$repl) {
462 push @repl,"n $j";
463 push @repl,"sp";
465 pop @repl; # remove final space
466 push @repl,"xe$xrefs{$k}";
467 splice @$pname,$i,1,@repl;
473 sub write_txt {
474 # This is called from the top level, so I won't bother using
475 # my or local.
477 # Open file.
478 print "writing file...";
479 open TEXT,">nasmdoc.txt";
480 select TEXT;
482 # Preamble.
483 $title = "The Netwide Assembler: NASM";
484 $spaces = ' ' x ((75-(length $title))/2);
485 ($underscore = $title) =~ s/./=/g;
486 print "$spaces$title\n$spaces$underscore\n";
488 for ($para = 0; $para <= $#pnames; $para++) {
489 $pname = $pnames[$para];
490 $pflags = $pflags[$para];
491 $ptype = substr($pflags,0,4);
493 print "\n"; # always one of these before a new paragraph
495 if ($ptype eq "chap") {
496 # Chapter heading. "Chapter N: Title" followed by a line of
497 # minus signs.
498 $pflags =~ /chap (.*) :(.*)/;
499 $title = "Chapter $1: ";
500 foreach $i (@$pname) {
501 $ww = &word_txt($i);
502 $title .= $ww unless $ww eq "\001";
504 print "$title\n";
505 $title =~ s/./-/g;
506 print "$title\n";
507 } elsif ($ptype eq "appn") {
508 # Appendix heading. "Appendix N: Title" followed by a line of
509 # minus signs.
510 $pflags =~ /appn (.*) :(.*)/;
511 $title = "Appendix $1: ";
512 foreach $i (@$pname) {
513 $ww = &word_txt($i);
514 $title .= $ww unless $ww eq "\001";
516 print "$title\n";
517 $title =~ s/./-/g;
518 print "$title\n";
519 } elsif ($ptype eq "head" || $ptype eq "subh") {
520 # Heading or subheading. Just a number and some text.
521 $pflags =~ /.... (.*) :(.*)/;
522 $title = sprintf "%6s ", $1;
523 foreach $i (@$pname) {
524 $ww = &word_txt($i);
525 $title .= $ww unless $ww eq "\001";
527 print "$title\n";
528 } elsif ($ptype eq "code") {
529 # Code paragraph. Emit each line with a seven character indent.
530 foreach $i (@$pname) {
531 warn "code line longer than 68 chars: $i\n" if length $i > 68;
532 print ' 'x7, $i, "\n";
534 } elsif ($ptype eq "bull" || $ptype eq "norm") {
535 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
536 # 75-char right margin and either 7 or 11 char left margin
537 # depending on bullets.
538 if ($ptype eq "bull") {
539 $line = ' 'x7 . '(*) ';
540 $next = ' 'x11;
541 } else {
542 $line = $next = ' 'x7;
544 @a = @$pname;
545 $wd = $wprev = '';
546 do {
547 do { $w = &word_txt(shift @a) } while $w eq "\001"; # nasty hack
548 $wd .= $wprev;
549 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
550 if (length ($line . $wd) > 75) {
551 $line =~ s/\s*$//; # trim trailing spaces
552 print "$line\n";
553 $line = $next;
554 $wd =~ s/^\s*//; # trim leading spaces
556 $line .= $wd;
557 $wd = '';
559 $wprev = $w;
560 } while ($w ne '' && $w ne undef);
561 if ($line =~ /\S/) {
562 $line =~ s/\s*$//; # trim trailing spaces
563 print "$line\n";
568 # Close file.
569 select STDOUT;
570 close TEXT;
573 sub word_txt {
574 my ($w) = @_;
575 my $wtype, $wmajt;
577 return undef if $w eq '' || $w eq undef;
578 $wtype = substr($w,0,2);
579 $wmajt = substr($wtype,0,1);
580 $w = substr($w,2);
581 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
582 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
583 return $w;
584 } elsif ($wtype eq "sp") {
585 return ' ';
586 } elsif ($wtype eq "da") {
587 return '-';
588 } elsif ($wmajt eq "c" || $wtype eq "wc") {
589 return "`${w}'";
590 } elsif ($wtype eq "es") {
591 return "_${w}";
592 } elsif ($wtype eq "ee") {
593 return "${w}_";
594 } elsif ($wtype eq "eo") {
595 return "_${w}_";
596 } elsif ($wmajt eq "x" || $wmajt eq "i") {
597 return "\001";
598 } else {
599 die "panic in word_txt: $wtype$w\n";
603 sub write_html {
604 # This is called from the top level, so I won't bother using
605 # my or local.
607 # Write contents file. Just the preamble, then a menu of links to the
608 # separate chapter files and the nodes therein.
609 print "writing contents file...";
610 open TEXT,">nasmdoc0.html";
611 select TEXT;
612 &html_preamble(0);
613 print "<p>This manual documents NASM, the Netwide Assembler: an assembler\n";
614 print "targetting the Intel x86 series of processors, with portable source.\n";
615 print "<p>";
616 for ($node = $tstruct_next{'Top'}; $node; $node = $tstruct_next{$node}) {
617 if ($tstruct_level{$node} == 1) {
618 # Invent a file name.
619 ($number = lc($xrefnodes{$node})) =~ s/.*-//;
620 $fname="nasmdocx.html";
621 substr($fname,8 - length $number, length $number) = $number;
622 $html_fnames{$node} = $fname;
623 $link = $fname;
624 print "<p>";
625 } else {
626 # Use the preceding filename plus a marker point.
627 $link = $fname . "#$xrefnodes{$node}";
629 $title = "$node: ";
630 $pname = $tstruct_pname{$node};
631 foreach $i (@$pname) {
632 $ww = &word_html($i);
633 $title .= $ww unless $ww eq "\001";
635 print "<a href=\"$link\">$title</a><br>\n";
637 print "<p><a href=\"nasmdoci.html\">Index</a>\n";
638 print "</body></html>\n";
639 select STDOUT;
640 close TEXT;
642 # Open a null file, to ensure output (eg random &html_jumppoints calls)
643 # goes _somewhere_.
644 print "writing chapter files...";
645 open TEXT,">/dev/null";
646 select TEXT;
647 $html_lastf = '';
649 $in_list = 0;
651 for ($para = 0; $para <= $#pnames; $para++) {
652 $pname = $pnames[$para];
653 $pflags = $pflags[$para];
654 $ptype = substr($pflags,0,4);
656 $in_list = 0, print "</ul>\n" if $in_list && $ptype ne "bull";
657 if ($ptype eq "chap") {
658 # Chapter heading. Begin a new file.
659 $pflags =~ /chap (.*) :(.*)/;
660 $title = "Chapter $1: ";
661 $xref = $2;
662 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
663 $html_lastf = $html_fnames{$chapternode};
664 $chapternode = $nodexrefs{$xref};
665 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
666 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
667 foreach $i (@$pname) {
668 $ww = &word_html($i);
669 $title .= $ww unless $ww eq "\001";
671 $h = "<h2><a name=\"$xref\">$title</a></h2>\n";
672 print $h; print FULL $h;
673 } elsif ($ptype eq "appn") {
674 # Appendix heading. Begin a new file.
675 $pflags =~ /appn (.*) :(.*)/;
676 $title = "Appendix $1: ";
677 $xref = $2;
678 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
679 $html_lastf = $html_fnames{$chapternode};
680 $chapternode = $nodexrefs{$xref};
681 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
682 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
683 foreach $i (@$pname) {
684 $ww = &word_html($i);
685 $title .= $ww unless $ww eq "\001";
687 print "<h2><a name=\"$xref\">$title</a></h2>\n";
688 } elsif ($ptype eq "head" || $ptype eq "subh") {
689 # Heading or subheading.
690 $pflags =~ /.... (.*) :(.*)/;
691 $hdr = ($ptype eq "subh" ? "h4" : "h3");
692 $title = $1 . " ";
693 $xref = $2;
694 foreach $i (@$pname) {
695 $ww = &word_html($i);
696 $title .= $ww unless $ww eq "\001";
698 print "<$hdr><a name=\"$xref\">$title</a></$hdr>\n";
699 } elsif ($ptype eq "code") {
700 # Code paragraph.
701 print "<p><pre>\n";
702 foreach $i (@$pname) {
703 $w = $i;
704 $w =~ s/&/&amp;/g;
705 $w =~ s/</&lt;/g;
706 $w =~ s/>/&gt;/g;
707 print $w, "\n";
709 print "</pre>\n";
710 } elsif ($ptype eq "bull" || $ptype eq "norm") {
711 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
712 # 75-char right margin and either 7 or 11 char left margin
713 # depending on bullets.
714 if ($ptype eq "bull") {
715 $in_list = 1, print "<ul>\n" unless $in_list;
716 $line = '<li>';
717 } else {
718 $line = '<p>';
720 @a = @$pname;
721 $wd = $wprev = '';
722 do {
723 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
724 $wd .= $wprev;
725 if ($w eq ' ' || $w eq '' || $w eq undef) {
726 if (length ($line . $wd) > 75) {
727 $line =~ s/\s*$//; # trim trailing spaces
728 print "$line\n";
729 $line = '';
730 $wd =~ s/^\s*//; # trim leading spaces
732 $line .= $wd;
733 $wd = '';
735 $wprev = $w;
736 } while ($w ne '' && $w ne undef);
737 if ($line =~ /\S/) {
738 $line =~ s/\s*$//; # trim trailing spaces
739 print "$line\n";
744 # Close whichever file was open.
745 &html_jumppoints;
746 print "</body></html>\n";
747 select STDOUT;
748 close TEXT;
750 print "\n writing index file...";
751 open TEXT,">nasmdoci.html";
752 select TEXT;
753 &html_preamble(0);
754 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
755 print "<p>";
756 &html_index;
757 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
758 print "</body></html>\n";
759 select STDOUT;
760 close TEXT;
763 sub html_preamble {
764 print "<html><head><title>NASM Manual</title></head>\n";
765 print "<body><h1 align=center>The Netwide Assembler: NASM</h1>\n\n";
766 &html_jumppoints if $_[0];
769 sub html_jumppoints {
770 print "<p align=center>";
771 print "<a href=\"$html_nextf\">Next Chapter</a> |\n" if $html_nextf;
772 print "<a href=\"$html_lastf\">Previous Chapter</a> |\n" if $html_lastf;
773 print "<a href=\"nasmdoc0.html\">Contents</a> |\n";
774 print "<a href=\"nasmdoci.html\">Index</a>\n";
777 sub html_index {
778 my $itag, $a, @ientry, $sep, $w, $wd, $wprev, $line;
780 $chapternode = '';
781 foreach $itag (@itags) {
782 $ientry = $idxmap{$itag};
783 @a = @$ientry;
784 push @a, "n :";
785 $sep = 0;
786 foreach $node (@nodes) {
787 next if !$idxnodes{$node,$itag};
788 push @a, "n ," if $sep;
789 push @a, "sp", "x $xrefnodes{$node}", "n $node", "xe$xrefnodes{$node}";
790 $sep = 1;
792 $line = '';
793 do {
794 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
795 $wd .= $wprev;
796 if ($w eq ' ' || $w eq '' || $w eq undef) {
797 if (length ($line . $wd) > 75) {
798 $line =~ s/\s*$//; # trim trailing spaces
799 print "$line\n";
800 $line = '';
801 $wd =~ s/^\s*//; # trim leading spaces
803 $line .= $wd;
804 $wd = '';
806 $wprev = $w;
807 } while ($w ne '' && $w ne undef);
808 if ($line =~ /\S/) {
809 $line =~ s/\s*$//; # trim trailing spaces
810 print "$line\n";
812 print "<br>\n";
816 sub word_html {
817 my ($w) = @_;
818 my $wtype, $wmajt, $pfx, $sfx;
820 return undef if $w eq '' || $w eq undef;
822 $wtype = substr($w,0,2);
823 $wmajt = substr($wtype,0,1);
824 $w = substr($w,2);
825 $pfx = $sfx = '';
826 $pfx = "<a href=\"$1\">", $sfx = "</a>", $w = $2
827 if $wmajt eq "w" && $w =~ /^<(.*)>(.*)$/;
828 $w =~ s/&/&amp;/g;
829 $w =~ s/</&lt;/g;
830 $w =~ s/>/&gt;/g;
831 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
832 return $pfx . $w . $sfx;
833 } elsif ($wtype eq "sp") {
834 return ' ';
835 } elsif ($wtype eq "da") {
836 return '-'; # sadly, en-dashes are non-standard in HTML
837 } elsif ($wmajt eq "c" || $wtype eq "wc") {
838 return $pfx . "<code><nobr>${w}</nobr></code>" . $sfx;
839 } elsif ($wtype eq "es") {
840 return "<em>${w}";
841 } elsif ($wtype eq "ee") {
842 return "${w}</em>";
843 } elsif ($wtype eq "eo") {
844 return "<em>${w}</em>";
845 } elsif ($wtype eq "x ") {
846 # Magic: we must resolve the cross reference into file and marker
847 # parts, then dispose of the file part if it's us, and dispose of
848 # the marker part if the cross reference describes the top node of
849 # another file.
850 my $node = $nodexrefs{$w}; # find the node we're aiming at
851 my $level = $tstruct_level{$node}; # and its level
852 my $up = $node, $uplev = $level-1;
853 $up = $tstruct_up{$up} while $uplev--; # get top node of containing file
854 my $file = ($up ne $chapternode) ? $html_fnames{$up} : "";
855 my $marker = ($level == 1 and $file) ? "" : "#$w";
856 return "<a href=\"$file$marker\">";
857 } elsif ($wtype eq "xe") {
858 return "</a>";
859 } elsif ($wmajt eq "i") {
860 return "\001";
861 } else {
862 die "panic in word_html: $wtype$w\n";
866 sub write_ps {
867 # This is called from the top level, so I won't bother using
868 # my or local.
870 # First, set up the font metric arrays.
871 &font_metrics;
873 # First stage: reprocess the source arrays into a list of
874 # lines, each of which is a list of word-strings, each of
875 # which has a single-letter font code followed by text.
876 # Each line also has an associated type, which will be
877 # used for final alignment and font selection and things.
879 # Font codes are:
880 # n == Normal
881 # e == Emphasised
882 # c == Code
883 # ' ' == space (no following text required)
884 # '-' == dash (no following text required)
886 # Line types are:
887 # chap == Chapter or appendix heading.
888 # head == Major heading.
889 # subh == Sub-heading.
890 # Ccha == Contents entry for a chapter.
891 # Chea == Contents entry for a heading.
892 # Csub == Contents entry for a subheading.
893 # cone == Code paragraph with just this one line on it.
894 # cbeg == First line of multi-line code paragraph.
895 # cbdy == Interior line of multi-line code paragraph.
896 # cend == Final line of multi-line code paragraph.
897 # none == Normal paragraph with just this one line on it.
898 # nbeg == First line of multi-line normal paragraph.
899 # nbdy == Interior line of multi-line normal paragraph.
900 # nend == Final line of multi-line normal paragraph.
901 # bone == Bulleted paragraph with just this one line on it.
902 # bbeg == First line of multi-line bulleted paragraph.
903 # bbdy == Interior line of multi-line bulleted paragraph.
904 # bend == Final line of multi-line bulleted paragraph.
905 print "line-breaks...";
906 $lname = "psline000000";
907 $lnamei = "idx" . $lname;
908 @lnames = @ltypes = ();
910 for ($para = 0; $para <= $#pnames; $para++) {
911 $pname = $pnames[$para];
912 $pflags = $pflags[$para];
913 $ptype = substr($pflags,0,4);
915 # New paragraph _ergo_ new line.
916 @line = ();
917 @lindex = (); # list of index tags referenced to this line
919 if ($ptype eq "chap") {
920 # Chapter heading. "Chapter N: Title" followed by a line of
921 # minus signs.
922 $pflags =~ /chap (.*) :(.*)/;
923 push @line, "nChapter", " ", "n$1:", " ";
924 foreach $i (@$pname) {
925 $ww = &word_ps($i);
926 push @line, $ww unless $ww eq "x";
928 @$lname = @line; @$lnamei = @lindex;
929 push @lnames, $lname++;
930 $lnamei = "idx" . $lname;
931 push @ltypes, "chap";
932 } elsif ($ptype eq "appn") {
933 # Appendix heading. "Appendix N: Title" followed by a line of
934 # minus signs.
935 $pflags =~ /appn (.*) :(.*)/;
936 push @line, "nAppendix", " ", "n$1:", " ";
937 foreach $i (@$pname) {
938 $ww = &word_ps($i);
939 push @line, $ww unless $ww eq "x";
941 @$lname = @line; @$lnamei = @lindex;
942 push @lnames, $lname++;
943 $lnamei = "idx" . $lname;
944 push @ltypes, "chap";
945 } elsif ($ptype eq "head") {
946 # Heading. Just a number and some text.
947 $pflags =~ /.... (.*) :(.*)/;
948 push @line, "n$1";
949 foreach $i (@$pname) {
950 $ww = &word_ps($i);
951 push @line, $ww unless $ww eq "x";
953 @$lname = @line; @$lnamei = @lindex;
954 push @lnames, $lname++;
955 $lnamei = "idx" . $lname;
956 push @ltypes, $ptype;
957 } elsif ($ptype eq "subh") {
958 # Subheading. Just a number and some text.
959 $pflags =~ /subh (.*) :(.*)/;
960 push @line, "n$1";
961 foreach $i (@$pname) {
962 push @line, &word_ps($i);
964 @$lname = @line; @$lnamei = @lindex;
965 push @lnames, $lname++;
966 $lnamei = "idx" . $lname;
967 push @ltypes, "subh";
968 } elsif ($ptype eq "code") {
969 # Code paragraph. Emit lines one at a time.
970 $type = "cbeg";
971 foreach $i (@$pname) {
972 @$lname = ("c$i");
973 push @lnames, $lname++;
974 $lnamei = "idx" . $lname;
975 push @ltypes, $type;
976 $type = "cbdy";
978 $ltypes[$#ltypes] = ($ltypes[$#ltypes] eq "cbeg" ? "cone" : "cend");
979 } elsif ($ptype eq "bull" || $ptype eq "norm") {
980 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
981 # 75-char right margin and either 7 or 11 char left margin
982 # depending on bullets.
983 if ($ptype eq "bull") {
984 $width = 456; # leave 12-pt left indent for the bullet
985 $type = $begtype = "bbeg";
986 $bodytype = "bbdy";
987 $onetype = "bone";
988 $endtype = "bend";
989 } else {
990 $width = 468;
991 $type = $begtype = "nbeg";
992 $bodytype = "nbdy";
993 $onetype = "none";
994 $endtype = "nend";
996 @a = @$pname;
997 @line = @wd = ();
998 $linelen = 0;
999 $wprev = undef;
1000 do {
1001 do { $w = &word_ps(shift @a) } while ($w eq "x");
1002 push @wd, $wprev if $wprev;
1003 if ($wprev =~ /^n.*-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1004 $wdlen = &len_ps(@wd);
1005 if ($linelen + $wdlen > $width) {
1006 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1007 @$lname = @line; @$lnamei = @lindex;
1008 push @lnames, $lname++;
1009 $lnamei = "idx" . $lname;
1010 push @ltypes, $type;
1011 $type = $bodytype;
1012 @line = @lindex = ();
1013 $linelen = 0;
1014 shift @wd while $wd[0] eq ' '; # trim leading spaces
1016 push @line, @wd;
1017 $linelen += $wdlen;
1018 @wd = ();
1020 $wprev = $w;
1021 } while ($w ne '' && $w ne undef);
1022 if (@line) {
1023 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1024 @$lname = @line; @$lnamei = @lindex;
1025 push @lnames, $lname++;
1026 $lnamei = "idx" . $lname;
1027 push @ltypes, $type;
1028 $type = $bodytype;
1030 $ltypes[$#ltypes] =
1031 ($ltypes[$#ltypes] eq $begtype ? $onetype : $endtype);
1035 # We've now processed the document source into lines. Before we
1036 # go on and do the page breaking, we'll fabricate a table of contents,
1037 # line by line, and then after doing page breaks we'll go back and
1038 # insert the page numbers into the contents entries.
1039 print "building contents...";
1040 @clnames = @cltypes = ();
1041 $clname = "pscont000000";
1042 @$clname = ("nContents"); # "chapter heading" for TOC
1043 push @clnames,$clname++;
1044 push @cltypes,"chap";
1045 for ($i=0; $i<=$#lnames; $i++) {
1046 $lname = $lnames[$i];
1047 if ($ltypes[$i] =~ /^(chap|head|subh)/) {
1048 @$clname = @$lname;
1049 splice @$clname,1,0," " if ($ltypes[$i] !~ /chap/);
1050 push @$clname,$i; # placeholder for page number
1051 push @clnames,$clname++;
1052 push @cltypes,"C" . substr($ltypes[$i],0,3);
1055 @$clname = ("nIndex"); # contents entry for Index
1056 push @$clname,$i; # placeholder for page number
1057 $idx_clname = $clname;
1058 push @clnames,$clname++;
1059 push @cltypes,"Ccha";
1060 $contlen = $#clnames + 1;
1061 unshift @lnames,@clnames;
1062 unshift @ltypes,@cltypes;
1064 # Second stage: now we have a list of lines, break them into pages.
1065 # We do this by means of adding a third array in parallel with
1066 # @lnames and @ltypes, called @lpages, in which we store the page
1067 # number that each line resides on. We also add @ycoord which
1068 # stores the vertical position of each line on the page.
1070 # Page breaks may not come after line-types:
1071 # chap head subh cbeg nbeg bbeg
1072 # and may not come before line-types:
1073 # cend nend bend
1074 # They are forced before line-types:
1075 # chap
1076 print "page-breaks...";
1077 $pmax = 600; # ADJUSTABLE: maximum length of a page in points
1078 $textht = 11; # ADJUSTABLE: height of a normal line in points
1079 $spacing = 6; # ADJUSTABLE: space between paragraphs, in points
1080 $headht = 14; # ADJUSTABLE: height of a major heading in points
1081 $subht = 12; # ADJUSTABLE: height of a sub-heading in points
1082 $pstart = 0; # start line of current page
1083 $plen = 0; # current length of current page
1084 $pnum = 1; # number of current page
1085 $bpt = -1; # last feasible break point
1086 $i = 0; # line number
1087 while ($i <= $#lnames) {
1088 $lname = $lnames[$i];
1089 # Add the height of this line (computed the last time we went round
1090 # the loop, unless we're a chapter heading in which case we do it
1091 # now) to the length of the current page. Also, _put_ this line on
1092 # the current page, and allocate it a y-coordinate.
1093 if ($ltypes[$i] =~ /^chap$/) {
1094 $plen = 100; # ADJUSTABLE: space taken up by a chapter heading
1095 $ycoord[$i] = 0; # chapter heading: y-coord doesn't matter
1096 } else {
1097 $ycoord[$i] = $plen + $space;
1098 $plen += $space + $ht;
1100 # See if we can break after this line.
1101 $bpt = $i if $ltypes[$i] !~ /^chap|head|subh|cbeg|nbeg|bbeg$/ &&
1102 $ltypes[$i+1] !~ /^cend|nend|bend$/;
1103 # Assume, to start with, that we don't break after this line.
1104 $break = 0;
1105 # See if a break is forced.
1106 $break = 1, $bpt = $i if $ltypes[$i+1] eq "chap" || !$ltypes[$i+1];
1107 # Otherwise, compute the height of the next line, and break if
1108 # it would make this page too long.
1109 $ht = $textht, $space = 0 if $ltypes[$i+1] =~ /^[nbc](bdy|end)$/;
1110 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^[nbc](one|beg)$/;
1111 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^C/;
1112 $ht = $subht, $space = $spacing if $ltypes[$i+1] eq "subh";
1113 $ht = $headht, $space = $spacing if $ltypes[$i+1] eq "head";
1114 $break = 1 if $plen + $space + $ht > $pmax;
1115 # Now, if we're breaking, assign page number $pnum to all lines up
1116 # to $bpt, set $i == $bpt+1, and zero $space since we are at the
1117 # start of a new page and don't want leading space.
1118 if ($break) {
1119 die "no feasible break point at all on page $pnum\n" if $bpt == -1;
1120 for ($j = $pstart; $j <= $bpt; $j++) {
1121 $lnamei = "idx" . $lnames[$j];
1122 foreach $k (@$lnamei) {
1123 ${$psidxpp{$k}}{$pnum} = 1;
1125 $lpages[$j] = $pnum;
1127 $pnum++;
1128 $i = $bpt;
1129 $bpt = -1;
1130 $pstart = $i+1;
1131 $plen = 0;
1132 $space = 0;
1134 $i++;
1137 # Now fix up the TOC with page numbers.
1138 print "\n fixing up contents...";
1139 for ($i=0; $i<=$#lnames; $i++) {
1140 $lname = $lnames[$i];
1141 if ($ltypes[$i] =~ /^C/) {
1142 $j = pop @$lname;
1143 push @$lname, "n" . $lpages[$j+$contlen];
1147 # Having got page numbers for most stuff, generate an index.
1148 print "building index...";
1149 $iwid = 222;
1150 $sep = 12;
1151 $commaindent = 32;
1152 foreach $k (@itags) {
1153 @line = ();
1154 $cmd = "index";
1155 @idxentry = @{$idxmap{$k}};
1156 if ($commaafter{$k} and !$commanext{$k}) {
1157 # This line is a null line beginning a multiple entry. We must
1158 # output the prefix on a line by itself.
1160 @idxhead = splice @idxentry,0,$commapos{$k};
1161 @line = ();
1162 foreach $i (@idxhead) {
1163 $ww = &word_ps($i);
1164 push @line, $ww unless $ww eq "x";
1166 &ps_idxout("index",\@line,[]);
1167 $cmd = "iindex";
1168 @line = ();
1170 $cmd = "iindex", splice @idxentry,0,$commapos{$k} if $commanext{$k};
1171 foreach $i (@idxentry) {
1172 $ww = &word_ps($i);
1173 push @line, $ww unless $ww eq "x";
1175 $len = $iwid - $sep - &len_ps(@line);
1176 warn "text for index tag `%s' is longer than one index line!\n"
1177 if $len < -$sep;
1178 @pp = ();
1179 $inums = join(',',sort { $a <=> $b } keys %{$psidxpp{$k}});
1180 while (length $inums) {
1181 $inums =~ /^([^,]+,?)(.*)$/;
1182 $inums = $2, $inum = $1;
1183 @pnum = (" ", "n$inum");
1184 $pnumlen = &len_ps(@pnum);
1185 if ($pnumlen > $len) {
1186 &ps_idxout($cmd,\@line,\@pp);
1187 @pp = ();
1188 @line = ();
1189 $cmd = "index";
1190 $len = $iwid - $sep;
1192 push @pp, @pnum;
1193 $len -= $pnumlen;
1195 &ps_idxout($cmd,\@line,\@pp) if (length @pp);
1196 $l1 = &len_ps(@line);
1197 $l2 = &len_ps($pp);
1199 $$idx_clname[$#$idx_clname] = "n" . $pnum; # fix up TOC entry for index
1201 print "writing file...";
1202 open PS,">nasmdoc.ps";
1203 select PS;
1204 $page = $lpages[0];
1205 &ps_header;
1206 for ($i=0; $i<=$#lnames; $i++) {
1207 &ps_throw_pg($page,$lpages[$i]) if $page != $lpages[$i];
1208 $page = $lpages[$i];
1209 &ps_out_line($ycoord[$i],$ltypes[$i],$lnames[$i]);
1211 $i = 0;
1212 while ($i <= $#psindex) {
1213 &ps_throw_pg($page, $pnum) if $page != $pnum;
1214 $page = $pnum++;
1215 $ypos = 0;
1216 $ypos = 100, &ps_out_line(0, "chap", ["nIndex"]) if !$i;
1217 $lines = ($pmax - $ypos) / $textht;
1218 my $col; # ps_out_line hits this variable
1219 PAGE:for ($col = 1; $col <= 2; $col++) {
1220 $y = $ypos; $l = $lines;
1221 COL: while ($l > 0) {
1222 $j = $i+1;
1223 $j++ while $psindex[$j] and ($psindex[$j][3] == 0); # find next break
1224 last COL if $j-$i > $l or $i > $#psindex;
1225 while ($i < $j) {
1226 &ps_out_line($y, $psindex[$i][0] eq "index" ? "idl$col" : "ldl$col",
1227 $psindex[$i][1]);
1228 &ps_out_line($y,"idr$col",$psindex[$i][2]);
1229 $i++;
1230 $y += $textht;
1231 $l--;
1234 last PAGE if $i > $#psindex;
1237 &ps_trailer;
1238 close PS;
1239 select STDOUT;
1242 sub ps_idxout {
1243 my ($cmd, $left, $right) = @_;
1244 my $break = 1;
1245 $break = 0
1246 if ($#psindex >= 0) and ( ($#$left < 0) or ($cmd eq "iindex") );
1247 push @psindex,[$cmd,[@$left],[@$right],$break];
1250 sub ps_header {
1251 @pshdr = (
1252 '/sp (n ) def', # here it's sure not to get wrapped inside ()
1253 '/nf /Times-Roman findfont 11 scalefont def',
1254 '/ef /Times-Italic findfont 11 scalefont def',
1255 '/cf /Courier findfont 11 scalefont def',
1256 '/nc /Helvetica-Bold findfont 18 scalefont def',
1257 '/ec /Helvetica-Oblique findfont 18 scalefont def',
1258 '/cc /Courier-Bold findfont 18 scalefont def',
1259 '/nh /Helvetica-Bold findfont 14 scalefont def',
1260 '/eh /Helvetica-Oblique findfont 14 scalefont def',
1261 '/ch /Courier-Bold findfont 14 scalefont def',
1262 '/ns /Helvetica-Bold findfont 12 scalefont def',
1263 '/es /Helvetica-Oblique findfont 12 scalefont def',
1264 '/cs /Courier-Bold findfont 12 scalefont def',
1265 '/n 16#6E def /e 16#65 def /c 16#63 def',
1266 '/chapter {',
1267 ' 100 620 moveto',
1268 ' {',
1269 ' dup 0 get',
1270 ' dup n eq {pop nc setfont} {',
1271 ' e eq {ec setfont} {cc setfont} ifelse',
1272 ' } ifelse',
1273 ' dup length 1 sub 1 exch getinterval show',
1274 ' } forall',
1275 ' 0 setlinecap 3 setlinewidth',
1276 ' newpath 100 610 moveto 468 0 rlineto stroke',
1277 '} def',
1278 '/heading {',
1279 ' 686 exch sub /y exch def /a exch def',
1280 ' 90 y moveto a 0 get dup length 1 sub 1 exch getinterval',
1281 ' nh setfont dup stringwidth pop neg 0 rmoveto show',
1282 ' 100 y moveto',
1283 ' a dup length 1 sub 1 exch getinterval {',
1284 ' /s exch def',
1285 ' s 0 get',
1286 ' dup n eq {pop nh setfont} {',
1287 ' e eq {eh setfont} {ch setfont} ifelse',
1288 ' } ifelse',
1289 ' s s length 1 sub 1 exch getinterval show',
1290 ' } forall',
1291 '} def',
1292 '/subhead {',
1293 ' 688 exch sub /y exch def /a exch def',
1294 ' 90 y moveto a 0 get dup length 1 sub 1 exch getinterval',
1295 ' ns setfont dup stringwidth pop neg 0 rmoveto show',
1296 ' 100 y moveto',
1297 ' a dup length 1 sub 1 exch getinterval {',
1298 ' /s exch def',
1299 ' s 0 get',
1300 ' dup n eq {pop ns setfont} {',
1301 ' e eq {es setfont} {cs setfont} ifelse',
1302 ' } ifelse',
1303 ' s s length 1 sub 1 exch getinterval show',
1304 ' } forall',
1305 '} def',
1306 '/disp { /j exch def',
1307 ' 568 exch sub exch 689 exch sub moveto',
1308 ' {',
1309 ' /s exch def',
1310 ' s 0 get',
1311 ' dup n eq {pop nf setfont} {',
1312 ' e eq {ef setfont} {cf setfont} ifelse',
1313 ' } ifelse',
1314 ' s s length 1 sub 1 exch getinterval show',
1315 ' s sp eq {j 0 rmoveto} if',
1316 ' } forall',
1317 '} def',
1318 '/contents { /w exch def /y exch def /a exch def',
1319 ' /yy 689 y sub def',
1320 ' a a length 1 sub get dup length 1 sub 1 exch getinterval /s exch def',
1321 ' nf setfont 568 s stringwidth pop sub /ex exch def',
1322 ' ex yy moveto s show',
1323 ' a 0 a length 1 sub getinterval y w 0 disp',
1324 ' /sx currentpoint pop def nf setfont',
1325 ' 100 10 568 { /i exch def',
1326 ' i 5 sub sx gt i 5 add ex lt and {',
1327 ' i yy moveto (.) show',
1328 ' } if',
1329 ' } for',
1330 '} def',
1331 '/just { /w exch def /y exch def /a exch def',
1332 ' /jj w def /spaces 0 def',
1333 ' a {',
1334 ' /s exch def',
1335 ' s 0 get',
1336 ' dup n eq {pop nf setfont} {',
1337 ' e eq {ef setfont} {cf setfont} ifelse',
1338 ' } ifelse',
1339 ' s s length 1 sub 1 exch getinterval stringwidth pop',
1340 ' jj exch sub /jj exch def',
1341 ' s sp eq {/spaces spaces 1 add def} if',
1342 ' } forall',
1343 ' a y w jj spaces spaces 0 eq {pop pop 0} {div} ifelse disp',
1344 '} def',
1345 '/idl { 468 exch sub 0 disp } def',
1346 '/ldl { 436 exch sub 0 disp } def',
1347 '/idr { 222 add 468 exch sub /x exch def /y exch def /a exch def',
1348 ' a {',
1349 ' /s exch def',
1350 ' s 0 get',
1351 ' dup n eq {pop nf setfont} {',
1352 ' e eq {ef setfont} {cf setfont} ifelse',
1353 ' } ifelse',
1354 ' s s length 1 sub 1 exch getinterval stringwidth pop',
1355 ' x add /x exch def',
1356 ' } forall',
1357 ' a y x 0 disp',
1358 '} def',
1359 '/left {0 disp} def',
1360 '/bullet {',
1361 ' nf setfont dup 100 exch 689 exch sub moveto (\267) show',
1362 '} def'
1364 print "%!PS-Adobe-3.0\n";
1365 print "%%BoundingBox: 95 95 590 705\n";
1366 print "%%Creator: a nasty Perl script\n";
1367 print "%%DocumentData: Clean7Bit\n";
1368 print "%%Orientation: Portrait\n";
1369 print "%%Pages: $lpages[$#lpages]\n";
1370 print "%%DocumentNeededResources: font Times-Roman Times-Italic\n";
1371 print "%%+ font Helvetica-Bold Courier Courier-Bold\n";
1372 print "%%EndComments\n%%BeginProlog\n%%EndProlog\n%%BeginSetup\nsave\n";
1373 $pshdr = join(' ',@pshdr);
1374 $pshdr =~ s/\s+/ /g;
1375 while ($pshdr =~ /\S/) {
1376 last if length($pshdr) < 72 || $pshdr !~ /^(.{0,72}\S)\s(.*)$/;
1377 $pshdr = $2;
1378 print "$1\n";
1380 print "$pshdr\n" if $pshdr =~ /\S/;
1381 print "%%EndSetup\n";
1382 &ps_initpg($lpages[0]);
1385 sub ps_trailer {
1386 &ps_donepg;
1387 print "%%Trailer\nrestore\n%%EOF\n";
1390 sub ps_throw_pg {
1391 my ($oldpg, $newpg) = @_;
1392 &ps_donepg;
1393 &ps_initpg($newpg);
1396 sub ps_initpg {
1397 my ($pgnum) = @_;
1398 print "%%Page: $pgnum $pgnum\n";
1399 print "%%BeginPageSetup\nsave\n%%EndPageSetup\n";
1402 sub ps_donepg {
1403 print "%%PageTrailer\nrestore showpage\n";
1406 sub ps_out_line {
1407 my ($ypos,$ltype,$lname) = @_;
1408 my $c,$d,$wid;
1410 print "[";
1411 $col = 1;
1412 foreach $c (@$lname) {#
1413 $c= "n " if $c eq " ";
1414 $c = "n\261" if $c eq "-";
1415 $d = '';
1416 while (length $c) {
1417 $d .= $1, $c = $2 while $c =~ /^([ -'\*-\[\]-~]+)(.*)$/;
1418 while (1) {
1419 $d .= "\\$1", $c = $2, next if $c =~ /^([\\\(\)])(.*)$/;
1420 ($d .= sprintf "\\%3o",unpack("C",$1)), $c = $2, next
1421 if $c =~ /^([^ -~])(.*)$/;
1422 last;
1425 $d = "($d)";
1426 $col = 0, print "\n" if $col>0 && $col+length $d > 77;
1427 print $d;
1428 $col += length $d;
1430 print "\n" if $col > 60;
1431 print "]";
1432 if ($ltype =~ /^[nb](beg|bdy)$/) {
1433 printf "%d %s%d just\n",
1434 $ypos, ($ltype eq "bbeg" ? "bullet " : ""),
1435 ($ltype =~ /^b/ ? 456 : 468);
1436 } elsif ($ltype =~ /^[nb](one|end)$/) {
1437 printf "%d %s%d left\n",
1438 $ypos, ($ltype eq "bone" ? "bullet " : ""),
1439 ($ltype =~ /^b/ ? 456 : 468);
1440 } elsif ($ltype =~ /^c(one|beg|bdy|end)$/) {
1441 printf "$ypos 468 left\n";
1442 } elsif ($ltype =~ /^C/) {
1443 $wid = 468;
1444 $wid = 456 if $ltype eq "Chea";
1445 $wid = 444 if $ltype eq "Csub";
1446 printf "$ypos $wid contents\n";
1447 } elsif ($ltype eq "chap") {
1448 printf "chapter\n";
1449 } elsif ($ltype eq "head") {
1450 printf "$ypos heading\n";
1451 } elsif ($ltype eq "subh") {
1452 printf "$ypos subhead\n";
1453 } elsif ($ltype =~ /([il]d[lr])([12])/) {
1454 $left = ($2 eq "2" ? 468-222 : 0);
1455 printf "$ypos $left $1\n";
1459 sub word_ps {
1460 my ($w) = @_;
1461 my $wtype, $wmajt;
1463 return undef if $w eq '' || $w eq undef;
1465 $wtype = substr($w,0,2);
1466 $wmajt = substr($wtype,0,1);
1467 $w = substr($w,2);
1468 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1469 if ($wmajt eq "n" || $wtype eq "w ") {
1470 return "n$w";
1471 } elsif ($wtype eq "sp") {
1472 return ' ';
1473 } elsif ($wtype eq "da") {
1474 return '-';
1475 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1476 return "c$w";
1477 } elsif ($wmajt eq "e") {
1478 return "e$w";
1479 } elsif ($wmajt eq "x") {
1480 return "x";
1481 } elsif ($wtype eq "i ") {
1482 push @lindex, $w;
1483 return "x";
1484 } else {
1485 die "panic in word_ps: $wtype$w\n";
1489 sub len_ps {
1490 my (@line) = @_;
1491 my $l = 0;
1492 my $w, $size;
1494 $size = 11/1000; # used only for length calculations
1495 while ($w = shift @line) {
1496 $w = "n " if $w eq " ";
1497 $w = "n\261" if $w eq "-";
1498 $f = substr($w,0,1);
1499 $f = "timesr" if $f eq "n";
1500 $f = "timesi" if $f eq "e";
1501 $f = "courr" if $f eq "c";
1502 foreach $c (unpack 'C*',substr($w,1)) {
1503 $l += $size * $$f[$c];
1506 return $l;
1509 sub write_texi {
1510 # This is called from the top level, so I won't bother using
1511 # my or local.
1513 # Open file.
1514 print "writing file...";
1515 open TEXT,">nasmdoc.texi";
1516 select TEXT;
1518 # Preamble.
1519 print "\input texinfo \@c -*-texinfo-*-\n";
1520 print "\@c \%**start of header\n";
1521 print "\@setfilename nasm.info\n";
1522 print "\@settitle NASM: The Netwide Assembler\n";
1523 print "\@setchapternewpage odd\n";
1524 print "\@c \%**end of header\n";
1525 print "\n";
1526 print "\@ifinfo\n";
1527 print "This file documents NASM, the Netwide Assembler: an assembler\n";
1528 print "targetting the Intel x86 series of processors, with portable source.\n";
1529 print "\n";
1530 print "Copyright 1997 Simon Tatham\n";
1531 print "\n";
1532 print "All rights reserved. This document is redistributable under the\n";
1533 print "licence given in the file \"Licence\" distributed in the NASM archive.\n";
1534 print "\@end ifinfo\n";
1535 print "\n";
1536 print "\@titlepage\n";
1537 print "\@title NASM: The Netwide Assembler\n";
1538 print "\@author Simon Tatham\n";
1539 print "\n";
1540 print "\@page\n";
1541 print "\@vskip 0pt plus 1filll\n";
1542 print "Copyright \@copyright{} 1997 Simon Tatham\n";
1543 print "\n";
1544 print "All rights reserved. This document is redistributable under the\n";
1545 print "licence given in the file \"Licence\" distributed in the NASM archive.\n";
1546 print "\@end titlepage\n";
1547 print "\n";
1548 print "\@node Top, $tstruct_next{'Top'}, (dir), (dir)\n";
1549 print "\@top\n";
1550 print "\n";
1551 print "\@ifinfo\n";
1552 print "This file documents NASM, the Netwide Assembler: an assembler\n";
1553 print "targetting the Intel x86 series of processors, with portable source.\n";
1554 print "\@end ifinfo\n";
1556 $node = "Top";
1558 $bulleting = 0;
1559 for ($para = 0; $para <= $#pnames; $para++) {
1560 $pname = $pnames[$para];
1561 $pflags = $pflags[$para];
1562 $ptype = substr($pflags,0,4);
1564 $bulleting = 0, print "\@end itemize\n" if $bulleting && $ptype ne "bull";
1565 print "\n"; # always one of these before a new paragraph
1567 if ($ptype eq "chap") {
1568 # Chapter heading. Begin a new node.
1569 &texi_menu($node)
1570 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1571 $pflags =~ /chap (.*) :(.*)/;
1572 $node = "Chapter $1";
1573 $title = "Chapter $1: ";
1574 foreach $i (@$pname) {
1575 $ww = &word_texi($i);
1576 $title .= $ww unless $ww eq "\001";
1578 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1579 print " $tstruct_up{$node}\n\@unnumbered $title\n";
1580 } elsif ($ptype eq "appn") {
1581 # Appendix heading. Begin a new node.
1582 &texi_menu($node)
1583 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1584 $pflags =~ /appn (.*) :(.*)/;
1585 $node = "Appendix $1";
1586 $title = "Appendix $1: ";
1587 foreach $i (@$pname) {
1588 $ww = &word_texi($i);
1589 $title .= $ww unless $ww eq "\001";
1591 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1592 print " $tstruct_up{$node}\n\@unnumbered $title\n";
1593 } elsif ($ptype eq "head" || $ptype eq "subh") {
1594 # Heading or subheading. Begin a new node.
1595 &texi_menu($node)
1596 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1597 $pflags =~ /.... (.*) :(.*)/;
1598 $node = "Section $1";
1599 $title = "$1. ";
1600 foreach $i (@$pname) {
1601 $ww = &word_texi($i);
1602 $title .= $ww unless $ww eq "\001";
1604 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1605 print " $tstruct_up{$node}\n\@unnumbered $title\n";
1606 } elsif ($ptype eq "code") {
1607 # Code paragraph. Surround with @example / @end example.
1608 print "\@example\n";
1609 foreach $i (@$pname) {
1610 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1611 $i =~ s/\@/\@\@/g;
1612 $i =~ s/\{/\@\{/g;
1613 $i =~ s/\}/\@\}/g;
1614 print "$i\n";
1616 print "\@end example\n";
1617 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1618 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1619 if ($ptype eq "bull") {
1620 $bulleting = 1, print "\@itemize \@bullet\n" if !$bulleting;
1621 print "\@item\n";
1623 $line = '';
1624 @a = @$pname;
1625 $wd = $wprev = '';
1626 do {
1627 do { $w = &word_texi(shift @a); } while $w eq "\001"; # hack
1628 $wd .= $wprev;
1629 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1630 if (length ($line . $wd) > 75) {
1631 $line =~ s/\s*$//; # trim trailing spaces
1632 print "$line\n";
1633 $line = '';
1634 $wd =~ s/^\s*//; # trim leading spaces
1636 $line .= $wd;
1637 $wd = '';
1639 $wprev = $w;
1640 } while ($w ne '' && $w ne undef);
1641 if ($line =~ /\S/) {
1642 $line =~ s/\s*$//; # trim trailing spaces
1643 print "$line\n";
1648 # Write index.
1649 &texi_index;
1651 # Close file.
1652 print "\n\@contents\n\@bye\n";
1653 select STDOUT;
1654 close TEXT;
1657 # Side effect of this procedure: update global `texiwdlen' to be the length
1658 # in chars of the formatted version of the word.
1659 sub word_texi {
1660 my ($w) = @_;
1661 my $wtype, $wmajt;
1663 return undef if $w eq '' || $w eq undef;
1664 $wtype = substr($w,0,2);
1665 $wmajt = substr($wtype,0,1);
1666 $w = substr($w,2);
1667 $wlen = length $w;
1668 $w =~ s/\@/\@\@/g;
1669 $w =~ s/\{/\@\{/g;
1670 $w =~ s/\}/\@\}/g;
1671 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1672 substr($w,0,1) =~ tr/a-z/A-Z/, $capital = 0 if $capital;
1673 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1674 $texiwdlen = $wlen;
1675 return $w;
1676 } elsif ($wtype eq "sp") {
1677 $texiwdlen = 1;
1678 return ' ';
1679 } elsif ($wtype eq "da") {
1680 $texiwdlen = 2;
1681 return '--';
1682 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1683 $texiwdlen = 2 + $wlen;
1684 return "\@code\{$w\}";
1685 } elsif ($wtype eq "es") {
1686 $texiwdlen = 1 + $wlen;
1687 return "\@emph\{${w}";
1688 } elsif ($wtype eq "ee") {
1689 $texiwdlen = 1 + $wlen;
1690 return "${w}\}";
1691 } elsif ($wtype eq "eo") {
1692 $texiwdlen = 2 + $wlen;
1693 return "\@emph\{${w}\}";
1694 } elsif ($wtype eq "x ") {
1695 $texiwdlen = 0; # we don't need it in this case
1696 $capital = 1; # hack
1697 return "\@ref\{";
1698 } elsif ($wtype eq "xe") {
1699 $texiwdlen = 0; # we don't need it in this case
1700 return "\}";
1701 } elsif ($wmajt eq "i") {
1702 $texiwdlen = 0; # we don't need it in this case
1703 return "\001";
1704 } else {
1705 die "panic in word_texi: $wtype$w\n";
1709 sub texi_menu {
1710 my ($topitem) = @_;
1711 my $item, $i, $mpname, $title, $wd;
1713 $item = $tstruct_next{$topitem};
1714 print "\@menu\n";
1715 while ($item) {
1716 $title = "";
1717 $mpname = $tstruct_pname{$item};
1718 foreach $i (@$mpname) {
1719 $wd = &word_texi($i);
1720 $title .= $wd unless $wd eq "\001";
1722 print "* ${item}:: $title\n";
1723 $item = $tstruct_mnext{$item};
1725 print "* Index::\n" if $topitem eq "Top";
1726 print "\@end menu\n";
1729 sub texi_index {
1730 my $itag, $ientry, @a, $wd, $item, $len;
1731 my $subnums = "123456789ABCDEFGHIJKLMNOPQRSTU" .
1732 "VWXYZabcdefghijklmnopqrstuvwxyz";
1734 print "\@ifinfo\n\@node Index, , $FIXMElastnode, Top\n";
1735 print "\@unnumbered Index\n\n\@menu\n";
1737 foreach $itag (@itags) {
1738 $ientry = $idxmap{$itag};
1739 @a = @$ientry;
1740 $item = '';
1741 $len = 0;
1742 foreach $i (@a) {
1743 $wd = &word_texi($i);
1744 $item .= $wd, $len += $texiwdlen unless $wd eq "\001";
1746 $i = 0;
1747 foreach $node (@nodes) {
1748 next if !$idxnodes{$node,$itag};
1749 printf "* %s%s (%s): %s.\n",
1750 $item, " " x (40-$len), substr($subnums,$i++,1), $node;
1753 print "\@end menu\n\@end ifinfo\n";
1756 sub write_hlp {
1757 # This is called from the top level, so I won't bother using
1758 # my or local.
1760 # Build the index-tag text forms.
1761 print "building index entries...";
1762 @hlp_index = map {
1763 my $i,$ww;
1764 my $ientry = $idxmap{$_};
1765 my $title = "";
1766 foreach $i (@$ientry) {
1767 $ww = &word_hlp($i,0);
1768 $title .= $ww unless $ww eq "\001";
1770 $title;
1771 } @itags;
1773 # Write the HPJ project-description file.
1774 print "writing .hpj file...";
1775 open HPJ,">nasmdoc.hpj";
1776 print HPJ "[OPTIONS]\ncompress=true\n";
1777 print HPJ "title=NASM: The Netwide Assembler\noldkeyphrase=no\n\n";
1778 print HPJ "[FILES]\nnasmdoc.rtf\n\n";
1779 print HPJ "[CONFIG]\n";
1780 print HPJ 'CreateButton("btn_up", "&Up",'.
1781 ' "JumpContents(`nasmdoc.hlp'."'".')")';
1782 print HPJ "\nBrowseButtons()\n";
1783 close HPJ;
1785 # Open file.
1786 print "\n writing .rtf file...";
1787 open TEXT,">nasmdoc.rtf";
1788 select TEXT;
1790 # Preamble.
1791 print "{\\rtf1\\ansi{\\fonttbl\n";
1792 print "\\f0\\froman Times New Roman;\\f1\\fmodern Courier New;\n";
1793 print "\\f2\\fswiss Arial;\\f3\\ftech Wingdings}\\deff0\n";
1794 print "#{\\footnote Top}\n";
1795 print "\${\\footnote Contents}\n";
1796 print "+{\\footnote browse:00000}\n";
1797 print "!{\\footnote DisableButton(\"btn_up\")}\n";
1798 print "\\keepn\\f2\\b\\fs30\\sb0\n";
1799 print "NASM: The Netwide Assembler\n";
1800 print "\\par\\pard\\plain\\sb120\n";
1801 print "This file documents NASM, the Netwide Assembler: an assembler \n";
1802 print "targetting the Intel x86 series of processors, with portable source.\n";
1804 $node = "Top";
1805 $browse = 0;
1807 $newpar = "\\par\\sb120\n";
1808 for ($para = 0; $para <= $#pnames; $para++) {
1809 $pname = $pnames[$para];
1810 $pflags = $pflags[$para];
1811 $ptype = substr($pflags,0,4);
1813 print $newpar;
1814 $newpar = "\\par\\sb120\n";
1816 if ($ptype eq "chap") {
1817 # Chapter heading. Begin a new node.
1818 &hlp_menu($node)
1819 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1820 $pflags =~ /chap (.*) :(.*)/;
1821 $node = "Chapter $1";
1822 $title = $footnotetitle = "Chapter $1: ";
1823 foreach $i (@$pname) {
1824 $ww = &word_hlp($i,1);
1825 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1827 print "\\page\n";
1828 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1829 print "\${\\footnote $footnotetitle}\n";
1830 printf "+{\\footnote browse:%05d}\n", ++$browse;
1831 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1832 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1833 &hlp_sectkw($tstruct_up{$node});
1834 print "EnableButton(\"btn_up\")}\n";
1835 &hlp_keywords($node);
1836 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1837 print "$title\n";
1838 $newpar = "\\par\\pard\\plain\\sb120\n";
1839 } elsif ($ptype eq "appn") {
1840 # Appendix heading. Begin a new node.
1841 &hlp_menu($node)
1842 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1843 $pflags =~ /appn (.*) :(.*)/;
1844 $node = "Appendix $1";
1845 $title = $footnotetitle = "Appendix $1: ";
1846 foreach $i (@$pname) {
1847 $ww = &word_hlp($i,1);
1848 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1850 print "\\page\n";
1851 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1852 print "\${\\footnote $footnotetitle}\n";
1853 printf "+{\\footnote browse:%05d}\n", ++$browse;
1854 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1855 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1856 &hlp_sectkw($tstruct_up{$node});
1857 print "EnableButton(\"btn_up\")}\n";
1858 &hlp_keywords($node);
1859 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1860 print "$title\n";
1861 $newpar = "\\par\\pard\\plain\\sb120\n";
1862 } elsif ($ptype eq "head" || $ptype eq "subh") {
1863 # Heading or subheading. Begin a new node.
1864 &hlp_menu($node)
1865 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1866 $pflags =~ /.... (.*) :(.*)/;
1867 $node = "Section $1";
1868 $title = $footnotetitle = "$1. ";
1869 foreach $i (@$pname) {
1870 $ww = &word_hlp($i,1);
1871 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1873 print "\\page\n";
1874 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1875 print "\${\\footnote $footnotetitle}\n";
1876 printf "+{\\footnote browse:%05d}\n", ++$browse;
1877 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1878 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1879 &hlp_sectkw($tstruct_up{$node});
1880 print "EnableButton(\"btn_up\")}\n";
1881 &hlp_keywords($node);
1882 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1883 print "$title\n";
1884 $newpar = "\\par\\pard\\plain\\sb120\n";
1885 } elsif ($ptype eq "code") {
1886 # Code paragraph.
1887 print "\\keep\\f1\\sb120\n";
1888 foreach $i (@$pname) {
1889 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1890 $i =~ s/\\/\\\\/g;
1891 $i =~ s/\{/\\\{/g;
1892 $i =~ s/\}/\\\}/g;
1893 print "$i\\par\\sb0\n";
1895 $newpar = "\\pard\\f0\\sb120\n";
1896 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1897 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1898 if ($ptype eq "bull") {
1899 print "\\tx360\\li360\\fi-360{\\f3\\'9F}\\tab\n";
1900 $newpar = "\\par\\pard\\sb120\n";
1901 } else {
1902 $newpar = "\\par\\sb120\n";
1904 $line = '';
1905 @a = @$pname;
1906 $wd = $wprev = '';
1907 do {
1908 do { $w = &word_hlp((shift @a),1); } while $w eq "\001"; # hack
1909 $wd .= $wprev;
1910 if ($w eq ' ' || $w eq '' || $w eq undef) {
1911 if (length ($line . $wd) > 75) {
1912 $line =~ s/\s*$//; # trim trailing spaces
1913 print "$line \n"; # and put one back
1914 $line = '';
1915 $wd =~ s/^\s*//; # trim leading spaces
1917 $line .= $wd;
1918 $wd = '';
1920 $wprev = $w;
1921 } while ($w ne '' && $w ne undef);
1922 if ($line =~ /\S/) {
1923 $line =~ s/\s*$//; # trim trailing spaces
1924 print "$line\n";
1929 # Close file.
1930 print "\\page}\n";
1931 select STDOUT;
1932 close TEXT;
1935 sub word_hlp {
1936 my ($w, $docode) = @_;
1937 my $wtype, $wmajt;
1939 return undef if $w eq '' || $w eq undef;
1940 $wtype = substr($w,0,2);
1941 $wmajt = substr($wtype,0,1);
1942 $w = substr($w,2);
1943 $w =~ s/\\/\\\\/g;
1944 $w =~ s/\{/\\\{/g;
1945 $w =~ s/\}/\\\}/g;
1946 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1947 substr($w,0,length($w)-1) =~ s/-/\\'AD/g if $wmajt ne "x"; #nonbreakhyphens
1948 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1949 return $w;
1950 } elsif ($wtype eq "sp") {
1951 return ' ';
1952 } elsif ($wtype eq "da") {
1953 return "\\'96";
1954 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1955 $w =~ s/ /\\'A0/g; # make spaces non-breaking
1956 return $docode ? "{\\f1 ${w}}" : $w;
1957 } elsif ($wtype eq "es") {
1958 return "{\\i ${w}";
1959 } elsif ($wtype eq "ee") {
1960 return "${w}}";
1961 } elsif ($wtype eq "eo") {
1962 return "{\\i ${w}}";
1963 } elsif ($wtype eq "x ") {
1964 return "{\\uldb ";
1965 } elsif ($wtype eq "xe") {
1966 $w = &hlp_sectkw($w);
1967 return "}{\\v ${w}}";
1968 } elsif ($wmajt eq "i") {
1969 return "\001";
1970 } else {
1971 die "panic in word_hlp: $wtype$w\n";
1975 sub hlp_menu {
1976 my ($topitem) = @_;
1977 my $item, $kword, $i, $mpname, $title;
1979 $item = $tstruct_next{$topitem};
1980 print "\\li360\\fi-360\n";
1981 while ($item) {
1982 $title = "";
1983 $mpname = $tstruct_pname{$item};
1984 foreach $i (@$mpname) {
1985 $ww = &word_hlp($i, 0);
1986 $title .= $ww unless $ww eq "\001";
1988 $kword = &hlp_sectkw($item);
1989 print "{\\uldb ${item}: $title}{\\v $kword}\\par\\sb0\n";
1990 $item = $tstruct_mnext{$item};
1992 print "\\pard\\sb120\n";
1995 sub hlp_sectkw {
1996 my ($node) = @_;
1997 $node =~ tr/A-Z/a-z/;
1998 $node =~ tr/- ./___/;
1999 $node;
2002 sub hlp_keywords {
2003 my ($node) = @_;
2004 my $pfx = "K{\\footnote ";
2005 my $done = 0;
2006 foreach $i (0..$#itags) {
2007 (print $pfx,$hlp_index[$i]), $pfx = ";\n", $done++
2008 if $idxnodes{$node,$itags[$i]};
2010 print "}\n" if $done;
2013 # Make tree structures. $tstruct_* is top-level and global.
2014 sub add_item {
2015 my ($item, $level) = @_;
2016 my $i;
2018 $tstruct_pname{$item} = $pname;
2019 $tstruct_next{$tstruct_previtem} = $item;
2020 $tstruct_prev{$item} = $tstruct_previtem;
2021 $tstruct_level{$item} = $level;
2022 $tstruct_up{$item} = $tstruct_last[$level-1];
2023 $tstruct_mnext{$tstruct_last[$level]} = $item;
2024 $tstruct_last[$level] = $item;
2025 for ($i=$level+1; $i<$MAXLEVEL; $i++) { $tstruct_last[$i] = undef; }
2026 $tstruct_previtem = $item;
2027 push @nodes, $item;
2030 # PostScript font metric data. Used for line breaking.
2031 sub font_metrics {
2032 @timesr = (
2033 250, 0, 0, 0, 0, 0, 0, 0,
2034 0, 0, 0, 0, 0, 0, 0, 0,
2035 0, 0, 0, 0, 0, 0, 0, 0,
2036 0, 0, 0, 0, 0, 0, 0, 0,
2037 250, 333, 408, 500, 500, 833, 778, 333,
2038 333, 333, 500, 564, 250, 333, 250, 278,
2039 500, 500, 500, 500, 500, 500, 500, 500,
2040 500, 500, 278, 278, 564, 564, 564, 444,
2041 921, 722, 667, 667, 722, 611, 556, 722,
2042 722, 333, 389, 722, 611, 889, 722, 722,
2043 556, 722, 667, 556, 611, 722, 722, 944,
2044 722, 722, 611, 333, 278, 333, 469, 500,
2045 333, 444, 500, 444, 500, 444, 333, 500,
2046 500, 278, 278, 500, 278, 778, 500, 500,
2047 500, 500, 333, 389, 278, 500, 500, 722,
2048 500, 500, 444, 480, 200, 480, 541, 0,
2049 0, 0, 0, 0, 0, 0, 0, 0,
2050 0, 0, 0, 0, 0, 0, 0, 0,
2051 0, 0, 0, 0, 0, 0, 0, 0,
2052 0, 0, 0, 0, 0, 0, 0, 0,
2053 0, 333, 500, 500, 167, 500, 500, 500,
2054 500, 180, 444, 500, 333, 333, 556, 556,
2055 0, 500, 500, 500, 250, 0, 453, 350,
2056 333, 444, 444, 500,1000,1000, 0, 444,
2057 0, 333, 333, 333, 333, 333, 333, 333,
2058 333, 0, 333, 333, 0, 333, 333, 333,
2059 1000, 0, 0, 0, 0, 0, 0, 0,
2060 0, 0, 0, 0, 0, 0, 0, 0,
2061 0, 889, 0, 276, 0, 0, 0, 0,
2062 611, 722, 889, 310, 0, 0, 0, 0,
2063 0, 667, 0, 0, 0, 278, 0, 0,
2064 278, 500, 722, 500, 0, 0, 0, 0
2066 @timesi = (
2067 250, 0, 0, 0, 0, 0, 0, 0,
2068 0, 0, 0, 0, 0, 0, 0, 0,
2069 0, 0, 0, 0, 0, 0, 0, 0,
2070 0, 0, 0, 0, 0, 0, 0, 0,
2071 250, 333, 420, 500, 500, 833, 778, 333,
2072 333, 333, 500, 675, 250, 333, 250, 278,
2073 500, 500, 500, 500, 500, 500, 500, 500,
2074 500, 500, 333, 333, 675, 675, 675, 500,
2075 920, 611, 611, 667, 722, 611, 611, 722,
2076 722, 333, 444, 667, 556, 833, 667, 722,
2077 611, 722, 611, 500, 556, 722, 611, 833,
2078 611, 556, 556, 389, 278, 389, 422, 500,
2079 333, 500, 500, 444, 500, 444, 278, 500,
2080 500, 278, 278, 444, 278, 722, 500, 500,
2081 500, 500, 389, 389, 278, 500, 444, 667,
2082 444, 444, 389, 400, 275, 400, 541, 0,
2083 0, 0, 0, 0, 0, 0, 0, 0,
2084 0, 0, 0, 0, 0, 0, 0, 0,
2085 0, 0, 0, 0, 0, 0, 0, 0,
2086 0, 0, 0, 0, 0, 0, 0, 0,
2087 0, 389, 500, 500, 167, 500, 500, 500,
2088 500, 214, 556, 500, 333, 333, 500, 500,
2089 0, 500, 500, 500, 250, 0, 523, 350,
2090 333, 556, 556, 500, 889,1000, 0, 500,
2091 0, 333, 333, 333, 333, 333, 333, 333,
2092 333, 0, 333, 333, 0, 333, 333, 333,
2093 889, 0, 0, 0, 0, 0, 0, 0,
2094 0, 0, 0, 0, 0, 0, 0, 0,
2095 0, 889, 0, 276, 0, 0, 0, 0,
2096 556, 722, 944, 310, 0, 0, 0, 0,
2097 0, 667, 0, 0, 0, 278, 0, 0,
2098 278, 500, 667, 500, 0, 0, 0, 0
2100 @courr = (
2101 600, 0, 0, 0, 0, 0, 0, 0,
2102 0, 0, 0, 0, 0, 0, 0, 0,
2103 0, 0, 0, 0, 0, 0, 0, 0,
2104 0, 0, 0, 0, 0, 0, 0, 0,
2105 600, 600, 600, 600, 600, 600, 600, 600,
2106 600, 600, 600, 600, 600, 600, 600, 600,
2107 600, 600, 600, 600, 600, 600, 600, 600,
2108 600, 600, 600, 600, 600, 600, 600, 600,
2109 600, 600, 600, 600, 600, 600, 600, 600,
2110 600, 600, 600, 600, 600, 600, 600, 600,
2111 600, 600, 600, 600, 600, 600, 600, 600,
2112 600, 600, 600, 600, 600, 600, 600, 600,
2113 600, 600, 600, 600, 600, 600, 600, 600,
2114 600, 600, 600, 600, 600, 600, 600, 600,
2115 600, 600, 600, 600, 600, 600, 600, 600,
2116 600, 600, 600, 600, 600, 600, 600, 0,
2117 0, 0, 0, 0, 0, 0, 0, 0,
2118 0, 0, 0, 0, 0, 0, 0, 0,
2119 0, 0, 0, 0, 0, 0, 0, 0,
2120 0, 0, 0, 0, 0, 0, 0, 0,
2121 0, 600, 600, 600, 600, 600, 600, 600,
2122 600, 600, 600, 600, 600, 600, 600, 600,
2123 0, 600, 600, 600, 600, 0, 600, 600,
2124 600, 600, 600, 600, 600, 600, 0, 600,
2125 0, 600, 600, 600, 600, 600, 600, 600,
2126 600, 0, 600, 600, 0, 600, 600, 600,
2127 600, 0, 0, 0, 0, 0, 0, 0,
2128 0, 0, 0, 0, 0, 0, 0, 0,
2129 0, 600, 0, 600, 0, 0, 0, 0,
2130 600, 600, 600, 600, 0, 0, 0, 0,
2131 0, 600, 0, 0, 0, 600, 0, 0,
2132 600, 600, 600, 600, 0, 0, 0, 0