rdsrc.pl 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. #!/usr/bin/perl
  2. ## --------------------------------------------------------------------------
  3. ##
  4. ## Copyright 1996-2018 The NASM Authors - All Rights Reserved
  5. ## See the file AUTHORS included with the NASM distribution for
  6. ## the specific copyright holders.
  7. ##
  8. ## Redistribution and use in source and binary forms, with or without
  9. ## modification, are permitted provided that the following
  10. ## conditions are met:
  11. ##
  12. ## * Redistributions of source code must retain the above copyright
  13. ## notice, this list of conditions and the following disclaimer.
  14. ## * Redistributions in binary form must reproduce the above
  15. ## copyright notice, this list of conditions and the following
  16. ## disclaimer in the documentation and/or other materials provided
  17. ## with the distribution.
  18. ##
  19. ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  20. ## CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  21. ## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  22. ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  23. ## DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26. ## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. ## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  30. ## OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  31. ## EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. ##
  33. ## --------------------------------------------------------------------------
  34. # Read the source-form of the NASM manual and generate the various
  35. # output forms.
  36. # TODO:
  37. #
  38. # Ellipsis support would be nice.
  39. # Source-form features:
  40. # ---------------------
  41. #
  42. # Bullet \b
  43. # Bullets the paragraph. Rest of paragraph is indented to cope. In
  44. # HTML, consecutive groups of bulleted paragraphs become unordered
  45. # lists.
  46. #
  47. # Indent \>
  48. # Indents the paragraph equvalently to a bulleted paragraph. In HTML,
  49. # an indented paragraph following a bulleted paragraph is included in the
  50. # same list item.
  51. #
  52. # Blockquote \q
  53. # Marks the paragraph as a block quote.
  54. #
  55. # Emphasis \e{foobar}
  56. # produces `_foobar_' in text and italics in HTML, PS, RTF
  57. #
  58. # Inline code \c{foobar}
  59. # produces ``foobar'' in text, and fixed-pitch font in HTML, PS, RTF
  60. #
  61. # Display code
  62. # \c line one
  63. # \c line two
  64. # produces fixed-pitch font where appropriate, and doesn't break
  65. # pages except sufficiently far into the middle of a display.
  66. #
  67. # Chapter, header and subheader
  68. # \C{intro} Introduction
  69. # \H{whatsnasm} What is NASM?
  70. # \S{free} NASM Is Free
  71. # dealt with as appropriate. Chapters begin on new sides, possibly
  72. # even new _pages_. (Sub)?headers are good places to begin new
  73. # pages. Just _after_ a (sub)?header isn't.
  74. # The keywords can be substituted with \K and \k.
  75. #
  76. # Keyword \K{cintro} \k{cintro}
  77. # Expands to `Chapter 1', `Section 1.1', `Section 1.1.1'. \K has an
  78. # initial capital whereas \k doesn't. In HTML, will produce
  79. # hyperlinks.
  80. #
  81. # Web link \W{http://foobar/}{text} or \W{mailto:me@here}\c{me@here}
  82. # the \W prefix is ignored except in HTML; in HTML the last part
  83. # becomes a hyperlink to the first part.
  84. #
  85. # Literals \{ \} \\
  86. # In case it's necessary, they expand to the real versions.
  87. #
  88. # Nonbreaking hyphen \-
  89. # Need more be said?
  90. #
  91. # Source comment \#
  92. # Causes everything after it on the line to be ignored by the
  93. # source-form processor.
  94. #
  95. # Indexable word \i{foobar} (or \i\e{foobar} or \i\c{foobar}, equally)
  96. # makes word appear in index, referenced to that point
  97. # \i\c comes up in code style even in the index; \i\e doesn't come
  98. # up in emphasised style.
  99. #
  100. # Indexable non-displayed word \I{foobar} or \I\c{foobar}
  101. # just as \i{foobar} except that nothing is displayed for it
  102. #
  103. # Index rewrite
  104. # \IR{foobar} \c{foobar} operator, uses of
  105. # tidies up the appearance in the index of something the \i or \I
  106. # operator was applied to
  107. #
  108. # Index alias
  109. # \IA{foobar}{bazquux}
  110. # aliases one index tag (as might be supplied to \i or \I) to
  111. # another, so that \I{foobar} has the effect of \I{bazquux}, and
  112. # \i{foobar} has the effect of \I{bazquux}foobar
  113. #
  114. # Metadata
  115. # \M{key}{something}
  116. # defines document metadata, such as authorship, title and copyright;
  117. # different output formats use this differently.
  118. #
  119. # Include subfile
  120. # \&{filename}
  121. # Includes filename. Recursion is allowed.
  122. #
  123. use File::Spec;
  124. @include_path = ();
  125. $out_path = File::Spec->curdir();
  126. while ($ARGV[0] =~ /^-/) {
  127. my $opt = shift @ARGV;
  128. if ($opt eq '-d') {
  129. $diag = 1;
  130. } elsif ($opt =~ /^\-[Ii](.*)$/) {
  131. push(@include_path, $1);
  132. } elsif ($opt =~ /^\-[Oo](.*)$/) {
  133. $out_path = $1;
  134. }
  135. }
  136. $out_format = shift(@ARGV);
  137. @files = @ARGV;
  138. @files = ('-') unless(scalar(@files));
  139. $| = 1;
  140. $tstruct_previtem = $node = "Top";
  141. $nodes = ($node);
  142. $tstruct_level{$tstruct_previtem} = 0;
  143. $tstruct_last[$tstruct_level{$tstruct_previtem}] = $tstruct_previtem;
  144. $MAXLEVEL = 10; # really 3, but play safe ;-)
  145. # Read the file; pass a paragraph at a time to the paragraph processor.
  146. print "Reading input...";
  147. $pname = "para000000";
  148. @pnames = @pflags = ();
  149. $para = undef;
  150. foreach $file (@files) {
  151. &include($file);
  152. }
  153. &got_para($para);
  154. print "done.\n";
  155. # Now we've read in the entire document and we know what all the
  156. # heading keywords refer to. Go through and fix up the \k references.
  157. print "Fixing up cross-references...";
  158. &fixup_xrefs;
  159. print "done.\n";
  160. # Sort the index tags, according to the slightly odd order I've decided on.
  161. print "Sorting index tags...";
  162. &indexsort;
  163. print "done.\n";
  164. # Make output directory if necessary
  165. mkdir($out_path);
  166. if ($diag) {
  167. print "Writing index-diagnostic file...";
  168. &indexdiag;
  169. print "done.\n";
  170. }
  171. # OK. Write out the various output files.
  172. if ($out_format eq 'txt') {
  173. print "Producing text output: ";
  174. &write_txt;
  175. print "done.\n";
  176. } elsif ($out_format eq 'html') {
  177. print "Producing HTML output: ";
  178. &write_html;
  179. print "done.\n";
  180. } elsif ($out_format eq 'dip') {
  181. print "Producing Documentation Intermediate Paragraphs: ";
  182. &write_dip;
  183. print "done.\n";
  184. } else {
  185. die "$0: unknown output format: $out_format\n";
  186. }
  187. sub untabify($) {
  188. my($s) = @_;
  189. my $o = '';
  190. my($c, $i, $p);
  191. $p = 0;
  192. for ($i = 0; $i < length($s); $i++) {
  193. $c = substr($s, $i, 1);
  194. if ($c eq "\t") {
  195. do {
  196. $o .= ' ';
  197. $p++;
  198. } while ($p & 7);
  199. } else {
  200. $o .= $c;
  201. $p++;
  202. }
  203. }
  204. return $o;
  205. }
  206. sub read_line {
  207. local $_ = shift;
  208. $_ = &untabify($_);
  209. if (/\\& (\S+)/) {
  210. &include($1);
  211. } else {
  212. &get_para($_);
  213. }
  214. }
  215. sub get_para($_) {
  216. chomp;
  217. if (!/\S/ || /^\\(IA|IR|M)/) { # special case: \IA \IR \M imply new-paragraph
  218. &got_para($para);
  219. $para = undef;
  220. }
  221. if (/\S/) {
  222. s/(^|[^\\])\\#.*$/\1/; # strip comments
  223. $para .= " " . $_;
  224. }
  225. }
  226. sub include {
  227. my $name = shift;
  228. my $F;
  229. if ($name eq '-') {
  230. open($F, '<-'); # stdin
  231. } else {
  232. my $found = 0;
  233. foreach my $idir ( File::Spec->curdir, @include_path ) {
  234. my $fpath = File::Spec->catfile($idir, $name);
  235. if (open($F, '<', $fpath)) {
  236. $found = 1;
  237. last;
  238. }
  239. }
  240. die "Cannot open $name: $!\n" unless ($found);
  241. }
  242. while (defined($_ = <$F>)) {
  243. &read_line($_);
  244. }
  245. close($F);
  246. }
  247. sub got_para {
  248. local ($_) = @_;
  249. my $pflags = "", $i, $w, $l, $t;
  250. return if !/\S/;
  251. @$pname = ();
  252. # Strip off _leading_ spaces, then determine type of paragraph.
  253. s/^\s*//;
  254. $irewrite = undef;
  255. if (/^\\c[^{]/) {
  256. # A code paragraph. The paragraph-array will contain the simple
  257. # strings which form each line of the paragraph.
  258. $pflags = "code";
  259. while (/^\\c (([^\\]|\\[^c])*)(.*)$/) {
  260. $l = $1;
  261. $_ = $3;
  262. $l =~ s/\\\{/\{/g;
  263. $l =~ s/\\\}/}/g;
  264. $l =~ s/\\\\/\\/g;
  265. push @$pname, $l;
  266. }
  267. $_ = ''; # suppress word-by-word code
  268. } elsif (/^\\C/) {
  269. # A chapter heading. Define the keyword and allocate a chapter
  270. # number.
  271. $cnum++;
  272. $hnum = 0;
  273. $snum = 0;
  274. $xref = "chapter-$cnum";
  275. $pflags = "chap $cnum :$xref";
  276. die "badly formatted chapter heading: $_\n" if !/^\\C\{([^\}]*)\}\s*(.*)$/;
  277. $refs{$1} = "chapter $cnum";
  278. $node = "Chapter $cnum";
  279. &add_item($node, 1);
  280. $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
  281. $xrefs{$1} = $xref;
  282. $_ = $2;
  283. # the standard word-by-word code will happen next
  284. } elsif (/^\\A/) {
  285. # An appendix heading. Define the keyword and allocate an appendix
  286. # letter.
  287. $cnum++;
  288. $cnum = 'A' if $cnum =~ /[0-9]+/;
  289. $hnum = 0;
  290. $snum = 0;
  291. $xref = "appendix-$cnum";
  292. $pflags = "appn $cnum :$xref";
  293. die "badly formatted appendix heading: $_\n" if !/^\\A\{([^\}]*)}\s*(.*)$/;
  294. $refs{$1} = "appendix $cnum";
  295. $node = "Appendix $cnum";
  296. &add_item($node, 1);
  297. $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
  298. $xrefs{$1} = $xref;
  299. $_ = $2;
  300. # the standard word-by-word code will happen next
  301. } elsif (/^\\H/) {
  302. # A major heading. Define the keyword and allocate a section number.
  303. $hnum++;
  304. $snum = 0;
  305. $xref = "section-$cnum.$hnum";
  306. $pflags = "head $cnum.$hnum :$xref";
  307. die "badly formatted heading: $_\n" if !/^\\[HP]\{([^\}]*)\}\s*(.*)$/;
  308. $refs{$1} = "section $cnum.$hnum";
  309. $node = "Section $cnum.$hnum";
  310. &add_item($node, 2);
  311. $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
  312. $xrefs{$1} = $xref;
  313. $_ = $2;
  314. # the standard word-by-word code will happen next
  315. } elsif (/^\\S/) {
  316. # A sub-heading. Define the keyword and allocate a section number.
  317. $snum++;
  318. $xref = "section-$cnum.$hnum.$snum";
  319. $pflags = "subh $cnum.$hnum.$snum :$xref";
  320. die "badly formatted subheading: $_\n" if !/^\\S\{([^\}]*)\}\s*(.*)$/;
  321. $refs{$1} = "section $cnum.$hnum.$snum";
  322. $node = "Section $cnum.$hnum.$snum";
  323. &add_item($node, 3);
  324. $xrefnodes{$node} = $xref; $nodexrefs{$xref} = $node;
  325. $xrefs{$1} = $xref;
  326. $_ = $2;
  327. # the standard word-by-word code will happen next
  328. } elsif (/^\\IR/) {
  329. # An index-rewrite.
  330. die "badly formatted index rewrite: $_\n" if !/^\\IR\{([^\}]*)\}\s*(.*)$/;
  331. $irewrite = $1;
  332. $_ = $2;
  333. # the standard word-by-word code will happen next
  334. } elsif (/^\\IA/) {
  335. # An index-alias.
  336. die "badly formatted index alias: $_\n" if !/^\\IA\{([^\}]*)}\{([^\}]*)\}\s*$/;
  337. $idxalias{$1} = $2;
  338. return; # avoid word-by-word code
  339. } elsif (/^\\M/) {
  340. # Metadata
  341. die "badly formed metadata: $_\n" if !/^\\M\{([^\}]*)}\{([^\}]*)\}\s*$/;
  342. $metadata{$1} = $2;
  343. return; # avoid word-by-word code
  344. } elsif (/^\\([b\>q])/) {
  345. # An indented paragraph of some sort. Strip off the initial \b and let the
  346. # word-by-word code take care of the rest.
  347. my %ipar = (
  348. 'b' => 'bull',
  349. '>' => 'indt',
  350. 'q' => 'bquo',
  351. );
  352. $pflags = $ipar{$1};
  353. s/^\\[b\>q]\s*//;
  354. } else {
  355. # A normal paragraph. Just set $pflags: the word-by-word code does
  356. # the rest.
  357. $pflags = "norm";
  358. }
  359. # The word-by-word code: unless @$pname is already defined (which it
  360. # will be in the case of a code paragraph), split the paragraph up
  361. # into words and push each on @$pname.
  362. #
  363. # Each thing pushed on @$pname should have a two-character type
  364. # code followed by the text.
  365. #
  366. # Type codes are:
  367. # "n " for normal
  368. # "da" for an en dash
  369. # "dm" for an em desh
  370. # "es" for first emphasised word in emphasised bit
  371. # "e " for emphasised in mid-emphasised-bit
  372. # "ee" for last emphasised word in emphasised bit
  373. # "eo" for single (only) emphasised word
  374. # "c " for code
  375. # "k " for cross-ref
  376. # "kK" for capitalised cross-ref
  377. # "w " for Web link
  378. # "wc" for code-type Web link
  379. # "x " for beginning of resolved cross-ref; generates no visible output,
  380. # and the text is the cross-reference code
  381. # "xe" for end of resolved cross-ref; text is same as for "x ".
  382. # "i " for point to be indexed: the text is the internal index into the
  383. # index-items arrays
  384. # "sp" for space
  385. while (/\S/) {
  386. s/^\s*//, push @$pname, "sp" if /^\s/;
  387. $indexing = $qindex = 0;
  388. if (/^(\\[iI])?\\c/) {
  389. $qindex = 1 if $1 eq "\\I";
  390. $indexing = 1, s/^\\[iI]// if $1;
  391. s/^\\c//;
  392. die "badly formatted \\c: \\c$_\n" if !/\{(([^\\}]|\\.)*)\}(.*)$/;
  393. $w = $1;
  394. $_ = $3;
  395. $w =~ s/\\\{/\{/g;
  396. $w =~ s/\\\}/\}/g;
  397. $w =~ s/\\-/-/g;
  398. $w =~ s/\\\\/\\/g;
  399. (push @$pname,"i"),$lastp = $#$pname if $indexing;
  400. push @$pname,"c $w" if !$qindex;
  401. $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
  402. } elsif (/^\\[iIe]/) {
  403. /^(\\[iI])?(\\e)?/;
  404. $emph = 0;
  405. $qindex = 1 if $1 eq "\\I";
  406. $indexing = 1, $type = "\\i" if $1;
  407. $emph = 1, $type = "\\e" if $2;
  408. s/^(\\[iI])?(\\e?)//;
  409. die "badly formatted $type: $type$_\n" if !/\{(([^\\}]|\\.)*)\}(.*)$/;
  410. $w = $1;
  411. $_ = $3;
  412. $w =~ s/\\\{/\{/g;
  413. $w =~ s/\\\}/\}/g;
  414. $w =~ s/\\-/-/g;
  415. $w =~ s/\\\\/\\/g;
  416. $t = $emph ? "es" : "n ";
  417. @ientry = ();
  418. (push @$pname,"i"),$lastp = $#$pname if $indexing;
  419. foreach $i (split /\s+/,$w) { # \e and \i can be multiple words
  420. push @$pname,"$t$i","sp" if !$qindex;
  421. ($ii=$i) =~ tr/A-Z/a-z/, push @ientry,"n $ii","sp" if $indexing;
  422. $t = $emph ? "e " : "n ";
  423. }
  424. $w =~ tr/A-Z/a-z/, pop @ientry if $indexing;
  425. $$pname[$lastp] = &addidx($node, $w, @ientry) if $indexing;
  426. pop @$pname if !$qindex; # remove final space
  427. if (substr($$pname[$#$pname],0,2) eq "es" && !$qindex) {
  428. substr($$pname[$#$pname],0,2) = "eo";
  429. } elsif ($emph && !$qindex) {
  430. substr($$pname[$#$pname],0,2) = "ee";
  431. }
  432. } elsif (/^\\[kK]/) {
  433. $t = "k ";
  434. $t = "kK" if /^\\K/;
  435. s/^\\[kK]//;
  436. die "badly formatted \\k: \\k$_\n" if !/\{([^\}]*)\}(.*)$/;
  437. $_ = $2;
  438. push @$pname,"$t$1";
  439. } elsif (/^\\W/) {
  440. s/^\\W//;
  441. die "badly formatted \\W: \\W$_\n"
  442. if !/\{([^\}]*)\}(\\i)?(\\c)?\{(([^\\}]|\\.)*)\}(.*)$/;
  443. $l = $1;
  444. $w = $4;
  445. $_ = $6;
  446. $t = "w ";
  447. $t = "wc" if $3 eq "\\c";
  448. $indexing = 1 if $2;
  449. $w =~ s/\\\{/\{/g;
  450. $w =~ s/\\\}/\}/g;
  451. $w =~ s/\\-/-/g;
  452. $w =~ s/\\\\/\\/g;
  453. (push @$pname,"i"),$lastp = $#$pname if $indexing;
  454. push @$pname,"$t<$l>$w";
  455. $$pname[$lastp] = &addidx($node, $w, "c $w") if $indexing;
  456. } else {
  457. die "what the hell? $_\n" if !/^(([^\s\\\-]|\\[\\{}\-])*-?)(.*)$/;
  458. die "painful death! $_\n" if !length $1;
  459. $w = $1;
  460. $_ = $3;
  461. $w =~ s/\\\{/\{/g;
  462. $w =~ s/\\\}/\}/g;
  463. $w =~ s/\\-/-/g;
  464. $w =~ s/\\\\/\\/g;
  465. if ($w eq '--') {
  466. push @$pname, 'dm';
  467. } elsif ($w eq '-') {
  468. push @$pname, 'da';
  469. } else {
  470. push @$pname,"n $w";
  471. }
  472. }
  473. }
  474. if ($irewrite ne undef) {
  475. &addidx(undef, $irewrite, @$pname);
  476. @$pname = ();
  477. } else {
  478. push @pnames, $pname;
  479. push @pflags, $pflags;
  480. $pname++;
  481. }
  482. }
  483. sub addidx {
  484. my ($node, $text, @ientry) = @_;
  485. $text = $idxalias{$text} || $text;
  486. if ($node eq undef || !$idxmap{$text}) {
  487. @$ientry = @ientry;
  488. $idxmap{$text} = $ientry;
  489. $ientry++;
  490. }
  491. if ($node) {
  492. $idxnodes{$node,$text} = 1;
  493. return "i $text";
  494. }
  495. }
  496. sub indexsort {
  497. my $iitem, $ientry, $i, $piitem, $pcval, $cval, $clrcval;
  498. @itags = map { # get back the original data as the 1st elt of each list
  499. $_->[0]
  500. } sort { # compare auxiliary (non-first) elements of lists
  501. $a->[1] cmp $b->[1] ||
  502. $a->[2] cmp $b->[2] ||
  503. $a->[0] cmp $b->[0]
  504. } map { # transform array into list of 3-element lists
  505. my $ientry = $idxmap{$_};
  506. my $a = substr($$ientry[0],2);
  507. $a =~ tr/A-Za-z0-9//cd;
  508. [$_, uc($a), substr($$ientry[0],0,2)]
  509. } keys %idxmap;
  510. # Having done that, check for comma-hood.
  511. $cval = 0;
  512. foreach $iitem (@itags) {
  513. $ientry = $idxmap{$iitem};
  514. $clrcval = 1;
  515. $pcval = $cval;
  516. FL:for ($i=0; $i <= $#$ientry; $i++) {
  517. if ($$ientry[$i] =~ /^(n .*,)(.*)/) {
  518. $$ientry[$i] = $1;
  519. splice @$ientry,$i+1,0,"n $2" if length $2;
  520. $commapos{$iitem} = $i+1;
  521. $cval = join("\002", @$ientry[0..$i]);
  522. $clrcval = 0;
  523. last FL;
  524. }
  525. }
  526. $cval = undef if $clrcval;
  527. $commanext{$iitem} = $commaafter{$piitem} = 1
  528. if $cval and ($cval eq $pcval);
  529. $piitem = $iitem;
  530. }
  531. }
  532. sub indexdiag {
  533. my $iitem,$ientry,$w,$ww,$foo,$node;
  534. open INDEXDIAG, '>', File::Spec->catfile($out_path, 'index.diag');
  535. foreach $iitem (@itags) {
  536. $ientry = $idxmap{$iitem};
  537. print INDEXDIAG "<$iitem> ";
  538. foreach $w (@$ientry) {
  539. $ww = &word_txt($w);
  540. print INDEXDIAG $ww unless $ww eq "\001";
  541. }
  542. print INDEXDIAG ":";
  543. $foo = " ";
  544. foreach $node (@nodes) {
  545. (print INDEXDIAG $foo,$node), $foo = ", " if $idxnodes{$node,$iitem};
  546. }
  547. print INDEXDIAG "\n";
  548. }
  549. close INDEXDIAG;
  550. }
  551. sub fixup_xrefs {
  552. my $pname, $p, $i, $j, $k, $caps, @repl;
  553. for ($p=0; $p<=$#pnames; $p++) {
  554. next if $pflags[$p] eq "code";
  555. $pname = $pnames[$p];
  556. for ($i=$#$pname; $i >= 0; $i--) {
  557. if ($$pname[$i] =~ /^k/) {
  558. $k = $$pname[$i];
  559. $caps = ($k =~ /^kK/);
  560. $k = substr($k,2);
  561. $repl = $refs{$k};
  562. die "undefined keyword `$k'\n" unless $repl;
  563. substr($repl,0,1) =~ tr/a-z/A-Z/ if $caps;
  564. @repl = ();
  565. push @repl,"x $xrefs{$k}";
  566. foreach $j (split /\s+/,$repl) {
  567. push @repl,"n $j";
  568. push @repl,"sp";
  569. }
  570. pop @repl; # remove final space
  571. push @repl,"xe$xrefs{$k}";
  572. splice @$pname,$i,1,@repl;
  573. }
  574. }
  575. }
  576. }
  577. sub write_txt {
  578. # This is called from the top level, so I won't bother using
  579. # my or local.
  580. # Open file.
  581. print "writing file...";
  582. open TEXT, '>', File::Spec->catfile($out_path, 'nasmdoc.txt');
  583. select TEXT;
  584. # Preamble.
  585. $title = $metadata{'title'};
  586. $spaces = ' ' x ((75-(length $title))/2);
  587. ($underscore = $title) =~ s/./=/g;
  588. print "$spaces$title\n$spaces$underscore\n";
  589. for ($para = 0; $para <= $#pnames; $para++) {
  590. $pname = $pnames[$para];
  591. $pflags = $pflags[$para];
  592. $ptype = substr($pflags,0,4);
  593. print "\n"; # always one of these before a new paragraph
  594. if ($ptype eq "chap") {
  595. # Chapter heading. "Chapter N: Title" followed by a line of
  596. # minus signs.
  597. $pflags =~ /chap (.*) :(.*)/;
  598. $title = "Chapter $1: ";
  599. foreach $i (@$pname) {
  600. $ww = &word_txt($i);
  601. $title .= $ww unless $ww eq "\001";
  602. }
  603. print "$title\n";
  604. $title =~ s/./-/g;
  605. print "$title\n";
  606. } elsif ($ptype eq "appn") {
  607. # Appendix heading. "Appendix N: Title" followed by a line of
  608. # minus signs.
  609. $pflags =~ /appn (.*) :(.*)/;
  610. $title = "Appendix $1: ";
  611. foreach $i (@$pname) {
  612. $ww = &word_txt($i);
  613. $title .= $ww unless $ww eq "\001";
  614. }
  615. print "$title\n";
  616. $title =~ s/./-/g;
  617. print "$title\n";
  618. } elsif ($ptype eq "head" || $ptype eq "subh") {
  619. # Heading or subheading. Just a number and some text.
  620. $pflags =~ /.... (.*) :(.*)/;
  621. $title = sprintf "%6s ", $1;
  622. foreach $i (@$pname) {
  623. $ww = &word_txt($i);
  624. $title .= $ww unless $ww eq "\001";
  625. }
  626. print "$title\n";
  627. } elsif ($ptype eq "code") {
  628. # Code paragraph. Emit each line with a seven character indent.
  629. foreach $i (@$pname) {
  630. warn "code line longer than 68 chars: $i\n" if length $i > 68;
  631. print ' 'x7, $i, "\n";
  632. }
  633. } elsif ($ptype =~ /^(norm|bull|indt|bquo)$/) {
  634. # Ordinary paragraph, optionally indented. We wrap, with ragged
  635. # 75-char right margin and either 7 or 11 char left margin
  636. # depending on bullets.
  637. if ($ptype ne 'norm') {
  638. $line = ' 'x7 . (($ptype eq 'bull') ? '(*) ' : ' ');
  639. $next = ' 'x11;
  640. } else {
  641. $line = $next = ' 'x7;
  642. }
  643. @a = @$pname;
  644. $wd = $wprev = '';
  645. do {
  646. do { $w = &word_txt(shift @a) } while $w eq "\001"; # nasty hack
  647. $wd .= $wprev;
  648. if ($wprev =~ /-$/ || $w eq ' ' || $w eq '' || $w eq undef) {
  649. if (length ($line . $wd) > 75) {
  650. $line =~ s/\s*$//; # trim trailing spaces
  651. print "$line\n";
  652. $line = $next;
  653. $wd =~ s/^\s*//; # trim leading spaces
  654. }
  655. $line .= $wd;
  656. $wd = '';
  657. }
  658. $wprev = $w;
  659. } while ($w ne '' && $w ne undef);
  660. if ($line =~ /\S/) {
  661. $line =~ s/\s*$//; # trim trailing spaces
  662. print "$line\n";
  663. }
  664. }
  665. }
  666. # Close file.
  667. select STDOUT;
  668. close TEXT;
  669. }
  670. sub word_txt {
  671. my ($w) = @_;
  672. my $wtype, $wmajt;
  673. return undef if $w eq '' || $w eq undef;
  674. $wtype = substr($w,0,2);
  675. $wmajt = substr($wtype,0,1);
  676. $w = substr($w,2);
  677. $w =~ s/<.*>// if $wmajt eq "w"; # remove web links
  678. if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
  679. return $w;
  680. } elsif ($wtype eq "sp") {
  681. return ' ';
  682. } elsif ($wtype eq 'da' || $wtype eq 'dm') {
  683. return '-';
  684. } elsif ($wmajt eq "c" || $wtype eq "wc") {
  685. return "`${w}'";
  686. } elsif ($wtype eq "es") {
  687. return "_${w}";
  688. } elsif ($wtype eq "ee") {
  689. return "${w}_";
  690. } elsif ($wtype eq "eo") {
  691. return "_${w}_";
  692. } elsif ($wmajt eq "x" || $wmajt eq "i") {
  693. return "\001";
  694. } else {
  695. die "panic in word_txt: $wtype$w\n";
  696. }
  697. }
  698. sub write_html {
  699. # This is called from the top level, so I won't bother using
  700. # my or local.
  701. # Write contents file. Just the preamble, then a menu of links to the
  702. # separate chapter files and the nodes therein.
  703. print "writing contents file...";
  704. open TEXT, '>', File::Spec->catfile($out_path, 'nasmdoc0.html');
  705. select TEXT;
  706. &html_preamble(0);
  707. print "<p>This manual documents NASM, the Netwide Assembler: an assembler\n";
  708. print "targetting the Intel x86 series of processors, with portable source.\n</p>";
  709. print "<div class=\"toc\">\n";
  710. $level = 0;
  711. for ($node = $tstruct_next{'Top'}; $node; $node = $tstruct_next{$node}) {
  712. my $lastlevel = $level;
  713. while ($tstruct_level{$node} < $level) {
  714. print "</li>\n</ol>\n";
  715. $level--;
  716. }
  717. while ($tstruct_level{$node} > $level) {
  718. print "<ol class=\"toc", ++$level, "\">\n";
  719. }
  720. if ($lastlevel >= $level) {
  721. print "</li>\n";
  722. }
  723. $level = $tstruct_level{$node};
  724. if ($level == 1) {
  725. # Invent a file name.
  726. ($number = lc($xrefnodes{$node})) =~ s/.*-//;
  727. $fname="nasmdocx.html";
  728. substr($fname,8 - length $number, length $number) = $number;
  729. $html_fnames{$node} = $fname;
  730. $link = $fname;
  731. } else {
  732. # Use the preceding filename plus a marker point.
  733. $link = $fname . "#$xrefnodes{$node}";
  734. }
  735. $title = '';
  736. $pname = $tstruct_pname{$node};
  737. foreach $i (@$pname) {
  738. $ww = &word_html($i);
  739. $title .= $ww unless $ww eq "\001";
  740. }
  741. print "<li class=\"toc${level}\">\n";
  742. print "<span class=\"node\">$node: </span><a href=\"$link\">$title</a>\n";
  743. }
  744. while ($level--) {
  745. print "</li>\n</ol>\n";
  746. }
  747. print "</div>\n";
  748. print "</body>\n";
  749. print "</html>\n";
  750. select STDOUT;
  751. close TEXT;
  752. # Open a null file, to ensure output (eg random &html_jumppoints calls)
  753. # goes _somewhere_.
  754. print "writing chapter files...";
  755. open TEXT, '>', File::Spec->devnull();
  756. select TEXT;
  757. undef $html_nav_last;
  758. undef $html_nav_next;
  759. $in_list = 0;
  760. $in_bquo = 0;
  761. $in_code = 0;
  762. for ($para = 0; $para <= $#pnames; $para++) {
  763. $pname = $pnames[$para];
  764. $pflags = $pflags[$para];
  765. $ptype = substr($pflags,0,4);
  766. $in_code = 0, print "</pre>\n" if ($in_code && $ptype ne 'code');
  767. $in_list = 0, print "</li>\n</ul>\n" if ($in_list && $ptype !~ /^(bull|indt|code)$/);
  768. $in_bquo = 0, print "</blockquote>\n" if ($in_bquo && $ptype ne 'bquo');
  769. $endtag = '';
  770. if ($ptype eq "chap") {
  771. # Chapter heading. Begin a new file.
  772. $pflags =~ /chap (.*) :(.*)/;
  773. $title = "Chapter $1: ";
  774. $xref = $2;
  775. &html_postamble; select STDOUT; close TEXT;
  776. $html_nav_last = $chapternode;
  777. $chapternode = $nodexrefs{$xref};
  778. $html_nav_next = $tstruct_mnext{$chapternode};
  779. open(TEXT, '>', File::Spec->catfile($out_path, $html_fnames{$chapternode}));
  780. select TEXT;
  781. &html_preamble(1);
  782. foreach $i (@$pname) {
  783. $ww = &word_html($i);
  784. $title .= $ww unless $ww eq "\001";
  785. }
  786. $h = "<h2 id=\"$xref\">$title</h2>\n";
  787. print $h; print FULL $h;
  788. } elsif ($ptype eq "appn") {
  789. # Appendix heading. Begin a new file.
  790. $pflags =~ /appn (.*) :(.*)/;
  791. $title = "Appendix $1: ";
  792. $xref = $2;
  793. &html_postamble; select STDOUT; close TEXT;
  794. $html_nav_last = $chapternode;
  795. $chapternode = $nodexrefs{$xref};
  796. $html_nav_next = $tstruct_mnext{$chapternode};
  797. open(TEXT, '>', File::Spec->catfile($out_path, $html_fnames{$chapternode}));
  798. select TEXT;
  799. &html_preamble(1);
  800. foreach $i (@$pname) {
  801. $ww = &word_html($i);
  802. $title .= $ww unless $ww eq "\001";
  803. }
  804. print "<h2 id=\"$xref\">$title</h2>\n";
  805. } elsif ($ptype eq "head" || $ptype eq "subh") {
  806. # Heading or subheading.
  807. $pflags =~ /.... (.*) :(.*)/;
  808. $hdr = ($ptype eq "subh" ? "h4" : "h3");
  809. $title = $1 . " ";
  810. $xref = $2;
  811. foreach $i (@$pname) {
  812. $ww = &word_html($i);
  813. $title .= $ww unless $ww eq "\001";
  814. }
  815. print "<$hdr id=\"$xref\">$title</$hdr>\n";
  816. } elsif ($ptype eq "code") {
  817. # Code paragraph.
  818. $in_code = 1, print "<pre>" unless $in_code;
  819. print "\n";
  820. foreach $i (@$pname) {
  821. $w = $i;
  822. $w =~ s/&/&amp;/g;
  823. $w =~ s/</&lt;/g;
  824. $w =~ s/>/&gt;/g;
  825. print $w, "\n";
  826. }
  827. } elsif ($ptype =~ /^(norm|bull|indt|bquo)$/) {
  828. # Ordinary paragraph, optionally indented.
  829. if ($ptype eq 'bull') {
  830. if (!$in_list) {
  831. $in_list = 1;
  832. print "<ul>\n";
  833. } else {
  834. print "</li>\n";
  835. }
  836. print "<li>\n";
  837. $line = '<p>';
  838. $endtag = '</p>';
  839. } elsif ($ptype eq 'indt') {
  840. if (!$in_list) {
  841. $in_list = 1;
  842. print "<ul>\n";
  843. print "<li class=\"indt\">\n"; # This is such a hack
  844. }
  845. $line = '<p>';
  846. $endtag = '</p>';
  847. } elsif ($ptype eq 'bquo') {
  848. $in_bquo = 1, print "<blockquote>\n" unless $in_bquo;
  849. $line = '<p>';
  850. $endtag = '</p>';
  851. } else {
  852. $line = '<p>';
  853. $endtag = '</p>';
  854. }
  855. @a = @$pname;
  856. $wd = $wprev = '';
  857. do {
  858. do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
  859. $wd .= $wprev;
  860. if ($w eq ' ' || $w eq '' || $w eq undef) {
  861. if (length ($line . $wd) > 75) {
  862. $line =~ s/\s*$//; # trim trailing spaces
  863. print "$line\n";
  864. $line = '';
  865. $wd =~ s/^\s*//; # trim leading spaces
  866. }
  867. $line .= $wd;
  868. $wd = '';
  869. }
  870. $wprev = $w;
  871. } while ($w ne '' && $w ne undef);
  872. if ($line =~ /\S/) {
  873. $line =~ s/\s*$//; # trim trailing spaces
  874. print $line;
  875. }
  876. print $endtag, "\n";
  877. }
  878. }
  879. # Close whichever file was open.
  880. print "</pre>\n" if ($in_code);
  881. print "</li>\n</ul>\n" if ($in_list);
  882. print "</blockquote>\n" if ($in_bquo);
  883. &html_postamble; select STDOUT; close TEXT;
  884. print "\n writing index file...";
  885. open TEXT, '>', File::Spec->catfile($out_path, 'nasmdoci.html');
  886. select TEXT;
  887. &html_preamble(0);
  888. print "<h2 class=\"index\">Index</h2>\n";
  889. print "<ul class=\"index\">\n";
  890. &html_index;
  891. print "</ul>\n</body>\n</html>\n";
  892. select STDOUT;
  893. close TEXT;
  894. }
  895. sub html_preamble {
  896. print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n";
  897. print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" ";
  898. print "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n";
  899. print "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
  900. print "<head>\n";
  901. print "<title>", $metadata{'title'}, "</title>\n";
  902. print "<link href=\"nasmdoc.css\" rel=\"stylesheet\" type=\"text/css\" />\n";
  903. print "<link href=\"local.css\" rel=\"stylesheet\" type=\"text/css\" />\n";
  904. print "</head>\n";
  905. print "<body>\n";
  906. # Navigation bar
  907. print "<ul class=\"navbar\">\n";
  908. if (defined($html_nav_last)) {
  909. my $lastf = $html_fnames{$html_nav_last};
  910. print "<li class=\"first\"><a class=\"prev\" href=\"$lastf\">$html_nav_last</a></li>\n";
  911. }
  912. if (defined($html_nav_next)) {
  913. my $nextf = $html_fnames{$html_nav_next};
  914. print "<li><a class=\"next\" href=\"$nextf\">$html_nav_next</a></li>\n";
  915. }
  916. print "<li><a class=\"toc\" href=\"nasmdoc0.html\">Contents</a></li>\n";
  917. print "<li class=\"last\"><a class=\"index\" href=\"nasmdoci.html\">Index</a></li>\n";
  918. print "</ul>\n";
  919. print "<div class=\"title\">\n";
  920. print "<h1>", $metadata{'title'}, "</h1>\n";
  921. print '<span class="subtitle">', $metadata{'subtitle'}, "</span>\n";
  922. print "</div>\n";
  923. print "<div class=\"contents\"\n>\n";
  924. }
  925. sub html_postamble {
  926. # Common closing tags
  927. print "</div>\n</body>\n</html>\n";
  928. }
  929. sub html_index {
  930. my $itag, $a, @ientry, $sep, $w, $wd, $wprev, $line;
  931. $chapternode = '';
  932. foreach $itag (@itags) {
  933. $ientry = $idxmap{$itag};
  934. @a = @$ientry;
  935. push @a, "n :";
  936. $sep = 0;
  937. foreach $node (@nodes) {
  938. next if !$idxnodes{$node,$itag};
  939. push @a, "n ," if $sep;
  940. push @a, "sp", "x $xrefnodes{$node}", "n $node", "xe$xrefnodes{$node}";
  941. $sep = 1;
  942. }
  943. print "<li class=\"index\">\n";
  944. $line = '';
  945. do {
  946. do { $w = &word_html(shift @a) } while $w eq "\001"; # nasty hack
  947. $wd .= $wprev;
  948. if ($w eq ' ' || $w eq '' || $w eq undef) {
  949. if (length ($line . $wd) > 75) {
  950. $line =~ s/\s*$//; # trim trailing spaces
  951. print "$line\n";
  952. $line = '';
  953. $wd =~ s/^\s*//; # trim leading spaces
  954. }
  955. $line .= $wd;
  956. $wd = '';
  957. }
  958. $wprev = $w;
  959. } while ($w ne '' && $w ne undef);
  960. if ($line =~ /\S/) {
  961. $line =~ s/\s*$//; # trim trailing spaces
  962. print $line, "\n";
  963. }
  964. print "</li>\n";
  965. }
  966. }
  967. sub word_html {
  968. my ($w) = @_;
  969. my $wtype, $wmajt, $pfx, $sfx;
  970. return undef if $w eq '' || $w eq undef;
  971. $wtype = substr($w,0,2);
  972. $wmajt = substr($wtype,0,1);
  973. $w = substr($w,2);
  974. $pfx = $sfx = '';
  975. $pfx = "<a href=\"$1\">", $sfx = "</a>", $w = $2
  976. if $wmajt eq "w" && $w =~ /^<(.*)>(.*)$/;
  977. $w =~ s/&/&amp;/g;
  978. $w =~ s/</&lt;/g;
  979. $w =~ s/>/&gt;/g;
  980. if ($wmajt eq "n" || $wtype eq "e " || $wtype eq "w ") {
  981. return $pfx . $w . $sfx;
  982. } elsif ($wtype eq "sp") {
  983. return ' ';
  984. } elsif ($wtype eq "da") {
  985. return '&ndash;';
  986. } elsif ($wtype eq "dm") {
  987. return '&mdash;';
  988. } elsif ($wmajt eq "c" || $wtype eq "wc") {
  989. return $pfx . "<code>${w}</code>" . $sfx;
  990. } elsif ($wtype eq "es") {
  991. return "<em>${w}";
  992. } elsif ($wtype eq "ee") {
  993. return "${w}</em>";
  994. } elsif ($wtype eq "eo") {
  995. return "<em>${w}</em>";
  996. } elsif ($wtype eq "x ") {
  997. # Magic: we must resolve the cross reference into file and marker
  998. # parts, then dispose of the file part if it's us, and dispose of
  999. # the marker part if the cross reference describes the top node of
  1000. # another file.
  1001. my $node = $nodexrefs{$w}; # find the node we're aiming at
  1002. my $level = $tstruct_level{$node}; # and its level
  1003. my $up = $node, $uplev = $level-1;
  1004. $up = $tstruct_up{$up} while $uplev--; # get top node of containing file
  1005. my $file = ($up ne $chapternode) ? $html_fnames{$up} : "";
  1006. my $marker = ($level == 1 and $file) ? "" : "#$w";
  1007. return "<a href=\"$file$marker\">";
  1008. } elsif ($wtype eq "xe") {
  1009. return "</a>";
  1010. } elsif ($wmajt eq "i") {
  1011. return "\001";
  1012. } else {
  1013. die "panic in word_html: $wtype$w\n";
  1014. }
  1015. }
  1016. # Make tree structures. $tstruct_* is top-level and global.
  1017. sub add_item {
  1018. my ($item, $level) = @_;
  1019. my $i;
  1020. $tstruct_pname{$item} = $pname;
  1021. $tstruct_next{$tstruct_previtem} = $item;
  1022. $tstruct_prev{$item} = $tstruct_previtem;
  1023. $tstruct_level{$item} = $level;
  1024. $tstruct_up{$item} = $tstruct_last[$level-1];
  1025. $tstruct_mnext{$tstruct_last[$level]} = $item;
  1026. $tstruct_last[$level] = $item;
  1027. for ($i=$level+1; $i<$MAXLEVEL; $i++) { $tstruct_last[$i] = undef; }
  1028. $tstruct_previtem = $item;
  1029. push @nodes, $item;
  1030. }
  1031. #
  1032. # This produces documentation intermediate paragraph format; this is
  1033. # basically the digested output of the front end. Intended for use
  1034. # by future backends, instead of putting it all in the same script.
  1035. #
  1036. sub write_dip {
  1037. open(PARAS, '>', File::Spec->catfile($out_path, 'nasmdoc.dip'));
  1038. foreach $k (sort(keys(%metadata))) {
  1039. print PARAS 'meta :', $k, "\n";
  1040. print PARAS $metadata{$k},"\n";
  1041. }
  1042. for ($para = 0; $para <= $#pnames; $para++) {
  1043. print PARAS $pflags[$para], "\n";
  1044. print PARAS join("\037", @{$pnames[$para]}, "\n");
  1045. }
  1046. foreach $k (@itags) {
  1047. print PARAS 'indx :', $k, "\n";
  1048. print PARAS join("\037", @{$idxmap{$k}}), "\n";
  1049. }
  1050. close(PARAS);
  1051. }