#!/usr/local/bin/perl use strict; use File::Find; use File::Path; use Getopt::Long; use HTML::Stream; use IO::File; use Pod::Tree::HTML; use File::Spec; my %Options = (bgcolor => '#ffffff', text => '#000000', hr => 1, toc => 1 ); my $ok = GetOptions(\%Options, "base:s", "css:s", "bgcolor:s", "empty", "index:s", "module", "text:s", "toc!", "hr:i", "variables:s"); $ok or die "Bad command line options\n"; my %Index; my @Dirs; my($PodDir, $HTMLDir, $Template, @Variables) = @ARGV; $HTMLDir or die "pods2html PodDir HTMLDir\n"; $PodDir = canonpath File::Spec $PodDir; $HTMLDir = rel2abs File::Spec $HTMLDir; mkpath($HTMLDir); do $Options{variables} if $Options{variables}; for (@Variables) { chomp; my($name, $value) = split /=/, $_, 2; $name =~ s(^\$)(); ${$Pod::Tree::HTML::{$name}} = $value; } umask 0022; find({ wanted => \&Translate, no_chdir => 1 }, $PodDir); Index () if $Options{index}; Cleanup() unless $Options{empty}; sub Translate { -d and &Translate_Dir; -f and &Translate_POD; } sub MkDir { my $dir = shift; -d $dir and return; mkdir $dir, 0755 or die "Can't mkdir $dir: $!\n"; push @Dirs, $dir; } sub Translate_Dir { my $dir = $File::Find::name; if ($HTMLDir eq rel2abs File::Spec $dir) { $File::Find::prune = 1; return; } if ($Options{module} and ( m(/t$) or m(/blib$) ) ) { $File::Find::prune = 1; return; } $dir =~ s/^$PodDir/$HTMLDir/o; -d $dir or MkDir $dir; print "$File::Find::name\n"; } sub Translate_POD { m( \.(pm|pod)$ )x or return; my $source = $File::Find::name; Hidden($source) and return; print "$source\n"; my $dest = $source; $dest =~ s/^$PodDir/$HTMLDir/; $dest =~ s( \.\w+$ )(.html)x; my $depth = Depth($source); my $pod = $source; $pod =~ s(^$PodDir/)(); $pod =~ s( \.\w+$ )()x; $Index{$pod} = 1; my $html = new Pod::Tree::HTML $source, $dest, %Options; $html->set_options(depth => $depth); $html->translate($Template); } sub Hidden { my $source = shift; $source =~ m(\.pm$) or return 0; $source =~ s(\.pm$)(.pod); -e $source } sub Depth { my $source = shift; my $tree = new Pod::Tree; $tree->load_file($source); my $children = $tree->get_root->get_children; my @pod = grep { is_pod $_ } @$children; my $node1 = $pod[1]; $node1 or return ''; my $text = $node1->get_deep_text; my($name) = split m(\s+-+\s+), $text; $name =~ s(^\s+)(); my @name = split /::/, $name; @name-1 } sub Index { my $index = "$HTMLDir/index.html"; my $fh = new IO::File ">$index"; defined $fh or die "Can't open $index: $!\n"; my $stream = new HTML::Stream $fh; my $title = $Options{index}; my $bgcolor = $Options{bgcolor}; my $text = $Options{text}; $stream-> HTML->HEAD; $stream-> TITLE->text($title)->_TITLE; $stream->_HEAD -> BODY(BGCOLOR => $bgcolor, TEXT => $text); $stream->H1->t($title)->_H1; Emit_Entries($stream); $stream->_BODY->_HTML; } sub Emit_Entries { my $stream = shift; $stream->UL; for my $entry (sort keys %Index) { $stream->LI ->A(HREF => "$entry.html") ->t($entry) ->_A ->_LI; } $stream->_UL; } sub Cleanup { while (@Dirs) { my $dir = pop @Dirs; rmdir $dir; # does nothing unless $dir is empty } } __END__ =head1 NAME pods2html - translate a tree of PODs to HTML =head1 SYNOPSIS C [C<--base> I] [C<--css> I] [C<--empty>] [C<--index> I] [C<--module>] [C<-->[C<no>]C<toc>] [C<--hr> I<level>] [C<--bgcolor> I<#rrggbb>] [C<--text> I<#rrggbb>] [C<--variables> I<values.pl>] I<PODdir> I<HTMLdir> [F<template> [I<variable>=I<value> ...]] =head1 DESCRIPTION C<pods2html> finds all the F<.pod> and F<.pm> files in the directory tree rooted at I<PODdir>. It translates each POD to HTML, and writes it to a parallel directory tree rooted at I<HTMLdir> It makes the HTML files world-readable. If a F<template> file is provided, then F<template> will be filled in by the C<Text::Template> module and written to F<dest>. Here is a minimal template, showing all the variables that are set by C<pods2html>. <html> <head> <base href="{$base}"> <link href="{$css}" rel="stylesheet" type="text/css"> <title>{$title} {$toc} {$body} If the C<--variables> option is provided, then the file I will be executed with a C call before the template is filled in. I may contain arbitrary Perl code. The program fragments in the template are evaulted in the C package. Any variables that I sets in this package will be available to the template. Additional scalar variables may be set on the command line with the I=I syntax. Variables set on the command line override variables set in I. =head1 OPTIONS =over 4 =item C<--base> I Specifies a base URL for HTML links. =item C<--css> I Specifies a Cascanding Style Sheet for the generated HTML pages. =item C<--empty> Creates HTML files for empty PODs. If this options is not provided, then no HTML file is created for empty PODs. =item C<--index> I Writes an index of all the HTML files to I<HTMLDir>F</index.html>. I<title> is used as the title of the index page. =item C<--module> Ignores files in directories named F<t/> and F<blib/>. Useful for translating PODs in a module development directory. =item C<-->[C<no>]C<toc> Includes or omits the table of contents. Default is to include the TOC. =item C<--hr> I<level> Controls the profusion of horizontal lines in the output, as follows: level horizontal lines 0 none 1 between TOC and body 2 after each =head1 3 after each =head1 and =head2 Default is level 1. =item C<--bgcolor> I<#rrggbb> Set the background color to I<#rrggbb>. Default is white. =item C<--text> I<#rrggbb> Set the text color to I<#rrggbb>. Default is black. =back =head1 REQUIRES L<C<Pod::Tree::HTML>>, L<C<HTML::Stream>> =head1 BUGS The recursion check doesn't work on Win32. This means that the program will enter an infinite recursion if I<HTMLdir> is a subdirectory of I<PODdir>. =head1 SEE ALSO L<C<pod2html>>, L<C<Pod::Tree::HTML>> =head1 AUTHOR Steven McDougall, <swmcd@world.std.com> =head1 COPYRIGHT Copyright (c) 1999-2006 by Steven McDougall. This program is free software; you can redistribute it and/or modify it under the same terms as Perl.