#!/usr/bin/perl -w # # perldoc2tree generates a tree of HTMLized documentation # for all installed Perl modules and POD documentation. # # Usage: # # perldoc2tree --target_dir=/www/yourserver/htdocs/perldocs \ # --html_base=/perldocs # # You can optionally exclude pods or modules from the tree # by using the --exclude option to specify one or more # regular expressions to exclude. # # Example: # # perldoc2tree --target_dir=/www/yourserver/htdocs/perldocs \ # --html_base=/perldocs \ # --exclude=^PrivateModules # # NOTE: perldoc2tree is not meant to work as a CGI but from the # command line. If you want to hack it to work as a CGI, fine - # but don't email me about it not working as CGI. That's # because it *ISN'T* a CGI program. # # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE. # # Use of this software in any way or in any form, source or binary, # is not allowed in any country which prohibits disclaimers of any # implied warranties of merchantability or fitness for a particular # purpose or any disclaimers of a similar nature. # # IN NO EVENT SHALL I BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, # SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE # USE OF THIS SOFTWARE AND ITS DOCUMENTATION (INCLUDING, BUT NOT # LIMITED TO, LOST PROFITS) EVEN IF I HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE # # Copyright September 2000, Benjamin Franz # # This software may be freely copied, changed or redistributed under # the same terms and conditions as Perl itself. package NihongoOrg::PerlDoc2Tree; use strict; use Config; use File::Find; use File::Path; use Pod::Html; use Getopt::Long; use vars qw($VERSION); $VERSION="1.00"; my $html_base; my $target_dir; my $exclusions = []; GetOptions( 'html_base=s' => \$html_base, 'target_dir=s' => \$target_dir, 'exclude=s' => $exclusions, ); if (! (defined ($html_base) && ($html_base ne ''))) { &usage; exit 1; } if (! (defined ($target_dir) && ($target_dir ne ''))) { &usage; exit 1; } if (! -e $target_dir) { die("--target_dir '$target_dir' does not exist\n"); } if (! -d $target_dir) { die("--target_dir '$target_dir' is not a directory\n"); } if ($#$exclusions > -1) { foreach (@$exclusions) { eval { qr/$_/ }; if ($@) { die ("-exclude pattern '$_' is not a valid regex: $!"); } } } # Because pod2html is noisy as hell and doesn't need to be. close(STDERR); # You know, File::Find's usage semantics _really really_ suck.... my @SCRATCH_LIST; my @module_dirs = grep(!/^$/,grep(!/^\.\.?$/,@INC)); $|++; print "Scanning for modules and pod files"; my $modules = find_module_docs({ -module_dirs => \@module_dirs, -exclusions => $exclusions, }); print "\nGenerating documentation: "; make_html_docs({ -target_dir => $target_dir, -modules => $modules, -html_root => $html_base, }); if (not -e "$target_dir/stylesheets") { if (not mkpath(["$target_dir/stylesheets"])) { die( "Unable to create $target_dir/stylesheets directory: $!\n"); } } write_file("$target_dir/stylesheets/default.css",stylesheet()); print "Done.\n"; exit; sub make_html_docs { my ($parms) = @_; my $target_dir = $parms->{-target_dir}; chdir $target_dir; my $html_root = $parms->{-html_root}; my $modules = $parms->{-modules}; my $exclusions = $parms->{-exclusions}; my @sorted_list = sort keys %$modules; my $links = {}; my $files = {}; my $site_lib = $Config{'sitelib'}; foreach my $module_name (@sorted_list) { my $len = length($module_name); my $eraser = ("\x08" x $len) . (" " x $len) .("\x08" x $len) ; print $module_name; my $pod_file = $modules->{$module_name}->{'-pod_file'}; my $target_path = $module_name; $target_path =~ s#::#/#g; $links->{$module_name} = "$target_path.html"; $target_path = "$target_dir/$target_path"; my $parent_dir = $target_path; $parent_dir =~ s#/[^/]+$##; if (not -e $parent_dir) { if (not mkpath([$parent_dir])) { #warn("Unable to create '$parent_dir' directory: $!\n"); print $eraser; next; } } my $output_file = "$target_path.html"; # The calling semantics here suck as well pod2html( "--htmlroot=$html_root", "--infile=$pod_file", "--outfile=$output_file", '--recurse', "--title=$module_name", "--podroot=$site_lib", ); if (not -e "$target_path.html") { print $eraser; next; } fix_pod2html({ -file => $output_file, -html_root => $html_root, -modules => $modules, }); $files->{$module_name} = $output_file; print $eraser; } my @final_sorted_list = sort keys %$files; # Make the index open (INDEXFILE,">$target_dir/index.html") or die ("Unable to open $target_dir/index.html for writing:$!\n"); print INDEXFILE <<"EOF"; Perl Documentation

Perl Modules Documentation

\n
    EOF my $split_at = int (@final_sorted_list / 2) + 1; my $counter = $split_at; foreach my $module_name (@final_sorted_list) { print INDEXFILE "
  • {$module_name}\">$module_name
  • \n"; $counter--; if ($counter <= 0) { print INDEXFILE "
\n
\n
    \n"; $counter = $split_at; } } print INDEXFILE <<"EOFPAGE";
EOFPAGE } sub find_module_docs { my $parms = shift; my @module_libs = @{$parms->{-module_dirs}}; my @exclusions = @{$parms->{-exclusions}}; my $exclusion_pattern; if ($#exclusions > -1) { my $bare_exclusion_pattern = join('|',@exclusions); $exclusion_pattern = qr/$bare_exclusion_pattern/; } find(\&pm_files,@module_libs); my @escaped_prefixes = map { quotemeta($_) } @module_libs; my $archname = quotemeta($Config{'archname'}); # Identify modules my $pod_files = {}; foreach my $file (@SCRATCH_LIST) { foreach my $module_dir (@escaped_prefixes) { if ($file =~ m#^$module_dir/{0,}(.+)#) { my $module_file = $1; my $module_name = $module_file; $module_name =~ s#/{2,}#/#g; $module_name =~ s#/#::#g; $module_name =~ s#\.(pm|pod)$##; $module_name =~ s#^${archname}::##o; next if ($exclusion_pattern && ($module_name =~ m/$exclusion_pattern/)); my ($type) = $module_file =~ m/\.(pm|pod)$/; $pod_files->{$module_name}->{"-${type}_file"} = $file; $pod_files->{$module_name}->{"-name"} = $module_name; last; } } } # Reconcile the 'pod' and 'pm' files foreach my $module_name (keys %$pod_files) { if ((not exists $pod_files->{$module_name}->{'-pod_file'}) and (exists $pod_files->{$module_name}->{'-pm_file'})) { $pod_files->{$module_name}->{'-pod_file'} = $pod_files->{$module_name}->{'-pm_file'} } } $pod_files; } sub pm_files { my $current_name = $File::Find::name; if ($current_name =~ m/\.(pm|pod)$/) { push (@SCRATCH_LIST,$current_name); } } sub fix_pod2html { my $parms = shift; my $file = $parms->{-file}; my $html_root = $parms->{-html_root}; my $modules = $parms->{-modules}; my $text = read_file ($file); next if (not defined $text); # Fix Pod2HTML's idea of 'HTML' as much as possible my $fixed_text = fix_screwups({ -text => $text, -html_root => $html_root }); # Hyperlink other modules we know about my @sorted_modules = sort { length($b) <=> length($a) } keys %$modules; foreach my $module_name (@sorted_modules) { my $link_to = $module_name; $link_to =~ s#::#/#g; $link_to = "$module_name"; $fixed_text =~ s#\s$module_name\s# $link_to #g; $fixed_text =~ s#\s$module_name

# $link_to

#g; $fixed_text =~ s#\s$module_name;# $link_to;#g; } # Save it write_file($file,$fixed_text); } sub read_file { my ($file) = @_; if (not open (FILE,$file)) { warn ("Could not open '$file' for reading\n$!"); return undef; } local $/ = undef; my $text = ; close (FILE); $text; } sub write_file { my ($file,$text) = @_; if (not open (FILE,">$file")) { warn ("Could not open '$file' for writing\n$!"); return undef; } my $old_select = select (FILE); $|++; print $text; $|--; select $old_select; close (FILE); 1; } sub fix_screwups { my $parms = shift; my $text = $parms->{-text}; my $html_root = $parms->{-html_root}; my $doctype = ''; $_ = $text; # If I wanted my email address where a spam # bot could snag it, I'd put it in myself s///o; # =item C<$ui-Eset_ui_mode($mode);> # WRONG WRONG WRONG!!!!! is illegal in
. > is the entity # for >. Failing to close
screws up some HTML 'parsers'. #
$ui-gtset_ui_mode($mode);
# Right. #
$ui->set_ui_mode($mode);
\n
s/-gt/-\>/go; s#
#
#go; s#
#
#go; # Close the
tags. Stylesheets don't work # right in the Big Two with implied block closures. s##
#go; #


is nonsense code. s#

([^<]*)

\s+


#

$1

\n
#go; # So is

	s#

([^<]*)

\s+

#

$1

\n
#go;
	s#

\s*

#
#goi;

	# close the dangling 

s#

([^<]*)#

$1

\n#go; #

IS NOT equivalent to '\n\n'. Grrr..... s#

([^<]*)

#

$1

#oig; s#

([^<]*)

#

$1

#oig; s#

([^<]*)
#

$1

\n
#oig; s#\n

([^<]*)

#

$1

#oig; s#\n

([^<]*)

#

$1

#oig; s#\n

([^<]*)

#

$1

#oig; # close dangling
  • s#
      \s*
        #
          \n
        • \n
            #goi; s#
          \s*
        #
      \n\n
    #goi; s#
  • ([^"]*)(\s+)(?=
  • )#
  • $2
  • $3#goi; s#(\s+)#$1#goi; s#(\s+)
  • #
  • $1
  • #goi; # Gah. s#>\s+

    \s+


    #>\n
    #go; s#
    \s+

    \s+#


    \n#go; s#\s+

    \s+


    #
    \n
    #go; # Patch up more P stuff s#([^\s>]+)\s*#$1\n

    #goi; s#([^\s>]+)\s*
    #$1\n

    \n
    #goi; s#

    \s*([^<]+)\s*

    #

    $1

    \n
    #goi; s#(\s*)#$1

    \n#goi; s#

    (\s*[^<\s])#

    $1#goi; s#([^>\s])\s*

    #$1

    #goi; s#([^\s>]+)\s*#$1

    \n#oi; s#

    \s*


    #
    #gois; # Insert a H1 title my ($title) = m#(.*?)#i; s//\n

    $title<\/h1>\n/is; # Install the stylesheet s#\n