$VERSION
= 1.02;
@ISA
= Exporter;
@EXPORT
=
qw(pod2html htmlify)
;
my
$cache_ext
= $^O eq
'VMS'
?
".tmp"
:
".x~~"
;
my
$dircache
=
"pod2htmd$cache_ext"
;
my
$itemcache
=
"pod2htmi$cache_ext"
;
my
@begin_stack
= ();
my
@libpods
= ();
my
$htmlroot
=
"/"
;
my
$htmldir
=
""
;
my
$htmlfile
=
""
;
my
$htmlfileurl
=
""
;
my
$podfile
=
""
;
my
@podpath
= ();
my
$podroot
=
"."
;
my
$css
=
''
;
my
$recurse
= 1;
my
$quiet
= 0;
my
$verbose
= 0;
my
$doindex
= 1;
my
$listlevel
= 0;
my
@listitem
= ();
my
@listdata
= ();
my
@listend
= ();
my
$ignore
= 1;
my
%items_named
= ();
my
@items_seen
= ();
my
$netscape
= 0;
my
$title
;
my
$header
= 0;
my
$top
= 1;
my
$paragraph
;
my
%pages
= ();
my
%sections
= ();
my
%items
= ();
my
$Is83
;
sub
init_globals {
$dircache
=
"pod2htmd$cache_ext"
;
$itemcache
=
"pod2htmi$cache_ext"
;
@begin_stack
= ();
@libpods
= ();
$htmlroot
=
"/"
;
$htmlfile
=
""
;
$podfile
=
""
;
@podpath
= ();
$podroot
=
"."
;
$css
=
''
;
$recurse
= 1;
$quiet
= 0;
$verbose
= 0;
$doindex
= 1;
$listlevel
= 0;
@listitem
= ();
@listdata
= ();
@listend
= ();
$ignore
= 1;
@items_seen
= ();
%items_named
= ();
$netscape
= 0;
$header
= 0;
$title
=
''
;
$top
= 1;
$paragraph
=
''
;
%sections
= ();
$Is83
=$^O eq
'dos'
;
}
sub
pod2html {
local
(
@ARGV
) =
@_
;
local
($/);
local
$_
;
init_globals();
$Is83
= 0
if
(
defined
(
&Dos::UseLFN
) && Dos::UseLFN());
parse_command_line();
local
*POD
;
unless
(
@ARGV
&&
$ARGV
[0]) {
$podfile
=
"-"
unless
$podfile
;
open
(POD,
"<$podfile"
)
||
die
"$0: cannot open $podfile file for input: $!\n"
;
}
else
{
$podfile
=
$ARGV
[0];
*POD
=
*ARGV
;
}
$htmlfile
=
"-"
unless
$htmlfile
;
$htmlroot
=
""
if
$htmlroot
eq
"/"
;
$htmldir
=~ s
if
(
$htmlroot
eq
''
&&
defined
(
$htmldir
)
&&
$htmldir
ne
''
&&
substr
(
$htmlfile
, 0,
length
(
$htmldir
) ) eq
$htmldir
)
{
$htmlfileurl
=
"$htmldir/"
.
substr
(
$htmlfile
,
length
(
$htmldir
) + 1);
}
warn
"Scanning for sections in input file(s)\n"
if
$verbose
;
$/ =
""
;
my
@poddata
= <POD>;
close
(POD);
my
$index
= scan_headings(\
%sections
,
@poddata
);
unless
(
$index
) {
warn
"No headings in $podfile\n"
if
$verbose
;
}
open
(HTML,
">$htmlfile"
)
||
die
"$0: cannot open $htmlfile file for output: $!\n"
;
if
(
$title
eq
''
) {
TITLE_SEARCH: {
for
(
my
$i
= 0;
$i
<
@poddata
;
$i
++) {
if
(
$poddata
[
$i
] =~ /^=head1\s
*NAME
\b/m) {
for
my
$para
(
@poddata
[
$i
,
$i
+1] ) {
last
TITLE_SEARCH
if
(
$title
) =
$para
=~ /(\S+\s+-+.*\S)/s;
}
}
}
}
}
if
(!
$title
and
$podfile
=~ /\.pod$/) {
for
(
my
$i
= 0;
$i
<
@poddata
;
$i
++) {
last
if
(
$title
) =
$poddata
[
$i
] =~ /^=head[12]\s*(.*)/;
}
warn
"adopted '$title' as title for $podfile\n"
if
$verbose
and
$title
;
}
if
(
$title
) {
$title
=~ s/\s*\(.*\)//;
}
else
{
warn
"$0: no title for $podfile"
unless
$quiet
;
$podfile
=~ /^(.*)(\.[^.\/]+)?$/;
$title
= (
$podfile
eq
"-"
?
'No Title'
: $1);
warn
"using $title"
if
$verbose
;
}
my
$csslink
=
$css
?
qq(\n<LINK REL="stylesheet" HREF="$css" TYPE="text/css">)
:
''
;
$csslink
=~ s,\\,/,g;
$csslink
=~ s,(/.):,$1|,;
my
$block
=
$header
?
<<END_OF_BLOCK : '';
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
<TR><TD CLASS=block VALIGN=MIDDLE WIDTH=100% BGCOLOR="#cccccc">
<FONT SIZE=+1><STRONG><P CLASS=block> $title</P></STRONG></FONT>
</TD></TR>
</TABLE>
END_OF_BLOCK
print
HTML
<<END_OF_HEAD;
<HTML>
<HEAD>
<TITLE>$title</TITLE>$csslink
<LINK REV="made" HREF="mailto:$Config{perladmin}">
</HEAD>
<BODY>
$block
END_OF_HEAD
get_cache(
$dircache
,
$itemcache
, \
@podpath
,
$podroot
,
$recurse
);
scan_items(
""
, \
%items
,
@poddata
);
$index
=~ s/--+/-/g;
print
HTML
"<!-- INDEX BEGIN -->\n"
;
print
HTML
"<!--\n"
unless
$doindex
;
print
HTML
$index
;
print
HTML
"-->\n"
unless
$doindex
;
print
HTML
"<!-- INDEX END -->\n\n"
;
print
HTML
"<HR>\n"
if
$doindex
and
$index
;
warn
"Converting input file\n"
if
$verbose
;
foreach
my
$i
(0..
$#poddata
) {
$_
=
$poddata
[
$i
];
$paragraph
=
$i
+1;
if
(/^(=.*)/s) {
$ignore
= 0;
$_
= $1;
if
(/^=begin\s+(\S+)\s*(.*)/si) {
process_begin($1, $2);
}
elsif
(/^=end\s+(\S+)\s*(.*)/si) {
process_end($1, $2);
}
elsif
(/^=cut/) {
process_cut();
}
elsif
(/^=pod/) {
process_pod();
}
else
{
next
if
@begin_stack
&&
$begin_stack
[-1] ne
'html'
;
if
(/^=(head[1-6])\s+(.*\S)/s) {
process_head($1, $2);
}
elsif
(/^=item\s*(.*\S)/sm) {
process_item($1);
}
elsif
(/^=over\s*(.*)/) {
process_over();
}
elsif
(/^=back/) {
process_back();
}
elsif
(/^=
for
\s+(\S+)\s+(.*)/si) {
process_for($1,$2);
}
else
{
/^=(\S*)\s*/;
warn
"$0: $podfile: unknown pod directive '$1' in "
.
"paragraph $paragraph. ignoring.\n"
;
}
}
$top
= 0;
}
else
{
next
if
$ignore
;
next
if
@begin_stack
&&
$begin_stack
[-1] ne
'html'
;
my
$text
=
$_
;
process_text(\
$text
, 1);
print
HTML
"<P>\n$text</P>\n"
;
}
}
finish_list();
print
HTML
<<END_OF_TAIL;
$block
</BODY>
</HTML>
END_OF_TAIL
close
(HTML);
warn
"Finished\n"
if
$verbose
;
}
my
$usage
;
sub
usage {
my
$podfile
=
shift
;
warn
"$0: $podfile: @_\n"
if
@_
;
die
$usage
;
}
$usage
=
<<END_OF_USAGE;
Usage: $0 --help --htmlroot=<name> --infile=<name> --outfile=<name>
--podpath=<name>:...:<name> --podroot=<name>
--libpods=<name>:...:<name> --recurse --verbose --index
--netscape --norecurse --noindex
--flush - flushes the item and directory caches.
--help - prints this message.
--htmlroot - http-server base directory from which all relative paths
in podpath stem (default is /).
--index - generate an index at the top of the resulting html
(default).
--infile - filename for the pod to convert (input taken from stdin
by default).
--libpods - colon-separated list of pages to search for =item pod
directives in as targets of C<> and implicit links (empty
by default). note, these are not filenames, but rather
page names like those that appear in L<> links.
--netscape - will use netscape html directives when applicable.
--nonetscape - will not use netscape directives (default).
--outfile - filename for the resulting html file (output sent to
stdout by default).
--podpath - colon-separated list of directories containing library
pods. empty by default.
--podroot - filesystem base directory from which all relative paths
in podpath stem (default is .).
--noindex - don't generate an index at the top of the resulting html.
--norecurse - don't recurse on those subdirectories listed in podpath.
--recurse - recurse on those subdirectories listed in podpath
(default behavior).
--title - title that will appear in resulting html file.
--header - produce block header/footer
--css - stylesheet URL
--verbose - self-explanatory
--quiet - supress some benign warning messages
END_OF_USAGE
sub
parse_command_line {
my
(
$opt_flush
,
$opt_help
,
$opt_htmldir
,
$opt_htmlroot
,
$opt_index
,
$opt_infile
,
$opt_libpods
,
$opt_netscape
,
$opt_outfile
,
$opt_podpath
,
$opt_podroot
,
$opt_norecurse
,
$opt_recurse
,
$opt_title
,
$opt_verbose
,
$opt_css
,
$opt_header
,
$opt_quiet
);
unshift
@ARGV
,
split
' '
,
$Config
{pod2html}
if
$Config
{pod2html};
my
$result
= GetOptions(
'flush'
=> \
$opt_flush
,
'help'
=> \
$opt_help
,
'htmldir=s'
=> \
$opt_htmldir
,
'htmlroot=s'
=> \
$opt_htmlroot
,
'index!'
=> \
$opt_index
,
'infile=s'
=> \
$opt_infile
,
'libpods=s'
=> \
$opt_libpods
,
'netscape!'
=> \
$opt_netscape
,
'outfile=s'
=> \
$opt_outfile
,
'podpath=s'
=> \
$opt_podpath
,
'podroot=s'
=> \
$opt_podroot
,
'norecurse'
=> \
$opt_norecurse
,
'recurse!'
=> \
$opt_recurse
,
'title=s'
=> \
$opt_title
,
'header'
=> \
$opt_header
,
'css=s'
=> \
$opt_css
,
'verbose'
=> \
$opt_verbose
,
'quiet'
=> \
$opt_quiet
,
);
usage(
"-"
,
"invalid parameters"
)
if
not
$result
;
usage(
"-"
)
if
defined
$opt_help
;
$opt_help
=
""
;
$podfile
=
$opt_infile
if
defined
$opt_infile
;
$htmlfile
=
$opt_outfile
if
defined
$opt_outfile
;
$htmldir
=
$opt_htmldir
if
defined
$opt_outfile
;
@podpath
=
split
(
":"
,
$opt_podpath
)
if
defined
$opt_podpath
;
@libpods
=
split
(
":"
,
$opt_libpods
)
if
defined
$opt_libpods
;
warn
"Flushing item and directory caches\n"
if
$opt_verbose
&&
defined
$opt_flush
;
unlink
(
$dircache
,
$itemcache
)
if
defined
$opt_flush
;
$htmlroot
=
$opt_htmlroot
if
defined
$opt_htmlroot
;
$podroot
=
$opt_podroot
if
defined
$opt_podroot
;
$doindex
=
$opt_index
if
defined
$opt_index
;
$recurse
=
$opt_recurse
if
defined
$opt_recurse
;
$title
=
$opt_title
if
defined
$opt_title
;
$header
=
defined
$opt_header
? 1 : 0;
$css
=
$opt_css
if
defined
$opt_css
;
$verbose
=
defined
$opt_verbose
? 1 : 0;
$quiet
=
defined
$opt_quiet
? 1 : 0;
$netscape
=
$opt_netscape
if
defined
$opt_netscape
;
}
my
$saved_cache_key
;
sub
get_cache {
my
(
$dircache
,
$itemcache
,
$podpath
,
$podroot
,
$recurse
) =
@_
;
my
@cache_key_args
=
@_
;
my
$this_cache_key
= cache_key(
@cache_key_args
);
return
if
$saved_cache_key
and
$this_cache_key
eq
$saved_cache_key
;
my
$tests
= 0;
if
(-f
$dircache
&& -f
$itemcache
) {
warn
"scanning for item cache\n"
if
$verbose
;
$tests
= load_cache(
$dircache
,
$itemcache
,
$podpath
,
$podroot
);
}
if
(!
$tests
) {
warn
"scanning directories in pod-path\n"
if
$verbose
;
scan_podpath(
$podroot
,
$recurse
, 0);
}
$saved_cache_key
= cache_key(
@cache_key_args
);
}
sub
cache_key {
my
(
$dircache
,
$itemcache
,
$podpath
,
$podroot
,
$recurse
) =
@_
;
return
join
(
'!'
,
$dircache
,
$itemcache
,
$recurse
,
@$podpath
,
$podroot
,
stat
(
$dircache
),
stat
(
$itemcache
));
}
sub
load_cache {
my
(
$dircache
,
$itemcache
,
$podpath
,
$podroot
) =
@_
;
my
(
$tests
);
local
$_
;
$tests
= 0;
open
(CACHE,
"<$itemcache"
) ||
die
"$0: error opening $itemcache for reading: $!\n"
;
$/ =
"\n"
;
$_
= <CACHE>;
chomp
(
$_
);
$tests
++
if
(
join
(
":"
,
@$podpath
) eq
$_
);
$_
= <CACHE>;
chomp
(
$_
);
$tests
++
if
(
$podroot
eq
$_
);
if
(
$tests
!= 2) {
close
(CACHE);
return
0;
}
warn
"loading item cache\n"
if
$verbose
;
while
(<CACHE>) {
/(.*?) (.*)$/;
$items
{$1} = $2;
}
close
(CACHE);
warn
"scanning for directory cache\n"
if
$verbose
;
open
(CACHE,
"<$dircache"
) ||
die
"$0: error opening $dircache for reading: $!\n"
;
$/ =
"\n"
;
$tests
= 0;
$_
= <CACHE>;
chomp
(
$_
);
$tests
++
if
(
join
(
":"
,
@$podpath
) eq
$_
);
$_
= <CACHE>;
chomp
(
$_
);
$tests
++
if
(
$podroot
eq
$_
);
if
(
$tests
!= 2) {
close
(CACHE);
return
0;
}
warn
"loading directory cache\n"
if
$verbose
;
while
(<CACHE>) {
/(.*?) (.*)$/;
$pages
{$1} = $2;
}
close
(CACHE);
return
1;
}
sub
scan_podpath {
my
(
$podroot
,
$recurse
,
$append
) =
@_
;
my
(
$pwd
,
$dir
);
my
(
$libpod
,
$dirname
,
$pod
,
@files
,
@poddata
);
unless
(
$append
) {
%items
= ();
%pages
= ();
}
$pwd
= getcwd();
chdir
(
$podroot
)
||
die
"$0: error changing to directory $podroot: $!\n"
;
foreach
$dir
(
@podpath
) {
scan_dir(
$dir
,
$recurse
);
}
foreach
$libpod
(
@libpods
) {
next
unless
defined
$pages
{
$libpod
} &&
$pages
{
$libpod
};
if
(
$pages
{
$libpod
} =~ /([^:]*(?<!\.pod)(?<!\.pm)):/) {
$dirname
= $1;
opendir
(DIR,
$dirname
) ||
die
"$0: error opening directory $dirname: $!\n"
;
@files
=
grep
(/(\.pod|\.pm)$/ && ! -d
$_
,
readdir
(DIR));
closedir
(DIR);
foreach
$pod
(
@files
) {
open
(POD,
"<$dirname/$pod"
) ||
die
"$0: error opening $dirname/$pod for input: $!\n"
;
@poddata
= <POD>;
close
(POD);
scan_items(
"$dirname/$pod"
,
@poddata
);
}
foreach
$pod
(
@files
) {
$pod
=~ /^(.*)(\.pod|\.pm)$/;
$items
{$1} =
"$dirname/$1.html"
if
$1;
}
}
elsif
(
$pages
{
$libpod
} =~ /([^:]*\.pod):/ ||
$pages
{
$libpod
} =~ /([^:]*\.pm):/) {
$pod
= $1;
open
(POD,
"<$pod"
) ||
die
"$0: error opening $pod for input: $!\n"
;
@poddata
= <POD>;
close
(POD);
scan_items(
"$pod"
,
@poddata
);
}
else
{
warn
"$0: shouldn't be here (line "
.__LINE__.
"\n"
;
}
}
@poddata
= ();
chdir
(
$pwd
)
||
die
"$0: error changing to directory $pwd: $!\n"
;
warn
"caching items for later use\n"
if
$verbose
;
open
(CACHE,
">$itemcache"
) ||
die
"$0: error open $itemcache for writing: $!\n"
;
print
CACHE
join
(
":"
,
@podpath
) .
"\n$podroot\n"
;
foreach
my
$key
(
keys
%items
) {
print
CACHE
"$key $items{$key}\n"
;
}
close
(CACHE);
warn
"caching directories for later use\n"
if
$verbose
;
open
(CACHE,
">$dircache"
) ||
die
"$0: error open $dircache for writing: $!\n"
;
print
CACHE
join
(
":"
,
@podpath
) .
"\n$podroot\n"
;
foreach
my
$key
(
keys
%pages
) {
print
CACHE
"$key $pages{$key}\n"
;
}
close
(CACHE);
}
sub
scan_dir {
my
(
$dir
,
$recurse
) =
@_
;
my
(
$t
,
@subdirs
,
@pods
,
$pod
,
$dirname
,
@dirs
);
local
$_
;
@subdirs
= ();
@pods
= ();
opendir
(DIR,
$dir
) ||
die
"$0: error opening directory $dir: $!\n"
;
while
(
defined
(
$_
=
readdir
(DIR))) {
if
(-d
"$dir/$_"
&&
$_
ne
"."
&&
$_
ne
".."
) {
$pages
{
$_
} =
""
unless
defined
$pages
{
$_
};
$pages
{
$_
} .=
"$dir/$_:"
;
push
(
@subdirs
,
$_
);
}
elsif
(/\.pod$/) {
s/\.pod$//;
$pages
{
$_
} =
""
unless
defined
$pages
{
$_
};
$pages
{
$_
} .=
"$dir/$_.pod:"
;
push
(
@pods
,
"$dir/$_.pod"
);
}
elsif
(/\.pm$/) {
s/\.pm$//;
$pages
{
$_
} =
""
unless
defined
$pages
{
$_
};
$pages
{
$_
} .=
"$dir/$_.pm:"
;
push
(
@pods
,
"$dir/$_.pm"
);
}
}
closedir
(DIR);
if
(
$recurse
) {
foreach
my
$subdir
(
@subdirs
) {
scan_dir(
"$dir/$subdir"
,
$recurse
);
}
}
}
sub
scan_headings {
my
(
$sections
,
@data
) =
@_
;
my
(
$tag
,
$which_head
,
$title
,
$listdepth
,
$index
);
$ignore
= 0;
$listdepth
= 0;
$index
=
""
;
foreach
my
$line
(
@data
) {
if
(
$line
=~ /^=(head)([1-6])\s+(.*)/) {
(
$tag
,
$which_head
,
$title
) = ($1,$2,$3);
chomp
(
$title
);
$$sections
{htmlify(0,
$title
)} = 1;
while
(
$which_head
!=
$listdepth
) {
if
(
$which_head
>
$listdepth
) {
$index
.=
"\n"
. (
"\t"
x
$listdepth
) .
"<UL>\n"
;
$listdepth
++;
}
elsif
(
$which_head
<
$listdepth
) {
$listdepth
--;
$index
.=
"\n"
. (
"\t"
x
$listdepth
) .
"</UL>\n"
;
}
}
$index
.=
"\n"
. (
"\t"
x
$listdepth
) .
"<LI>"
.
"<A HREF=\"#"
. htmlify(0,
$title
) .
"\">"
.
html_escape(process_text(\
$title
, 0)) .
"</A></LI>"
;
}
}
while
(
$listdepth
--) {
$index
.=
"\n"
. (
"\t"
x
$listdepth
) .
"</UL>\n"
;
}
$index
=~ s,\t*<UL>\s*</UL>\n,,g;
$ignore
= 1;
return
$index
;
}
sub
scan_items {
my
(
$pod
,
@poddata
) =
@_
;
my
(
$i
,
$item
);
local
$_
;
$pod
=~ s/\.pod$//;
$pod
.=
".html"
if
$pod
;
foreach
$i
(0..
$#poddata
) {
$_
=
$poddata
[
$i
];
s,[A-Z]<([^<>]*)>,$1,g;
if
(/^=item\s+(\w*)\s*.*$/s) {
if
($1 eq
"*"
) {
/\A=item\s+\*\s*(.*?)\s*\Z/s;
$item
= $1;
}
elsif
($1 =~ /^\d+/) {
/\A=item\s+\d+\.?(.*?)\s*\Z/s;
$item
= $1;
}
else
{
/\A=item\s+(\w*)/s;
$item
= $1;
}
$items
{
$item
} =
"$pod"
if
$item
;
}
}
}
sub
process_head {
my
(
$tag
,
$heading
) =
@_
;
my
$firstword
;
$tag
=~ /head([1-6])/;
my
$level
= $1;
$firstword
=
$heading
;
$firstword
=~ s/\s*(\w+)\s.*/$1/;
print
HTML
"<P>\n"
unless
$listlevel
;
print
HTML
"<HR>\n"
unless
$listlevel
||
$top
;
print
HTML
"<H$level>"
;
my
$convert
=
$heading
; process_text(\
$convert
, 0);
$convert
= html_escape(
$convert
);
print
HTML
'<A NAME="'
. htmlify(0,
$heading
) . "\
">$convert</A>"
;
print
HTML
"</H$level>"
;
print
HTML
"\n"
;
}
sub
process_item {
my
$text
=
$_
[0];
my
(
$i
,
$quote
,
$name
);
my
$need_preamble
= 0;
my
$this_entry
;
warn
"$0: $podfile: unexpected =item directive in paragraph $paragraph. ignoring.\n"
unless
$listlevel
;
process_over()
unless
$listlevel
;
return
unless
$listlevel
;
1
while
$text
=~ s/[A-Z]<([^<>]*)>/$1/g;
pre_escape(\
$text
);
$need_preamble
=
$items_seen
[
$listlevel
]++ == 0;
$i
=
$listlevel
- 1;
my
$need_new
=
$listlevel
>=
@listitem
;
if
(
$text
=~ /\A\*/) {
if
(
$need_preamble
) {
push
(
@listend
,
"</UL>"
);
print
HTML
"<UL>\n"
;
}
print
HTML
'<LI>'
;
if
(
$text
=~ /\A\*\s*(.+)\Z/s) {
print
HTML
'<STRONG>'
;
if
(
$items_named
{$1}++) {
print
HTML html_escape($1);
}
else
{
my
$name
=
'item_'
. htmlify(1,$1);
print
HTML
qq(<A NAME="$name">)
, html_escape($1),
'</A>'
;
}
print
HTML
'</STRONG>'
;
}
}
elsif
(
$text
=~ /\A[\d
if
(
$need_preamble
) {
push
(
@listend
,
"</OL>"
);
print
HTML
"<OL>\n"
;
}
print
HTML
'<LI>'
;
if
(
$text
=~ /\A\d+\.?\s*(.+)\Z/s) {
print
HTML
'<STRONG>'
;
if
(
$items_named
{$1}++) {
print
HTML html_escape($1);
}
else
{
my
$name
=
'item_'
. htmlify(0,$1);
print
HTML
qq(<A NAME="$name">)
, html_escape($1),
'</A>'
;
}
print
HTML
'</STRONG>'
;
}
}
else
{
if
(
$need_preamble
) {
push
(
@listend
,
'</DL>'
);
print
HTML
"<DL>\n"
;
}
print
HTML
'<DT>'
;
if
(
$text
=~ /(\S+)/) {
print
HTML
'<STRONG>'
;
if
(
$items_named
{$1}++) {
print
HTML html_escape(
$text
);
}
else
{
my
$name
=
'item_'
. htmlify(1,
$text
);
print
HTML
qq(<A NAME="$name">)
, html_escape(
$text
),
'</A>'
;
}
print
HTML
'</STRONG>'
;
}
print
HTML
'<DD>'
;
}
print
HTML
"\n"
;
}
sub
process_over {
$listlevel
++;
}
sub
process_back {
warn
"$0: $podfile: unexpected =back directive in paragraph $paragraph. ignoring.\n"
unless
$listlevel
;
return
unless
$listlevel
;
$listlevel
--;
print
HTML
$listend
[
$listlevel
]
if
defined
$listend
[
$listlevel
];
print
HTML
"\n"
;
pop
(
@listitem
);
pop
(
@listdata
);
pop
(
@listend
);
pop
(
@items_seen
);
}
sub
process_cut {
$ignore
= 1;
}
sub
process_pod {
}
sub
process_for {
my
(
$whom
,
$text
) =
@_
;
if
(
$whom
=~ /^(pod2)?html$/i) {
print
HTML
$text
;
}
elsif
(
$whom
=~ /^illustration$/i) {
1
while
chomp
$text
;
for
my
$ext
(
qw[.png .gif .jpeg .jpg .tga .pcl .bmp]
) {
$text
.=
$ext
,
last
if
-r
"$text$ext"
;
}
print
HTML
qq{<p align = "center"><img src = "$text" alt = "$text illustration"></p>}
;
}
}
sub
process_begin {
my
(
$whom
,
$text
) =
@_
;
$whom
=
lc
(
$whom
);
push
(
@begin_stack
,
$whom
);
if
(
$whom
=~ /^(pod2)?html$/) {
print
HTML
$text
if
$text
;
}
}
sub
process_end {
my
(
$whom
,
$text
) =
@_
;
$whom
=
lc
(
$whom
);
if
(
$begin_stack
[-1] ne
$whom
) {
die
"Unmatched begin/end at chunk $paragraph\n"
}
pop
@begin_stack
;
}
sub
process_text {
my
(
$text
,
$escapeQuotes
) =
@_
;
my
(
$result
,
$rest
,
$s1
,
$s2
,
$s3
,
$s4
,
$match
,
$bf
);
my
(
$podcommand
,
$params
,
$tag
,
$quote
);
return
if
$ignore
;
$quote
= 0;
$result
=
""
;
$rest
=
$$text
;
if
(
$rest
=~ /^\s+/) {
$rest
=~ s/\n+\Z//;
$rest
=~ s
my
$line
= $&;
1
while
$line
=~ s/\t+/
' '
x (
length
($&) * 8 -
length
($`) % 8)/e;
$line
;
$rest
=~ s/&/
&
;/g;
$rest
=~ s/</
<
;/g;
$rest
=~ s/>/
>
;/g;
$rest
=~ s/"/
"
;/g;
$rest
=~ s{
(\s*)(perl\w+)
}{
if
(
defined
$pages
{$2}) {
qq($1<A HREF="$htmlroot/$pages{$2}">$2</A>)
;
}
elsif
(
defined
$pages
{dosify($2)}) {
qq($1<A HREF="$htmlroot/$pages{dosify($2)
}">$2</A>);
}
else
{
"$1$2"
;
}
}xeg;
$rest
=~ s{
(<A\ HREF="?) ([^>:]*:)? ([^>:]*) \.pod: ([^>:]*:)?
}{
my
$url
;
if
(
$htmlfileurl
ne
''
) {
my
$old_url
= $3 ;
$old_url
=
"$htmldir$old_url"
if
(
$old_url
=~ m{^\/} ) ;
$url
= relativize_url(
"$old_url.html"
,
$htmlfileurl
);
}
else
{
$url
=
"$3.html"
;
}
"$1$url"
;
}xeg;
my
$urls
=
'('
.
join
(
'|'
,
qw{
http
telnet
mailto
news
gopher
file
wais
ftp
}
)
.
')'
;
my
$ltrs
=
'\w'
;
my
$gunk
=
'/#~:.?+=&%@!\-'
;
my
$punc
=
'.:?\-'
;
my
$any
=
"${ltrs}${gunk}${punc}"
;
$rest
=~ s{
\b
(
$urls
:
(?!:)
[
$any
] +?
)
(?=
[
$punc
]*
[^
$any
]
|
$
)
}{<A HREF=
"$1"
>$1</A>}igox;
$result
=
"<PRE>"
.
"$rest\n"
.
"</PRE>\n"
;
}
else
{
while
(
length
$rest
) {
if
(
$rest
=~ m/[BCEIFLSZ]</) {
warn
"\$rest\t= $rest\n"
unless
$rest
=~ /\A
([^<]*?)
([BCEIFLSZ]?)
<
(.*)\Z/xs;
$s1
= $1;
$s2
= $2;
$s3
=
'<'
;
$s4
= $3;
}
else
{
$s1
=
$rest
;
$s2
=
""
;
$s3
=
""
;
$s4
=
""
;
}
if
(
$s3
eq
'<'
&&
$s2
) {
$result
.= (
$escapeQuotes
? process_puretext(
$s1
, \
$quote
) :
$s1
);
$podcommand
=
"$s2<"
;
$rest
=
$s4
;
$match
= 1;
$bf
= 0;
while
(
$match
&& !
$bf
) {
$bf
= 1;
if
(
$rest
=~ /\A([^<>]*[BCEIFLSZ]<)(.*)\Z/s) {
$bf
= 0;
$match
++;
$podcommand
.= $1;
$rest
= $2;
}
elsif
(
$rest
=~ /\A([^>]*>)(.*)\Z/s) {
$bf
= 0;
$match
--;
$podcommand
.= $1;
$rest
= $2;
}
}
if
(
$match
!= 0) {
warn
<<WARN;
$0: $podfile: cannot find matching > for $s2 in paragraph $paragraph.
WARN
$result
.=
substr
$podcommand
, 0, 2;
$rest
=
substr
(
$podcommand
, 2) .
$rest
;
next
;
}
$podcommand
=~ /^([BCFEILSZ]?)<(.*)>$/s;
$tag
= $1;
$params
= $2;
process_text(\
$params
, 0)
unless
$tag
eq
'L'
;
$s1
=
$params
;
if
(!
$tag
||
$tag
eq
" "
) {
$s1
=
"<$params>"
;
}
elsif
(
$tag
eq
"L"
) {
$s1
= process_L(
$params
);
}
elsif
(
$tag
eq
"I"
||
$tag
eq
"B"
||
$tag
eq
"F"
) {
$s1
= process_BFI(
$tag
,
$params
);
}
elsif
(
$tag
eq
"C"
) {
$s1
= process_C(
$params
, 1);
}
elsif
(
$tag
eq
"E"
) {
$s1
= process_E(
$params
);
}
elsif
(
$tag
eq
"Z"
) {
$s1
= process_Z(
$params
);
}
elsif
(
$tag
eq
"S"
) {
$s1
= process_S(
$params
);
}
elsif
(
$tag
eq
"X"
) {
$s1
= process_X(
$params
);
}
else
{
warn
"$0: $podfile: unhandled tag '$tag' in paragraph $paragraph\n"
;
}
$result
.=
"$s1"
;
}
else
{
$result
.= (
$escapeQuotes
? process_puretext(
"$s1$s2$s3"
, \
$quote
) :
"$s1$s2$s3"
);
$rest
=
$s4
;
}
}
}
$$text
=
$result
;
}
sub
html_escape {
my
$rest
=
$_
[0];
$rest
=~ s/&(?!\w+;|
$rest
=~ s/</
<
;/g;
$rest
=~ s/>/
>
;/g;
$rest
=~ s/"/
"
;/g;
return
$rest
;
}
sub
process_puretext {
my
(
$text
,
$quote
) =
@_
;
my
(
@words
,
$result
,
$rest
,
$lead
,
$trail
);
$text
=~ s/\A([^
"]*)"
/$1
''
/s
if
$$quote
;
while
(
$text
=~ s/\A([^
"]*)["
]([^
"]*)["
]/$1``$2
''
/sg) {}
$$quote
= (
$text
=~ m/"/ ? 1 : 0);
$text
=~ s/\A([^
"]*)"
/$1``/s
if
$$quote
;
$lead
= (
$text
=~ /\A(\s*)/s ? $1 :
""
);
$trail
= (
$text
=~ /(\s*)\Z/s ? $1 :
""
);
$text
=~ s/\s+/ /g;
@words
=
split
(
" "
,
$text
);
foreach
my
$word
(
@words
) {
if
(
$word
=~ /^\w+\(/) {
$word
= process_C(
$word
);
}
elsif
(
$word
=~ /^[\$\@%&*]+\w+$/) {
$word
= process_C(
$word
, 1);
}
elsif
(
$word
=~ m,^\w+://\w,) {
$word
=
qq(<A HREF="$word">$word</A>)
;
}
elsif
(
$word
=~ /[\w.-]+\@[\w-]+\.\w/) {
my
(
$w1
,
$w2
,
$w3
) = (
""
,
$word
,
""
);
(
$w1
,
$w2
,
$w3
) = (
"("
, $1,
")$2"
)
if
$word
=~ /^\((.*?)\)(,?)/;
(
$w1
,
$w2
,
$w3
) = (
"<"
, $1,
">$2"
)
if
$word
=~ /^<(.*?)>(,?)/;
$word
=
qq($w1<A HREF="mailto:$w2">$w2</A>$w3)
;
}
elsif
(
$word
!~ /[a-z]/ &&
$word
=~ /[A-Z]/) {
$word
= html_escape(
$word
)
if
$word
=~ /["&<>]/;
$word
=
"\n<FONT SIZE=-1>$word</FONT>"
if
$netscape
;
}
else
{
$word
= html_escape(
$word
)
if
$word
=~ /["&<>]/;
}
}
$result
=
""
;
$rest
=
join
(
" "
,
@words
);
while
(
length
(
$rest
) > 75) {
if
(
$rest
=~ m/^(.{0,75})\s(.*?)$/o ||
$rest
=~ m/^(\S*)\s(.*?)$/o) {
$result
.=
"$1\n"
;
$rest
= $2;
}
else
{
$result
.=
"$rest\n"
;
$rest
=
""
;
}
}
$result
.=
$rest
if
$rest
;
$result
=
"$lead$result$trail"
;
return
$result
;
}
sub
pre_escape {
my
(
$str
) =
@_
;
$$str
=~ s/&(?!\w+;|
}
sub
dosify {
my
(
$str
) =
@_
;
return
lc
(
$str
)
if
$^O eq
'VMS'
;
if
(
$Is83
) {
$str
=
lc
$str
;
$str
=~ s/(\.\w+)/
substr
($1,0,4)/ge;
$str
=~ s/(\w+)/
substr
($1,0,8)/ge;
}
return
$str
;
}
sub
process_L {
my
(
$str
) =
@_
;
my
(
$s1
,
$s2
,
$linktext
,
$page
,
$page83
,
$section
,
$link
);
$str
=~ s/\n/ /g;
$s1
=
$str
;
for
(
$s1
) {
$linktext
= $1
if
s:^([^|]+)\|::;
s,^
",/"
,g;
s,^,/,g
if
(!m,/, && / /);
if
(m,^(.*?)/
"?(.*?)"
?$,) {
(
$page
,
$section
) = ($1, $2);
}
else
{
(
$page
,
$section
) = (
$str
,
""
);
}
if
(!
defined
$pages
{
$page
} &&
defined
$sections
{
$page
}) {
$section
=
$page
;
$page
=
""
;
}
$section
=~ s/\W*$// ;
}
$page83
=dosify(
$page
);
$page
=
$page83
if
(
defined
$pages
{
$page83
});
if
(
$page
eq
""
) {
$link
=
"#"
. htmlify(0,
$section
);
$linktext
=
$section
unless
defined
(
$linktext
);
}
elsif
(
$page
=~ /::/ ) {
$linktext
= (
$section
?
"$section"
:
"$page"
);
$page
=~ s,::,/,g;
my
$page_name
=
$page
;
$page_name
=~ s,^.*/,, ;
if
(
defined
(
$pages
{
$page_name
} ) &&
$pages
{
$page_name
} =~ /([^:]
*$page
)\.(?:pod|pm):/
) {
$page
= $1 ;
}
else
{
}
$link
=
"$htmlroot/$page.html"
;
$link
.=
"#"
. htmlify(0,
$section
)
if
(
$section
);
}
elsif
(!
defined
$pages
{
$page
}) {
warn
"$0: $podfile: cannot resolve L<$str> in paragraph $paragraph: no such page '$page'\n"
unless
$quiet
;
$link
=
""
;
$linktext
=
$page
unless
defined
(
$linktext
);
}
else
{
$linktext
= (
$section
?
"$section"
:
"the $page manpage"
)
unless
defined
(
$linktext
);
$section
= htmlify(0,
$section
)
if
$section
ne
""
;
if
(
$section
ne
""
&&
$pages
{
$page
} =~ /([^:]*(?<!\.pod)(?<!\.pm)):/) {
$link
=
"$htmlroot/$1/$section.html"
;
}
else
{
$section
=
"#$section"
;
if
(
$pages
{
$page
} =~ /([^:]*)\.pod:/) {
$link
=
"$htmlroot/$1.html$section"
;
}
elsif
(
$pages
{
$page
} =~ /([^:]*)\.pm:/) {
$link
=
"$htmlroot/$1.html$section"
;
}
else
{
warn
"$0: $podfile: cannot resolve L$str in paragraph $paragraph: "
.
"no .pod or .pm found\n"
;
$link
=
""
;
$linktext
=
$section
unless
defined
(
$linktext
);
}
}
}
process_text(\
$linktext
, 0);
if
(
$link
) {
my
$url
;
if
(
$htmlfileurl
ne
''
) {
$link
=
"$htmldir$link"
if
(
$link
=~ m{^/} ) ;
$url
= relativize_url(
$link
,
$htmlfileurl
) ;
}
else
{
$url
=
$link
;
}
$s1
=
"<A HREF=\"$url\">$linktext</A>"
;
}
else
{
$s1
=
"<EM>$linktext</EM>"
;
}
return
$s1
;
}
sub
relativize_url {
my
(
$dest
,
$source
) =
@_
;
my
(
$dest_volume
,
$dest_directory
,
$dest_file
) =
File::Spec::Unix->splitpath(
$dest
) ;
$dest
= File::Spec::Unix->catpath(
$dest_volume
,
$dest_directory
,
''
) ;
my
(
$source_volume
,
$source_directory
,
$source_file
) =
File::Spec::Unix->splitpath(
$source
) ;
$source
= File::Spec::Unix->catpath(
$source_volume
,
$source_directory
,
''
) ;
my
$rel_path
=
''
;
if
(
$dest
ne
''
) {
$rel_path
= File::Spec::Unix->abs2rel(
$dest
,
$source
) ;
}
if
(
$rel_path
ne
''
&&
substr
(
$rel_path
, -1 ) ne
'/'
&&
substr
(
$dest_file
, 0, 1 ) ne
'#'
) {
$rel_path
.=
"/$dest_file"
;
}
else
{
$rel_path
.=
"$dest_file"
;
}
return
$rel_path
;
}
sub
process_BFI {
my
(
$tag
,
$str
) =
@_
;
my
(
$s1
);
my
(
%repltext
) = (
'B'
=>
'STRONG'
,
'F'
=>
'EM'
,
'I'
=>
'EM'
);
$s1
=
"<$repltext{$tag}>$str</$repltext{$tag}>"
;
return
$s1
;
}
sub
process_C {
my
(
$str
,
$doref
) =
@_
;
my
(
$s1
,
$s2
);
$s1
=
$str
;
$s1
=~ s/\([^()]*\)//g;
$s2
=
$s1
;
$s1
=~ s/\W//g;
$str
= html_escape(
$str
);
if
(
$doref
&&
defined
$items
{
$s1
}) {
if
(
$items
{
$s1
} ) {
my
$link
=
"$htmlroot/$items{$s1}#item_"
. htmlify(0,
$s2
) ;
my
$url
;
if
(
$htmlfileurl
ne
''
) {
$link
=
"$htmldir$link"
;
$url
= relativize_url(
$link
,
$htmlfileurl
) ;
}
else
{
$url
=
$link
;
}
$s1
=
"<A HREF=\"$url\">$str</A>"
;
}
else
{
$s1
=
"<A HREF=\"#item_"
. htmlify(0,
$s2
) .
"\">$str</A>"
;
}
$s1
=~ s,(perl\w+/(\S+)\.html)
confess
"s1 has space: $s1"
if
$s1
=~ /HREF=
"[^"
]*\s[^
"]*"
/;
}
else
{
$s1
=
"<CODE>$str</CODE>"
;
}
return
$s1
;
}
sub
process_E {
my
(
$str
) =
@_
;
for
(
$str
) {
s,([^/].*),\&$1\;,g;
}
return
$str
;
}
sub
process_Z {
my
(
$str
) =
@_
;
$str
=
""
;
return
$str
;
}
sub
process_S {
my
(
$str
) =
@_
;
$str
=~ s/ /
 
;/g;
return
$str
;
}
sub
process_X {
return
''
;
}
sub
relative_url {
my
$source_file
=
shift
;
my
$destination_file
=
shift
;
my
$source
= URI::file->new_abs(
$source_file
);
my
$uo
= URI::file->new(
$destination_file
,
$source
)->
abs
;
return
$uo
->rel->as_string;
}
sub
finish_list {
while
(
$listlevel
> 0) {
print
HTML
"</DL>\n"
;
$listlevel
--;
}
}
sub
htmlify {
my
(
$compact
,
$heading
) =
@_
;
if
(
$compact
) {
$heading
=~ /^(\w+)/;
$heading
= $1;
}
$heading
=~ s/[^\w\s]/_/g;
$heading
=~ s/(\s+)/ /g;
$heading
=~ s/^\s*(.*?)\s*$/$1/s;
$heading
=~ s/ /_/g;
$heading
=~ s/\A(.{32}).*\Z/$1/s;
$heading
=~ s/\s+\Z//;
$heading
=~ s/_{2,}/_/g;
return
$heading
;
}
BEGIN {
}
1;