#!/usr/bin/perl # (Works with both perl 4 and perl 5) # # $Id$ # $version = 'Jan 2 1996'; $copyright = < `$$' $n =~ s/_/\$_/g; # `_' -> `$_' $n =~ s/\s+/_/g; # whitespace -> `_' # anything else that's funky get # translated to `$xx' where `xx' # are hex digits. while ($n =~ /(.*)([^-a-zA-Z0-9\$_.])(.*)/) { $n = $1 . sprintf("\$%02x",ord($2)) . $3; } if ($uselongnames) { return "$p$n.html" if ($n); } else { if ($n eq 'Top') { $lookup{"$p$n"}= "Top.html"; return $lookup{"$p$n"}; } elsif ($n) { if (! $lookup{"$p$n"}) { $outcount = $outcount + 1; #$lookup{"$p$n"}= "$base$outcount.html"; $lookup{"$p$n"} = sprintf "%s%05d.html", $base, $outcount; } return $lookup{"$p$n"}; } } return ""; } # canonical ######################################################################## sub deduce_node_links # # On entry, $_ is a node line and $start_index is the index (in @texinfo) # the node line. # # &deduce_node_links() sets $next, $prev, and $up. { local ($level,$i,$node,$j); # First, search down from this node to the next sectioning command. $level = &determine_node_level($start_index+1); # Next, look for the `next' node (i.e., the next node at the # same or a higher level). undef($next); for ($i=$start_index+1; $i < $ntexinfo; ++$i) { $_ = $texinfo[$i]; next unless /^\@node +([^,]+).*\n/; $j = &determine_node_level($i+1); if ($j <= $level) { if ($j == $level) {$next = $1;} last; } } # Look for the `prev' and `up' nodes undef($prev); undef($up); for ($i=$start_index-1; $i > 1; --$i) { $_ = $texinfo[$i]; next unless /^\@node\s+([^,]+).*\n/; $j = &determine_node_level($i+1); if ($j == $level) { unless ($prev) {$prev = $1;} } elsif ($j < $level) { $up = $1; last; } } unless (defined($up)) {$up = "(dir)";} $xthis = $this; $xthis =~ s/\n//; } # deduce_node_links ######################################################################## sub determine_node_level { local ($i) = @_; local ($level); $level = 0; while ($i < $ntexinfo) { $_ = $texinfo[$i]; ++$i; next if /^\s+$/; last if (/\@node/); last unless (/\@(\w+)/); if ($directive_section{$1}) { $level = $directive_section{$1}; last; } } return $level; } # determine_node_level ######################################################################## sub expand_xref { local ($cmd,$arg) = @_; local ($node,$xrefname,$topic,$infofile,$manual,$url,$x); if ($cmd eq 'inforef') { ($node,$xrefname,$infofile) = split(/,/,$arg); $topic = $manual = ''; } elsif ($cmd eq 'href') { ($xrefname,$node,$infofile,$url) = split(/,/,$arg); } else { ($node,$xrefname,$topic,$infofile,$manual) = split(/,/,$arg); } $xrefname =~ s/^\s+//; $infofile =~ s/^\s+//; $xrefname =~ s/\s+$//; $infofile =~ s/\s+$//; $xrefname =~ s/\s+/ /; $infofile =~ s/\s+/ /; $infofile =~ s/\.texi$//; $infofile =~ s/\.texinfo$//; if ($xrefname =~ /^$/) {$xrefname = $node;} $node = &canonical($node); unless ($url) { unless ($infofile =~ /^$/) {$url = "../$infofile/";} $url = $url . $node; } $x = "$xrefname"; } # expand_xref ######################################################################## sub get_more_stuff_to_parse { $start_index = $texinfo_index; $_ = ''; do { if ($texinfo_index >= @texinfo) { print "Unclosed \@x{y} in chunk beginning at " . "$origin[$start_index]\n"; return; } s/\n$/ /; $more = $texinfo[$texinfo_index++]; $more =~ s/\@\*/
\n/g; $more =~ s/\@\./\./g; $more =~ s/\@\://g; $more =~ s/\@refill//g; $_ .= $more; # Expand all @a{b} in line while (/\@(\w+)\{([^{}]*)\}/) { $atcmd = $1; $atarg = $2; if ($z = $atxy_2_zyz{$atcmd}) { if ($z =~ /(.+),(.+),(.+)/) { $left = $1; $z = $2; $right = $3; } else { $left = ''; $right = ''; } if ($z =~ s/^\^//) {$atarg =~ tr/a-z/A-Z/;} $x = "$left<$z>$atarg$right"; } elsif ($atxy_2_y{$atcmd}) { $x = $atarg; } elsif ($z = $atxy_2_z{$atcmd}) { $x = $z; } elsif ($z = $atxy_2_ref{$atcmd}) { $x = $z . &expand_xref($atcmd,$atarg); $x =~ s/^X//; # works because $z must start with 'X'! } elsif ($atcmd eq 'value') { $x = $texinfo_variable{$atarg}; } elsif ($atcmd eq 'today') { $x = &today(); } elsif ($atcmd eq 'footnote') { $footnote[$nfootnotes++] = $atarg; $x = "\[$nfootnotes\]"; } elsif ($atcmd eq 'gif') { $atarg =~ s/,.*//; ©_to_destdir($atarg); $atarg =~ s|.*/||; $x = ""; } else { print "**WARNING** Don't know how to expand " . "\@$atcmd\{$atarg\}\n"; $debug = 1; $x = "?$atcmd\?$atarg\?"; } print "$origin[$start_index]: \@$atcmd\{$atarg\} => $x\n" if $debug{expansions}; s/\@\w+\{[^{}]*\}/$x/; } } while (/\@\w+\{[^}]*$/); print "$origin[$start_index]: $_" if $debug{chunks}; } # get_more_stuff_to_parse ######################################################################## sub parse # On entry: # $_ -- the line(s) to parse. # $start_index -- where, in $texinfo, $_ begins. { local ($x); if (/^\@(\w+)/) { if ($x=$directive_block{$1}) { # @example, @quotation, etc. &parse_block($1,$x); } elsif ($directive_section{$1}) { # @chapter, @subsection, etc. &process_section(); } elsif ($1 eq 'bye') { if ($nfootnotes > 0) { &printHTML("


\n"); for ($n=0; $n < $nfootnotes; ++$n) { &printHTML("

\[" . ($n+1) . "\] $footnote[$n]

\n"); } } &printHTML("


\n"); &print_arrows; &printHTML("

\n"); &print_footer if $footer; &printHTML("\n"); close (HTML); return; } elsif ($1 eq 'center') { /^\@center\s+(.*)/; &printHTML("$paragraph_end") if $in_paragraph; &printHTML("

$1

\n"); $in_paragraph = 0; } elsif ($1 eq 'clear') { /^\@clear\s+(\S+)/; undef($texinfo_variable{$1}); } elsif ($1 =~ /^def(code)?index/) { /^\@(def|defcode)index\s+(\w+)/; $index_name{$2} = $2 . "index"; $index_style{$2} = 'CODE' if ($1 eq "defcode"); } elsif ($1 =~ /^(def.*)/) { # @defn, @defun, ... @deftp &parse_def($1); } elsif ($1 eq 'enumerate') { &parse_enumerate(); } elsif ($1 eq 'exdent') { /^\@exdent\s+(.*)/; &printHTML("$paragraph_end") if $in_paragraph; # A bug -- doesn't exdent the line! &printHTML("

$1

\n"); $in_paragraph = 0; } elsif ($1 eq 'flushleft' || $1 eq 'flushright') { &parse_flush(); } elsif ($1 eq 'html') { while ($texinfo_index < @texinfo) { &get_more_stuff_to_parse(); last if (/^\@end\s+html/); s/\"/\"/g; s/\>/\>/g; s/\</\\n"); $in_paragraph = 1; $paragraph_end = "

\n"; } } &printHTML("$_"); } } } # parse ######################################################################## sub parse_block # # Handles @example, @display, etc. # # > @example >
#    > a + b = c     ==>   > a + b = c
#    > @end example        > 
{ local ($block,$pre) = @_; local ($started_at); $started_at = $start_index; &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; if ($pre eq '>PRE') { &printHTML("
\n
\n");
    } else {
	&printHTML("<$pre>\n") unless ($pre eq '-');
    }
    $in_preformatted = $block;
    while ($texinfo_index < @texinfo) {
	&get_more_stuff_to_parse();
	if (/^\@end\s+$block/) {
	    if ($pre eq 'HR') {
		&printHTML("\n");
	    } elsif ($pre eq '>PRE') {
		&printHTML("
\n
\n"); } else { &printHTML("\n") unless ($pre eq '-'); } $in_preformatted = 0; return; } &parse(); } print "**ERROR** reached EOF while searching for end of the \@$block " . "block that started on $origin[$started_at]\n"; } # parse_block ######################################################################## sub parse_def # $_ contains a @def* command { local ($def) = @_; local ($started_at,$in_dd); $started_at = $start_index; &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; &printHTML("
\n"); &printdef(); while ($texinfo_index < @texinfo) { &get_more_stuff_to_parse(); if (/^\@end\s+$def/) { &printHTML("
\n"); $in_paragraph = 0; return; } if (s/^(\@def\w+)x\s/$1 /) {&printdef();} else { unless ($in_dd) { &printHTML("
\n"); ++$in_dd; $in_paragraph = 1; $paragraph_end = "\n"; } &parse(); } } print "**ERROR** reached EOF while searching for end of the $def " . "definition that started on $origin[$started_at]\n"; } # parse_def sub printdef { s/\@defun(x?)\s/\@deffn Function / || s/\@defmac(x?)\s/\@deffn Macro / || s/\@defspec(x?)\s/\@deffn \{Special Form\} / || s/\@defvar(x?)\s/\@defvr Variable / || s/\@defopt(x?)\s/\@defvr \{User Option\} / || s/\@deftypefun(x?)\s/\@deftypefn Function / || s/\@deftypevar(x?)\s/\@deftypefn Variable / || s/\@defivar(x?)\s/\@defcv \{Instance Variable\} / || s/\@defmethod(x?)\s/\@defop Method /; s/(\@\w+)x\s/$1 /; @words = split; $i = 1; $category = $words[$i++]; while ($i < @words && $category =~ /^\{[^}]*$/) { $category .= ' ' . $words[$i++]; } if ($i>=@words) { print "def error at $origin{$started_at}\n"; } $category =~ s/^\{//; $category =~ s/\}$//; &printHTML("
$category: "); if ($words[0] eq '@deftypefn' || $words[0] eq '@deftypevr' || $words[0] eq '@defcv' || $words[0] eq '@defop') { if ($words[$i] =~ s/^\{//) { &printHTML(""); until ($words[$i] =~ s/\}$//) {&printHTML("$words[$i++]");} &printHTML("$words[$i++] "); } else { &printHTML("$words[$i++] "); } $words[0] =~ /.*([a-z][a-z])/; $_ = "\@" . $1 . "index " . $words[$i]; &process_index; } &printHTML("$words[$i++]\n"); while ($i < @words) {&printHTML(" $words[$i++]");} &printHTML("\n"); } # printdef ######################################################################## sub parse_enumerate # $_ is `@enumerate'. Note that @enumerate with an arg (`@enumerate 3', # for example) is kinda funky due to HTML limitations. { local ($count,$started_at); $started_at = $start_index; &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; if (/^\@enumerate\s*(\S+)/) {$count = $1;} &printHTML("<" . ($count ? "UL" : "OL") . ">\n"); while ($texinfo_index < @texinfo) { &get_more_stuff_to_parse(); if (/^\@end\s+enumerate/) { &printHTML("\n"); return; } if (/^\@item\s+(.*)/ || /^\@item()$/) { if ($count) { &printHTML("
  • $count: $1\n"); ++$count; } else { &printHTML("
  • $1\n"); } $in_paragraph = 1; $paragraph_end = "\n"; } else { &parse(); } } print "**ERROR** reached EOF while searching for end of the \@enumerate " . "that started on $origin[$started_at]\n"; } # parse_enumerate ######################################################################## sub parse_flush { local ($started_at,$flush); /^\@(\w+)\s/; $flush = $1; $started_at = $start_index; &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; while ($texinfo_index < @texinfo) { &get_more_stuff_to_parse(); if (/^\@end\s+$flush/) { return; } &parse(); } print "**ERROR** reached EOF while searching for end of the $flush " . "that started on $origin[$started_at]\n"; } # parse_flush ######################################################################## sub parse_itemize # $_ is `@itemize'. Due to HTML limitation, `@itemize @bullet' comes # out the same as `@itemize @minus'. { local ($started_at); $started_at = $start_index; &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; &printHTML("
      \n"); while ($texinfo_index < @texinfo) { &get_more_stuff_to_parse(); if (/^\@end\s+itemize/) { &printHTML("
    \n"); return; } if (/^\@item\s+(.*)/ || /^\@item()$/) { &printHTML("
  • $1\n"); $in_paragraph = 1; $paragraph_end = "\n"; } else { &parse(); } } print "**ERROR** reached EOF while searching for end of the itemize " . "that started on $origin[$started_at]\n"; } # parse_itemize ######################################################################## sub parse_menu { local ($started_at); $started_at = $start_index; &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; &printHTML("\n"); while ($texinfo_index < @texinfo) { &get_more_stuff_to_parse(); if (/^\@end\s+menu/) { &printHTML("\n"); return; } # Like ` * menu-item:: description of item' if (/^\s*\*\s*([^:]*)\s*::\s*(.*)$/) { &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; $node = &canonical($1); &printHTML("
  • $1\n"); &printHTML("$2\n") if $2; # Like ` * menu-item: cross-reference. description of item' } elsif (/^\s*\*\s*([^:]*)\s*:([^.]*)\.\s*(.*)$/) { &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; $node = &canonical($2); &printHTML("
  • $1\n"); &printHTML("$3\n"); } elsif (/^\@/) { print "**WARNING** Don\'t know how to process \`$_\' inside " . "a menu!\n"; } else { if (/^\s*$/ && !$in_paragraph) { &printHTML("

    "); $in_paragraph = "1"; $paragraph_end = "

    \n"; } &printHTML("$_"); } } print "**ERROR** reached EOF while searching for end of the menu " . "that started on $origin[$started_at]\n"; } # parse_menu ######################################################################## sub parse_table # $_ is `@itemize'. Due to HTML limitation, `@itemize @bullet' comes # out the same as `@itemize @minus'. { local ($table,$ttype,$after_DT,$started_at,$first_para); ($table,$ttype) = @_; $started_at = $start_index; &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; &printHTML("
    \n"); while ($texinfo_index < @texinfo) { &get_more_stuff_to_parse(); if (/^\@end\s+$table/) { &printHTML("
    \n"); return; } if (/^\@item(x?)\s+(.*)/ || /^\@item(x?)()$/) { $atarg = $2; if ($ttype) { if ($ttype =~ /(.+),(.+),(.+)/) { $left = $1; $z = $2; $right = $3; } else { $left = ''; $z = $ttype; $right = ''; } if ($z =~ s/^\^//) {$atarg =~ tr/a-z/A-Z/;} &printHTML("
    $left<$z>$atarg$right\n"); } else { &printHTML("
    $2\n"); } $item = $2; if ($item && $table =~ /([fv])table/) { $_ = "\@" . $1 . "index " . $item; &process_index; } $after_DT = 1; } else { if ($after_DT) { &printHTML("
    \n"); $in_paragraph = 1; $paragraph_end = "\n"; $after_DT = 0; $first_para = 1; } unless ($first_para && /^\s*$/) { $first_para = 0; &parse(); } } } print "**ERROR** reached EOF while searching for end of the table " . "that started on $origin[$started_at]\n"; } # parse_table ######################################################################## sub print_index { local ($index) = @_; $index = $index_name{$index}; eval "\@keys = keys \%$index"; &printHTML("\n"); foreach $item (sort texinfo_sort @keys) { eval "\$val = \$$index\{\$item\}"; &printHTML("
  • $val\n"); } &printHTML("
  • \n"); } # print_index sub texinfo_sort { $x = $a; $x =~ s/<[^>]*>//g; $x =~ tr/A-Z/a-z/; $y = $b; $y =~ s/<[^>]*>//g; $y =~ tr/A-Z/a-z/; $x cmp $y; } # texinfo_sort ######################################################################## sub process_index # # For example, `@cindex whatever' generates an entry in %cpindex # { s/\@cindex/\@cpindex/ || s/\@findex/\@fnindex/ || s/\@vindex/\@vrindex/ || s/\@kindex/\@kyindex/ || s/\@pindex/\@pgindex/ || s/\@tindex/\@tpindex/; /\@(..)index\s+(.*)/; if ($x=$index_style{$1}) { $entry = "<$x>$2"; } else { $entry = "$2"; } print "*** \$$index_name{$1}\{$2\} = $entry\n" if $debug{'index'}; eval "\$$index_name{$1}\{\$2\} = \$entry"; } # process_index ######################################################################## sub print_arrows { &printHTML("\n") if $next; &printHTML("\n") if $prev; &printHTML("\n") if $up; &printHTML("\n") if $dirfile; &printHTML("

    \n"); if ($cprev) { &printHTML("\"PREV\"\n"); } else { &printHTML("\"prev\"\n"); } if ($cup) { &printHTML(" \"UP\"\n"); } else { &printHTML("\"up\"\n"); } if ($cnext) { &printHTML("\"NEXT\"\n"); } else { &printHTML("\"next\"\n"); } if ($dirfile) { # XXX need new graphic for this one &printHTML(" \"Bookshelf\"\n"); } else { &printHTML("\"Bookshelf\"\n"); } &printHTML("$title") if $title; } ######################################################################## sub process_node # On entry, $_ is an @node line. { s/^\@node\s+//; ($this,$next,$prev,$up) = split(/,/); &deduce_node_links() unless ($next || $prev || $up); $cthis = &canonical($this); $cnext = &canonical($next); $cprev = &canonical($prev); $cup = &canonical($up); &terminate_node(); print "... opening $dir$cthis ...\n" if $debug{nodes}; open(HTML,">$dir/$cthis") || die "Couldn't open $dir$cthis -- $!\n"; $nfootnotes = 0; &printHTML("\n"); &printHTML("\n"); &print_header if $header; &printHTML("\n$this\n"); &print_arrows; &printHTML("

    \n"); } # process_node sub terminate_node { if ($nfootnotes) { &printHTML("


    \n"); for ($n=0; $n < $nfootnotes; ++$n) { &printHTML("

    \[" . ($n+1) . "\] $footnote[$n]

    \n"); } } &printHTML("


    \n"); &print_arrows; &printHTML("

    \n"); &print_footer if $footer; &printHTML("\n"); close (HTML); } ######################################################################## sub process_section # # On entry: # $_ is the section command (I.e. `@chapter Overview') # $i is the index to $_ in @lines { &printHTML("$paragraph_end") if $in_paragraph; $in_paragraph = 0; /^\@(\w+)\s+(.*)/; $section_number = ''; if ($1 eq 'chapter') { ++$chapter; $section=$subsection=$subsubsection=0; $section_number = "Chapter $chapter: "; } elsif ($1 eq 'section') { ++$section; $subsection=$subsubsection=0; $section_number = "$chapter.$section: "; } elsif ($1 eq 'subsection') { ++$subsection; $subsubsection=0; $section_number = "$chapter.$section.$subsection: "; } elsif ($1 eq 'subsubsection') { ++$subsubsection; $section_number = "$chapter.$section.$subsection.$subsubsection: "; } elsif ($1 eq 'appendix') { ++$appendix; $section=$subsection=$subsubsection=0; $x = ('A'..'Z')[$appendix-1]; $section_number = "Appendix $x: "; } elsif ($1 eq 'appendixsec') { ++$section; $subsection=$subsubsection=0; $x = ('A'..'Z')[$appendix-1]; $section_number = "$x.$section: "; } elsif ($1 eq 'appendixsubsec') { ++$subsection; $subsubsection=0; $x = ('A'..'Z')[$appendix-1]; $section_number = "$x.$section.$subsection: "; } elsif ($1 eq 'appendixsubsubsec') { ++$subsubsection; $x = ('A'..'Z')[$appendix-1]; $section_number = "$x.$section.$subsection.$subsubsection: "; } $x = $directive_section{$1}; &printHTML("$section_number$2\n"); } # process_section ######################################################################## sub process_synindex # # There's perhaps a bug here -- this presumes the @synindex comes before # any @?index directives; anything already in doesn't get merged # into ! # { local ($code) = @_; # Either 0 or 1; 1 means @syncodeindex /\@syn\w*index\s+(\w+)\s+(\w+)/; print "*** synindex $1 $2\n" if $debug{'index'}; $index_name{$1} = $2 . "index"; $index_style{$1} = 'CODE' if $code; } # process_synindex ######################################################################## sub printHTML { local ($line) = @_; $line =~ s/\$R/\}/g; $line =~ s/\$L/\{/g; $line =~ s/\$A/\@/g; $line =~ s/\$D/\$/g; if ($debug{printHTML}) { print $line; } else { print HTML $line; } } # printHTML ######################################################################## sub print_header { unless (open(HEADER,$header)) { print "WARNING -- couldn't open header file \"$header\" -- $!\n"; $header = 0; return; } while (
    ) { &printHTML($_); } close(HEADER); } ######################################################################## sub print_footer { unless (open(FOOTER,$footer)) { print "WARNING -- couldn't open footer file \"$footer\" -- $!\n"; $footer = 0; return; } while (