NASM 0.98.08
[nasm/avx512.git] / doc / rdsrc.pl
blobb174dd29e1614df8492a283f86e55f84d1330e4a
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 $diag = 1, shift @ARGV if $ARGV[0] eq "-d";
79 $| = 1;
81 $tstruct_previtem = $node = "Top";
82 $nodes = ($node);
83 $tstruct_level{$tstruct_previtem} = 0;
84 $tstruct_last[$tstruct_level{$tstruct_previtem}] = $tstruct_previtem;
85 $MAXLEVEL = 10; # really 3, but play safe ;-)
87 # Read the file; pass a paragraph at a time to the paragraph processor.
88 print "Reading input...";
89 $pname = "para000000";
90 @pnames = @pflags = ();
91 $para = undef;
92 while (<>) {
93 chomp;
94 if (!/\S/ || /^\\I[AR]/) { # special case: \I[AR] implies new-paragraph
95 &got_para($para);
96 $para = undef;
98 if (/\S/) {
99 s/\\#.*$//; # strip comments
100 $para .= " " . $_;
103 &got_para($para);
104 print "done.\n";
106 # Now we've read in the entire document and we know what all the
107 # heading keywords refer to. Go through and fix up the \k references.
108 print "Fixing up cross-references...";
109 &fixup_xrefs;
110 print "done.\n";
112 # Sort the index tags, according to the slightly odd order I've decided on.
113 print "Sorting index tags...";
114 &indexsort;
115 print "done.\n";
117 if ($diag) {
118 print "Writing index-diagnostic file...";
119 &indexdiag;
120 print "done.\n";
123 # OK. Write out the various output files.
124 print "Producing text output: ";
125 &write_txt;
126 print "done.\n";
127 print "Producing HTML output: ";
128 &write_html;
129 print "done.\n";
130 print "Producing PostScript output: ";
131 &write_ps;
132 print "done.\n";
133 print "Producing Texinfo output: ";
134 &write_texi;
135 print "done.\n";
136 print "Producing WinHelp output: ";
137 &write_hlp;
138 print "done.\n";
140 sub got_para {
141 local ($_) = @_;
142 my $pflags = "", $i, $w, $l, $t;
143 return if !/\S/;
145 @$pname = ();
147 # Strip off _leading_ spaces, then determine type of paragraph.
148 s/^\s*//;
149 $irewrite = undef;
150 if (/^\\c[^{]/) {
151 # A code paragraph. The paragraph-array will contain the simple
152 # strings which form each line of the paragraph.
153 $pflags = "code";
154 while (/^\\c (([^\\]|\\[^c])*)(.*)$/) {
155 $l = $1;
156 $_ = $3;
157 $l =~ s/\\{/{/g;
158 $l =~ s/\\}/}/g;
159 $l =~ s/\\\\/\\/g;
160 push @$pname, $l;
162 $_ = ''; # suppress word-by-word code
163 } elsif (/^\\C/) {
164 # A chapter heading. Define the keyword and allocate a chapter
165 # number.
166 $cnum++;
167 $hnum = 0;
168 $snum = 0;
169 $xref = "chapter-$cnum";
170 $pflags = "chap $cnum :$xref";
171 die "badly formatted chapter heading: $_\n" if !/^\\C{([^}]*)}\s*(.*)$/;
172 $refs{$1} = "chapter $cnum";
173 $node = "Chapter $cnum";
174 &add_item($node, 1);
175 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
176 $xrefs{$1} = $xref;
177 $_ = $2;
178 # the standard word-by-word code will happen next
179 } elsif (/^\\A/) {
180 # An appendix heading. Define the keyword and allocate an appendix
181 # letter.
182 $cnum++;
183 $cnum = 'A' if $cnum =~ /[0-9]+/;
184 $hnum = 0;
185 $snum = 0;
186 $xref = "appendix-$cnum";
187 $pflags = "appn $cnum :$xref";
188 die "badly formatted appendix heading: $_\n" if !/^\\A{([^}]*)}\s*(.*)$/;
189 $refs{$1} = "appendix $cnum";
190 $node = "Appendix $cnum";
191 &add_item($node, 1);
192 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
193 $xrefs{$1} = $xref;
194 $_ = $2;
195 # the standard word-by-word code will happen next
196 } elsif (/^\\H/) {
197 # A major heading. Define the keyword and allocate a section number.
198 $hnum++;
199 $snum = 0;
200 $xref = "section-$cnum.$hnum";
201 $pflags = "head $cnum.$hnum :$xref";
202 die "badly formatted heading: $_\n" if !/^\\[HP]{([^}]*)}\s*(.*)$/;
203 $refs{$1} = "section $cnum.$hnum";
204 $node = "Section $cnum.$hnum";
205 &add_item($node, 2);
206 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
207 $xrefs{$1} = $xref;
208 $_ = $2;
209 # the standard word-by-word code will happen next
210 } elsif (/^\\S/) {
211 # A sub-heading. Define the keyword and allocate a section number.
212 $snum++;
213 $xref = "section-$cnum.$hnum.$snum";
214 $pflags = "subh $cnum.$hnum.$snum :$xref";
215 die "badly formatted subheading: $_\n" if !/^\\S{([^}]*)}\s*(.*)$/;
216 $refs{$1} = "section $cnum.$hnum.$snum";
217 $node = "Section $cnum.$hnum.$snum";
218 &add_item($node, 3);
219 $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
220 $xrefs{$1} = $xref;
221 $_ = $2;
222 # the standard word-by-word code will happen next
223 } elsif (/^\\IR/) {
224 # An index-rewrite.
225 die "badly formatted index rewrite: $_\n" if !/^\\IR{([^}]*)}\s*(.*)$/;
226 $irewrite = $1;
227 $_ = $2;
228 # the standard word-by-word code will happen next
229 } elsif (/^\\IA/) {
230 # An index-alias.
231 die "badly formatted index alias: $_\n" if !/^\\IA{([^}]*)}{([^}]*)}\s*$/;
232 $idxalias{$1} = $2;
233 return; # avoid word-by-word code
234 } elsif (/^\\b/) {
235 # A bulleted paragraph. Strip off the initial \b and let the
236 # word-by-word code take care of the rest.
237 $pflags = "bull";
238 s/^\\b\s*//;
239 } else {
240 # A normal paragraph. Just set $pflags: the word-by-word code does
241 # the rest.
242 $pflags = "norm";
245 # The word-by-word code: unless @$pname is already defined (which it
246 # will be in the case of a code paragraph), split the paragraph up
247 # into words and push each on @$pname.
249 # Each thing pushed on @$pname should have a two-character type
250 # code followed by the text.
252 # Type codes are:
253 # "n " for normal
254 # "da" for a dash
255 # "es" for first emphasised word in emphasised bit
256 # "e " for emphasised in mid-emphasised-bit
257 # "ee" for last emphasised word in emphasised bit
258 # "eo" for single (only) emphasised word
259 # "c " for code
260 # "k " for cross-ref
261 # "kK" for capitalised cross-ref
262 # "w " for Web link
263 # "wc" for code-type Web link
264 # "x " for beginning of resolved cross-ref; generates no visible output,
265 # and the text is the cross-reference code
266 # "xe" for end of resolved cross-ref; text is same as for "x ".
267 # "i " for point to be indexed: the text is the internal index into the
268 # index-items arrays
269 # "sp" for space
270 while (/\S/) {
271 s/^\s*//, push @$pname, "sp" if /^\s/;
272 $indexing = $qindex = 0;
273 if (/^(\\[iI])?\\c/) {
274 $qindex = 1 if $1 eq "\\I";
275 $indexing = 1, s/^\\[iI]// if $1;
276 s/^\\c//;
277 die "badly formatted \\c: \\c$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
278 $w = $1;
279 $_ = $3;
280 $w =~ s/\\{/{/g;
281 $w =~ s/\\}/}/g;
282 $w =~ s/\\-/-/g;
283 $w =~ s/\\\\/\\/g;
284 (push @$pname,"i"),$lastp = $#$pname if $indexing;
285 push @$pname,"c $w" if !$qindex;
286 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
287 } elsif (/^\\[iIe]/) {
288 /^(\\[iI])?(\\e)?/;
289 $emph = 0;
290 $qindex = 1 if $1 eq "\\I";
291 $indexing = 1, $type = "\\i" if $1;
292 $emph = 1, $type = "\\e" if $2;
293 s/^(\\[iI])?(\\e?)//;
294 die "badly formatted $type: $type$_\n" if !/{(([^\\}]|\\.)*)}(.*)$/;
295 $w = $1;
296 $_ = $3;
297 $w =~ s/\\{/{/g;
298 $w =~ s/\\}/}/g;
299 $w =~ s/\\-/-/g;
300 $w =~ s/\\\\/\\/g;
301 $t = $emph ? "es" : "n ";
302 @ientry = ();
303 (push @$pname,"i"),$lastp = $#$pname if $indexing;
304 foreach $i (split /\s+/,$w) { # \e and \i can be multiple words
305 push @$pname,"$t$i","sp" if !$qindex;
306 ($ii=$i) =~ tr/A-Z/a-z/, push @ientry,"n $ii","sp" if $indexing;
307 $t = $emph ? "e " : "n ";
309 $w =~ tr/A-Z/a-z/, pop @ientry if $indexing;
310 $$pname[$lastp] = &addidx($node, $w, @ientry) if $indexing;
311 pop @$pname if !$qindex; # remove final space
312 if (substr($$pname[$#$pname],0,2) eq "es" && !$qindex) {
313 substr($$pname[$#$pname],0,2) = "eo";
314 } elsif ($emph && !$qindex) {
315 substr($$pname[$#$pname],0,2) = "ee";
317 } elsif (/^\\[kK]/) {
318 $t = "k ";
319 $t = "kK" if /^\\K/;
320 s/^\\[kK]//;
321 die "badly formatted \\k: \\c$_\n" if !/{([^}]*)}(.*)$/;
322 $_ = $2;
323 push @$pname,"$t$1";
324 } elsif (/^\\W/) {
325 s/^\\W//;
326 die "badly formatted \\W: \\W$_\n"
327 if !/{([^}]*)}(\\i)?(\\c)?{(([^\\}]|\\.)*)}(.*)$/;
328 $l = $1;
329 $w = $4;
330 $_ = $6;
331 $t = "w ";
332 $t = "wc" if $3 eq "\\c";
333 $indexing = 1 if $2;
334 $w =~ s/\\{/{/g;
335 $w =~ s/\\}/}/g;
336 $w =~ s/\\-/-/g;
337 $w =~ s/\\\\/\\/g;
338 (push @$pname,"i"),$lastp = $#$pname if $indexing;
339 push @$pname,"$t<$l>$w";
340 $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
341 } else {
342 die "what the hell? $_\n" if !/^(([^\s\\\-]|\\[\\{}\-])*-?)(.*)$/;
343 die "painful death! $_\n" if !length $1;
344 $w = $1;
345 $_ = $3;
346 $w =~ s/\\{/{/g;
347 $w =~ s/\\}/}/g;
348 $w =~ s/\\-/-/g;
349 $w =~ s/\\\\/\\/g;
350 if ($w eq "-") {
351 push @$pname,"da";
352 } else {
353 push @$pname,"n $w";
357 if ($irewrite ne undef) {
358 &addidx(undef, $irewrite, @$pname);
359 @$pname = ();
360 } else {
361 push @pnames, $pname;
362 push @pflags, $pflags;
363 $pname++;
367 sub addidx {
368 my ($node, $text, @ientry) = @_;
369 $text = $idxalias{$text} || $text;
370 if ($node eq undef || !$idxmap{$text}) {
371 @$ientry = @ientry;
372 $idxmap{$text} = $ientry;
373 $ientry++;
375 if ($node) {
376 $idxnodes{$node,$text} = 1;
377 return "i $text";
381 sub indexsort {
382 my $iitem, $ientry, $i, $piitem, $pcval, $cval, $clrcval;
384 @itags = map { # get back the original data as the 1st elt of each list
385 $_->[0]
386 } sort { # compare auxiliary (non-first) elements of lists
387 $a->[1] cmp $b->[1] ||
388 $a->[2] cmp $b->[2] ||
389 $a->[0] cmp $b->[0]
390 } map { # transform array into list of 3-element lists
391 my $ientry = $idxmap{$_};
392 my $a = substr($$ientry[0],2);
393 $a =~ tr/A-Za-z//cd;
394 [$_, uc($a), substr($$ientry[0],0,2)]
395 } keys %idxmap;
397 # Having done that, check for comma-hood.
398 $cval = 0;
399 foreach $iitem (@itags) {
400 $ientry = $idxmap{$iitem};
401 $clrcval = 1;
402 $pcval = $cval;
403 FL:for ($i=0; $i <= $#$ientry; $i++) {
404 if ($$ientry[$i] =~ /^(n .*,)(.*)/) {
405 $$ientry[$i] = $1;
406 splice @$ientry,$i+1,0,"n $2" if length $2;
407 $commapos{$iitem} = $i+1;
408 $cval = join("\002", @$ientry[0..$i]);
409 $clrcval = 0;
410 last FL;
413 $cval = undef if $clrcval;
414 $commanext{$iitem} = $commaafter{$piitem} = 1
415 if $cval and ($cval eq $pcval);
416 $piitem = $iitem;
420 sub indexdiag {
421 my $iitem,$ientry,$w,$ww,$foo,$node;
422 open INDEXDIAG,">index.diag";
423 foreach $iitem (@itags) {
424 $ientry = $idxmap{$iitem};
425 print INDEXDIAG "<$iitem> ";
426 foreach $w (@$ientry) {
427 $ww = &word_txt($w);
428 print INDEXDIAG $ww unless $ww eq "\001";
430 print INDEXDIAG ":";
431 $foo = " ";
432 foreach $node (@nodes) {
433 (print INDEXDIAG $foo,$node), $foo = ", " if $idxnodes{$node,$iitem};
435 print INDEXDIAG "\n";
437 close INDEXDIAG;
440 sub fixup_xrefs {
441 my $pname, $p, $i, $j, $k, $caps, @repl;
443 for ($p=0; $p<=$#pnames; $p++) {
444 next if $pflags[$p] eq "code";
445 $pname = $pnames[$p];
446 for ($i=$#$pname; $i >= 0; $i--) {
447 if ($$pname[$i] =~ /^k/) {
448 $k = $$pname[$i];
449 $caps = ($k =~ /^kK/);
450 $k = substr($k,2);
451 $repl = $refs{$k};
452 die "undefined keyword `$k'\n" unless $repl;
453 substr($repl,0,1) =~ tr/a-z/A-Z/ if $caps;
454 @repl = ();
455 push @repl,"x $xrefs{$k}";
456 foreach $j (split /\s+/,$repl) {
457 push @repl,"n $j";
458 push @repl,"sp";
460 pop @repl; # remove final space
461 push @repl,"xe$xrefs{$k}";
462 splice @$pname,$i,1,@repl;
468 sub write_txt {
469 # This is called from the top level, so I won't bother using
470 # my or local.
472 # Open file.
473 print "writing file...";
474 open TEXT,">nasmdoc.txt";
475 select TEXT;
477 # Preamble.
478 $title = "The Netwide Assembler: NASM";
479 $spaces = ' ' x ((75-(length $title))/2);
480 ($underscore = $title) =~ s/./=/g;
481 print "$spaces$title\n$spaces$underscore\n";
483 for ($para = 0; $para <= $#pnames; $para++) {
484 $pname = $pnames[$para];
485 $pflags = $pflags[$para];
486 $ptype = substr($pflags,0,4);
488 print "\n"; # always one of these before a new paragraph
490 if ($ptype eq "chap") {
491 # Chapter heading. "Chapter N: Title" followed by a line of
492 # minus signs.
493 $pflags =~ /chap (.*) :(.*)/;
494 $title = "Chapter $1: ";
495 foreach $i (@$pname) {
496 $ww = &word_txt($i);
497 $title .= $ww unless $ww eq "\001";
499 print "$title\n";
500 $title =~ s/./-/g;
501 print "$title\n";
502 } elsif ($ptype eq "appn") {
503 # Appendix heading. "Appendix N: Title" followed by a line of
504 # minus signs.
505 $pflags =~ /appn (.*) :(.*)/;
506 $title = "Appendix $1: ";
507 foreach $i (@$pname) {
508 $ww = &word_txt($i);
509 $title .= $ww unless $ww eq "\001";
511 print "$title\n";
512 $title =~ s/./-/g;
513 print "$title\n";
514 } elsif ($ptype eq "head" || $ptype eq "subh") {
515 # Heading or subheading. Just a number and some text.
516 $pflags =~ /.... (.*) :(.*)/;
517 $title = sprintf "%6s ", $1;
518 foreach $i (@$pname) {
519 $ww = &word_txt($i);
520 $title .= $ww unless $ww eq "\001";
522 print "$title\n";
523 } elsif ($ptype eq "code") {
524 # Code paragraph. Emit each line with a seven character indent.
525 foreach $i (@$pname) {
526 warn "code line longer than 68 chars: $i\n" if length $i > 68;
527 print ' 'x7, $i, "\n";
529 } elsif ($ptype eq "bull" || $ptype eq "norm") {
530 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
531 # 75-char right margin and either 7 or 11 char left margin
532 # depending on bullets.
533 if ($ptype eq "bull") {
534 $line = ' 'x7 . '(*) ';
535 $next = ' 'x11;
536 } else {
537 $line = $next = ' 'x7;
539 @a = @$pname;
540 $wd = $wprev = '';
541 do {
542 do { $w = &word_txt(shift @a) } while $w eq "\001"; # nasty hack
543 $wd .= $wprev;
544 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
545 if (length ($line . $wd) > 75) {
546 $line =~ s/\s*$//; # trim trailing spaces
547 print "$line\n";
548 $line = $next;
549 $wd =~ s/^\s*//; # trim leading spaces
551 $line .= $wd;
552 $wd = '';
554 $wprev = $w;
555 } while ($w ne '' && $w ne undef);
556 if ($line =~ /\S/) {
557 $line =~ s/\s*$//; # trim trailing spaces
558 print "$line\n";
563 # Close file.
564 select STDOUT;
565 close TEXT;
568 sub word_txt {
569 my ($w) = @_;
570 my $wtype, $wmajt;
572 return undef if $w eq '' || $w eq undef;
573 $wtype = substr($w,0,2);
574 $wmajt = substr($wtype,0,1);
575 $w = substr($w,2);
576 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
577 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
578 return $w;
579 } elsif ($wtype eq "sp") {
580 return ' ';
581 } elsif ($wtype eq "da") {
582 return '-';
583 } elsif ($wmajt eq "c" || $wtype eq "wc") {
584 return "`${w}'";
585 } elsif ($wtype eq "es") {
586 return "_${w}";
587 } elsif ($wtype eq "ee") {
588 return "${w}_";
589 } elsif ($wtype eq "eo") {
590 return "_${w}_";
591 } elsif ($wmajt eq "x" || $wmajt eq "i") {
592 return "\001";
593 } else {
594 die "panic in word_txt: $wtype$w\n";
598 sub write_html {
599 # This is called from the top level, so I won't bother using
600 # my or local.
602 # Write contents file. Just the preamble, then a menu of links to the
603 # separate chapter files and the nodes therein.
604 print "writing contents file...";
605 open TEXT,">nasmdoc0.html";
606 select TEXT;
607 &html_preamble(0);
608 print "<p>This manual documents NASM, the Netwide Assembler: an assembler\n";
609 print "targetting the Intel x86 series of processors, with portable source.\n";
610 print "<p>";
611 for ($node = $tstruct_next{'Top'}; $node; $node = $tstruct_next{$node}) {
612 if ($tstruct_level{$node} == 1) {
613 # Invent a file name.
614 ($number = lc($xrefnodes{$node})) =~ s/.*-//;
615 $fname="nasmdocx.html";
616 substr($fname,8 - length $number, length $number) = $number;
617 $html_fnames{$node} = $fname;
618 $link = $fname;
619 print "<p>";
620 } else {
621 # Use the preceding filename plus a marker point.
622 $link = $fname . "#$xrefnodes{$node}";
624 $title = "$node: ";
625 $pname = $tstruct_pname{$node};
626 foreach $i (@$pname) {
627 $ww = &word_html($i);
628 $title .= $ww unless $ww eq "\001";
630 print "<a href=\"$link\">$title</a><br>\n";
632 print "<p><a href=\"nasmdoci.html\">Index</a>\n";
633 print "</body></html>\n";
634 select STDOUT;
635 close TEXT;
637 # Open a null file, to ensure output (eg random &html_jumppoints calls)
638 # goes _somewhere_.
639 print "writing chapter files...";
640 open TEXT,">/dev/null";
641 select TEXT;
642 $html_lastf = '';
644 $in_list = 0;
646 for ($para = 0; $para <= $#pnames; $para++) {
647 $pname = $pnames[$para];
648 $pflags = $pflags[$para];
649 $ptype = substr($pflags,0,4);
651 $in_list = 0, print "</ul>\n" if $in_list && $ptype ne "bull";
652 if ($ptype eq "chap") {
653 # Chapter heading. Begin a new file.
654 $pflags =~ /chap (.*) :(.*)/;
655 $title = "Chapter $1: ";
656 $xref = $2;
657 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
658 $html_lastf = $html_fnames{$chapternode};
659 $chapternode = $nodexrefs{$xref};
660 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
661 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
662 foreach $i (@$pname) {
663 $ww = &word_html($i);
664 $title .= $ww unless $ww eq "\001";
666 $h = "<h2><a name=\"$xref\">$title</a></h2>\n";
667 print $h; print FULL $h;
668 } elsif ($ptype eq "appn") {
669 # Appendix heading. Begin a new file.
670 $pflags =~ /appn (.*) :(.*)/;
671 $title = "Appendix $1: ";
672 $xref = $2;
673 &html_jumppoints; print "</body></html>\n"; select STDOUT; close TEXT;
674 $html_lastf = $html_fnames{$chapternode};
675 $chapternode = $nodexrefs{$xref};
676 $html_nextf = $html_fnames{$tstruct_mnext{$chapternode}};
677 open TEXT,">$html_fnames{$chapternode}"; select TEXT; &html_preamble(1);
678 foreach $i (@$pname) {
679 $ww = &word_html($i);
680 $title .= $ww unless $ww eq "\001";
682 print "<h2><a name=\"$xref\">$title</a></h2>\n";
683 } elsif ($ptype eq "head" || $ptype eq "subh") {
684 # Heading or subheading.
685 $pflags =~ /.... (.*) :(.*)/;
686 $hdr = ($ptype eq "subh" ? "h4" : "h3");
687 $title = $1 . " ";
688 $xref = $2;
689 foreach $i (@$pname) {
690 $ww = &word_html($i);
691 $title .= $ww unless $ww eq "\001";
693 print "<$hdr><a name=\"$xref\">$title</a></$hdr>\n";
694 } elsif ($ptype eq "code") {
695 # Code paragraph.
696 print "<p><pre>\n";
697 foreach $i (@$pname) {
698 $w = $i;
699 $w =~ s/&/&amp;/g;
700 $w =~ s/</&lt;/g;
701 $w =~ s/>/&gt;/g;
702 print $w, "\n";
704 print "</pre>\n";
705 } elsif ($ptype eq "bull" || $ptype eq "norm") {
706 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
707 # 75-char right margin and either 7 or 11 char left margin
708 # depending on bullets.
709 if ($ptype eq "bull") {
710 $in_list = 1, print "<ul>\n" unless $in_list;
711 $line = '<li>';
712 } else {
713 $line = '<p>';
715 @a = @$pname;
716 $wd = $wprev = '';
717 do {
718 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
719 $wd .= $wprev;
720 if ($w eq ' ' || $w eq '' || $w eq undef) {
721 if (length ($line . $wd) > 75) {
722 $line =~ s/\s*$//; # trim trailing spaces
723 print "$line\n";
724 $line = '';
725 $wd =~ s/^\s*//; # trim leading spaces
727 $line .= $wd;
728 $wd = '';
730 $wprev = $w;
731 } while ($w ne '' && $w ne undef);
732 if ($line =~ /\S/) {
733 $line =~ s/\s*$//; # trim trailing spaces
734 print "$line\n";
739 # Close whichever file was open.
740 &html_jumppoints;
741 print "</body></html>\n";
742 select STDOUT;
743 close TEXT;
745 print "\n writing index file...";
746 open TEXT,">nasmdoci.html";
747 select TEXT;
748 &html_preamble(0);
749 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
750 print "<p>";
751 &html_index;
752 print "<p align=center><a href=\"nasmdoc0.html\">Contents</a>\n";
753 print "</body></html>\n";
754 select STDOUT;
755 close TEXT;
758 sub html_preamble {
759 print "<html><head><title>NASM Manual</title></head>\n";
760 print "<body><h1 align=center>The Netwide Assembler: NASM</h1>\n\n";
761 &html_jumppoints if $_[0];
764 sub html_jumppoints {
765 print "<p align=center>";
766 print "<a href=\"$html_nextf\">Next Chapter</a> |\n" if $html_nextf;
767 print "<a href=\"$html_lastf\">Previous Chapter</a> |\n" if $html_lastf;
768 print "<a href=\"nasmdoc0.html\">Contents</a> |\n";
769 print "<a href=\"nasmdoci.html\">Index</a>\n";
772 sub html_index {
773 my $itag, $a, @ientry, $sep, $w, $wd, $wprev, $line;
775 $chapternode = '';
776 foreach $itag (@itags) {
777 $ientry = $idxmap{$itag};
778 @a = @$ientry;
779 push @a, "n :";
780 $sep = 0;
781 foreach $node (@nodes) {
782 next if !$idxnodes{$node,$itag};
783 push @a, "n ," if $sep;
784 push @a, "sp", "x $xrefnodes{$node}", "n $node", "xe$xrefnodes{$node}";
785 $sep = 1;
787 $line = '';
788 do {
789 do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
790 $wd .= $wprev;
791 if ($w eq ' ' || $w eq '' || $w eq undef) {
792 if (length ($line . $wd) > 75) {
793 $line =~ s/\s*$//; # trim trailing spaces
794 print "$line\n";
795 $line = '';
796 $wd =~ s/^\s*//; # trim leading spaces
798 $line .= $wd;
799 $wd = '';
801 $wprev = $w;
802 } while ($w ne '' && $w ne undef);
803 if ($line =~ /\S/) {
804 $line =~ s/\s*$//; # trim trailing spaces
805 print "$line\n";
807 print "<br>\n";
811 sub word_html {
812 my ($w) = @_;
813 my $wtype, $wmajt, $pfx, $sfx;
815 return undef if $w eq '' || $w eq undef;
817 $wtype = substr($w,0,2);
818 $wmajt = substr($wtype,0,1);
819 $w = substr($w,2);
820 $pfx = $sfx = '';
821 $pfx = "<a href=\"$1\">", $sfx = "</a>", $w = $2
822 if $wmajt eq "w" && $w =~ /^<(.*)>(.*)$/;
823 $w =~ s/&/&amp;/g;
824 $w =~ s/</&lt;/g;
825 $w =~ s/>/&gt;/g;
826 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
827 return $pfx . $w . $sfx;
828 } elsif ($wtype eq "sp") {
829 return ' ';
830 } elsif ($wtype eq "da") {
831 return '-'; # sadly, en-dashes are non-standard in HTML
832 } elsif ($wmajt eq "c" || $wtype eq "wc") {
833 return $pfx . "<code><nobr>${w}</nobr></code>" . $sfx;
834 } elsif ($wtype eq "es") {
835 return "<em>${w}";
836 } elsif ($wtype eq "ee") {
837 return "${w}</em>";
838 } elsif ($wtype eq "eo") {
839 return "<em>${w}</em>";
840 } elsif ($wtype eq "x ") {
841 # Magic: we must resolve the cross reference into file and marker
842 # parts, then dispose of the file part if it's us, and dispose of
843 # the marker part if the cross reference describes the top node of
844 # another file.
845 my $node = $nodexrefs{$w}; # find the node we're aiming at
846 my $level = $tstruct_level{$node}; # and its level
847 my $up = $node, $uplev = $level-1;
848 $up = $tstruct_up{$up} while $uplev--; # get top node of containing file
849 my $file = ($up ne $chapternode) ? $html_fnames{$up} : "";
850 my $marker = ($level == 1 and $file) ? "" : "#$w";
851 return "<a href=\"$file$marker\">";
852 } elsif ($wtype eq "xe") {
853 return "</a>";
854 } elsif ($wmajt eq "i") {
855 return "\001";
856 } else {
857 die "panic in word_html: $wtype$w\n";
861 sub write_ps {
862 # This is called from the top level, so I won't bother using
863 # my or local.
865 # First, set up the font metric arrays.
866 &font_metrics;
868 # First stage: reprocess the source arrays into a list of
869 # lines, each of which is a list of word-strings, each of
870 # which has a single-letter font code followed by text.
871 # Each line also has an associated type, which will be
872 # used for final alignment and font selection and things.
874 # Font codes are:
875 # n == Normal
876 # e == Emphasised
877 # c == Code
878 # ' ' == space (no following text required)
879 # '-' == dash (no following text required)
881 # Line types are:
882 # chap == Chapter or appendix heading.
883 # head == Major heading.
884 # subh == Sub-heading.
885 # Ccha == Contents entry for a chapter.
886 # Chea == Contents entry for a heading.
887 # Csub == Contents entry for a subheading.
888 # cone == Code paragraph with just this one line on it.
889 # cbeg == First line of multi-line code paragraph.
890 # cbdy == Interior line of multi-line code paragraph.
891 # cend == Final line of multi-line code paragraph.
892 # none == Normal paragraph with just this one line on it.
893 # nbeg == First line of multi-line normal paragraph.
894 # nbdy == Interior line of multi-line normal paragraph.
895 # nend == Final line of multi-line normal paragraph.
896 # bone == Bulleted paragraph with just this one line on it.
897 # bbeg == First line of multi-line bulleted paragraph.
898 # bbdy == Interior line of multi-line bulleted paragraph.
899 # bend == Final line of multi-line bulleted paragraph.
900 print "line-breaks...";
901 $lname = "psline000000";
902 $lnamei = "idx" . $lname;
903 @lnames = @ltypes = ();
905 for ($para = 0; $para <= $#pnames; $para++) {
906 $pname = $pnames[$para];
907 $pflags = $pflags[$para];
908 $ptype = substr($pflags,0,4);
910 # New paragraph _ergo_ new line.
911 @line = ();
912 @lindex = (); # list of index tags referenced to this line
914 if ($ptype eq "chap") {
915 # Chapter heading. "Chapter N: Title" followed by a line of
916 # minus signs.
917 $pflags =~ /chap (.*) :(.*)/;
918 push @line, "nChapter", " ", "n$1:", " ";
919 foreach $i (@$pname) {
920 $ww = &word_ps($i);
921 push @line, $ww unless $ww eq "x";
923 @$lname = @line; @$lnamei = @lindex;
924 push @lnames, $lname++;
925 $lnamei = "idx" . $lname;
926 push @ltypes, "chap";
927 } elsif ($ptype eq "appn") {
928 # Appendix heading. "Appendix N: Title" followed by a line of
929 # minus signs.
930 $pflags =~ /appn (.*) :(.*)/;
931 push @line, "nAppendix", " ", "n$1:", " ";
932 foreach $i (@$pname) {
933 $ww = &word_ps($i);
934 push @line, $ww unless $ww eq "x";
936 @$lname = @line; @$lnamei = @lindex;
937 push @lnames, $lname++;
938 $lnamei = "idx" . $lname;
939 push @ltypes, "chap";
940 } elsif ($ptype eq "head") {
941 # Heading. Just a number and some text.
942 $pflags =~ /.... (.*) :(.*)/;
943 push @line, "n$1";
944 foreach $i (@$pname) {
945 $ww = &word_ps($i);
946 push @line, $ww unless $ww eq "x";
948 @$lname = @line; @$lnamei = @lindex;
949 push @lnames, $lname++;
950 $lnamei = "idx" . $lname;
951 push @ltypes, $ptype;
952 } elsif ($ptype eq "subh") {
953 # Subheading. Just a number and some text.
954 $pflags =~ /subh (.*) :(.*)/;
955 push @line, "n$1";
956 foreach $i (@$pname) {
957 push @line, &word_ps($i);
959 @$lname = @line; @$lnamei = @lindex;
960 push @lnames, $lname++;
961 $lnamei = "idx" . $lname;
962 push @ltypes, "subh";
963 } elsif ($ptype eq "code") {
964 # Code paragraph. Emit lines one at a time.
965 $type = "cbeg";
966 foreach $i (@$pname) {
967 @$lname = ("c$i");
968 push @lnames, $lname++;
969 $lnamei = "idx" . $lname;
970 push @ltypes, $type;
971 $type = "cbdy";
973 $ltypes[$#ltypes] = ($ltypes[$#ltypes] eq "cbeg" ? "cone" : "cend");
974 } elsif ($ptype eq "bull" || $ptype eq "norm") {
975 # Ordinary paragraph, optionally bulleted. We wrap, with ragged
976 # 75-char right margin and either 7 or 11 char left margin
977 # depending on bullets.
978 if ($ptype eq "bull") {
979 $width = 456; # leave 12-pt left indent for the bullet
980 $type = $begtype = "bbeg";
981 $bodytype = "bbdy";
982 $onetype = "bone";
983 $endtype = "bend";
984 } else {
985 $width = 468;
986 $type = $begtype = "nbeg";
987 $bodytype = "nbdy";
988 $onetype = "none";
989 $endtype = "nend";
991 @a = @$pname;
992 @line = @wd = ();
993 $linelen = 0;
994 $wprev = undef;
995 do {
996 do { $w = &word_ps(shift @a) } while ($w eq "x");
997 push @wd, $wprev if $wprev;
998 if ($wprev =~ /^n.*-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
999 $wdlen = &len_ps(@wd);
1000 if ($linelen + $wdlen > $width) {
1001 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1002 @$lname = @line; @$lnamei = @lindex;
1003 push @lnames, $lname++;
1004 $lnamei = "idx" . $lname;
1005 push @ltypes, $type;
1006 $type = $bodytype;
1007 @line = @lindex = ();
1008 $linelen = 0;
1009 shift @wd while $wd[0] eq ' '; # trim leading spaces
1011 push @line, @wd;
1012 $linelen += $wdlen;
1013 @wd = ();
1015 $wprev = $w;
1016 } while ($w ne '' && $w ne undef);
1017 if (@line) {
1018 pop @line while $line[$#line] eq ' '; # trim trailing spaces
1019 @$lname = @line; @$lnamei = @lindex;
1020 push @lnames, $lname++;
1021 $lnamei = "idx" . $lname;
1022 push @ltypes, $type;
1023 $type = $bodytype;
1025 $ltypes[$#ltypes] =
1026 ($ltypes[$#ltypes] eq $begtype ? $onetype : $endtype);
1030 # We've now processed the document source into lines. Before we
1031 # go on and do the page breaking, we'll fabricate a table of contents,
1032 # line by line, and then after doing page breaks we'll go back and
1033 # insert the page numbers into the contents entries.
1034 print "building contents...";
1035 @clnames = @cltypes = ();
1036 $clname = "pscont000000";
1037 @$clname = ("nContents"); # "chapter heading" for TOC
1038 push @clnames,$clname++;
1039 push @cltypes,"chap";
1040 for ($i=0; $i<=$#lnames; $i++) {
1041 $lname = $lnames[$i];
1042 if ($ltypes[$i] =~ /^(chap|head|subh)/) {
1043 @$clname = @$lname;
1044 splice @$clname,1,0," " if ($ltypes[$i] !~ /chap/);
1045 push @$clname,$i; # placeholder for page number
1046 push @clnames,$clname++;
1047 push @cltypes,"C" . substr($ltypes[$i],0,3);
1050 @$clname = ("nIndex"); # contents entry for Index
1051 push @$clname,$i; # placeholder for page number
1052 $idx_clname = $clname;
1053 push @clnames,$clname++;
1054 push @cltypes,"Ccha";
1055 $contlen = $#clnames + 1;
1056 unshift @lnames,@clnames;
1057 unshift @ltypes,@cltypes;
1059 # Second stage: now we have a list of lines, break them into pages.
1060 # We do this by means of adding a third array in parallel with
1061 # @lnames and @ltypes, called @lpages, in which we store the page
1062 # number that each line resides on. We also add @ycoord which
1063 # stores the vertical position of each line on the page.
1065 # Page breaks may not come after line-types:
1066 # chap head subh cbeg nbeg bbeg
1067 # and may not come before line-types:
1068 # cend nend bend
1069 # They are forced before line-types:
1070 # chap
1071 print "page-breaks...";
1072 $pmax = 600; # ADJUSTABLE: maximum length of a page in points
1073 $textht = 11; # ADJUSTABLE: height of a normal line in points
1074 $spacing = 6; # ADJUSTABLE: space between paragraphs, in points
1075 $headht = 14; # ADJUSTABLE: height of a major heading in points
1076 $subht = 12; # ADJUSTABLE: height of a sub-heading in points
1077 $pstart = 0; # start line of current page
1078 $plen = 0; # current length of current page
1079 $pnum = 1; # number of current page
1080 $bpt = -1; # last feasible break point
1081 $i = 0; # line number
1082 while ($i <= $#lnames) {
1083 $lname = $lnames[$i];
1084 # Add the height of this line (computed the last time we went round
1085 # the loop, unless we're a chapter heading in which case we do it
1086 # now) to the length of the current page. Also, _put_ this line on
1087 # the current page, and allocate it a y-coordinate.
1088 if ($ltypes[$i] =~ /^chap$/) {
1089 $pnum += 1 - ($pnum & 1); # advance to odd numbered page if necessary
1090 $plen = 100; # ADJUSTABLE: space taken up by a chapter heading
1091 $ycoord[$i] = 0; # chapter heading: y-coord doesn't matter
1092 } else {
1093 $ycoord[$i] = $plen + $space;
1094 $plen += $space + $ht;
1096 # See if we can break after this line.
1097 $bpt = $i if $ltypes[$i] !~ /^chap|head|subh|cbeg|nbeg|bbeg$/ &&
1098 $ltypes[$i+1] !~ /^cend|nend|bend$/;
1099 # Assume, to start with, that we don't break after this line.
1100 $break = 0;
1101 # See if a break is forced.
1102 $break = 1, $bpt = $i if $ltypes[$i+1] eq "chap" || !$ltypes[$i+1];
1103 # Otherwise, compute the height of the next line, and break if
1104 # it would make this page too long.
1105 $ht = $textht, $space = 0 if $ltypes[$i+1] =~ /^[nbc](bdy|end)$/;
1106 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^[nbc](one|beg)$/;
1107 $ht = $textht, $space = $spacing if $ltypes[$i+1] =~ /^C/;
1108 $ht = $subht, $space = $spacing if $ltypes[$i+1] eq "subh";
1109 $ht = $headht, $space = $spacing if $ltypes[$i+1] eq "head";
1110 $break = 1 if $plen + $space + $ht > $pmax;
1111 # Now, if we're breaking, assign page number $pnum to all lines up
1112 # to $bpt, set $i == $bpt+1, and zero $space since we are at the
1113 # start of a new page and don't want leading space.
1114 if ($break) {
1115 die "no feasible break point at all on page $pnum\n" if $bpt == -1;
1116 for ($j = $pstart; $j <= $bpt; $j++) {
1117 $lnamei = "idx" . $lnames[$j];
1118 foreach $k (@$lnamei) {
1119 ${$psidxpp{$k}}{$pnum} = 1;
1121 $lpages[$j] = $pnum;
1123 $pnum++;
1124 $i = $bpt;
1125 $bpt = -1;
1126 $pstart = $i+1;
1127 $plen = 0;
1128 $space = 0;
1130 $i++;
1133 # Now fix up the TOC with page numbers.
1134 print "\n fixing up contents...";
1135 for ($i=0; $i<=$#lnames; $i++) {
1136 $lname = $lnames[$i];
1137 if ($ltypes[$i] =~ /^C/) {
1138 $j = pop @$lname;
1139 push @$lname, "n" . $lpages[$j+$contlen];
1143 # Having got page numbers for most stuff, generate an index.
1144 print "building index...";
1145 $iwid = 222;
1146 $sep = 12;
1147 $commaindent = 32;
1148 foreach $k (@itags) {
1149 @line = ();
1150 $cmd = "index";
1151 @idxentry = @{$idxmap{$k}};
1152 if ($commaafter{$k} and !$commanext{$k}) {
1153 # This line is a null line beginning a multiple entry. We must
1154 # output the prefix on a line by itself.
1156 @idxhead = splice @idxentry,0,$commapos{$k};
1157 @line = ();
1158 foreach $i (@idxhead) {
1159 $ww = &word_ps($i);
1160 push @line, $ww unless $ww eq "x";
1162 &ps_idxout("index",\@line,[]);
1163 $cmd = "iindex";
1164 @line = ();
1166 $cmd = "iindex", splice @idxentry,0,$commapos{$k} if $commanext{$k};
1167 foreach $i (@idxentry) {
1168 $ww = &word_ps($i);
1169 push @line, $ww unless $ww eq "x";
1171 $len = $iwid - $sep - &len_ps(@line);
1172 warn "text for index tag `%s' is longer than one index line!\n"
1173 if $len < -$sep;
1174 @pp = ();
1175 $inums = join(',',sort { $a <=> $b } keys %{$psidxpp{$k}});
1176 while (length $inums) {
1177 $inums =~ /^([^,]+,?)(.*)$/;
1178 $inums = $2, $inum = $1;
1179 @pnum = (" ", "n$inum");
1180 $pnumlen = &len_ps(@pnum);
1181 if ($pnumlen > $len) {
1182 &ps_idxout($cmd,\@line,\@pp);
1183 @pp = ();
1184 @line = ();
1185 $cmd = "index";
1186 $len = $iwid - $sep;
1188 push @pp, @pnum;
1189 $len -= $pnumlen;
1191 &ps_idxout($cmd,\@line,\@pp) if (length @pp);
1192 $l1 = &len_ps(@line);
1193 $l2 = &len_ps($pp);
1195 $$idx_clname[$#$idx_clname] = "n" . $pnum; # fix up TOC entry for index
1197 print "writing file...";
1198 open PS,">nasmdoc.ps";
1199 select PS;
1200 $page = $lpages[0];
1201 &ps_header;
1202 for ($i=0; $i<=$#lnames; $i++) {
1203 &ps_throw_pg($page,$lpages[$i]) if $page != $lpages[$i];
1204 $page = $lpages[$i];
1205 &ps_out_line($ycoord[$i],$ltypes[$i],$lnames[$i]);
1207 $i = 0;
1208 while ($i <= $#psindex) {
1209 &ps_throw_pg($page, $pnum) if $page != $pnum;
1210 $page = $pnum++;
1211 $ypos = 0;
1212 $ypos = 100, &ps_out_line(0, "chap", ["nIndex"]) if !$i;
1213 $lines = ($pmax - $ypos) / $textht;
1214 my $col; # ps_out_line hits this variable
1215 PAGE:for ($col = 1; $col <= 2; $col++) {
1216 $y = $ypos; $l = $lines;
1217 COL: while ($l > 0) {
1218 $j = $i+1;
1219 $j++ while $psindex[$j] and ($psindex[$j][3] == 0); # find next break
1220 last COL if $j-$i > $l or $i > $#psindex;
1221 while ($i < $j) {
1222 &ps_out_line($y, $psindex[$i][0] eq "index" ? "idl$col" : "ldl$col",
1223 $psindex[$i][1]);
1224 &ps_out_line($y,"idr$col",$psindex[$i][2]);
1225 $i++;
1226 $y += $textht;
1227 $l--;
1230 last PAGE if $i > $#psindex;
1233 &ps_trailer($page);
1234 close PS;
1235 select STDOUT;
1238 sub ps_idxout {
1239 my ($cmd, $left, $right) = @_;
1240 my $break = 1;
1241 $break = 0
1242 if ($#psindex >= 0) and ( ($#$left < 0) or ($cmd eq "iindex") );
1243 push @psindex,[$cmd,[@$left],[@$right],$break];
1246 sub ps_header {
1247 @pshdr = (
1248 '/sp (n ) def', # here it's sure not to get wrapped inside ()
1249 '/nf /Times-Roman findfont 11 scalefont def',
1250 '/ef /Times-Italic findfont 11 scalefont def',
1251 '/cf /Courier findfont 11 scalefont def',
1252 '/nc /Helvetica-Bold findfont 18 scalefont def',
1253 '/ec /Helvetica-Oblique findfont 18 scalefont def',
1254 '/cc /Courier-Bold findfont 18 scalefont def',
1255 '/nh /Helvetica-Bold findfont 14 scalefont def',
1256 '/eh /Helvetica-Oblique findfont 14 scalefont def',
1257 '/ch /Courier-Bold findfont 14 scalefont def',
1258 '/ns /Helvetica-Bold findfont 12 scalefont def',
1259 '/es /Helvetica-Oblique findfont 12 scalefont def',
1260 '/cs /Courier-Bold findfont 12 scalefont def',
1261 '/n 16#6E def /e 16#65 def /c 16#63 def',
1262 '/pageodd {',
1263 ' 550 50 moveto ns setfont dup stringwidth pop neg 0 rmoveto show',
1264 '} def',
1265 '/pageeven { 50 50 moveto ns setfont show } 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 my ($oldpg) = @_;
1387 &ps_donepg($oldpg);
1388 print "%%Trailer\nrestore\n%%EOF\n";
1391 sub ps_throw_pg {
1392 my ($oldpg, $newpg) = @_;
1393 while ($oldpg < $newpg) {
1394 &ps_donepg($oldpg);
1395 $oldpg++;
1396 &ps_initpg($oldpg);
1400 sub ps_initpg {
1401 my ($pgnum) = @_;
1402 print "%%Page: $pgnum $pgnum\n";
1403 print "%%BeginPageSetup\nsave\n%%EndPageSetup\n";
1406 sub ps_donepg {
1407 my ($pgnum) = @_;
1408 if ($pgnum & 1) {
1409 print "%%PageTrailer\n($pgnum)pageodd restore showpage\n";
1410 } else {
1411 print "%%PageTrailer\n($pgnum)pageeven restore showpage\n";
1415 sub ps_out_line {
1416 my ($ypos,$ltype,$lname) = @_;
1417 my $c,$d,$wid;
1419 print "[";
1420 $col = 1;
1421 foreach $c (@$lname) {#
1422 $c= "n " if $c eq " ";
1423 $c = "n\261" if $c eq "-";
1424 $d = '';
1425 while (length $c) {
1426 $d .= $1, $c = $2 while $c =~ /^([ -'\*-\[\]-~]+)(.*)$/;
1427 while (1) {
1428 $d .= "\\$1", $c = $2, next if $c =~ /^([\\\(\)])(.*)$/;
1429 ($d .= sprintf "\\%3o",unpack("C",$1)), $c = $2, next
1430 if $c =~ /^([^ -~])(.*)$/;
1431 last;
1434 $d = "($d)";
1435 $col = 0, print "\n" if $col>0 && $col+length $d > 77;
1436 print $d;
1437 $col += length $d;
1439 print "\n" if $col > 60;
1440 print "]";
1441 if ($ltype =~ /^[nb](beg|bdy)$/) {
1442 printf "%d %s%d just\n",
1443 $ypos, ($ltype eq "bbeg" ? "bullet " : ""),
1444 ($ltype =~ /^b/ ? 456 : 468);
1445 } elsif ($ltype =~ /^[nb](one|end)$/) {
1446 printf "%d %s%d left\n",
1447 $ypos, ($ltype eq "bone" ? "bullet " : ""),
1448 ($ltype =~ /^b/ ? 456 : 468);
1449 } elsif ($ltype =~ /^c(one|beg|bdy|end)$/) {
1450 printf "$ypos 468 left\n";
1451 } elsif ($ltype =~ /^C/) {
1452 $wid = 468;
1453 $wid = 456 if $ltype eq "Chea";
1454 $wid = 444 if $ltype eq "Csub";
1455 printf "$ypos $wid contents\n";
1456 } elsif ($ltype eq "chap") {
1457 printf "chapter\n";
1458 } elsif ($ltype eq "head") {
1459 printf "$ypos heading\n";
1460 } elsif ($ltype eq "subh") {
1461 printf "$ypos subhead\n";
1462 } elsif ($ltype =~ /([il]d[lr])([12])/) {
1463 $left = ($2 eq "2" ? 468-222 : 0);
1464 printf "$ypos $left $1\n";
1468 sub word_ps {
1469 my ($w) = @_;
1470 my $wtype, $wmajt;
1472 return undef if $w eq '' || $w eq undef;
1474 $wtype = substr($w,0,2);
1475 $wmajt = substr($wtype,0,1);
1476 $w = substr($w,2);
1477 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1478 if ($wmajt eq "n" || $wtype eq "w ") {
1479 return "n$w";
1480 } elsif ($wtype eq "sp") {
1481 return ' ';
1482 } elsif ($wtype eq "da") {
1483 return '-';
1484 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1485 return "c$w";
1486 } elsif ($wmajt eq "e") {
1487 return "e$w";
1488 } elsif ($wmajt eq "x") {
1489 return "x";
1490 } elsif ($wtype eq "i ") {
1491 push @lindex, $w;
1492 return "x";
1493 } else {
1494 die "panic in word_ps: $wtype$w\n";
1498 sub len_ps {
1499 my (@line) = @_;
1500 my $l = 0;
1501 my $w, $size;
1503 $size = 11/1000; # used only for length calculations
1504 while ($w = shift @line) {
1505 $w = "n " if $w eq " ";
1506 $w = "n\261" if $w eq "-";
1507 $f = substr($w,0,1);
1508 $f = "timesr" if $f eq "n";
1509 $f = "timesi" if $f eq "e";
1510 $f = "courr" if $f eq "c";
1511 foreach $c (unpack 'C*',substr($w,1)) {
1512 $l += $size * $$f[$c];
1515 return $l;
1518 sub write_texi {
1519 # This is called from the top level, so I won't bother using
1520 # my or local.
1522 # Open file.
1523 print "writing file...";
1524 open TEXT,">nasmdoc.texi";
1525 select TEXT;
1527 # Preamble.
1528 print "\\input texinfo \@c -*-texinfo-*-\n";
1529 print "\@c \%**start of header\n";
1530 print "\@setfilename nasm.info\n";
1531 print "\@dircategory Programming\n";
1532 print "\@direntry\n";
1533 print "* NASM: (nasm). The Netwide Assembler for x86.\n";
1534 print "\@end direntry\n";
1535 print "\@settitle NASM: The Netwide Assembler\n";
1536 print "\@setchapternewpage odd\n";
1537 print "\@c \%**end of header\n";
1538 print "\n";
1539 print "\@ifinfo\n";
1540 print "This file documents NASM, the Netwide Assembler: an assembler\n";
1541 print "targetting the Intel x86 series of processors, with portable source.\n";
1542 print "\n";
1543 print "Copyright 1997 Simon Tatham\n";
1544 print "\n";
1545 print "All rights reserved. This document is redistributable under the\n";
1546 print "licence given in the file \"Licence\" distributed in the NASM archive.\n";
1547 print "\@end ifinfo\n";
1548 print "\n";
1549 print "\@titlepage\n";
1550 print "\@title NASM: The Netwide Assembler\n";
1551 print "\@author Simon Tatham\n";
1552 print "\n";
1553 print "\@page\n";
1554 print "\@vskip 0pt plus 1filll\n";
1555 print "Copyright \@copyright{} 1997 Simon Tatham\n";
1556 print "\n";
1557 print "All rights reserved. This document is redistributable under the\n";
1558 print "licence given in the file \"Licence\" distributed in the NASM archive.\n";
1559 print "\@end titlepage\n";
1560 print "\n";
1561 print "\@node Top, $tstruct_next{'Top'}, (dir), (dir)\n";
1562 print "\@top Netwide Assembler\n";
1563 print "\n";
1564 print "\@ifinfo\n";
1565 print "This file documents NASM, the Netwide Assembler: an assembler\n";
1566 print "targetting the Intel x86 series of processors, with portable source.\n";
1567 print "\@end ifinfo\n";
1569 $node = "Top";
1571 $bulleting = 0;
1572 for ($para = 0; $para <= $#pnames; $para++) {
1573 $pname = $pnames[$para];
1574 $pflags = $pflags[$para];
1575 $ptype = substr($pflags,0,4);
1577 $bulleting = 0, print "\@end itemize\n" if $bulleting && $ptype ne "bull";
1578 print "\n"; # always one of these before a new paragraph
1580 if ($ptype eq "chap") {
1581 # Chapter heading. Begin a new node.
1582 &texi_menu($node)
1583 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1584 $pflags =~ /chap (.*) :(.*)/;
1585 $node = "Chapter $1";
1586 $title = "Chapter $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 "appn") {
1594 # Appendix heading. Begin a new node.
1595 &texi_menu($node)
1596 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1597 $pflags =~ /appn (.*) :(.*)/;
1598 $node = "Appendix $1";
1599 $title = "Appendix $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 "head" || $ptype eq "subh") {
1607 # Heading or subheading. Begin a new node.
1608 &texi_menu($node)
1609 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1610 $pflags =~ /.... (.*) :(.*)/;
1611 $node = "Section $1";
1612 $title = "$1. ";
1613 foreach $i (@$pname) {
1614 $ww = &word_texi($i);
1615 $title .= $ww unless $ww eq "\001";
1617 print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},";
1618 print " $tstruct_up{$node}\n";
1619 $hdr = ($ptype eq "subh" ? "\@unnumberedsubsec" : "\@unnumberedsec");
1620 print "$hdr $title\n";
1621 } elsif ($ptype eq "code") {
1622 # Code paragraph. Surround with @example / @end example.
1623 print "\@example\n";
1624 foreach $i (@$pname) {
1625 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1626 $i =~ s/\@/\@\@/g;
1627 $i =~ s/\{/\@\{/g;
1628 $i =~ s/\}/\@\}/g;
1629 print "$i\n";
1631 print "\@end example\n";
1632 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1633 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1634 if ($ptype eq "bull") {
1635 $bulleting = 1, print "\@itemize \@bullet\n" if !$bulleting;
1636 print "\@item\n";
1638 $line = '';
1639 @a = @$pname;
1640 $wd = $wprev = '';
1641 do {
1642 do { $w = &word_texi(shift @a); } while $w eq "\001"; # hack
1643 $wd .= $wprev;
1644 if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
1645 if (length ($line . $wd) > 75) {
1646 $line =~ s/\s*$//; # trim trailing spaces
1647 print "$line\n";
1648 $line = '';
1649 $wd =~ s/^\s*//; # trim leading spaces
1651 $line .= $wd;
1652 $wd = '';
1654 $wprev = $w;
1655 } while ($w ne '' && $w ne undef);
1656 if ($line =~ /\S/) {
1657 $line =~ s/\s*$//; # trim trailing spaces
1658 print "$line\n";
1663 # Write index.
1664 &texi_index;
1666 # Close file.
1667 print "\n\@contents\n\@bye\n";
1668 select STDOUT;
1669 close TEXT;
1672 # Side effect of this procedure: update global `texiwdlen' to be the length
1673 # in chars of the formatted version of the word.
1674 sub word_texi {
1675 my ($w) = @_;
1676 my $wtype, $wmajt;
1678 return undef if $w eq '' || $w eq undef;
1679 $wtype = substr($w,0,2);
1680 $wmajt = substr($wtype,0,1);
1681 $w = substr($w,2);
1682 $wlen = length $w;
1683 $w =~ s/\@/\@\@/g;
1684 $w =~ s/\{/\@\{/g;
1685 $w =~ s/\}/\@\}/g;
1686 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1687 substr($w,0,1) =~ tr/a-z/A-Z/, $capital = 0 if $capital;
1688 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1689 $texiwdlen = $wlen;
1690 return $w;
1691 } elsif ($wtype eq "sp") {
1692 $texiwdlen = 1;
1693 return ' ';
1694 } elsif ($wtype eq "da") {
1695 $texiwdlen = 2;
1696 return '--';
1697 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1698 $texiwdlen = 2 + $wlen;
1699 return "\@code\{$w\}";
1700 } elsif ($wtype eq "es") {
1701 $texiwdlen = 1 + $wlen;
1702 return "\@emph\{${w}";
1703 } elsif ($wtype eq "ee") {
1704 $texiwdlen = 1 + $wlen;
1705 return "${w}\}";
1706 } elsif ($wtype eq "eo") {
1707 $texiwdlen = 2 + $wlen;
1708 return "\@emph\{${w}\}";
1709 } elsif ($wtype eq "x ") {
1710 $texiwdlen = 0; # we don't need it in this case
1711 $capital = 1; # hack
1712 return "\@ref\{";
1713 } elsif ($wtype eq "xe") {
1714 $texiwdlen = 0; # we don't need it in this case
1715 return "\}";
1716 } elsif ($wmajt eq "i") {
1717 $texiwdlen = 0; # we don't need it in this case
1718 return "\001";
1719 } else {
1720 die "panic in word_texi: $wtype$w\n";
1724 sub texi_menu {
1725 my ($topitem) = @_;
1726 my $item, $i, $mpname, $title, $wd;
1728 $item = $tstruct_next{$topitem};
1729 print "\@menu\n";
1730 while ($item) {
1731 $title = "";
1732 $mpname = $tstruct_pname{$item};
1733 foreach $i (@$mpname) {
1734 $wd = &word_texi($i);
1735 $title .= $wd unless $wd eq "\001";
1737 print "* ${item}:: $title\n";
1738 $item = $tstruct_mnext{$item};
1740 print "* Index::\n" if $topitem eq "Top";
1741 print "\@end menu\n";
1744 sub texi_index {
1745 my $itag, $ientry, @a, $wd, $item, $len;
1746 my $subnums = "123456789ABCDEFGHIJKLMNOPQRSTU" .
1747 "VWXYZabcdefghijklmnopqrstuvwxyz";
1749 print "\@ifinfo\n\@node Index, , $FIXMElastnode, Top\n";
1750 print "\@unnumbered Index\n\n\@menu\n";
1752 foreach $itag (@itags) {
1753 $ientry = $idxmap{$itag};
1754 @a = @$ientry;
1755 $item = '';
1756 $len = 0;
1757 foreach $i (@a) {
1758 $wd = &word_texi($i);
1759 $item .= $wd, $len += $texiwdlen unless $wd eq "\001";
1761 $i = 0;
1762 foreach $node (@nodes) {
1763 next if !$idxnodes{$node,$itag};
1764 printf "* %s%s (%s): %s.\n",
1765 $item, " " x (40-$len), substr($subnums,$i++,1), $node;
1768 print "\@end menu\n\@end ifinfo\n";
1771 sub write_hlp {
1772 # This is called from the top level, so I won't bother using
1773 # my or local.
1775 # Build the index-tag text forms.
1776 print "building index entries...";
1777 @hlp_index = map {
1778 my $i,$ww;
1779 my $ientry = $idxmap{$_};
1780 my $title = "";
1781 foreach $i (@$ientry) {
1782 $ww = &word_hlp($i,0);
1783 $title .= $ww unless $ww eq "\001";
1785 $title;
1786 } @itags;
1788 # Write the HPJ project-description file.
1789 print "writing .hpj file...";
1790 open HPJ,">nasmdoc.hpj";
1791 print HPJ "[OPTIONS]\ncompress=true\n";
1792 print HPJ "title=NASM: The Netwide Assembler\noldkeyphrase=no\n\n";
1793 print HPJ "[FILES]\nnasmdoc.rtf\n\n";
1794 print HPJ "[CONFIG]\n";
1795 print HPJ 'CreateButton("btn_up", "&Up",'.
1796 ' "JumpContents(`nasmdoc.hlp'."'".')")';
1797 print HPJ "\nBrowseButtons()\n";
1798 close HPJ;
1800 # Open file.
1801 print "\n writing .rtf file...";
1802 open TEXT,">nasmdoc.rtf";
1803 select TEXT;
1805 # Preamble.
1806 print "{\\rtf1\\ansi{\\fonttbl\n";
1807 print "\\f0\\froman Times New Roman;\\f1\\fmodern Courier New;\n";
1808 print "\\f2\\fswiss Arial;\\f3\\ftech Wingdings}\\deff0\n";
1809 print "#{\\footnote Top}\n";
1810 print "\${\\footnote Contents}\n";
1811 print "+{\\footnote browse:00000}\n";
1812 print "!{\\footnote DisableButton(\"btn_up\")}\n";
1813 print "\\keepn\\f2\\b\\fs30\\sb0\n";
1814 print "NASM: The Netwide Assembler\n";
1815 print "\\par\\pard\\plain\\sb120\n";
1816 print "This file documents NASM, the Netwide Assembler: an assembler \n";
1817 print "targetting the Intel x86 series of processors, with portable source.\n";
1819 $node = "Top";
1820 $browse = 0;
1822 $newpar = "\\par\\sb120\n";
1823 for ($para = 0; $para <= $#pnames; $para++) {
1824 $pname = $pnames[$para];
1825 $pflags = $pflags[$para];
1826 $ptype = substr($pflags,0,4);
1828 print $newpar;
1829 $newpar = "\\par\\sb120\n";
1831 if ($ptype eq "chap") {
1832 # Chapter heading. Begin a new node.
1833 &hlp_menu($node)
1834 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1835 $pflags =~ /chap (.*) :(.*)/;
1836 $node = "Chapter $1";
1837 $title = $footnotetitle = "Chapter $1: ";
1838 foreach $i (@$pname) {
1839 $ww = &word_hlp($i,1);
1840 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1842 print "\\page\n";
1843 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1844 print "\${\\footnote $footnotetitle}\n";
1845 printf "+{\\footnote browse:%05d}\n", ++$browse;
1846 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1847 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1848 &hlp_sectkw($tstruct_up{$node});
1849 print "EnableButton(\"btn_up\")}\n";
1850 &hlp_keywords($node);
1851 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1852 print "$title\n";
1853 $newpar = "\\par\\pard\\plain\\sb120\n";
1854 } elsif ($ptype eq "appn") {
1855 # Appendix heading. Begin a new node.
1856 &hlp_menu($node)
1857 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1858 $pflags =~ /appn (.*) :(.*)/;
1859 $node = "Appendix $1";
1860 $title = $footnotetitle = "Appendix $1: ";
1861 foreach $i (@$pname) {
1862 $ww = &word_hlp($i,1);
1863 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1865 print "\\page\n";
1866 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1867 print "\${\\footnote $footnotetitle}\n";
1868 printf "+{\\footnote browse:%05d}\n", ++$browse;
1869 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1870 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1871 &hlp_sectkw($tstruct_up{$node});
1872 print "EnableButton(\"btn_up\")}\n";
1873 &hlp_keywords($node);
1874 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1875 print "$title\n";
1876 $newpar = "\\par\\pard\\plain\\sb120\n";
1877 } elsif ($ptype eq "head" || $ptype eq "subh") {
1878 # Heading or subheading. Begin a new node.
1879 &hlp_menu($node)
1880 if $tstruct_level{$tstruct_next{$node}} > $tstruct_level{$node};
1881 $pflags =~ /.... (.*) :(.*)/;
1882 $node = "Section $1";
1883 $title = $footnotetitle = "$1. ";
1884 foreach $i (@$pname) {
1885 $ww = &word_hlp($i,1);
1886 $title .= $ww, $footnotetitle .= &word_hlp($i,0) unless $ww eq "\001";
1888 print "\\page\n";
1889 printf "#{\\footnote %s}\n", &hlp_sectkw($node);
1890 print "\${\\footnote $footnotetitle}\n";
1891 printf "+{\\footnote browse:%05d}\n", ++$browse;
1892 printf "!{\\footnote ChangeButtonBinding(\"btn_up\"," .
1893 "\"JumpId(\`nasmdoc.hlp',\`%s')\");\n",
1894 &hlp_sectkw($tstruct_up{$node});
1895 print "EnableButton(\"btn_up\")}\n";
1896 &hlp_keywords($node);
1897 print "\\keepn\\f2\\b\\fs30\\sb60\\sa60\n";
1898 print "$title\n";
1899 $newpar = "\\par\\pard\\plain\\sb120\n";
1900 } elsif ($ptype eq "code") {
1901 # Code paragraph.
1902 print "\\keep\\f1\\sb120\n";
1903 foreach $i (@$pname) {
1904 warn "code line longer than 68 chars: $i\n" if length $i > 68;
1905 $i =~ s/\\/\\\\/g;
1906 $i =~ s/\{/\\\{/g;
1907 $i =~ s/\}/\\\}/g;
1908 print "$i\\par\\sb0\n";
1910 $newpar = "\\pard\\f0\\sb120\n";
1911 } elsif ($ptype eq "bull" || $ptype eq "norm") {
1912 # Ordinary paragraph, optionally bulleted. We wrap, FWIW.
1913 if ($ptype eq "bull") {
1914 print "\\tx360\\li360\\fi-360{\\f3\\'9F}\\tab\n";
1915 $newpar = "\\par\\pard\\sb120\n";
1916 } else {
1917 $newpar = "\\par\\sb120\n";
1919 $line = '';
1920 @a = @$pname;
1921 $wd = $wprev = '';
1922 do {
1923 do { $w = &word_hlp((shift @a),1); } while $w eq "\001"; # hack
1924 $wd .= $wprev;
1925 if ($w eq ' ' || $w eq '' || $w eq undef) {
1926 if (length ($line . $wd) > 75) {
1927 $line =~ s/\s*$//; # trim trailing spaces
1928 print "$line \n"; # and put one back
1929 $line = '';
1930 $wd =~ s/^\s*//; # trim leading spaces
1932 $line .= $wd;
1933 $wd = '';
1935 $wprev = $w;
1936 } while ($w ne '' && $w ne undef);
1937 if ($line =~ /\S/) {
1938 $line =~ s/\s*$//; # trim trailing spaces
1939 print "$line\n";
1944 # Close file.
1945 print "\\page}\n";
1946 select STDOUT;
1947 close TEXT;
1950 sub word_hlp {
1951 my ($w, $docode) = @_;
1952 my $wtype, $wmajt;
1954 return undef if $w eq '' || $w eq undef;
1955 $wtype = substr($w,0,2);
1956 $wmajt = substr($wtype,0,1);
1957 $w = substr($w,2);
1958 $w =~ s/\\/\\\\/g;
1959 $w =~ s/\{/\\\{/g;
1960 $w =~ s/\}/\\\}/g;
1961 $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
1962 substr($w,0,length($w)-1) =~ s/-/\\'AD/g if $wmajt ne "x"; #nonbreakhyphens
1963 if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
1964 return $w;
1965 } elsif ($wtype eq "sp") {
1966 return ' ';
1967 } elsif ($wtype eq "da") {
1968 return "\\'96";
1969 } elsif ($wmajt eq "c" || $wtype eq "wc") {
1970 $w =~ s/ /\\'A0/g; # make spaces non-breaking
1971 return $docode ? "{\\f1 ${w}}" : $w;
1972 } elsif ($wtype eq "es") {
1973 return "{\\i ${w}";
1974 } elsif ($wtype eq "ee") {
1975 return "${w}}";
1976 } elsif ($wtype eq "eo") {
1977 return "{\\i ${w}}";
1978 } elsif ($wtype eq "x ") {
1979 return "{\\uldb ";
1980 } elsif ($wtype eq "xe") {
1981 $w = &hlp_sectkw($w);
1982 return "}{\\v ${w}}";
1983 } elsif ($wmajt eq "i") {
1984 return "\001";
1985 } else {
1986 die "panic in word_hlp: $wtype$w\n";
1990 sub hlp_menu {
1991 my ($topitem) = @_;
1992 my $item, $kword, $i, $mpname, $title;
1994 $item = $tstruct_next{$topitem};
1995 print "\\li360\\fi-360\n";
1996 while ($item) {
1997 $title = "";
1998 $mpname = $tstruct_pname{$item};
1999 foreach $i (@$mpname) {
2000 $ww = &word_hlp($i, 0);
2001 $title .= $ww unless $ww eq "\001";
2003 $kword = &hlp_sectkw($item);
2004 print "{\\uldb ${item}: $title}{\\v $kword}\\par\\sb0\n";
2005 $item = $tstruct_mnext{$item};
2007 print "\\pard\\sb120\n";
2010 sub hlp_sectkw {
2011 my ($node) = @_;
2012 $node =~ tr/A-Z/a-z/;
2013 $node =~ tr/- ./___/;
2014 $node;
2017 sub hlp_keywords {
2018 my ($node) = @_;
2019 my $pfx = "K{\\footnote ";
2020 my $done = 0;
2021 foreach $i (0..$#itags) {
2022 (print $pfx,$hlp_index[$i]), $pfx = ";\n", $done++
2023 if $idxnodes{$node,$itags[$i]};
2025 print "}\n" if $done;
2028 # Make tree structures. $tstruct_* is top-level and global.
2029 sub add_item {
2030 my ($item, $level) = @_;
2031 my $i;
2033 $tstruct_pname{$item} = $pname;
2034 $tstruct_next{$tstruct_previtem} = $item;
2035 $tstruct_prev{$item} = $tstruct_previtem;
2036 $tstruct_level{$item} = $level;
2037 $tstruct_up{$item} = $tstruct_last[$level-1];
2038 $tstruct_mnext{$tstruct_last[$level]} = $item;
2039 $tstruct_last[$level] = $item;
2040 for ($i=$level+1; $i<$MAXLEVEL; $i++) { $tstruct_last[$i] = undef; }
2041 $tstruct_previtem = $item;
2042 push @nodes, $item;
2045 # PostScript font metric data. Used for line breaking.
2046 sub font_metrics {
2047 @timesr = (
2048 250, 0, 0, 0, 0, 0, 0, 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 250, 333, 408, 500, 500, 833, 778, 333,
2053 333, 333, 500, 564, 250, 333, 250, 278,
2054 500, 500, 500, 500, 500, 500, 500, 500,
2055 500, 500, 278, 278, 564, 564, 564, 444,
2056 921, 722, 667, 667, 722, 611, 556, 722,
2057 722, 333, 389, 722, 611, 889, 722, 722,
2058 556, 722, 667, 556, 611, 722, 722, 944,
2059 722, 722, 611, 333, 278, 333, 469, 500,
2060 333, 444, 500, 444, 500, 444, 333, 500,
2061 500, 278, 278, 500, 278, 778, 500, 500,
2062 500, 500, 333, 389, 278, 500, 500, 722,
2063 500, 500, 444, 480, 200, 480, 541, 0,
2064 0, 0, 0, 0, 0, 0, 0, 0,
2065 0, 0, 0, 0, 0, 0, 0, 0,
2066 0, 0, 0, 0, 0, 0, 0, 0,
2067 0, 0, 0, 0, 0, 0, 0, 0,
2068 0, 333, 500, 500, 167, 500, 500, 500,
2069 500, 180, 444, 500, 333, 333, 556, 556,
2070 0, 500, 500, 500, 250, 0, 453, 350,
2071 333, 444, 444, 500,1000,1000, 0, 444,
2072 0, 333, 333, 333, 333, 333, 333, 333,
2073 333, 0, 333, 333, 0, 333, 333, 333,
2074 1000, 0, 0, 0, 0, 0, 0, 0,
2075 0, 0, 0, 0, 0, 0, 0, 0,
2076 0, 889, 0, 276, 0, 0, 0, 0,
2077 611, 722, 889, 310, 0, 0, 0, 0,
2078 0, 667, 0, 0, 0, 278, 0, 0,
2079 278, 500, 722, 500, 0, 0, 0, 0
2081 @timesi = (
2082 250, 0, 0, 0, 0, 0, 0, 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 250, 333, 420, 500, 500, 833, 778, 333,
2087 333, 333, 500, 675, 250, 333, 250, 278,
2088 500, 500, 500, 500, 500, 500, 500, 500,
2089 500, 500, 333, 333, 675, 675, 675, 500,
2090 920, 611, 611, 667, 722, 611, 611, 722,
2091 722, 333, 444, 667, 556, 833, 667, 722,
2092 611, 722, 611, 500, 556, 722, 611, 833,
2093 611, 556, 556, 389, 278, 389, 422, 500,
2094 333, 500, 500, 444, 500, 444, 278, 500,
2095 500, 278, 278, 444, 278, 722, 500, 500,
2096 500, 500, 389, 389, 278, 500, 444, 667,
2097 444, 444, 389, 400, 275, 400, 541, 0,
2098 0, 0, 0, 0, 0, 0, 0, 0,
2099 0, 0, 0, 0, 0, 0, 0, 0,
2100 0, 0, 0, 0, 0, 0, 0, 0,
2101 0, 0, 0, 0, 0, 0, 0, 0,
2102 0, 389, 500, 500, 167, 500, 500, 500,
2103 500, 214, 556, 500, 333, 333, 500, 500,
2104 0, 500, 500, 500, 250, 0, 523, 350,
2105 333, 556, 556, 500, 889,1000, 0, 500,
2106 0, 333, 333, 333, 333, 333, 333, 333,
2107 333, 0, 333, 333, 0, 333, 333, 333,
2108 889, 0, 0, 0, 0, 0, 0, 0,
2109 0, 0, 0, 0, 0, 0, 0, 0,
2110 0, 889, 0, 276, 0, 0, 0, 0,
2111 556, 722, 944, 310, 0, 0, 0, 0,
2112 0, 667, 0, 0, 0, 278, 0, 0,
2113 278, 500, 667, 500, 0, 0, 0, 0
2115 @courr = (
2116 600, 0, 0, 0, 0, 0, 0, 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 600, 600, 600, 600, 600, 600, 600, 600,
2121 600, 600, 600, 600, 600, 600, 600, 600,
2122 600, 600, 600, 600, 600, 600, 600, 600,
2123 600, 600, 600, 600, 600, 600, 600, 600,
2124 600, 600, 600, 600, 600, 600, 600, 600,
2125 600, 600, 600, 600, 600, 600, 600, 600,
2126 600, 600, 600, 600, 600, 600, 600, 600,
2127 600, 600, 600, 600, 600, 600, 600, 600,
2128 600, 600, 600, 600, 600, 600, 600, 600,
2129 600, 600, 600, 600, 600, 600, 600, 600,
2130 600, 600, 600, 600, 600, 600, 600, 600,
2131 600, 600, 600, 600, 600, 600, 600, 0,
2132 0, 0, 0, 0, 0, 0, 0, 0,
2133 0, 0, 0, 0, 0, 0, 0, 0,
2134 0, 0, 0, 0, 0, 0, 0, 0,
2135 0, 0, 0, 0, 0, 0, 0, 0,
2136 0, 600, 600, 600, 600, 600, 600, 600,
2137 600, 600, 600, 600, 600, 600, 600, 600,
2138 0, 600, 600, 600, 600, 0, 600, 600,
2139 600, 600, 600, 600, 600, 600, 0, 600,
2140 0, 600, 600, 600, 600, 600, 600, 600,
2141 600, 0, 600, 600, 0, 600, 600, 600,
2142 600, 0, 0, 0, 0, 0, 0, 0,
2143 0, 0, 0, 0, 0, 0, 0, 0,
2144 0, 600, 0, 600, 0, 0, 0, 0,
2145 600, 600, 600, 600, 0, 0, 0, 0,
2146 0, 600, 0, 0, 0, 600, 0, 0,
2147 600, 600, 600, 600, 0, 0, 0, 0