source: trunk/third/perl/installhtml @ 10724

Revision 10724, 17.1 KB checked in by ghudson, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10723, which included commits to RCS files with non-trunk default branches.
  • Property svn:executable set to *
Line 
1#!./perl -w
2
3# This file should really be a extracted from a .PL
4
5use lib 'lib';          # use source library if present
6
7use Config;             # for config options in the makefile
8use Getopt::Long;       # for command-line parsing
9use Cwd;
10use Pod::Html;
11
12umask 022;
13
14=head1 NAME
15
16installhtml - converts a collection of POD pages to HTML format.
17
18=head1 SYNOPSIS
19
20    installhtml  [--help] [--podpath=<name>:...:<name>] [--podroot=<name>]
21         [--htmldir=<name>] [--htmlroot=<name>]  [--norecurse] [--recurse]
22         [--splithead=<name>,...,<name>]   [--splititem=<name>,...,<name>]
23         [--libpods=<name>,...,<name>]  [--verbose]
24
25=head1 DESCRIPTION
26
27I<installhtml> converts a collection of POD pages to a corresponding
28collection of HTML pages.  This is primarily used to convert the pod
29pages found in the perl distribution.
30
31=head1 OPTIONS
32
33=over 4
34
35=item B<--help> help
36
37Displays the usage.
38
39=item B<--podroot> POD search path base directory
40
41The base directory to search for all .pod and .pm files to be converted.
42Default is current directory.
43
44=item B<--podpath> POD search path
45
46The list of directories to search for .pod and .pm files to be converted.
47Default is `podroot/.'.
48
49=item B<--recurse> recurse on subdirectories
50
51Whether or not to convert all .pm and .pod files found in subdirectories
52too.  Default is to not recurse.
53
54=item B<--htmldir> HTML destination directory
55
56The base directory which all HTML files will be written to.  This should
57be a path relative to the filesystem, not the resulting URL.
58
59=item B<--htmlroot> URL base directory
60
61The base directory which all resulting HTML files will be visible at in
62a URL.  The default is `/'.
63
64=item B<--splithead> POD files to split on =head directive
65
66Colon-separated list of pod files to split by the =head directive.  The
67.pod suffix is optional. These files should have names specified
68relative to podroot.
69
70=item B<--splititem> POD files to split on =item directive
71
72Colon-separated list of all pod files to split by the =item directive.
73The .pod suffix is optional.  I<installhtml> does not do the actual
74split, rather it invokes I<splitpod> to do the dirty work.  As with
75--splithead, these files should have names specified relative to podroot.
76
77=item B<--splitpod> Directory containing the splitpod program
78
79The directory containing the splitpod program. The default is `podroot/pod'.
80
81=item B<--libpods> library PODs for LE<lt>E<gt> links
82
83Colon-separated list of "library" pod files.  This is the same list that
84will be passed to pod2html when any pod is converted.
85
86=item B<--verbose> verbose output
87
88Self-explanatory.
89
90=back
91
92=head1 EXAMPLE
93
94The following command-line is an example of the one we use to convert
95perl documentation:
96
97    ./installhtml --podpath=lib:ext:pod:vms   \
98                        --podroot=/usr/src/perl     \
99                        --htmldir=/perl/nmanual     \
100                        --htmlroot=/perl/nmanual    \
101                        --splithead=pod/perlipc     \
102                        --splititem=pod/perlfunc    \
103                        --libpods=perlfunc:perlguts:perlvar:perlrun:perlop \
104                        --recurse \
105                        --verbose
106
107=head1 AUTHOR
108
109Chris Hall E<lt>hallc@cs.colorado.eduE<gt>
110
111=head1 TODO
112
113=cut
114
115$usage =<<END_OF_USAGE;
116Usage: $0 --help --podpath=<name>:...:<name> --podroot=<name>
117         --htmldir=<name> --htmlroot=<name> --norecurse --recurse
118         --splithead=<name>,...,<name> --splititem=<name>,...,<name>
119         --libpods=<name>,...,<name> --verbose
120
121    --help      - this message
122    --podpath   - colon-separated list of directories containing .pod and
123                  .pm files to be converted (. by default).
124    --podroot   - filesystem base directory from which all relative paths in
125                  podpath stem (default is .).
126    --htmldir   - directory to store resulting html files in relative
127                  to the filesystem (\$podroot/html by default).
128    --htmlroot  - http-server base directory from which all relative paths
129                  in podpath stem (default is /).
130    --libpods   - comma-separated list of files to search for =item pod
131                  directives in as targets of C<> and implicit links (empty
132                  by default).
133    --norecurse - don't recurse on those subdirectories listed in podpath.
134                  (default behavior).
135    --recurse   - recurse on those subdirectories listed in podpath
136    --splithead - comma-separated list of .pod or .pm files to split.  will
137                  split each file into several smaller files at every occurrence
138                  of a pod =head[1-6] directive.
139    --splititem - comma-separated list of .pod or .pm files to split using
140                  splitpod.
141    --splitpod  - directory where the program splitpod can be found
142                  (\$podroot/pod by default).
143    --verbose   - self-explanatory.
144
145END_OF_USAGE
146
147@libpods = ();
148@podpath = ( "." );     # colon-separated list of directories containing .pod
149                        # and .pm files to be converted.
150$podroot = ".";         # assume the pods we want are here
151$htmldir = "";          # nothing for now...
152$htmlroot = "/";        # default value
153$recurse = 0;           # default behavior
154@splithead = ();        # don't split any files by default
155@splititem = ();        # don't split any files by default
156$splitpod = "";         # nothing for now.
157
158$verbose = 0;           # whether or not to print debugging info
159
160$pod2html = "pod/pod2html";
161
162usage("") unless @ARGV;
163
164# parse the command-line
165$result = GetOptions( qw(
166        help
167        podpath=s
168        podroot=s
169        htmldir=s
170        htmlroot=s
171        libpods=s
172        recurse!
173        splithead=s
174        splititem=s
175        splitpod=s
176        verbose
177));
178usage("invalid parameters") unless $result;
179parse_command_line();
180
181
182# set these variables to appropriate values if the user didn't specify
183#  values for them.
184$htmldir = "$htmlroot/html" unless $htmldir;
185$splitpod = "$podroot/pod" unless $splitpod;
186
187
188# make sure that the destination directory exists
189(mkdir($htmldir, 0755) ||
190        die "$0: cannot make directory $htmldir: $!\n") if ! -d $htmldir;
191
192
193# the following array will eventually contain files that are to be
194# ignored in the conversion process.  these are files that have been
195# process by splititem or splithead and should not be converted as a
196# result.
197@ignore = ();
198
199
200# split pods.  its important to do this before convert ANY pods because
201#  it may effect some of the links
202@splitdirs = ();    # files in these directories won't get an index
203split_on_head($podroot, $htmldir, \@splitdirs, \@ignore, @splithead);
204split_on_item($podroot,           \@splitdirs, \@ignore, @splititem);
205
206
207# convert the pod pages found in @poddirs
208#warn "converting files\n" if $verbose;
209#warn "\@ignore\t= @ignore\n" if $verbose;
210foreach $dir (@podpath) {
211    installdir($dir, $recurse, $podroot, \@splitdirs, \@ignore);
212}
213
214
215# now go through and create master indices for each pod we split
216foreach $dir (@splititem) {
217    print "creating index $htmldir/$dir.html\n" if $verbose;
218    create_index("$htmldir/$dir.html", "$htmldir/$dir");
219}
220
221foreach $dir (@splithead) {
222    $dir .= ".pod" unless $dir =~ /(\.pod|\.pm)$/;
223    # let pod2html create the file
224    runpod2html($dir, 1);
225
226    # now go through and truncate after the index
227    $dir =~ /^(.*?)(\.pod|\.pm)?$/sm;
228    $file = "$htmldir/$1";
229    print "creating index $file.html\n" if $verbose;
230
231    # read in everything until what would have been the first =head
232    # directive, patching the index as we go.
233    open(H, "<$file.html") ||
234        die "$0: error opening $file.html for input: $!\n";
235    $/ = "";
236    @data = ();
237    while (<H>) {
238        last if /NAME=/;
239        s,HREF="#(.*)">,HREF="$file/$1.html">,g;
240        push @data, $_;
241    }
242    close(H);
243
244    # now rewrite the file
245    open(H, ">$file.html") ||
246        die "$0: error opening $file.html for output: $!\n";
247    print H "@data\n";
248    close(H);
249}
250
251##############################################################################
252
253
254sub usage {
255    warn "$0: @_\n" if @_;
256    die $usage;
257}
258
259
260sub parse_command_line {
261    usage() if defined $opt_help;
262    $opt_help = "";                 # make -w shut up
263
264    # list of directories
265    @podpath   = split(":", $opt_podpath) if defined $opt_podpath;
266
267    # lists of files
268    @splithead = split(",", $opt_splithead) if defined $opt_splithead;
269    @splititem = split(",", $opt_splititem) if defined $opt_splititem;
270    @libpods   = split(",", $opt_libpods) if defined $opt_libpods;
271
272    $htmldir  = $opt_htmldir        if defined $opt_htmldir;
273    $htmlroot = $opt_htmlroot       if defined $opt_htmlroot;
274    $podroot  = $opt_podroot        if defined $opt_podroot;
275    $splitpod = $opt_splitpod       if defined $opt_splitpod;
276
277    $recurse  = $opt_recurse        if defined $opt_recurse;
278    $verbose  = $opt_verbose        if defined $opt_verbose;
279}
280
281
282sub absolute_path {
283    my($cwd, $path) = @_;
284        return "$cwd/$path" unless $path =~ m:/:;
285    # add cwd if path is not already an absolute path
286    $path = "$cwd/$path" if (substr($path,0,1) ne '/');
287    return $path;
288}
289
290
291sub create_index {
292    my($html, $dir) = @_;
293    my(@files, @filedata, @index, $file);
294
295    # get the list of .html files in this directory
296    opendir(DIR, $dir) ||
297        die "$0: error opening directory $dir for reading: $!\n";
298    @files = sort(grep(/\.html$/, readdir(DIR)));
299    closedir(DIR);
300
301    open(HTML, ">$html") ||
302        die "$0: error opening $html for output: $!\n";
303
304    # for each .html file in the directory, extract the index
305    #   embedded in the file and throw it into the big index.
306    print HTML "<DL COMPACT>\n";
307    foreach $file (@files) {
308        $/ = "";
309
310        open(IN, "<$dir/$file") ||
311            die "$0: error opening $dir/$file for input: $!\n";
312        @filedata = <IN>;
313        close(IN);
314
315        # pull out the NAME section
316        ($name) = grep(/NAME=/, @filedata);
317        $name =~ m,/H1>\s(\S+)\s[\s-]*(.*?)\s*$,sm;
318        print HTML qq(<A HREF="$dir/$file">);
319        print HTML "<DT>$1</A><DD>$2\n" if defined $1;
320#       print HTML qq(<A HREF="$dir/$file">$1</A><BR>\n") if defined $1;
321
322        next;
323
324        @index = grep(/<!-- INDEX BEGIN -->.*<!-- INDEX END -->/s,
325                    @filedata);
326        for (@index) {
327            s/<!-- INDEX BEGIN -->(\s*<!--)(.*)(-->\s*)<!-- INDEX END -->/$2/s;
328            s,#,$dir/$file#,g;
329            # print HTML "$_\n";
330            print HTML "$_\n<P><HR><P>\n";
331        }
332    }
333    print HTML "</DL>\n";
334
335    close(HTML);
336}
337
338
339sub split_on_head {
340    my($podroot, $htmldir, $splitdirs, $ignore, @splithead) = @_;
341    my($pod, $dirname, $filename);
342
343    # split the files specified in @splithead on =head[1-6] pod directives
344    print "splitting files by head.\n" if $verbose && $#splithead >= 0;
345    foreach $pod (@splithead) {
346        # figure out the directory name and filename
347        $pod      =~ s,^([^/]*)$,/$1,;
348        $pod      =~ m,(.*?)/(.*?)(\.pod)?$,;
349        $dirname  = $1;
350        $filename = "$2.pod";
351
352        # since we are splitting this file it shouldn't be converted.
353        push(@$ignore, "$podroot/$dirname/$filename");
354
355        # split the pod
356        splitpod("$podroot/$dirname/$filename", "$podroot/$dirname", $htmldir,
357            $splitdirs);
358    }
359}
360
361
362sub split_on_item {
363    my($podroot, $splitdirs, $ignore, @splititem) = @_;
364    my($pwd, $dirname, $filename);
365
366    print "splitting files by item.\n" if $verbose && $#splititem >= 0;
367    $pwd = getcwd();
368        my $splitter = absolute_path($pwd, "$splitpod/splitpod");
369    foreach $pod (@splititem) {
370        # figure out the directory to split into
371        $pod      =~ s,^([^/]*)$,/$1,;
372        $pod      =~ m,(.*?)/(.*?)(\.pod)?$,;
373        $dirname  = "$1/$2";
374        $filename = "$2.pod";
375
376        # since we are splitting this file it shouldn't be converted.
377        push(@$ignore, "$podroot/$dirname.pod");
378
379        # split the pod
380        push(@$splitdirs, "$podroot/$dirname");
381        if (! -d "$podroot/$dirname") {
382            mkdir("$podroot/$dirname", 0755) ||
383                    die "$0: error creating directory $podroot/$dirname: $!\n";
384        }
385        chdir("$podroot/$dirname") ||
386            die "$0: error changing to directory $podroot/$dirname: $!\n";
387        die "$splitter not found. Use '-splitpod dir' option.\n"
388            unless -f $splitter;
389        system("perl", $splitter, "../$filename") &&
390            warn "$0: error running '$splitter ../$filename'"
391                 ." from $podroot/$dirname";
392    }
393    chdir($pwd);
394}
395
396
397#
398# splitpod - splits a .pod file into several smaller .pod files
399#  where a new file is started each time a =head[1-6] pod directive
400#  is encountered in the input file.
401#
402sub splitpod {
403    my($pod, $poddir, $htmldir, $splitdirs) = @_;
404    my(@poddata, @filedata, @heads);
405    my($file, $i, $j, $prevsec, $section, $nextsec);
406
407    print "splitting $pod\n" if $verbose;
408
409    # read the file in paragraphs
410    $/ = "";
411    open(SPLITIN, "<$pod") ||
412        die "$0: error opening $pod for input: $!\n";
413    @filedata = <SPLITIN>;
414    close(SPLITIN) ||
415        die "$0: error closing $pod: $!\n";
416
417    # restore the file internally by =head[1-6] sections
418    @poddata = ();
419    for ($i = 0, $j = -1; $i <= $#filedata; $i++) {
420        $j++ if ($filedata[$i] =~ /^\s*=head[1-6]/);
421        if ($j >= 0) {
422            $poddata[$j]  = "" unless defined $poddata[$j];
423            $poddata[$j] .= "\n$filedata[$i]" if $j >= 0;
424        }
425    }
426
427    # create list of =head[1-6] sections so that we can rewrite
428    #  L<> links as necessary.
429    %heads = ();
430    foreach $i (0..$#poddata) {
431        $heads{htmlize($1)} = 1 if $poddata[$i] =~ /=head[1-6]\s+(.*)/;
432    }
433
434    # create a directory of a similar name and store all the
435    #  files in there
436    $pod =~ s,.*/(.*),$1,;      # get the last part of the name
437    $dir = $pod;
438    $dir =~ s/\.pod//g;
439    push(@$splitdirs, "$poddir/$dir");
440    mkdir("$poddir/$dir", 0755) ||
441        die "$0: could not create directory $poddir/$dir: $!\n"
442        unless -d "$poddir/$dir";
443
444    $poddata[0] =~ /^\s*=head[1-6]\s+(.*)/;
445    $section    = "";
446    $nextsec    = $1;
447
448    # for each section of the file create a separate pod file
449    for ($i = 0; $i <= $#poddata; $i++) {
450        # determine the "prev" and "next" links
451        $prevsec = $section;
452        $section = $nextsec;
453        if ($i < $#poddata) {
454            $poddata[$i+1] =~ /^\s*=head[1-6]\s+(.*)/;
455            $nextsec       = $1;
456        } else {
457            $nextsec = "";
458        }
459
460        # determine an appropriate filename (this must correspond with
461        #  what pod2html will try and guess)
462        # $poddata[$i] =~ /^\s*=head[1-6]\s+(.*)/;
463        $file = "$dir/" . htmlize($section) . ".pod";
464
465        # create the new .pod file
466        print "\tcreating $poddir/$file\n" if $verbose;
467        open(SPLITOUT, ">$poddir/$file") ||
468            die "$0: error opening $poddir/$file for output: $!\n";
469        $poddata[$i] =~ s,L<([^<>]*)>,
470                            defined $heads{htmlize($1)} ? "L<$dir/$1>" : "L<$1>"
471                         ,ge;
472        print SPLITOUT $poddata[$i]."\n\n";
473        print SPLITOUT "=over 4\n\n";
474        print SPLITOUT "=item *\n\nBack to L<$dir/\"$prevsec\">\n\n" if $prevsec;
475        print SPLITOUT "=item *\n\nForward to L<$dir/\"$nextsec\">\n\n" if $nextsec;
476        print SPLITOUT "=item *\n\nUp to L<$dir>\n\n";
477        print SPLITOUT "=back\n\n";
478        close(SPLITOUT) ||
479            die "$0: error closing $poddir/$file: $!\n";
480    }
481}
482
483
484#
485# installdir - takes care of converting the .pod and .pm files in the
486#  current directory to .html files and then installing those.
487#
488sub installdir {
489    my($dir, $recurse, $podroot, $splitdirs, $ignore) = @_;
490    my(@dirlist, @podlist, @pmlist, $doindex);
491
492    @dirlist = ();      # directories to recurse on
493    @podlist = ();      # .pod files to install
494    @pmlist  = ();      # .pm files to install
495
496    # should files in this directory get an index?
497    $doindex = (grep($_ eq "$podroot/$dir", @$splitdirs) ? 0 : 1);
498
499    opendir(DIR, "$podroot/$dir")
500        || die "$0: error opening directory $podroot/$dir: $!\n";
501
502    # find the directories to recurse on
503    @dirlist = map { "$dir/$_" }
504        grep(-d "$podroot/$dir/$_" && !/^\.{1,2}/, readdir(DIR)) if $recurse;
505    rewinddir(DIR);
506
507    # find all the .pod files within the directory
508    @podlist = map { /^(.*)\.pod$/; "$dir/$1" }
509        grep(! -d "$podroot/$dir/$_" && /\.pod$/, readdir(DIR));
510    rewinddir(DIR);
511
512    # find all the .pm files within the directory
513    @pmlist = map { /^(.*)\.pm$/; "$dir/$1" }
514        grep(! -d "$podroot/$dir/$_" && /\.pm$/, readdir(DIR));
515
516    closedir(DIR);
517
518    # recurse on all subdirectories we kept track of
519    foreach $dir (@dirlist) {
520        installdir($dir, $recurse, $podroot, $splitdirs, $ignore);
521    }
522
523    # install all the pods we found
524    foreach $pod (@podlist) {
525        # check if we should ignore it.
526        next if grep($_ eq "$podroot/$pod.pod", @$ignore);
527
528        # check if a .pm files exists too
529        if (grep($_ eq "$pod.pm", @pmlist)) {
530            print  "$0: Warning both `$podroot/$pod.pod' and "
531                . "`$podroot/$pod.pm' exist, using pod\n";
532            push(@ignore, "$pod.pm");
533        }
534        runpod2html("$pod.pod", $doindex);
535    }
536
537    # install all the .pm files we found
538    foreach $pm (@pmlist) {
539        # check if we should ignore it.
540        next if grep($_ eq "$pm.pm", @ignore);
541
542        runpod2html("$pm.pm", $doindex);
543    }
544}
545
546
547#
548# runpod2html - invokes pod2html to convert a .pod or .pm file to a .html
549#  file.
550#
551sub runpod2html {
552    my($pod, $doindex) = @_;
553    my($html, $i, $dir, @dirs);
554
555    $html = $pod;
556    $html =~ s/\.(pod|pm)$/.html/g;
557
558    # make sure the destination directories exist
559    @dirs = split("/", $html);
560    $dir  = "$htmldir/";
561    for ($i = 0; $i < $#dirs; $i++) {
562        if (! -d "$dir$dirs[$i]") {
563            mkdir("$dir$dirs[$i]", 0755) ||
564                die "$0: error creating directory $dir$dirs[$i]: $!\n";
565        }
566        $dir .= "$dirs[$i]/";
567    }
568
569    # invoke pod2html
570    print "$podroot/$pod => $htmldir/$html\n" if $verbose;
571#system("./pod2html",
572        Pod::Html'pod2html(
573        #Pod::Html'pod2html($pod2html,
574        "--htmlroot=$htmlroot",
575        "--podpath=".join(":", @podpath),
576        "--podroot=$podroot", "--netscape",
577        ($doindex ? "--index" : "--noindex"),
578        "--" . ($recurse ? "" : "no") . "recurse",
579        ($#libpods >= 0) ? "--libpods=" . join(":", @libpods) : "",
580        "--infile=$podroot/$pod", "--outfile=$htmldir/$html");
581    die "$0: error running $pod2html: $!\n" if $?;
582}
583
584sub htmlize { htmlify(0, @_) }
Note: See TracBrowser for help on using the repository browser.