| Server IP : 170.10.162.208 / Your IP : 216.73.216.181 Web Server : LiteSpeed System : Linux altar19.supremepanel19.com 4.18.0-553.69.1.lve.el8.x86_64 #1 SMP Wed Aug 13 19:53:59 UTC 2025 x86_64 User : deltahospital ( 1806) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /var/tmp/ |
Upload File : |
Functions.pm 0000644 00000034036 15051126136 0007060 0 ustar 00 package Pod::Functions;
use strict;
=head1 NAME
Pod::Functions - Group Perl's functions a la perlfunc.pod
=head1 SYNOPSIS
use Pod::Functions;
my @misc_ops = @{ $Kinds{ 'Misc' } };
my $misc_dsc = $Type_Description{ 'Misc' };
or
perl /path/to/lib/Pod/Functions.pm
This will print a grouped list of Perl's functions, like the
L<perlfunc/"Perl Functions by Category"> section.
=head1 DESCRIPTION
It exports the following variables:
=over 4
=item %Kinds
This holds a hash-of-lists. Each list contains the functions in the category
the key denotes.
=item %Type
In this hash each key represents a function and the value is the category.
The category can be a comma separated list.
=item %Flavor
In this hash each key represents a function and the value is a short
description of that function.
=item %Type_Description
In this hash each key represents a category of functions and the value is
a short description of that category.
=item @Type_Order
This list of categories is used to produce the same order as the
L<perlfunc/"Perl Functions by Category"> section.
=back
=cut
our $VERSION = '1.11';
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(%Kinds %Type %Flavor %Type_Description @Type_Order);
our(%Kinds, %Type, %Flavor, %Type_Description, @Type_Order);
foreach (
[String => 'Functions for SCALARs or strings'],
[Regexp => 'Regular expressions and pattern matching'],
[Math => 'Numeric functions'],
[ARRAY => 'Functions for real @ARRAYs'],
[LIST => 'Functions for list data'],
[HASH => 'Functions for real %HASHes'],
['I/O' => 'Input and output functions'],
[Binary => 'Functions for fixed-length data or records'],
[File => 'Functions for filehandles, files, or directories'],
[Flow => 'Keywords related to the control flow of your Perl program'],
[Namespace => 'Keywords related to scoping'],
[Misc => 'Miscellaneous functions'],
[Process => 'Functions for processes and process groups'],
[Modules => 'Keywords related to Perl modules'],
[Objects => 'Keywords related to classes and object-orientation'],
[Socket => 'Low-level socket functions'],
[SysV => 'System V interprocess communication functions'],
[User => 'Fetching user and group info'],
[Network => 'Fetching network info'],
[Time => 'Time-related functions'],
) {
push @Type_Order, $_->[0];
$Type_Description{$_->[0]} = $_->[1];
};
while (<DATA>) {
chomp;
s/^#.*//;
next unless $_;
my($name, @data) = split "\t", $_;
$Flavor{$name} = pop @data;
$Type{$name} = join ',', @data;
for my $t (@data) {
push @{$Kinds{$t}}, $name;
}
}
close DATA;
my( $typedesc, $list );
unless (caller) {
foreach my $type ( @Type_Order ) {
$list = join(", ", sort @{$Kinds{$type}});
$typedesc = $Type_Description{$type} . ":";
write;
}
}
format =
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$typedesc
~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$typedesc
~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$list
.
1;
__DATA__
-X File a file test (-r, -x, etc)
abs Math absolute value function
accept Socket accept an incoming socket connect
alarm Process schedule a SIGALRM
atan2 Math arctangent of Y/X in the range -PI to PI
bind Socket binds an address to a socket
binmode I/O prepare binary files for I/O
bless Objects create an object
break Flow break out of a C<given> block
caller Flow Namespace get context of the current subroutine call
chdir File change your current working directory
chmod File changes the permissions on a list of files
chomp String remove a trailing record separator from a string
chop String remove the last character from a string
chown File change the ownership on a list of files
chr String get character this number represents
chroot File make directory new root for path lookups
close I/O close file (or pipe or socket) handle
closedir I/O close directory handle
connect Socket connect to a remote socket
continue Flow optional trailing block in a while or foreach
cos Math cosine function
crypt String one-way passwd-style encryption
dbmclose I/O Objects breaks binding on a tied dbm file
dbmopen I/O Objects create binding on a tied dbm file
defined Misc test whether a value, variable, or function is defined
delete HASH deletes a value from a hash
die Flow I/O raise an exception or bail out
do Flow Modules turn a BLOCK into a TERM
dump Flow create an immediate core dump
each ARRAY HASH retrieve the next key/value pair from a hash
endgrent User be done using group file
endhostent User be done using hosts file
endnetent User be done using networks file
endprotoent Network be done using protocols file
endpwent User be done using passwd file
endservent Network be done using services file
eof I/O test a filehandle for its end
eval Flow catch exceptions or compile and run code
evalbytes Flow similar to string eval, but intend to parse a bytestream
exec Process abandon this program to run another
exists HASH test whether a hash key is present
exit Flow terminate this program
exp Math raise I<e> to a power
fc String return casefolded version of a string
fcntl File file control system call
__FILE__ Flow the name of the current source file
fileno I/O return file descriptor from filehandle
flock I/O lock an entire file with an advisory lock
fork Process create a new process just like this one
format I/O declare a picture format with use by the write() function
formline Misc internal function used for formats
getc I/O get the next character from the filehandle
getgrent User get next group record
getgrgid User get group record given group user ID
getgrnam User get group record given group name
gethostbyaddr Network get host record given its address
gethostbyname Network get host record given name
gethostent Network get next hosts record
getlogin User return who logged in at this tty
getnetbyaddr Network get network record given its address
getnetbyname Network get networks record given name
getnetent Network get next networks record
getpeername Socket find the other end of a socket connection
getpgrp Process get process group
getppid Process get parent process ID
getpriority Process get current nice value
getprotobyname Network get protocol record given name
getprotobynumber Network get protocol record numeric protocol
getprotoent Network get next protocols record
getpwent User get next passwd record
getpwnam User get passwd record given user login name
getpwuid User get passwd record given user ID
getservbyname Network get services record given its name
getservbyport Network get services record given numeric port
getservent Network get next services record
getsockname Socket retrieve the sockaddr for a given socket
getsockopt Socket get socket options on a given socket
glob File expand filenames using wildcards
gmtime Time convert UNIX time into record or string using Greenwich time
goto Flow create spaghetti code
grep LIST locate elements in a list test true against a given criterion
hex Math String convert a hexadecimal string to a number
import Modules Namespace patch a module's namespace into your own
index String find a substring within a string
int Math get the integer portion of a number
ioctl File system-dependent device control system call
join LIST join a list into a string using a separator
keys ARRAY HASH retrieve list of indices from a hash
kill Process send a signal to a process or process group
last Flow exit a block prematurely
lc String return lower-case version of a string
lcfirst String return a string with just the next letter in lower case
length String return the number of characters in a string
__LINE__ Flow the current source line number
link File create a hard link in the filesystem
listen Socket register your socket as a server
local Namespace create a temporary value for a global variable (dynamic scoping)
localtime Time convert UNIX time into record or string using local time
lock Misc get a thread lock on a variable, subroutine, or method
log Math retrieve the natural logarithm for a number
lstat File stat a symbolic link
m// Regexp match a string with a regular expression pattern
map LIST apply a change to a list to get back a new list with the changes
mkdir File create a directory
msgctl SysV SysV IPC message control operations
msgget SysV get SysV IPC message queue
msgrcv SysV receive a SysV IPC message from a message queue
msgsnd SysV send a SysV IPC message to a message queue
my Namespace declare and assign a local variable (lexical scoping)
next Flow iterate a block prematurely
no Modules unimport some module symbols or semantics at compile time
oct Math String convert a string to an octal number
open File open a file, pipe, or descriptor
opendir File open a directory
ord String find a character's numeric representation
our Namespace declare and assign a package variable (lexical scoping)
pack Binary String convert a list into a binary representation
package Modules Namespace Objects declare a separate global namespace
__PACKAGE__ Flow the current package
pipe Process open a pair of connected filehandles
pop ARRAY remove the last element from an array and return it
pos Regexp find or set the offset for the last/next m//g search
print I/O output a list to a filehandle
printf I/O output a formatted list to a filehandle
prototype Misc get the prototype (if any) of a subroutine
push ARRAY append one or more elements to an array
q/STRING/ String singly quote a string
qq/STRING/ String doubly quote a string
qr/STRING/ Regexp compile pattern
quotemeta Regexp quote regular expression magic characters
qw/STRING/ LIST quote a list of words
qx/STRING/ Process backquote quote a string
rand Math retrieve the next pseudorandom number
read Binary I/O fixed-length buffered input from a filehandle
readdir I/O get a directory from a directory handle
readline I/O fetch a record from a file
readlink File determine where a symbolic link is pointing
readpipe Process execute a system command and collect standard output
recv Socket receive a message over a Socket
redo Flow start this loop iteration over again
ref Objects find out the type of thing being referenced
rename File change a filename
require Modules load in external functions from a library at runtime
reset Misc clear all variables of a given name
return Flow get out of a function early
reverse LIST String flip a string or a list
rewinddir I/O reset directory handle
rindex String right-to-left substring search
rmdir File remove a directory
s/// Regexp replace a pattern with a string
say I/O output a list to a filehandle, appending a newline
scalar Misc force a scalar context
seek I/O reposition file pointer for random-access I/O
seekdir I/O reposition directory pointer
select File I/O reset default output or do I/O multiplexing
semctl SysV SysV semaphore control operations
semget SysV get set of SysV semaphores
semop SysV SysV semaphore operations
send Socket send a message over a socket
setgrent User prepare group file for use
sethostent Network prepare hosts file for use
setnetent Network prepare networks file for use
setpgrp Process set the process group of a process
setpriority Process set a process's nice value
setprotoent Network prepare protocols file for use
setpwent User prepare passwd file for use
setservent Network prepare services file for use
setsockopt Socket set some socket options
shift ARRAY remove the first element of an array, and return it
shmctl SysV SysV shared memory operations
shmget SysV get SysV shared memory segment identifier
shmread SysV read SysV shared memory
shmwrite SysV write SysV shared memory
shutdown Socket close down just half of a socket connection
sin Math return the sine of a number
sleep Process block for some number of seconds
socket Socket create a socket
socketpair Socket create a pair of sockets
sort LIST sort a list of values
splice ARRAY add or remove elements anywhere in an array
split Regexp split up a string using a regexp delimiter
sprintf String formatted print into a string
sqrt Math square root function
srand Math seed the random number generator
stat File get a file's status information
state Namespace declare and assign a persistent lexical variable
study Regexp no-op, formerly optimized input data for repeated searches
sub Flow declare a subroutine, possibly anonymously
__SUB__ Flow the current subroutine, or C<undef> if not in a subroutine
substr String get or alter a portion of a string
symlink File create a symbolic link to a file
syscall Binary I/O execute an arbitrary system call
sysopen File open a file, pipe, or descriptor
sysread Binary I/O fixed-length unbuffered input from a filehandle
sysseek Binary I/O position I/O pointer on handle used with sysread and syswrite
system Process run a separate program
syswrite Binary I/O fixed-length unbuffered output to a filehandle
tell I/O get current seekpointer on a filehandle
telldir I/O get current seekpointer on a directory handle
tie Objects bind a variable to an object class
tied Objects get a reference to the object underlying a tied variable
time Time return number of seconds since 1970
times Process Time return elapsed time for self and child processes
tr/// String transliterate a string
truncate I/O shorten a file
uc String return upper-case version of a string
ucfirst String return a string with just the next letter in upper case
umask File set file creation mode mask
undef Misc remove a variable or function definition
unlink File remove one link to a file
unpack Binary LIST convert binary structure into normal perl variables
unshift ARRAY prepend more elements to the beginning of a list
untie Objects break a tie binding to a variable
use Modules Namespace Objects load in a module at compile time and import its namespace
utime File set a file's last access and modify times
values ARRAY HASH return a list of the values in a hash
vec Binary test or set particular bits in a string
wait Process wait for any child process to die
waitpid Process wait for a particular child process to die
wantarray Flow get void vs scalar vs list context of current subroutine call
warn I/O print debugging info
write I/O print a picture record
y/// String transliterate a string
Html.pm 0000644 00000057507 15051126136 0006024 0 ustar 00 package Pod::Html;
use strict;
require Exporter;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
$VERSION = 1.2202;
@ISA = qw(Exporter);
@EXPORT = qw(pod2html htmlify);
@EXPORT_OK = qw(anchorify);
use Carp;
use Config;
use Cwd;
use File::Basename;
use File::Spec;
use File::Spec::Unix;
use Getopt::Long;
use Pod::Simple::Search;
use locale; # make \w work right in non-ASCII lands
=head1 NAME
Pod::Html - module to convert pod files to HTML
=head1 SYNOPSIS
use Pod::Html;
pod2html([options]);
=head1 DESCRIPTION
Converts files from pod format (see L<perlpod>) to HTML format. It
can automatically generate indexes and cross-references, and it keeps
a cache of things it knows how to cross-reference.
=head1 FUNCTIONS
=head2 pod2html
pod2html("pod2html",
"--podpath=lib:ext:pod:vms",
"--podroot=/usr/src/perl",
"--htmlroot=/perl/nmanual",
"--recurse",
"--infile=foo.pod",
"--outfile=/perl/nmanual/foo.html");
pod2html takes the following arguments:
=over 4
=item backlink
--backlink
Turns every C<head1> heading into a link back to the top of the page.
By default, no backlinks are generated.
=item cachedir
--cachedir=name
Creates the directory cache in the given directory.
=item css
--css=stylesheet
Specify the URL of a cascading style sheet. Also disables all HTML/CSS
C<style> attributes that are output by default (to avoid conflicts).
=item flush
--flush
Flushes the directory cache.
=item header
--header
--noheader
Creates header and footer blocks containing the text of the C<NAME>
section. By default, no headers are generated.
=item help
--help
Displays the usage message.
=item htmldir
--htmldir=name
Sets the directory to which all cross references in the resulting
html file will be relative. Not passing this causes all links to be
absolute since this is the value that tells Pod::Html the root of the
documentation tree.
Do not use this and --htmlroot in the same call to pod2html; they are
mutually exclusive.
=item htmlroot
--htmlroot=name
Sets the base URL for the HTML files. When cross-references are made,
the HTML root is prepended to the URL.
Do not use this if relative links are desired: use --htmldir instead.
Do not pass both this and --htmldir to pod2html; they are mutually
exclusive.
=item index
--index
--noindex
Generate an index at the top of the HTML file. This is the default
behaviour.
=item infile
--infile=name
Specify the pod file to convert. Input is taken from STDIN if no
infile is specified.
=item outfile
--outfile=name
Specify the HTML file to create. Output goes to STDOUT if no outfile
is specified.
=item poderrors
--poderrors
--nopoderrors
Include a "POD ERRORS" section in the outfile if there were any POD
errors in the infile. This section is included by default.
=item podpath
--podpath=name:...:name
Specify which subdirectories of the podroot contain pod files whose
HTML converted forms can be linked to in cross references.
=item podroot
--podroot=name
Specify the base directory for finding library pods. Default is the
current working directory.
=item quiet
--quiet
--noquiet
Don't display I<mostly harmless> warning messages. These messages
will be displayed by default. But this is not the same as C<verbose>
mode.
=item recurse
--recurse
--norecurse
Recurse into subdirectories specified in podpath (default behaviour).
=item title
--title=title
Specify the title of the resulting HTML file.
=item verbose
--verbose
--noverbose
Display progress messages. By default, they won't be displayed.
=back
=head2 htmlify
htmlify($heading);
Converts a pod section specification to a suitable section specification
for HTML. Note that we keep spaces and special characters except
C<", ?> (Netscape problem) and the hyphen (writer's problem...).
=head2 anchorify
anchorify(@heading);
Similar to C<htmlify()>, but turns non-alphanumerics into underscores. Note
that C<anchorify()> is not exported by default.
=head1 ENVIRONMENT
Uses C<$Config{pod2html}> to setup default options.
=head1 AUTHOR
Marc Green, E<lt>marcgreen@cpan.orgE<gt>.
Original version by Tom Christiansen, E<lt>tchrist@perl.comE<gt>.
=head1 SEE ALSO
L<perlpod>
=head1 COPYRIGHT
This program is distributed under the Artistic License.
=cut
my $Cachedir;
my $Dircache;
my($Htmlroot, $Htmldir, $Htmlfile, $Htmlfileurl);
my($Podfile, @Podpath, $Podroot);
my $Poderrors;
my $Css;
my $Recurse;
my $Quiet;
my $Verbose;
my $Doindex;
my $Backlink;
my($Title, $Header);
my %Pages = (); # associative array used to find the location
# of pages referenced by L<> links.
my $Curdir = File::Spec->curdir;
init_globals();
sub init_globals {
$Cachedir = "."; # The directory to which directory caches
# will be written.
$Dircache = "pod2htmd.tmp";
$Htmlroot = "/"; # http-server base directory from which all
# relative paths in $podpath stem.
$Htmldir = ""; # The directory to which the html pages
# will (eventually) be written.
$Htmlfile = ""; # write to stdout by default
$Htmlfileurl = ""; # The url that other files would use to
# refer to this file. This is only used
# to make relative urls that point to
# other files.
$Poderrors = 1;
$Podfile = ""; # read from stdin by default
@Podpath = (); # list of directories containing library pods.
$Podroot = $Curdir; # filesystem base directory from which all
# relative paths in $podpath stem.
$Css = ''; # Cascading style sheet
$Recurse = 1; # recurse on subdirectories in $podpath.
$Quiet = 0; # not quiet by default
$Verbose = 0; # not verbose by default
$Doindex = 1; # non-zero if we should generate an index
$Backlink = 0; # no backlinks added by default
$Header = 0; # produce block header/footer
$Title = ''; # title to give the pod(s)
}
sub pod2html {
local(@ARGV) = @_;
local $_;
init_globals();
parse_command_line();
# prevent '//' in urls
$Htmlroot = "" if $Htmlroot eq "/";
$Htmldir =~ s#/\z##;
if ( $Htmlroot eq ''
&& defined( $Htmldir )
&& $Htmldir ne ''
&& substr( $Htmlfile, 0, length( $Htmldir ) ) eq $Htmldir
) {
# Set the 'base' url for this file, so that we can use it
# as the location from which to calculate relative links
# to other files. If this is '', then absolute links will
# be used throughout.
#$Htmlfileurl = "$Htmldir/" . substr( $Htmlfile, length( $Htmldir ) + 1);
# Is the above not just "$Htmlfileurl = $Htmlfile"?
$Htmlfileurl = Pod::Html::_unixify($Htmlfile);
}
# load or generate/cache %Pages
unless (get_cache($Dircache, \@Podpath, $Podroot, $Recurse)) {
# generate %Pages
my $pwd = getcwd();
chdir($Podroot) ||
die "$0: error changing to directory $Podroot: $!\n";
# find all pod modules/pages in podpath, store in %Pages
# - callback used to remove Podroot and extension from each file
# - laborious to allow '.' in dirnames (e.g., /usr/share/perl/5.14.1)
Pod::Simple::Search->new->inc(0)->verbose($Verbose)->laborious(1)
->callback(\&_save_page)->recurse($Recurse)->survey(@Podpath);
chdir($pwd) || die "$0: error changing to directory $pwd: $!\n";
# cache the directory list for later use
warn "caching directories for later use\n" if $Verbose;
open my $cache, '>', $Dircache
or die "$0: error open $Dircache for writing: $!\n";
print $cache join(":", @Podpath) . "\n$Podroot\n";
my $_updirs_only = ($Podroot =~ /\.\./) && !($Podroot =~ /[^\.\\\/]/);
foreach my $key (keys %Pages) {
if($_updirs_only) {
my $_dirlevel = $Podroot;
while($_dirlevel =~ /\.\./) {
$_dirlevel =~ s/\.\.//;
# Assume $Pages{$key} has '/' separators (html dir separators).
$Pages{$key} =~ s/^[\w\s\-\.]+\///;
}
}
print $cache "$key $Pages{$key}\n";
}
close $cache or die "error closing $Dircache: $!";
}
# set options for the parser
my $parser = Pod::Simple::XHTML::LocalPodLinks->new();
$parser->codes_in_verbatim(0);
$parser->anchor_items(1); # the old Pod::Html always did
$parser->backlink($Backlink); # linkify =head1 directives
$parser->htmldir($Htmldir);
$parser->htmlfileurl($Htmlfileurl);
$parser->htmlroot($Htmlroot);
$parser->index($Doindex);
$parser->no_errata_section(!$Poderrors); # note the inverse
$parser->output_string(\my $output); # written to file later
$parser->pages(\%Pages);
$parser->quiet($Quiet);
$parser->verbose($Verbose);
# XXX: implement default title generator in pod::simple::xhtml
# copy the way the old Pod::Html did it
$Title = html_escape($Title);
# We need to add this ourselves because we use our own header, not
# ::XHTML's header. We need to set $parser->backlink to linkify
# the =head1 directives
my $bodyid = $Backlink ? ' id="_podtop_"' : '';
my $csslink = '';
my $tdstyle = ' style="background-color: #cccccc; color: #000"';
if ($Css) {
$csslink = qq(\n<link rel="stylesheet" href="$Css" type="text/css" />);
$csslink =~ s,\\,/,g;
$csslink =~ s,(/.):,$1|,;
$tdstyle= '';
}
# header/footer block
my $block = $Header ? <<END_OF_BLOCK : '';
<table border="0" width="100%" cellspacing="0" cellpadding="3">
<tr><td class="_podblock_"$tdstyle valign="middle">
<big><strong><span class="_podblock_"> $Title</span></strong></big>
</td></tr>
</table>
END_OF_BLOCK
# create own header/footer because of --header
$parser->html_header(<<"HTMLHEAD");
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>$Title</title>$csslink
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rev="made" href="mailto:$Config{perladmin}" />
</head>
<body$bodyid>
$block
HTMLHEAD
$parser->html_footer(<<"HTMLFOOT");
$block
</body>
</html>
HTMLFOOT
my $input;
unless (@ARGV && $ARGV[0]) {
if ($Podfile and $Podfile ne '-') {
$input = $Podfile;
} else {
$input = '-'; # XXX: make a test case for this
}
} else {
$Podfile = $ARGV[0];
$input = *ARGV;
}
warn "Converting input file $Podfile\n" if $Verbose;
$parser->parse_file($input);
# Write output to file
$Htmlfile = "-" unless $Htmlfile; # stdout
my $fhout;
if($Htmlfile and $Htmlfile ne '-') {
open $fhout, ">", $Htmlfile
or die "$0: cannot open $Htmlfile file for output: $!\n";
} else {
open $fhout, ">-";
}
binmode $fhout, ":utf8";
print $fhout $output;
close $fhout or die "Failed to close $Htmlfile: $!";
chmod 0644, $Htmlfile unless $Htmlfile eq '-';
}
##############################################################################
sub usage {
my $podfile = shift;
warn "$0: $podfile: @_\n" if @_;
die <<END_OF_USAGE;
Usage: $0 --help --htmldir=<name> --htmlroot=<URL>
--infile=<name> --outfile=<name>
--podpath=<name>:...:<name> --podroot=<name>
--cachedir=<name> --flush --recurse --norecurse
--quiet --noquiet --verbose --noverbose
--index --noindex --backlink --nobacklink
--header --noheader --poderrors --nopoderrors
--css=<URL> --title=<name>
--[no]backlink - turn =head1 directives into links pointing to the top of
the page (off by default).
--cachedir - directory for the directory cache files.
--css - stylesheet URL
--flush - flushes the directory cache.
--[no]header - produce block header/footer (default is no headers).
--help - prints this message.
--htmldir - directory for resulting HTML files.
--htmlroot - http-server base directory from which all relative paths
in podpath stem (default is /).
--[no]index - generate an index at the top of the resulting html
(default behaviour).
--infile - filename for the pod to convert (input taken from stdin
by default).
--outfile - filename for the resulting html file (output sent to
stdout by default).
--[no]poderrors - include a POD ERRORS section in the output if there were
any POD errors in the input (default behavior).
--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 .).
--[no]quiet - suppress some benign warning messages (default is off).
--[no]recurse - recurse on those subdirectories listed in podpath
(default behaviour).
--title - title that will appear in resulting html file.
--[no]verbose - self-explanatory (off by default).
END_OF_USAGE
}
sub parse_command_line {
my ($opt_backlink,$opt_cachedir,$opt_css,$opt_flush,$opt_header,
$opt_help,$opt_htmldir,$opt_htmlroot,$opt_index,$opt_infile,
$opt_outfile,$opt_poderrors,$opt_podpath,$opt_podroot,
$opt_quiet,$opt_recurse,$opt_title,$opt_verbose);
unshift @ARGV, split ' ', $Config{pod2html} if $Config{pod2html};
my $result = GetOptions(
'backlink!' => \$opt_backlink,
'cachedir=s' => \$opt_cachedir,
'css=s' => \$opt_css,
'flush' => \$opt_flush,
'help' => \$opt_help,
'header!' => \$opt_header,
'htmldir=s' => \$opt_htmldir,
'htmlroot=s' => \$opt_htmlroot,
'index!' => \$opt_index,
'infile=s' => \$opt_infile,
'outfile=s' => \$opt_outfile,
'poderrors!' => \$opt_poderrors,
'podpath=s' => \$opt_podpath,
'podroot=s' => \$opt_podroot,
'quiet!' => \$opt_quiet,
'recurse!' => \$opt_recurse,
'title=s' => \$opt_title,
'verbose!' => \$opt_verbose,
);
usage("-", "invalid parameters") if not $result;
usage("-") if defined $opt_help; # see if the user asked for help
$opt_help = ""; # just to make -w shut-up.
@Podpath = split(":", $opt_podpath) if defined $opt_podpath;
$Backlink = $opt_backlink if defined $opt_backlink;
$Cachedir = _unixify($opt_cachedir) if defined $opt_cachedir;
$Css = $opt_css if defined $opt_css;
$Header = $opt_header if defined $opt_header;
$Htmldir = _unixify($opt_htmldir) if defined $opt_htmldir;
$Htmlroot = _unixify($opt_htmlroot) if defined $opt_htmlroot;
$Doindex = $opt_index if defined $opt_index;
$Podfile = _unixify($opt_infile) if defined $opt_infile;
$Htmlfile = _unixify($opt_outfile) if defined $opt_outfile;
$Poderrors = $opt_poderrors if defined $opt_poderrors;
$Podroot = _unixify($opt_podroot) if defined $opt_podroot;
$Quiet = $opt_quiet if defined $opt_quiet;
$Recurse = $opt_recurse if defined $opt_recurse;
$Title = $opt_title if defined $opt_title;
$Verbose = $opt_verbose if defined $opt_verbose;
warn "Flushing directory caches\n"
if $opt_verbose && defined $opt_flush;
$Dircache = "$Cachedir/pod2htmd.tmp";
if (defined $opt_flush) {
1 while unlink($Dircache);
}
}
my $Saved_Cache_Key;
sub get_cache {
my($dircache, $podpath, $podroot, $recurse) = @_;
my @cache_key_args = @_;
# A first-level cache:
# Don't bother reading the cache files if they still apply
# and haven't changed since we last read them.
my $this_cache_key = cache_key(@cache_key_args);
return 1 if $Saved_Cache_Key and $this_cache_key eq $Saved_Cache_Key;
$Saved_Cache_Key = $this_cache_key;
# load the cache of %Pages if possible. $tests will be
# non-zero if successful.
my $tests = 0;
if (-f $dircache) {
warn "scanning for directory cache\n" if $Verbose;
$tests = load_cache($dircache, $podpath, $podroot);
}
return $tests;
}
sub cache_key {
my($dircache, $podpath, $podroot, $recurse) = @_;
return join('!',$dircache,$recurse,@$podpath,$podroot,stat($dircache));
}
#
# load_cache - tries to find if the cache stored in $dircache is a valid
# cache of %Pages. if so, it loads them and returns a non-zero value.
#
sub load_cache {
my($dircache, $podpath, $podroot) = @_;
my $tests = 0;
local $_;
warn "scanning for directory cache\n" if $Verbose;
open(my $cachefh, '<', $dircache) ||
die "$0: error opening $dircache for reading: $!\n";
$/ = "\n";
# is it the same podpath?
$_ = <$cachefh>;
chomp($_);
$tests++ if (join(":", @$podpath) eq $_);
# is it the same podroot?
$_ = <$cachefh>;
chomp($_);
$tests++ if ($podroot eq $_);
# load the cache if its good
if ($tests != 2) {
close($cachefh);
return 0;
}
warn "loading directory cache\n" if $Verbose;
while (<$cachefh>) {
/(.*?) (.*)$/;
$Pages{$1} = $2;
}
close($cachefh);
return 1;
}
#
# html_escape: make text safe for HTML
#
sub html_escape {
my $rest = $_[0];
$rest =~ s/&/&/g;
$rest =~ s/</</g;
$rest =~ s/>/>/g;
$rest =~ s/"/"/g;
# ' is only in XHTML, not HTML4. Be conservative
#$rest =~ s/'/'/g;
return $rest;
}
#
# htmlify - converts a pod section specification to a suitable section
# specification for HTML. Note that we keep spaces and special characters
# except ", ? (Netscape problem) and the hyphen (writer's problem...).
#
sub htmlify {
my( $heading) = @_;
$heading =~ s/(\s+)/ /g;
$heading =~ s/\s+\Z//;
$heading =~ s/\A\s+//;
# The hyphen is a disgrace to the English language.
# $heading =~ s/[-"?]//g;
$heading =~ s/["?]//g;
$heading = lc( $heading );
return $heading;
}
#
# similar to htmlify, but turns non-alphanumerics into underscores
#
sub anchorify {
my ($anchor) = @_;
$anchor = htmlify($anchor);
$anchor =~ s/\W/_/g;
return $anchor;
}
#
# store POD files in %Pages
#
sub _save_page {
my ($modspec, $modname) = @_;
# Remove Podroot from path
$modspec = $Podroot eq File::Spec->curdir
? File::Spec->abs2rel($modspec)
: File::Spec->abs2rel($modspec,
File::Spec->canonpath($Podroot));
# Convert path to unix style path
$modspec = Pod::Html::_unixify($modspec);
my ($file, $dir) = fileparse($modspec, qr/\.[^.]*/); # strip .ext
$Pages{$modname} = $dir.$file;
}
sub _unixify {
my $full_path = shift;
return '' unless $full_path;
return $full_path if $full_path eq '/';
my ($vol, $dirs, $file) = File::Spec->splitpath($full_path);
my @dirs = $dirs eq File::Spec->curdir()
? (File::Spec::Unix->curdir())
: File::Spec->splitdir($dirs);
if (defined($vol) && $vol) {
$vol =~ s/:$// if $^O eq 'VMS';
$vol = uc $vol if $^O eq 'MSWin32';
if( $dirs[0] ) {
unshift @dirs, $vol;
}
else {
$dirs[0] = $vol;
}
}
unshift @dirs, '' if File::Spec->file_name_is_absolute($full_path);
return $file unless scalar(@dirs);
$full_path = File::Spec::Unix->catfile(File::Spec::Unix->catdir(@dirs),
$file);
$full_path =~ s|^\/|| if $^O eq 'MSWin32'; # C:/foo works, /C:/foo doesn't
$full_path =~ s/\^\././g if $^O eq 'VMS'; # unescape dots
return $full_path;
}
package Pod::Simple::XHTML::LocalPodLinks;
use strict;
use warnings;
use parent 'Pod::Simple::XHTML';
use File::Spec;
use File::Spec::Unix;
__PACKAGE__->_accessorize(
'htmldir',
'htmlfileurl',
'htmlroot',
'pages', # Page name => relative/path/to/page from root POD dir
'quiet',
'verbose',
);
sub resolve_pod_page_link {
my ($self, $to, $section) = @_;
return undef unless defined $to || defined $section;
if (defined $section) {
$section = '#' . $self->idify($section, 1);
return $section unless defined $to;
} else {
$section = '';
}
my $path; # path to $to according to %Pages
unless (exists $self->pages->{$to}) {
# Try to find a POD that ends with $to and use that.
# e.g., given L<XHTML>, if there is no $Podpath/XHTML in %Pages,
# look for $Podpath/*/XHTML in %Pages, with * being any path,
# as a substitute (e.g., $Podpath/Pod/Simple/XHTML)
my @matches;
foreach my $modname (keys %{$self->pages}) {
push @matches, $modname if $modname =~ /::\Q$to\E\z/;
}
if ($#matches == -1) {
warn "Cannot find \"$to\" in podpath: " .
"cannot find suitable replacement path, cannot resolve link\n"
unless $self->quiet;
return '';
} elsif ($#matches == 0) {
warn "Cannot find \"$to\" in podpath: " .
"using $matches[0] as replacement path to $to\n"
unless $self->quiet;
$path = $self->pages->{$matches[0]};
} else {
warn "Cannot find \"$to\" in podpath: " .
"more than one possible replacement path to $to, " .
"using $matches[-1]\n" unless $self->quiet;
# Use [-1] so newer (higher numbered) perl PODs are used
$path = $self->pages->{$matches[-1]};
}
} else {
$path = $self->pages->{$to};
}
my $url = File::Spec::Unix->catfile(Pod::Html::_unixify($self->htmlroot),
$path);
if ($self->htmlfileurl ne '') {
# then $self->htmlroot eq '' (by definition of htmlfileurl) so
# $self->htmldir needs to be prepended to link to get the absolute path
# that will be relativized
$url = relativize_url(
File::Spec::Unix->catdir(Pod::Html::_unixify($self->htmldir), $url),
$self->htmlfileurl # already unixified
);
}
return $url . ".html$section";
}
#
# relativize_url - convert an absolute URL to one relative to a base URL.
# Assumes both end in a filename.
#
sub relativize_url {
my ($dest, $source) = @_;
# Remove each file from its path
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 '/') {
$rel_path .= "/$dest_file";
} else {
$rel_path .= "$dest_file";
}
return $rel_path;
}
1;
Perldoc/GetOptsOO.pm 0000644 00000007460 15051135563 0010330 0 ustar 00 package Pod::Perldoc::GetOptsOO;
use strict;
use vars qw($VERSION);
$VERSION = '3.28';
BEGIN { # Make a DEBUG constant ASAP
*DEBUG = defined( &Pod::Perldoc::DEBUG )
? \&Pod::Perldoc::DEBUG
: sub(){10};
}
sub getopts {
my($target, $args, $truth) = @_;
$args ||= \@ARGV;
$target->aside(
"Starting switch processing. Scanning arguments [@$args]\n"
) if $target->can('aside');
return unless @$args;
$truth = 1 unless @_ > 2;
DEBUG > 3 and print " Truth is $truth\n";
my $error_count = 0;
while( @$args and ($_ = $args->[0]) =~ m/^-(.)(.*)/s ) {
my($first,$rest) = ($1,$2);
if ($_ eq '--') { # early exit if "--"
shift @$args;
last;
}
if ($first eq '-' and $rest) { # GNU style long param names
($first, $rest) = split '=', $rest, 2;
}
my $method = "opt_${first}_with";
if( $target->can($method) ) { # it's argumental
if($rest eq '') { # like -f bar
shift @$args;
$target->warn( "Option $first needs a following argument!\n" ) unless @$args;
$rest = shift @$args;
} else { # like -fbar (== -f bar)
shift @$args;
}
DEBUG > 3 and print " $method => $rest\n";
$target->$method( $rest );
# Otherwise, it's not argumental...
} else {
if( $target->can( $method = "opt_$first" ) ) {
DEBUG > 3 and print " $method is true ($truth)\n";
$target->$method( $truth );
# Otherwise it's an unknown option...
} elsif( $target->can('handle_unknown_option') ) {
DEBUG > 3
and print " calling handle_unknown_option('$first')\n";
$error_count += (
$target->handle_unknown_option( $first ) || 0
);
} else {
++$error_count;
$target->warn( "Unknown option: $first\n" );
}
if($rest eq '') { # like -f
shift @$args
} else { # like -fbar (== -f -bar )
DEBUG > 2 and print " Setting args->[0] to \"-$rest\"\n";
$args->[0] = "-$rest";
}
}
}
$target->aside(
"Ending switch processing. Args are [@$args] with $error_count errors.\n"
) if $target->can('aside');
$error_count == 0;
}
1;
__END__
=head1 NAME
Pod::Perldoc::GetOptsOO - Customized option parser for Pod::Perldoc
=head1 SYNOPSIS
use Pod::Perldoc::GetOptsOO ();
Pod::Perldoc::GetOptsOO::getopts( $obj, \@args, $truth )
or die "wrong usage";
=head1 DESCRIPTION
Implements a customized option parser used for
L<Pod::Perldoc>.
Rather like Getopt::Std's getopts:
=over
=item Call Pod::Perldoc::GetOptsOO::getopts($object, \@ARGV, $truth)
=item Given -n, if there's a opt_n_with, it'll call $object->opt_n_with( ARGUMENT )
(e.g., "-n foo" => $object->opt_n_with('foo'). Ditto "-nfoo")
=item Otherwise (given -n) if there's an opt_n, we'll call it $object->opt_n($truth)
(Truth defaults to 1)
=item Otherwise we try calling $object->handle_unknown_option('n')
(and we increment the error count by the return value of it)
=item If there's no handle_unknown_option, then we just warn, and then increment
the error counter
=back
The return value of Pod::Perldoc::GetOptsOO::getopts is true if no errors,
otherwise it's false.
=head1 SEE ALSO
L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002-2007 Sean M. Burke.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToChecker.pm 0000644 00000003233 15051135563 0010346 0 ustar 00 package Pod::Perldoc::ToChecker;
use strict;
use warnings;
use vars qw(@ISA);
use vars qw($VERSION);
$VERSION = '3.28';
# Pick our superclass...
#
eval 'require Pod::Simple::Checker';
if($@) {
require Pod::Checker;
@ISA = ('Pod::Checker');
} else {
@ISA = ('Pod::Simple::Checker');
}
sub is_pageable { 1 }
sub write_with_binmode { 0 }
sub output_extension { 'txt' }
sub if_zero_length {
my( $self, $file, $tmp, $tmpfd ) = @_;
print "No Pod errors in $file\n";
}
1;
__END__
=head1 NAME
Pod::Perldoc::ToChecker - let Perldoc check Pod for errors
=head1 SYNOPSIS
% perldoc -o checker SomeFile.pod
No Pod errors in SomeFile.pod
(or an error report)
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Simple::Checker as a "formatter" class (or if that is
not available, then Pod::Checker), to check for errors in a given
Pod file.
This is actually a Pod::Simple::Checker (or Pod::Checker) subclass, and
inherits all its options.
=head1 SEE ALSO
L<Pod::Simple::Checker>, L<Pod::Simple>, L<Pod::Checker>, L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002 Sean M. Burke. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToNroff.pm 0000644 00000005336 15051135563 0010062 0 ustar 00 package Pod::Perldoc::ToNroff;
use strict;
use warnings;
use parent qw(Pod::Perldoc::BaseTo);
use vars qw($VERSION);
$VERSION = '3.28';
# This is unlike ToMan.pm in that it emits the raw nroff source!
sub is_pageable { 1 } # well, if you ask for it...
sub write_with_binmode { 0 }
sub output_extension { 'man' }
use Pod::Man ();
sub center { shift->_perldoc_elem('center' , @_) }
sub date { shift->_perldoc_elem('date' , @_) }
sub fixed { shift->_perldoc_elem('fixed' , @_) }
sub fixedbold { shift->_perldoc_elem('fixedbold' , @_) }
sub fixeditalic { shift->_perldoc_elem('fixeditalic' , @_) }
sub fixedbolditalic { shift->_perldoc_elem('fixedbolditalic', @_) }
sub quotes { shift->_perldoc_elem('quotes' , @_) }
sub release { shift->_perldoc_elem('release' , @_) }
sub section { shift->_perldoc_elem('section' , @_) }
sub new { return bless {}, ref($_[0]) || $_[0] }
sub parse_from_file {
my $self = shift;
my $file = $_[0];
my @options =
map {; $_, $self->{$_} }
grep !m/^_/s,
keys %$self
;
defined(&Pod::Perldoc::DEBUG)
and Pod::Perldoc::DEBUG()
and print "About to call new Pod::Man ",
$Pod::Man::VERSION ? "(v$Pod::Man::VERSION) " : '',
"with options: ",
@options ? "[@options]" : "(nil)", "\n";
;
Pod::Man->new(@options)->parse_from_file(@_);
}
1;
__END__
=head1 NAME
Pod::Perldoc::ToNroff - let Perldoc convert Pod to nroff
=head1 SYNOPSIS
perldoc -o nroff -d something.3 Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Man as a formatter class.
The following options are supported: center, date, fixed, fixedbold,
fixeditalic, fixedbolditalic, quotes, release, section
Those options are explained in L<Pod::Man>.
For example:
perldoc -o nroff -w center:Pod -d something.3 Some::Modulename
=head1 CAVEAT
This module may change to use a different pod-to-nroff formatter class
in the future, and this may change what options are supported.
=head1 SEE ALSO
L<Pod::Man>, L<Pod::Perldoc>, L<Pod::Perldoc::ToMan>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002 Sean M. Burke. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToPod.pm 0000644 00000003647 15051135563 0007535 0 ustar 00 package Pod::Perldoc::ToPod;
use strict;
use warnings;
use parent qw(Pod::Perldoc::BaseTo);
use vars qw($VERSION);
$VERSION = '3.28';
sub is_pageable { 1 }
sub write_with_binmode { 0 }
sub output_extension { 'pod' }
sub new { return bless {}, ref($_[0]) || $_[0] }
sub parse_from_file {
my( $self, $in, $outfh ) = @_;
open(IN, "<", $in) or $self->die( "Can't read-open $in: $!\nAborting" );
my $cut_mode = 1;
# A hack for finding things between =foo and =cut, inclusive
local $_;
while (<IN>) {
if( m/^=(\w+)/s ) {
if($cut_mode = ($1 eq 'cut')) {
print $outfh "\n=cut\n\n";
# Pass thru the =cut line with some harmless
# (and occasionally helpful) padding
}
}
next if $cut_mode;
print $outfh $_ or $self->die( "Can't print to $outfh: $!" );
}
close IN or $self->die( "Can't close $in: $!" );
return;
}
1;
__END__
=head1 NAME
Pod::Perldoc::ToPod - let Perldoc render Pod as ... Pod!
=head1 SYNOPSIS
perldoc -opod Some::Modulename
(That's currently the same as the following:)
perldoc -u Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to display Pod source as
itself! Pretty Zen, huh?
Currently this class works by just filtering out the non-Pod stuff from
a given input file.
=head1 SEE ALSO
L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002 Sean M. Burke. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallencpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/BaseTo.pm 0000644 00000007065 15051135563 0007663 0 ustar 00 package Pod::Perldoc::BaseTo;
use strict;
use warnings;
use vars qw($VERSION);
$VERSION = '3.28';
use Carp qw(croak carp);
use Config qw(%Config);
use File::Spec::Functions qw(catfile);
sub is_pageable { '' }
sub write_with_binmode { 1 }
sub output_extension { 'txt' } # override in subclass!
# sub new { my $self = shift; ... }
# sub parse_from_file( my($class, $in, $out) = ...; ... }
#sub new { return bless {}, ref($_[0]) || $_[0] }
# this is also in Perldoc.pm, but why look there when you're a
# subclass of this?
sub TRUE () {1}
sub FALSE () {return}
BEGIN {
*is_vms = $^O eq 'VMS' ? \&TRUE : \&FALSE unless defined &is_vms;
*is_mswin32 = $^O eq 'MSWin32' ? \&TRUE : \&FALSE unless defined &is_mswin32;
*is_dos = $^O eq 'dos' ? \&TRUE : \&FALSE unless defined &is_dos;
*is_os2 = $^O eq 'os2' ? \&TRUE : \&FALSE unless defined &is_os2;
*is_cygwin = $^O eq 'cygwin' ? \&TRUE : \&FALSE unless defined &is_cygwin;
*is_linux = $^O eq 'linux' ? \&TRUE : \&FALSE unless defined &is_linux;
*is_hpux = $^O =~ m/hpux/ ? \&TRUE : \&FALSE unless defined &is_hpux;
*is_openbsd = $^O =~ m/openbsd/ ? \&TRUE : \&FALSE unless defined &is_openbsd;
*is_freebsd = $^O =~ m/freebsd/ ? \&TRUE : \&FALSE unless defined &is_freebsd;
*is_bitrig = $^O =~ m/bitrig/ ? \&TRUE : \&FALSE unless defined &is_bitrig;
}
sub _perldoc_elem {
my($self, $name) = splice @_,0,2;
if(@_) {
$self->{$name} = $_[0];
} else {
$self->{$name};
}
}
sub debugging {
my( $self, @messages ) = @_;
( defined(&Pod::Perldoc::DEBUG) and &Pod::Perldoc::DEBUG() )
}
sub debug {
my( $self, @messages ) = @_;
return unless $self->debugging;
print STDERR map { "DEBUG $_" } @messages;
}
sub warn {
my( $self, @messages ) = @_;
carp join "\n", @messages, '';
}
sub die {
my( $self, @messages ) = @_;
croak join "\n", @messages, '';
}
sub _get_path_components {
my( $self ) = @_;
my @paths = split /\Q$Config{path_sep}/, $ENV{PATH};
return @paths;
}
sub _find_executable_in_path {
my( $self, $program ) = @_;
my @found = ();
foreach my $dir ( $self->_get_path_components ) {
my $binary = catfile( $dir, $program );
$self->debug( "Looking for $binary\n" );
next unless -e $binary;
unless( -x $binary ) {
$self->warn( "Found $binary but it's not executable. Skipping.\n" );
next;
}
$self->debug( "Found $binary\n" );
push @found, $binary;
}
return @found;
}
1;
__END__
=head1 NAME
Pod::Perldoc::BaseTo - Base for Pod::Perldoc formatters
=head1 SYNOPSIS
package Pod::Perldoc::ToMyFormat;
use parent qw( Pod::Perldoc::BaseTo );
...
=head1 DESCRIPTION
This package is meant as a base of Pod::Perldoc formatters,
like L<Pod::Perldoc::ToText>, L<Pod::Perldoc::ToMan>, etc.
It provides default implementations for the methods
is_pageable
write_with_binmode
output_extension
_perldoc_elem
The concrete formatter must implement
new
parse_from_file
=head1 SEE ALSO
L<perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002-2007 Sean M. Burke.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToText.pm 0000644 00000004332 15051135563 0007727 0 ustar 00 package Pod::Perldoc::ToText;
use strict;
use warnings;
use vars qw($VERSION);
$VERSION = '3.28';
use parent qw(Pod::Perldoc::BaseTo);
sub is_pageable { 1 }
sub write_with_binmode { 0 }
sub output_extension { 'txt' }
use Pod::Text ();
sub alt { shift->_perldoc_elem('alt' , @_) }
sub indent { shift->_perldoc_elem('indent' , @_) }
sub loose { shift->_perldoc_elem('loose' , @_) }
sub quotes { shift->_perldoc_elem('quotes' , @_) }
sub sentence { shift->_perldoc_elem('sentence', @_) }
sub width { shift->_perldoc_elem('width' , @_) }
sub new { return bless {}, ref($_[0]) || $_[0] }
sub parse_from_file {
my $self = shift;
my @options =
map {; $_, $self->{$_} }
grep !m/^_/s,
keys %$self
;
defined(&Pod::Perldoc::DEBUG)
and Pod::Perldoc::DEBUG()
and print "About to call new Pod::Text ",
$Pod::Text::VERSION ? "(v$Pod::Text::VERSION) " : '',
"with options: ",
@options ? "[@options]" : "(nil)", "\n";
;
Pod::Text->new(@options)->parse_from_file(@_);
}
1;
=head1 NAME
Pod::Perldoc::ToText - let Perldoc render Pod as plaintext
=head1 SYNOPSIS
perldoc -o text Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Text as a formatter class.
It supports the following options, which are explained in
L<Pod::Text>: alt, indent, loose, quotes, sentence, width
For example:
perldoc -o text -w indent:5 Some::Modulename
=head1 CAVEAT
This module may change to use a different text formatter class in the
future, and this may change what options are supported.
=head1 SEE ALSO
L<Pod::Text>, L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002 Sean M. Burke. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToTk.pm 0000644 00000007640 15051135563 0007366 0 ustar 00 package Pod::Perldoc::ToTk;
use strict;
use warnings;
use vars qw($VERSION);
$VERSION = '3.28';
use parent qw(Pod::Perldoc::BaseTo);
sub is_pageable { 1 }
sub write_with_binmode { 0 }
sub output_extension { 'txt' } # doesn't matter
sub if_zero_length { } # because it will be 0-length!
sub new { return bless {}, ref($_[0]) || $_[0] }
# TODO: document these and their meanings...
sub tree { shift->_perldoc_elem('tree' , @_) }
sub tk_opt { shift->_perldoc_elem('tk_opt' , @_) }
sub forky { shift->_perldoc_elem('forky' , @_) }
use Pod::Perldoc ();
use File::Spec::Functions qw(catfile);
BEGIN{ # Tk is not core, but this is
eval { require Tk } ||
__PACKAGE__->die( <<"HERE" );
You must have the Tk module to use Pod::Perldoc::ToTk.
If you have it installed, ensure it's in your Perl library
path.
HERE
__PACKAGE__->die(
__PACKAGE__,
" doesn't work nice with Tk.pm version $Tk::VERSION"
) if $Tk::VERSION eq '800.003';
}
BEGIN { eval { require Tk::FcyEntry; }; };
BEGIN{ # Tk::Pod is not core, but this is
eval { require Tk::Pod } ||
__PACKAGE__->die( <<"HERE" );
You must have the Tk::Pod module to use Pod::Perldoc::ToTk.
If you have it installed, ensure it's in your Perl library
path.
HERE
}
# The following was adapted from "tkpod" in the Tk-Pod dist.
sub parse_from_file {
my($self, $Input_File) = @_;
if($self->{'forky'}) {
return if fork; # i.e., parent process returns
}
$Input_File =~ s{\\}{/}g
if $self->is_mswin32 or $self->is_dos
# and maybe OS/2
;
my($tk_opt, $tree);
$tree = $self->{'tree' };
$tk_opt = $self->{'tk_opt'};
#require Tk::ErrorDialog;
# Add 'Tk' subdirectories to search path so, e.g.,
# 'Scrolled' will find doc in 'Tk/Scrolled'
if( $tk_opt ) {
push @INC, grep -d $_, map catfile($_,'Tk'), @INC;
}
my $mw = MainWindow->new();
#eval 'use blib "/home/e/eserte/src/perl/Tk-App";require Tk::App::Debug';
$mw->withdraw;
# CDE use Font Settings if available
my $ufont = $mw->optionGet('userFont','UserFont'); # fixed width
my $sfont = $mw->optionGet('systemFont','SystemFont'); # proportional
if (defined($ufont) and defined($sfont)) {
foreach ($ufont, $sfont) { s/:$//; };
$mw->optionAdd('*Font', $sfont);
$mw->optionAdd('*Entry.Font', $ufont);
$mw->optionAdd('*Text.Font', $ufont);
}
$mw->optionAdd('*Menu.tearOff', $Tk::platform ne 'MSWin32' ? 1 : 0);
$mw->Pod(
'-file' => $Input_File,
(($Tk::Pod::VERSION >= 4) ? ('-tree' => $tree) : ())
)->focusNext;
# xxx dirty but it works. A simple $mw->destroy if $mw->children
# does not work because Tk::ErrorDialogs could be created.
# (they are withdrawn after Ok instead of destory'ed I guess)
if ($mw->children) {
$mw->repeat(1000, sub {
# ErrorDialog is withdrawn not deleted :-(
foreach ($mw->children) {
return if "$_" =~ /^Tk::Pod/ # ->isa('Tk::Pod')
}
$mw->destroy;
});
} else {
$mw->destroy;
}
#$mw->WidgetDump;
MainLoop();
exit if $self->{'forky'}; # we were the child! so exit now!
return;
}
1;
__END__
=head1 NAME
Pod::Perldoc::ToTk - let Perldoc use Tk::Pod to render Pod
=head1 SYNOPSIS
perldoc -o tk Some::Modulename &
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Tk::Pod as a formatter class.
You have to have installed Tk::Pod first, or this class won't load.
=head1 SEE ALSO
L<Tk::Pod>, L<Pod::Perldoc>
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>;
Sean M. Burke C<< <sburke@cpan.org> >>;
significant portions copied from
F<tkpod> in the Tk::Pod dist, by Nick Ing-Simmons, Slaven Rezic, et al.
=cut
Perldoc/ToTerm.pm 0000644 00000007350 15051135563 0007715 0 ustar 00 package Pod::Perldoc::ToTerm;
use strict;
use warnings;
use vars qw($VERSION);
$VERSION = '3.28';
use parent qw(Pod::Perldoc::BaseTo);
sub is_pageable { 1 }
sub write_with_binmode { 0 }
sub output_extension { 'txt' }
use Pod::Text::Termcap ();
sub alt { shift->_perldoc_elem('alt' , @_) }
sub indent { shift->_perldoc_elem('indent' , @_) }
sub loose { shift->_perldoc_elem('loose' , @_) }
sub quotes { shift->_perldoc_elem('quotes' , @_) }
sub sentence { shift->_perldoc_elem('sentence', @_) }
sub width {
my $self = shift;
$self->_perldoc_elem('width' , @_) ||
$self->_get_columns_from_manwidth ||
$self->_get_columns_from_stty ||
$self->_get_default_width;
}
sub pager_configuration {
my($self, $pager, $perldoc) = @_;
# do not modify anything on Windows or DOS
return if ( $perldoc->is_mswin32 || $perldoc->is_dos );
if ( $pager =~ /less/ ) {
$self->_maybe_modify_environment('LESS');
}
elsif ( $pager =~ /more/ ) {
$self->_maybe_modify_environment('MORE');
}
return;
}
sub _maybe_modify_environment {
my($self, $name) = @_;
if ( ! defined $ENV{$name} ) {
$ENV{$name} = "-R";
}
# if the environment is set, don't modify
# anything
}
sub _get_stty { `stty -a` }
sub _get_columns_from_stty {
my $output = $_[0]->_get_stty;
if( $output =~ /\bcolumns\s+(\d+)/ ) { return $1; }
elsif( $output =~ /;\s*(\d+)\s+columns;/ ) { return $1; }
else { return 0 }
}
sub _get_columns_from_manwidth {
my( $self ) = @_;
return 0 unless defined $ENV{MANWIDTH};
unless( $ENV{MANWIDTH} =~ m/\A\d+\z/ ) {
$self->warn( "Ignoring non-numeric MANWIDTH ($ENV{MANWIDTH})\n" );
return 0;
}
if( $ENV{MANWIDTH} == 0 ) {
$self->warn( "Ignoring MANWIDTH of 0. Really? Why even run the program? :)\n" );
return 0;
}
if( $ENV{MANWIDTH} =~ m/\A(\d+)\z/ ) { return $1 }
return 0;
}
sub _get_default_width {
76
}
sub new { return bless {}, ref($_[0]) || $_[0] }
sub parse_from_file {
my $self = shift;
$self->{width} = $self->width();
my @options =
map {; $_, $self->{$_} }
grep !m/^_/s,
keys %$self
;
defined(&Pod::Perldoc::DEBUG)
and Pod::Perldoc::DEBUG()
and print "About to call new Pod::Text::Termcap ",
$Pod::Text::VERSION ? "(v$Pod::Text::Termcap::VERSION) " : '',
"with options: ",
@options ? "[@options]" : "(nil)", "\n";
;
Pod::Text::Termcap->new(@options)->parse_from_file(@_);
}
1;
=head1 NAME
Pod::Perldoc::ToTerm - render Pod with terminal escapes
=head1 SYNOPSIS
perldoc -o term Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Text as a formatter class.
It supports the following options, which are explained in
L<Pod::Text>: alt, indent, loose, quotes, sentence, width
For example:
perldoc -o term -w indent:5 Some::Modulename
=head1 PAGER FORMATTING
Depending on the platform, and because this class emits terminal escapes it
will attempt to set the C<-R> flag on your pager by injecting the flag into
your environment variable for C<less> or C<more>.
On Windows and DOS, this class will not modify any environment variables.
=head1 CAVEAT
This module may change to use a different text formatter class in the
future, and this may change what options are supported.
=head1 SEE ALSO
L<Pod::Text>, L<Pod::Text::Termcap>, L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2017 Mark Allen.
This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
=head1 AUTHOR
Mark Allen C<< <mallen@cpan.org> >>
=cut
Perldoc/ToMan.pm 0000644 00000033650 15051135563 0007523 0 ustar 00 require 5.006;
package Pod::Perldoc::ToMan;
use strict;
use warnings;
use parent qw(Pod::Perldoc::BaseTo);
use vars qw($VERSION);
$VERSION = '3.28';
use File::Spec::Functions qw(catfile);
use Pod::Man 2.18;
# This class is unlike ToText.pm et al, because we're NOT paging thru
# the output in our particular format -- we make the output and
# then we run nroff (or whatever) on it, and then page thru the
# (plaintext) output of THAT!
sub SUCCESS () { 1 }
sub FAILED () { 0 }
sub is_pageable { 1 }
sub write_with_binmode { 0 }
sub output_extension { 'txt' }
sub __filter_nroff { shift->_perldoc_elem('__filter_nroff' , @_) }
sub __nroffer { shift->_perldoc_elem('__nroffer' , @_) }
sub __bindir { shift->_perldoc_elem('__bindir' , @_) }
sub __pod2man { shift->_perldoc_elem('__pod2man' , @_) }
sub __output_file { shift->_perldoc_elem('__output_file' , @_) }
sub center { shift->_perldoc_elem('center' , @_) }
sub date { shift->_perldoc_elem('date' , @_) }
sub fixed { shift->_perldoc_elem('fixed' , @_) }
sub fixedbold { shift->_perldoc_elem('fixedbold' , @_) }
sub fixeditalic { shift->_perldoc_elem('fixeditalic' , @_) }
sub fixedbolditalic { shift->_perldoc_elem('fixedbolditalic', @_) }
sub name { shift->_perldoc_elem('name' , @_) }
sub quotes { shift->_perldoc_elem('quotes' , @_) }
sub release { shift->_perldoc_elem('release' , @_) }
sub section { shift->_perldoc_elem('section' , @_) }
sub new {
my( $either ) = shift;
my $self = bless {}, ref($either) || $either;
$self->init( @_ );
return $self;
}
sub init {
my( $self, @args ) = @_;
unless( $self->__nroffer ) {
my $roffer = $self->_find_roffer( $self->_roffer_candidates );
$self->debug( "Using $roffer\n" );
$self->__nroffer( $roffer );
}
else {
$self->debug( "__nroffer is " . $self->__nroffer() . "\n" );
}
$self->_check_nroffer;
}
sub _roffer_candidates {
my( $self ) = @_;
if( $self->is_openbsd || $self->is_freebsd || $self->is_bitrig ) { qw( mandoc groff nroff ) }
else { qw( groff nroff mandoc ) }
}
sub _find_roffer {
my( $self, @candidates ) = @_;
my @found = ();
foreach my $candidate ( @candidates ) {
push @found, $self->_find_executable_in_path( $candidate );
}
return wantarray ? @found : $found[0];
}
sub _check_nroffer {
return 1;
# where is it in the PATH?
# is it executable?
# what is its real name?
# what is its version?
# does it support the flags we need?
# is it good enough for us?
}
sub _get_stty { `stty -a` }
sub _get_columns_from_stty {
my $output = $_[0]->_get_stty;
if( $output =~ /\bcolumns\s+(\d+)/ ) { return $1 }
elsif( $output =~ /;\s*(\d+)\s+columns;/ ) { return $1 }
else { return 0 }
}
sub _get_columns_from_manwidth {
my( $self ) = @_;
return 0 unless defined $ENV{MANWIDTH};
unless( $ENV{MANWIDTH} =~ m/\A\d+\z/ ) {
$self->warn( "Ignoring non-numeric MANWIDTH ($ENV{MANWIDTH})\n" );
return 0;
}
if( $ENV{MANWIDTH} == 0 ) {
$self->warn( "Ignoring MANWIDTH of 0. Really? Why even run the program? :)\n" );
return 0;
}
if( $ENV{MANWIDTH} =~ m/\A(\d+)\z/ ) { return $1 }
return 0;
}
sub _get_default_width {
73
}
sub _get_columns {
$_[0]->_get_columns_from_manwidth ||
$_[0]->_get_columns_from_stty ||
$_[0]->_get_default_width;
}
sub _get_podman_switches {
my( $self ) = @_;
my @switches = map { $_, $self->{$_} } grep !m/^_/s, keys %$self;
# There needs to be a cleaner way to handle setting
# the UTF-8 flag, but for now, comment out this
# line because it often does the wrong thing.
#
# See RT #77465
#
#push @switches, 'utf8' => 1;
$self->debug( "Pod::Man switches are [@switches]\n" );
return @switches;
}
sub _parse_with_pod_man {
my( $self, $file ) = @_;
#->output_fh and ->output_string from Pod::Simple aren't
# working, apparently, so there's this ugly hack:
local *STDOUT;
open STDOUT, '>', $self->{_text_ref};
my $parser = Pod::Man->new( $self->_get_podman_switches );
$self->debug( "Parsing $file\n" );
$parser->parse_from_file( $file );
$self->debug( "Done parsing $file\n" );
close STDOUT;
$self->die( "No output from Pod::Man!\n" )
unless length $self->{_text_ref};
$self->_save_pod_man_output if $self->debugging;
return SUCCESS;
}
sub _save_pod_man_output {
my( $self, $fh ) = @_;
$fh = do {
my $file = "podman.out.$$.txt";
$self->debug( "Writing $file with Pod::Man output\n" );
open my $fh2, '>', $file;
$fh2;
} unless $fh;
print { $fh } ${ $self->{_text_ref} };
}
sub _have_groff_with_utf8 {
my( $self ) = @_;
return 0 unless $self->_is_groff;
my $roffer = $self->__nroffer;
my $minimum_groff_version = '1.20.1';
my $version_string = `$roffer -v`;
my( $version ) = $version_string =~ /\(?groff\)? version (\d+\.\d+(?:\.\d+)?)/;
$self->debug( "Found groff $version\n" );
# is a string comparison good enough?
if( $version lt $minimum_groff_version ) {
$self->warn(
"You have an old groff." .
" Update to version $minimum_groff_version for good Unicode support.\n" .
"If you don't upgrade, wide characters may come out oddly.\n"
);
}
$version ge $minimum_groff_version;
}
sub _have_mandoc_with_utf8 {
my( $self ) = @_;
$self->_is_mandoc and not system 'mandoc -Tlocale -V > /dev/null 2>&1';
}
sub _collect_nroff_switches {
my( $self ) = shift;
my @render_switches = ('-man', $self->_get_device_switches);
# Thanks to Brendan O'Dea for contributing the following block
if( $self->_is_roff and -t STDOUT and my ($cols) = $self->_get_columns ) {
my $c = $cols * 39 / 40;
$cols = $c > $cols - 2 ? $c : $cols -2;
push @render_switches, '-rLL=' . (int $c) . 'n' if $cols > 80;
}
# I hear persistent reports that adding a -c switch to $render
# solves many people's problems. But I also hear that some mans
# don't have a -c switch, so that unconditionally adding it here
# would presumably be a Bad Thing -- sburke@cpan.org
push @render_switches, '-c' if( $self->_is_roff and $self->is_cygwin );
return @render_switches;
}
sub _get_device_switches {
my( $self ) = @_;
if( $self->_is_nroff ) { qw() }
elsif( $self->_have_groff_with_utf8 ) { qw(-Kutf8 -Tutf8) }
elsif( $self->_is_ebcdic ) { qw(-Tcp1047) }
elsif( $self->_have_mandoc_with_utf8 ) { qw(-Tlocale) }
elsif( $self->_is_mandoc ) { qw() }
else { qw(-Tlatin1) }
}
sub _is_roff {
my( $self ) = @_;
$self->_is_nroff or $self->_is_groff;
}
sub _is_nroff {
my( $self ) = @_;
$self->__nroffer =~ /\bnroff\b/;
}
sub _is_groff {
my( $self ) = @_;
$self->__nroffer =~ /\bgroff\b/;
}
sub _is_mandoc {
my ( $self ) = @_;
$self->__nroffer =~ /\bmandoc\b/;
}
sub _is_ebcdic {
my( $self ) = @_;
return 0;
}
sub _filter_through_nroff {
my( $self ) = shift;
$self->debug( "Filtering through " . $self->__nroffer() . "\n" );
# Maybe someone set rendering switches as part of the opt_n value
# Deal with that here.
my ($render, $switches) = $self->__nroffer() =~ /\A([\/a-zA-Z0-9_\.-]+)\b(.+)?\z/;
$self->die("no nroffer!?") unless $render;
my @render_switches = $self->_collect_nroff_switches;
if ( $switches ) {
# Eliminate whitespace
$switches =~ s/\s//g;
# Then separate the switches with a zero-width positive
# lookahead on the dash.
#
# See:
# http://www.effectiveperlprogramming.com/blog/1411
# for a good discussion of this technique
push @render_switches, split(/(?=-)/, $switches);
}
$self->debug( "render is $render\n" );
$self->debug( "render options are @render_switches\n" );
require Symbol;
require IPC::Open3;
require IO::Handle;
my $pid = IPC::Open3::open3(
my $writer,
my $reader,
my $err = Symbol::gensym(),
$render,
@render_switches
);
$reader->autoflush(1);
use IO::Select;
my $selector = IO::Select->new( $reader );
$self->debug( "Writing to pipe to $render\n" );
my $offset = 0;
my $chunk_size = 4096;
my $length = length( ${ $self->{_text_ref} } );
my $chunks = $length / $chunk_size;
my $done;
my $buffer;
while( $offset <= $length ) {
$self->debug( "Writing chunk $chunks\n" ); $chunks++;
syswrite $writer, ${ $self->{_text_ref} }, $chunk_size, $offset
or $self->die( $! );
$offset += $chunk_size;
$self->debug( "Checking read\n" );
READ: {
last READ unless $selector->can_read( 0.01 );
$self->debug( "Reading\n" );
my $bytes = sysread $reader, $buffer, 4096;
$self->debug( "Read $bytes bytes\n" );
$done .= $buffer;
$self->debug( sprintf "Output is %d bytes\n",
length $done
);
next READ;
}
}
close $writer;
$self->debug( "Done writing\n" );
# read any leftovers
$done .= do { local $/; <$reader> };
$self->debug( sprintf "Done reading. Output is %d bytes\n",
length $done
);
if( $? ) {
$self->warn( "Error from pipe to $render!\n" );
$self->debug( 'Error: ' . do { local $/; <$err> } );
}
close $reader;
if( my $err = $? ) {
$self->debug(
"Nonzero exit ($?) while running `$render @render_switches`.\n" .
"Falling back to Pod::Perldoc::ToPod\n"
);
return $self->_fallback_to_pod( @_ );
}
$self->debug( "Output:\n----\n$done\n----\n" );
${ $self->{_text_ref} } = $done;
return length ${ $self->{_text_ref} } ? SUCCESS : FAILED;
}
sub parse_from_file {
my( $self, $file, $outfh) = @_;
# We have a pipeline of filters each affecting the reference
# in $self->{_text_ref}
$self->{_text_ref} = \my $output;
$self->_parse_with_pod_man( $file );
# so far, nroff is an external command so we ensure it worked
my $result = $self->_filter_through_nroff;
return $self->_fallback_to_pod( @_ ) unless $result == SUCCESS;
$self->_post_nroff_processing;
print { $outfh } $output or
$self->die( "Can't print to $$self{__output_file}: $!" );
return;
}
sub _fallback_to_pod {
my( $self, @args ) = @_;
$self->warn( "Falling back to Pod because there was a problem!\n" );
require Pod::Perldoc::ToPod;
return Pod::Perldoc::ToPod->new->parse_from_file(@_);
}
# maybe there's a user setting we should check?
sub _get_tab_width { 4 }
sub _expand_tabs {
my( $self ) = @_;
my $tab_width = ' ' x $self->_get_tab_width;
${ $self->{_text_ref} } =~ s/\t/$tab_width/g;
}
sub _post_nroff_processing {
my( $self ) = @_;
if( $self->is_hpux ) {
$self->debug( "On HP-UX, I'm going to expand tabs for you\n" );
# this used to be a pipe to `col -x` for HP-UX
$self->_expand_tabs;
}
if( $self->{'__filter_nroff'} ) {
$self->debug( "filter_nroff is set, so filtering\n" );
$self->_remove_nroff_header;
$self->_remove_nroff_footer;
}
else {
$self->debug( "filter_nroff is not set, so not filtering\n" );
}
$self->_handle_unicode;
return 1;
}
# I don't think this does anything since there aren't two consecutive
# newlines in the Pod::Man output
sub _remove_nroff_header {
my( $self ) = @_;
$self->debug( "_remove_nroff_header is still a stub!\n" );
return 1;
# my @data = split /\n{2,}/, shift;
# shift @data while @data and $data[0] !~ /\S/; # Go to header
# shift @data if @data and $data[0] =~ /Contributed\s+Perl/; # Skip header
}
# I don't think this does anything since there aren't two consecutive
# newlines in the Pod::Man output
sub _remove_nroff_footer {
my( $self ) = @_;
$self->debug( "_remove_nroff_footer is still a stub!\n" );
return 1;
${ $self->{_text_ref} } =~ s/\n\n+.*\w.*\Z//m;
# my @data = split /\n{2,}/, shift;
# pop @data if @data and $data[-1] =~ /^\w/; # Skip footer, like
# 28/Jan/99 perl 5.005, patch 53 1
}
sub _unicode_already_handled {
my( $self ) = @_;
$self->_have_groff_with_utf8 ||
1 # so, we don't have a case that needs _handle_unicode
;
}
sub _handle_unicode {
# this is the job of preconv
# we don't need this with groff 1.20 and later.
my( $self ) = @_;
return 1 if $self->_unicode_already_handled;
require Encode;
# it's UTF-8 here, but we need character data
my $text = Encode::decode( 'UTF-8', ${ $self->{_text_ref} } ) ;
# http://www.mail-archive.com/groff@gnu.org/msg01378.html
# http://linux.die.net/man/7/groff_char
# http://www.gnu.org/software/groff/manual/html_node/Using-Symbols.html
# http://lists.gnu.org/archive/html/groff/2011-05/msg00007.html
# http://www.simplicidade.org/notes/archives/2009/05/fixing_the_pod.html
# http://lists.freebsd.org/pipermail/freebsd-questions/2011-July/232239.html
$text =~ s/(\P{ASCII})/
sprintf '\\[u%04X]', ord $1
/eg;
# should we encode?
${ $self->{_text_ref} } = $text;
}
1;
__END__
=head1 NAME
Pod::Perldoc::ToMan - let Perldoc render Pod as man pages
=head1 SYNOPSIS
perldoc -o man Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Man and C<groff> for reading Pod pages.
The following options are supported: center, date, fixed, fixedbold,
fixeditalic, fixedbolditalic, quotes, release, section
(Those options are explained in L<Pod::Man>.)
For example:
perldoc -o man -w center:Pod Some::Modulename
=head1 CAVEAT
This module may change to use a different pod-to-nroff formatter class
in the future, and this may change what options are supported.
=head1 SEE ALSO
L<Pod::Man>, L<Pod::Perldoc>, L<Pod::Perldoc::ToNroff>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2011 brian d foy. All rights reserved.
Copyright (c) 2002,3,4 Sean M. Burke. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToANSI.pm 0000644 00000004377 15051135563 0007546 0 ustar 00 package Pod::Perldoc::ToANSI;
use strict;
use warnings;
use parent qw(Pod::Perldoc::BaseTo);
use vars qw($VERSION);
$VERSION = '3.28';
sub is_pageable { 1 }
sub write_with_binmode { 0 }
sub output_extension { 'txt' }
use Pod::Text::Color ();
sub alt { shift->_perldoc_elem('alt' , @_) }
sub indent { shift->_perldoc_elem('indent' , @_) }
sub loose { shift->_perldoc_elem('loose' , @_) }
sub quotes { shift->_perldoc_elem('quotes' , @_) }
sub sentence { shift->_perldoc_elem('sentence', @_) }
sub width { shift->_perldoc_elem('width' , @_) }
sub new { return bless {}, ref($_[0]) || $_[0] }
sub parse_from_file {
my $self = shift;
my @options =
map {; $_, $self->{$_} }
grep !m/^_/s,
keys %$self
;
defined(&Pod::Perldoc::DEBUG)
and Pod::Perldoc::DEBUG()
and print "About to call new Pod::Text::Color ",
$Pod::Text::VERSION ? "(v$Pod::Text::VERSION) " : '',
"with options: ",
@options ? "[@options]" : "(nil)", "\n";
;
Pod::Text::Color->new(@options)->parse_from_file(@_);
}
1;
=head1 NAME
Pod::Perldoc::ToANSI - render Pod with ANSI color escapes
=head1 SYNOPSIS
perldoc -o ansi Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Text as a formatter class.
It supports the following options, which are explained in
L<Pod::Text>: alt, indent, loose, quotes, sentence, width
For example:
perldoc -o term -w indent:5 Some::Modulename
=head1 CAVEAT
This module may change to use a different text formatter class in the
future, and this may change what options are supported.
=head1 SEE ALSO
L<Pod::Text>, L<Pod::Text::Color>, L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2011 Mark Allen. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToRtf.pm 0000644 00000004145 15051135563 0007540 0 ustar 00 package Pod::Perldoc::ToRtf;
use strict;
use warnings;
use parent qw( Pod::Simple::RTF );
use vars qw($VERSION);
$VERSION = '3.28';
sub is_pageable { 0 }
sub write_with_binmode { 0 }
sub output_extension { 'rtf' }
sub page_for_perldoc {
my($self, $tempfile, $perldoc) = @_;
return unless $perldoc->IS_MSWin32;
my $rtf_pager = $ENV{'RTFREADER'} || 'write.exe';
$perldoc->aside( "About to launch <\"$rtf_pager\" \"$tempfile\">\n" );
return 1 if system( qq{"$rtf_pager"}, qq{"$tempfile"} ) == 0;
return 0;
}
1;
__END__
=head1 NAME
Pod::Perldoc::ToRtf - let Perldoc render Pod as RTF
=head1 SYNOPSIS
perldoc -o rtf Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Simple::RTF as a formatter class.
This is actually a Pod::Simple::RTF subclass, and inherits
all its options.
You have to have Pod::Simple::RTF installed (from the Pod::Simple dist),
or this module won't work.
If Perldoc is running under MSWin and uses this class as a formatter,
the output will be opened with F<write.exe> or whatever program is
specified in the environment variable C<RTFREADER>. For example, to
specify that RTF files should be opened the same as they are when you
double-click them, you would do C<set RTFREADER=start.exe> in your
F<autoexec.bat>.
Handy tip: put C<set PERLDOC=-ortf> in your F<autoexec.bat>
and that will set this class as the default formatter to run when
you do C<perldoc whatever>.
=head1 SEE ALSO
L<Pod::Simple::RTF>, L<Pod::Simple>, L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002 Sean M. Burke. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Perldoc/ToXml.pm 0000644 00000002577 15051135563 0007554 0 ustar 00 package Pod::Perldoc::ToXml;
use strict;
use warnings;
use vars qw($VERSION);
use parent qw( Pod::Simple::XMLOutStream );
use vars qw($VERSION);
$VERSION = '3.28';
sub is_pageable { 0 }
sub write_with_binmode { 0 }
sub output_extension { 'xml' }
1;
__END__
=head1 NAME
Pod::Perldoc::ToXml - let Perldoc render Pod as XML
=head1 SYNOPSIS
perldoc -o xml -d out.xml Some::Modulename
=head1 DESCRIPTION
This is a "plug-in" class that allows Perldoc to use
Pod::Simple::XMLOutStream as a formatter class.
This is actually a Pod::Simple::XMLOutStream subclass, and inherits
all its options.
You have to have installed Pod::Simple::XMLOutStream (from the Pod::Simple
dist), or this class won't work.
=head1 SEE ALSO
L<Pod::Simple::XMLOutStream>, L<Pod::Simple>, L<Pod::Perldoc>
=head1 COPYRIGHT AND DISCLAIMERS
Copyright (c) 2002 Sean M. Burke. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
=head1 AUTHOR
Current maintainer: Mark Allen C<< <mallen@cpan.org> >>
Past contributions from:
brian d foy C<< <bdfoy@cpan.org> >>
Adriano R. Ferreira C<< <ferreira@cpan.org> >>,
Sean M. Burke C<< <sburke@cpan.org> >>
=cut
Text.pm 0000644 00000107145 15051135563 0006042 0 ustar 00 # Convert POD data to formatted text.
#
# This module converts POD to formatted text. It replaces the old Pod::Text
# module that came with versions of Perl prior to 5.6.0 and attempts to match
# its output except for some specific circumstances where other decisions
# seemed to produce better output. It uses Pod::Parser and is designed to be
# very easy to subclass.
#
# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl
##############################################################################
# Modules and declarations
##############################################################################
package Pod::Text;
use 5.006;
use strict;
use warnings;
use vars qw(@ISA @EXPORT %ESCAPES $VERSION);
use Carp qw(carp croak);
use Encode qw(encode);
use Exporter ();
use Pod::Simple ();
@ISA = qw(Pod::Simple Exporter);
# We have to export pod2text for backward compatibility.
@EXPORT = qw(pod2text);
$VERSION = '4.11';
# Ensure that $Pod::Simple::nbsp and $Pod::Simple::shy are available. Code
# taken from Pod::Simple 3.32, but was only added in 3.30.
my ($NBSP, $SHY);
if ($Pod::Simple::VERSION ge 3.30) {
$NBSP = $Pod::Simple::nbsp;
$SHY = $Pod::Simple::shy;
} else {
if ($] ge 5.007_003) {
$NBSP = chr utf8::unicode_to_native(0xA0);
$SHY = chr utf8::unicode_to_native(0xAD);
} elsif (Pod::Simple::ASCII) {
$NBSP = "\xA0";
$SHY = "\xAD";
} else {
$NBSP = "\x41";
$SHY = "\xCA";
}
}
##############################################################################
# Initialization
##############################################################################
# This function handles code blocks. It's registered as a callback to
# Pod::Simple and therefore doesn't work as a regular method call, but all it
# does is call output_code with the line.
sub handle_code {
my ($line, $number, $parser) = @_;
$parser->output_code ($line . "\n");
}
# Initialize the object and set various Pod::Simple options that we need.
# Here, we also process any additional options passed to the constructor or
# set up defaults if none were given. Note that all internal object keys are
# in all-caps, reserving all lower-case object keys for Pod::Simple and user
# arguments.
sub new {
my $class = shift;
my $self = $class->SUPER::new;
# Tell Pod::Simple to handle S<> by automatically inserting .
$self->nbsp_for_S (1);
# Tell Pod::Simple to keep whitespace whenever possible.
if ($self->can ('preserve_whitespace')) {
$self->preserve_whitespace (1);
} else {
$self->fullstop_space_harden (1);
}
# The =for and =begin targets that we accept.
$self->accept_targets (qw/text TEXT/);
# Ensure that contiguous blocks of code are merged together. Otherwise,
# some of the guesswork heuristics don't work right.
$self->merge_text (1);
# Pod::Simple doesn't do anything useful with our arguments, but we want
# to put them in our object as hash keys and values. This could cause
# problems if we ever clash with Pod::Simple's own internal class
# variables.
my %opts = @_;
my @opts = map { ("opt_$_", $opts{$_}) } keys %opts;
%$self = (%$self, @opts);
# Send errors to stderr if requested.
if ($$self{opt_stderr} and not $$self{opt_errors}) {
$$self{opt_errors} = 'stderr';
}
delete $$self{opt_stderr};
# Validate the errors parameter and act on it.
if (not defined $$self{opt_errors}) {
$$self{opt_errors} = 'pod';
}
if ($$self{opt_errors} eq 'stderr' || $$self{opt_errors} eq 'die') {
$self->no_errata_section (1);
$self->complain_stderr (1);
if ($$self{opt_errors} eq 'die') {
$$self{complain_die} = 1;
}
} elsif ($$self{opt_errors} eq 'pod') {
$self->no_errata_section (0);
$self->complain_stderr (0);
} elsif ($$self{opt_errors} eq 'none') {
$self->no_errata_section (1);
$self->no_whining (1);
} else {
croak (qq(Invalid errors setting: "$$self{errors}"));
}
delete $$self{errors};
# Initialize various things from our parameters.
$$self{opt_alt} = 0 unless defined $$self{opt_alt};
$$self{opt_indent} = 4 unless defined $$self{opt_indent};
$$self{opt_margin} = 0 unless defined $$self{opt_margin};
$$self{opt_loose} = 0 unless defined $$self{opt_loose};
$$self{opt_sentence} = 0 unless defined $$self{opt_sentence};
$$self{opt_width} = 76 unless defined $$self{opt_width};
# Figure out what quotes we'll be using for C<> text.
$$self{opt_quotes} ||= '"';
if ($$self{opt_quotes} eq 'none') {
$$self{LQUOTE} = $$self{RQUOTE} = '';
} elsif (length ($$self{opt_quotes}) == 1) {
$$self{LQUOTE} = $$self{RQUOTE} = $$self{opt_quotes};
} elsif (length ($$self{opt_quotes}) % 2 == 0) {
my $length = length ($$self{opt_quotes}) / 2;
$$self{LQUOTE} = substr ($$self{opt_quotes}, 0, $length);
$$self{RQUOTE} = substr ($$self{opt_quotes}, $length);
} else {
croak qq(Invalid quote specification "$$self{opt_quotes}");
}
# If requested, do something with the non-POD text.
$self->code_handler (\&handle_code) if $$self{opt_code};
# Return the created object.
return $self;
}
##############################################################################
# Core parsing
##############################################################################
# This is the glue that connects the code below with Pod::Simple itself. The
# goal is to convert the event stream coming from the POD parser into method
# calls to handlers once the complete content of a tag has been seen. Each
# paragraph or POD command will have textual content associated with it, and
# as soon as all of a paragraph or POD command has been seen, that content
# will be passed in to the corresponding method for handling that type of
# object. The exceptions are handlers for lists, which have opening tag
# handlers and closing tag handlers that will be called right away.
#
# The internal hash key PENDING is used to store the contents of a tag until
# all of it has been seen. It holds a stack of open tags, each one
# represented by a tuple of the attributes hash for the tag and the contents
# of the tag.
# Add a block of text to the contents of the current node, formatting it
# according to the current formatting instructions as we do.
sub _handle_text {
my ($self, $text) = @_;
my $tag = $$self{PENDING}[-1];
$$tag[1] .= $text;
}
# Given an element name, get the corresponding method name.
sub method_for_element {
my ($self, $element) = @_;
$element =~ tr/-/_/;
$element =~ tr/A-Z/a-z/;
$element =~ tr/_a-z0-9//cd;
return $element;
}
# Handle the start of a new element. If cmd_element is defined, assume that
# we need to collect the entire tree for this element before passing it to the
# element method, and create a new tree into which we'll collect blocks of
# text and nested elements. Otherwise, if start_element is defined, call it.
sub _handle_element_start {
my ($self, $element, $attrs) = @_;
my $method = $self->method_for_element ($element);
# If we have a command handler, we need to accumulate the contents of the
# tag before calling it.
if ($self->can ("cmd_$method")) {
push (@{ $$self{PENDING} }, [ $attrs, '' ]);
} elsif ($self->can ("start_$method")) {
my $method = 'start_' . $method;
$self->$method ($attrs, '');
}
}
# Handle the end of an element. If we had a cmd_ method for this element,
# this is where we pass along the text that we've accumulated. Otherwise, if
# we have an end_ method for the element, call that.
sub _handle_element_end {
my ($self, $element) = @_;
my $method = $self->method_for_element ($element);
# If we have a command handler, pull off the pending text and pass it to
# the handler along with the saved attribute hash.
if ($self->can ("cmd_$method")) {
my $tag = pop @{ $$self{PENDING} };
my $method = 'cmd_' . $method;
my $text = $self->$method (@$tag);
if (defined $text) {
if (@{ $$self{PENDING} } > 1) {
$$self{PENDING}[-1][1] .= $text;
} else {
$self->output ($text);
}
}
} elsif ($self->can ("end_$method")) {
my $method = 'end_' . $method;
$self->$method ();
}
}
##############################################################################
# Output formatting
##############################################################################
# Wrap a line, indenting by the current left margin. We can't use Text::Wrap
# because it plays games with tabs. We can't use formline, even though we'd
# really like to, because it screws up non-printing characters. So we have to
# do the wrapping ourselves.
sub wrap {
my $self = shift;
local $_ = shift;
my $output = '';
my $spaces = ' ' x $$self{MARGIN};
my $width = $$self{opt_width} - $$self{MARGIN};
while (length > $width) {
if (s/^([^\n]{0,$width})\s+// || s/^([^\n]{$width})//) {
$output .= $spaces . $1 . "\n";
} else {
last;
}
}
$output .= $spaces . $_;
$output =~ s/\s+$/\n\n/;
return $output;
}
# Reformat a paragraph of text for the current margin. Takes the text to
# reformat and returns the formatted text.
sub reformat {
my $self = shift;
local $_ = shift;
# If we're trying to preserve two spaces after sentences, do some munging
# to support that. Otherwise, smash all repeated whitespace.
if ($$self{opt_sentence}) {
s/ +$//mg;
s/\.\n/. \n/g;
s/\n/ /g;
s/ +/ /g;
} else {
s/\s+/ /g;
}
return $self->wrap ($_);
}
# Output text to the output device. Replace non-breaking spaces with spaces
# and soft hyphens with nothing, and then try to fix the output encoding if
# necessary to match the input encoding unless UTF-8 output is forced. This
# preserves the traditional pass-through behavior of Pod::Text.
sub output {
my ($self, @text) = @_;
my $text = join ('', @text);
if ($NBSP) {
$text =~ s/$NBSP/ /g;
}
if ($SHY) {
$text =~ s/$SHY//g;
}
unless ($$self{opt_utf8}) {
my $encoding = $$self{encoding} || '';
if ($encoding && $encoding ne $$self{ENCODING}) {
$$self{ENCODING} = $encoding;
eval { binmode ($$self{output_fh}, ":encoding($encoding)") };
}
}
if ($$self{ENCODE}) {
print { $$self{output_fh} } encode ('UTF-8', $text);
} else {
print { $$self{output_fh} } $text;
}
}
# Output a block of code (something that isn't part of the POD text). Called
# by preprocess_paragraph only if we were given the code option. Exists here
# only so that it can be overridden by subclasses.
sub output_code { $_[0]->output ($_[1]) }
##############################################################################
# Document initialization
##############################################################################
# Set up various things that have to be initialized on a per-document basis.
sub start_document {
my ($self, $attrs) = @_;
if ($$attrs{contentless} && !$$self{ALWAYS_EMIT_SOMETHING}) {
$$self{CONTENTLESS} = 1;
} else {
delete $$self{CONTENTLESS};
}
my $margin = $$self{opt_indent} + $$self{opt_margin};
# Initialize a few per-document variables.
$$self{INDENTS} = []; # Stack of indentations.
$$self{MARGIN} = $margin; # Default left margin.
$$self{PENDING} = [[]]; # Pending output.
# We have to redo encoding handling for each document.
$$self{ENCODING} = '';
# When UTF-8 output is set, check whether our output file handle already
# has a PerlIO encoding layer set. If it does not, we'll need to encode
# our output before printing it (handled in the output() sub). Wrap the
# check in an eval to handle versions of Perl without PerlIO.
$$self{ENCODE} = 0;
if ($$self{opt_utf8}) {
$$self{ENCODE} = 1;
eval {
my @options = (output => 1, details => 1);
my $flag = (PerlIO::get_layers ($$self{output_fh}, @options))[-1];
if ($flag & PerlIO::F_UTF8 ()) {
$$self{ENCODE} = 0;
$$self{ENCODING} = 'UTF-8';
}
};
}
return '';
}
# Handle the end of the document. The only thing we do is handle dying on POD
# errors, since Pod::Parser currently doesn't.
sub end_document {
my ($self) = @_;
if ($$self{complain_die} && $self->errors_seen) {
croak ("POD document had syntax errors");
}
}
##############################################################################
# Text blocks
##############################################################################
# Intended for subclasses to override, this method returns text with any
# non-printing formatting codes stripped out so that length() correctly
# returns the length of the text. For basic Pod::Text, it does nothing.
sub strip_format {
my ($self, $string) = @_;
return $string;
}
# This method is called whenever an =item command is complete (in other words,
# we've seen its associated paragraph or know for certain that it doesn't have
# one). It gets the paragraph associated with the item as an argument. If
# that argument is empty, just output the item tag; if it contains a newline,
# output the item tag followed by the newline. Otherwise, see if there's
# enough room for us to output the item tag in the margin of the text or if we
# have to put it on a separate line.
sub item {
my ($self, $text) = @_;
my $tag = $$self{ITEM};
unless (defined $tag) {
carp "Item called without tag";
return;
}
undef $$self{ITEM};
# Calculate the indentation and margin. $fits is set to true if the tag
# will fit into the margin of the paragraph given our indentation level.
my $indent = $$self{INDENTS}[-1];
$indent = $$self{opt_indent} unless defined $indent;
my $margin = ' ' x $$self{opt_margin};
my $tag_length = length ($self->strip_format ($tag));
my $fits = ($$self{MARGIN} - $indent >= $tag_length + 1);
# If the tag doesn't fit, or if we have no associated text, print out the
# tag separately. Otherwise, put the tag in the margin of the paragraph.
if (!$text || $text =~ /^\s+$/ || !$fits) {
my $realindent = $$self{MARGIN};
$$self{MARGIN} = $indent;
my $output = $self->reformat ($tag);
$output =~ s/^$margin /$margin:/ if ($$self{opt_alt} && $indent > 0);
$output =~ s/\n*$/\n/;
# If the text is just whitespace, we have an empty item paragraph;
# this can result from =over/=item/=back without any intermixed
# paragraphs. Insert some whitespace to keep the =item from merging
# into the next paragraph.
$output .= "\n" if $text && $text =~ /^\s*$/;
$self->output ($output);
$$self{MARGIN} = $realindent;
$self->output ($self->reformat ($text)) if ($text && $text =~ /\S/);
} else {
my $space = ' ' x $indent;
$space =~ s/^$margin /$margin:/ if $$self{opt_alt};
$text = $self->reformat ($text);
$text =~ s/^$margin /$margin:/ if ($$self{opt_alt} && $indent > 0);
my $tagspace = ' ' x $tag_length;
$text =~ s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item";
$self->output ($text);
}
}
# Handle a basic block of text. The only tricky thing here is that if there
# is a pending item tag, we need to format this as an item paragraph.
sub cmd_para {
my ($self, $attrs, $text) = @_;
$text =~ s/\s+$/\n/;
if (defined $$self{ITEM}) {
$self->item ($text . "\n");
} else {
$self->output ($self->reformat ($text . "\n"));
}
return '';
}
# Handle a verbatim paragraph. Just print it out, but indent it according to
# our margin.
sub cmd_verbatim {
my ($self, $attrs, $text) = @_;
$self->item if defined $$self{ITEM};
return if $text =~ /^\s*$/;
$text =~ s/^(\n*)([ \t]*\S+)/$1 . (' ' x $$self{MARGIN}) . $2/gme;
$text =~ s/\s*$/\n\n/;
$self->output ($text);
return '';
}
# Handle literal text (produced by =for and similar constructs). Just output
# it with the minimum of changes.
sub cmd_data {
my ($self, $attrs, $text) = @_;
$text =~ s/^\n+//;
$text =~ s/\n{0,2}$/\n/;
$self->output ($text);
return '';
}
##############################################################################
# Headings
##############################################################################
# The common code for handling all headers. Takes the header text, the
# indentation, and the surrounding marker for the alt formatting method.
sub heading {
my ($self, $text, $indent, $marker) = @_;
$self->item ("\n\n") if defined $$self{ITEM};
$text =~ s/\s+$//;
if ($$self{opt_alt}) {
my $closemark = reverse (split (//, $marker));
my $margin = ' ' x $$self{opt_margin};
$self->output ("\n" . "$margin$marker $text $closemark" . "\n\n");
} else {
$text .= "\n" if $$self{opt_loose};
my $margin = ' ' x ($$self{opt_margin} + $indent);
$self->output ($margin . $text . "\n");
}
return '';
}
# First level heading.
sub cmd_head1 {
my ($self, $attrs, $text) = @_;
$self->heading ($text, 0, '====');
}
# Second level heading.
sub cmd_head2 {
my ($self, $attrs, $text) = @_;
$self->heading ($text, $$self{opt_indent} / 2, '== ');
}
# Third level heading.
sub cmd_head3 {
my ($self, $attrs, $text) = @_;
$self->heading ($text, $$self{opt_indent} * 2 / 3 + 0.5, '= ');
}
# Fourth level heading.
sub cmd_head4 {
my ($self, $attrs, $text) = @_;
$self->heading ($text, $$self{opt_indent} * 3 / 4 + 0.5, '- ');
}
##############################################################################
# List handling
##############################################################################
# Handle the beginning of an =over block. Takes the type of the block as the
# first argument, and then the attr hash. This is called by the handlers for
# the four different types of lists (bullet, number, text, and block).
sub over_common_start {
my ($self, $attrs) = @_;
$self->item ("\n\n") if defined $$self{ITEM};
# Find the indentation level.
my $indent = $$attrs{indent};
unless (defined ($indent) && $indent =~ /^\s*[-+]?\d{1,4}\s*$/) {
$indent = $$self{opt_indent};
}
# Add this to our stack of indents and increase our current margin.
push (@{ $$self{INDENTS} }, $$self{MARGIN});
$$self{MARGIN} += ($indent + 0);
return '';
}
# End an =over block. Takes no options other than the class pointer. Output
# any pending items and then pop one level of indentation.
sub over_common_end {
my ($self) = @_;
$self->item ("\n\n") if defined $$self{ITEM};
$$self{MARGIN} = pop @{ $$self{INDENTS} };
return '';
}
# Dispatch the start and end calls as appropriate.
sub start_over_bullet { $_[0]->over_common_start ($_[1]) }
sub start_over_number { $_[0]->over_common_start ($_[1]) }
sub start_over_text { $_[0]->over_common_start ($_[1]) }
sub start_over_block { $_[0]->over_common_start ($_[1]) }
sub end_over_bullet { $_[0]->over_common_end }
sub end_over_number { $_[0]->over_common_end }
sub end_over_text { $_[0]->over_common_end }
sub end_over_block { $_[0]->over_common_end }
# The common handler for all item commands. Takes the type of the item, the
# attributes, and then the text of the item.
sub item_common {
my ($self, $type, $attrs, $text) = @_;
$self->item if defined $$self{ITEM};
# Clean up the text. We want to end up with two variables, one ($text)
# which contains any body text after taking out the item portion, and
# another ($item) which contains the actual item text. Note the use of
# the internal Pod::Simple attribute here; that's a potential land mine.
$text =~ s/\s+$//;
my ($item, $index);
if ($type eq 'bullet') {
$item = '*';
} elsif ($type eq 'number') {
$item = $$attrs{'~orig_content'};
} else {
$item = $text;
$item =~ s/\s*\n\s*/ /g;
$text = '';
}
$$self{ITEM} = $item;
# If body text for this item was included, go ahead and output that now.
if ($text) {
$text =~ s/\s*$/\n/;
$self->item ($text);
}
return '';
}
# Dispatch the item commands to the appropriate place.
sub cmd_item_bullet { my $self = shift; $self->item_common ('bullet', @_) }
sub cmd_item_number { my $self = shift; $self->item_common ('number', @_) }
sub cmd_item_text { my $self = shift; $self->item_common ('text', @_) }
sub cmd_item_block { my $self = shift; $self->item_common ('block', @_) }
##############################################################################
# Formatting codes
##############################################################################
# The simple ones.
sub cmd_b { return $_[0]{alt} ? "``$_[2]''" : $_[2] }
sub cmd_f { return $_[0]{alt} ? "\"$_[2]\"" : $_[2] }
sub cmd_i { return '*' . $_[2] . '*' }
sub cmd_x { return '' }
# Apply a whole bunch of messy heuristics to not quote things that don't
# benefit from being quoted. These originally come from Barrie Slaymaker and
# largely duplicate code in Pod::Man.
sub cmd_c {
my ($self, $attrs, $text) = @_;
# A regex that matches the portion of a variable reference that's the
# array or hash index, separated out just because we want to use it in
# several places in the following regex.
my $index = '(?: \[.*\] | \{.*\} )?';
# Check for things that we don't want to quote, and if we find any of
# them, return the string with just a font change and no quoting.
$text =~ m{
^\s*
(?:
( [\'\`\"] ) .* \1 # already quoted
| \` .* \' # `quoted'
| \$+ [\#^]? \S $index # special ($^Foo, $")
| [\$\@%&*]+ \#? [:\'\w]+ $index # plain var or func
| [\$\@%&*]* [:\'\w]+ (?: -> )? \(\s*[^\s,]\s*\) # 0/1-arg func call
| [+-]? ( \d[\d.]* | \.\d+ ) (?: [eE][+-]?\d+ )? # a number
| 0x [a-fA-F\d]+ # a hex constant
)
\s*\z
}xo && return $text;
# If we didn't return, go ahead and quote the text.
return $$self{opt_alt}
? "``$text''"
: "$$self{LQUOTE}$text$$self{RQUOTE}";
}
# Links reduce to the text that we're given, wrapped in angle brackets if it's
# a URL.
sub cmd_l {
my ($self, $attrs, $text) = @_;
if ($$attrs{type} eq 'url') {
if (not defined($$attrs{to}) or $$attrs{to} eq $text) {
return "<$text>";
} elsif ($$self{opt_nourls}) {
return $text;
} else {
return "$text <$$attrs{to}>";
}
} else {
return $text;
}
}
##############################################################################
# Backwards compatibility
##############################################################################
# The old Pod::Text module did everything in a pod2text() function. This
# tries to provide the same interface for legacy applications.
sub pod2text {
my @args;
# This is really ugly; I hate doing option parsing in the middle of a
# module. But the old Pod::Text module supported passing flags to its
# entry function, so handle -a and -<number>.
while ($_[0] =~ /^-/) {
my $flag = shift;
if ($flag eq '-a') { push (@args, alt => 1) }
elsif ($flag =~ /^-(\d+)$/) { push (@args, width => $1) }
else {
unshift (@_, $flag);
last;
}
}
# Now that we know what arguments we're using, create the parser.
my $parser = Pod::Text->new (@args);
# If two arguments were given, the second argument is going to be a file
# handle. That means we want to call parse_from_filehandle(), which means
# we need to turn the first argument into a file handle. Magic open will
# handle the <&STDIN case automagically.
if (defined $_[1]) {
my @fhs = @_;
local *IN;
unless (open (IN, $fhs[0])) {
croak ("Can't open $fhs[0] for reading: $!\n");
return;
}
$fhs[0] = \*IN;
$parser->output_fh ($fhs[1]);
my $retval = $parser->parse_file ($fhs[0]);
my $fh = $parser->output_fh ();
close $fh;
return $retval;
} else {
$parser->output_fh (\*STDOUT);
return $parser->parse_file (@_);
}
}
# Reset the underlying Pod::Simple object between calls to parse_from_file so
# that the same object can be reused to convert multiple pages.
sub parse_from_file {
my $self = shift;
$self->reinit;
# Fake the old cutting option to Pod::Parser. This fiddles with internal
# Pod::Simple state and is quite ugly; we need a better approach.
if (ref ($_[0]) eq 'HASH') {
my $opts = shift @_;
if (defined ($$opts{-cutting}) && !$$opts{-cutting}) {
$$self{in_pod} = 1;
$$self{last_was_blank} = 1;
}
}
# Do the work.
my $retval = $self->Pod::Simple::parse_from_file (@_);
# Flush output, since Pod::Simple doesn't do this. Ideally we should also
# close the file descriptor if we had to open one, but we can't easily
# figure this out.
my $fh = $self->output_fh ();
my $oldfh = select $fh;
my $oldflush = $|;
$| = 1;
print $fh '';
$| = $oldflush;
select $oldfh;
return $retval;
}
# Pod::Simple failed to provide this backward compatibility function, so
# implement it ourselves. File handles are one of the inputs that
# parse_from_file supports.
sub parse_from_filehandle {
my $self = shift;
$self->parse_from_file (@_);
}
# Pod::Simple's parse_file doesn't set output_fh. Wrap the call and do so
# ourself unless it was already set by the caller, since our documentation has
# always said that this should work.
sub parse_file {
my ($self, $in) = @_;
unless (defined $$self{output_fh}) {
$self->output_fh (\*STDOUT);
}
return $self->SUPER::parse_file ($in);
}
# Do the same for parse_lines, just to be polite. Pod::Simple's man page
# implies that the caller is responsible for setting this, but I don't see any
# reason not to set a default.
sub parse_lines {
my ($self, @lines) = @_;
unless (defined $$self{output_fh}) {
$self->output_fh (\*STDOUT);
}
return $self->SUPER::parse_lines (@lines);
}
# Likewise for parse_string_document.
sub parse_string_document {
my ($self, $doc) = @_;
unless (defined $$self{output_fh}) {
$self->output_fh (\*STDOUT);
}
return $self->SUPER::parse_string_document ($doc);
}
##############################################################################
# Module return value and documentation
##############################################################################
1;
__END__
=for stopwords
alt stderr Allbery Sean Burke's Christiansen UTF-8 pre-Unicode utf8 nourls
parsers
=head1 NAME
Pod::Text - Convert POD data to formatted text
=head1 SYNOPSIS
use Pod::Text;
my $parser = Pod::Text->new (sentence => 1, width => 78);
# Read POD from STDIN and write to STDOUT.
$parser->parse_from_filehandle;
# Read POD from file.pod and write to file.txt.
$parser->parse_from_file ('file.pod', 'file.txt');
=head1 DESCRIPTION
Pod::Text is a module that can convert documentation in the POD format
(the preferred language for documenting Perl) into formatted text. It
uses no special formatting controls or codes whatsoever, and its output is
therefore suitable for nearly any device.
As a derived class from Pod::Simple, Pod::Text supports the same methods and
interfaces. See L<Pod::Simple> for all the details; briefly, one creates a
new parser with C<< Pod::Text->new() >> and then normally calls parse_file().
new() can take options, in the form of key/value pairs, that control the
behavior of the parser. The currently recognized options are:
=over 4
=item alt
If set to a true value, selects an alternate output format that, among other
things, uses a different heading style and marks C<=item> entries with a
colon in the left margin. Defaults to false.
=item code
If set to a true value, the non-POD parts of the input file will be included
in the output. Useful for viewing code documented with POD blocks with the
POD rendered and the code left intact.
=item errors
How to report errors. C<die> says to throw an exception on any POD
formatting error. C<stderr> says to report errors on standard error, but
not to throw an exception. C<pod> says to include a POD ERRORS section
in the resulting documentation summarizing the errors. C<none> ignores
POD errors entirely, as much as possible.
The default is C<pod>.
=item indent
The number of spaces to indent regular text, and the default indentation for
C<=over> blocks. Defaults to 4.
=item loose
If set to a true value, a blank line is printed after a C<=head1> heading.
If set to false (the default), no blank line is printed after C<=head1>,
although one is still printed after C<=head2>. This is the default because
it's the expected formatting for manual pages; if you're formatting
arbitrary text documents, setting this to true may result in more pleasing
output.
=item margin
The width of the left margin in spaces. Defaults to 0. This is the margin
for all text, including headings, not the amount by which regular text is
indented; for the latter, see the I<indent> option. To set the right
margin, see the I<width> option.
=item nourls
Normally, LZ<><> formatting codes with a URL but anchor text are formatted
to show both the anchor text and the URL. In other words:
L<foo|http://example.com/>
is formatted as:
foo <http://example.com/>
This option, if set to a true value, suppresses the URL when anchor text
is given, so this example would be formatted as just C<foo>. This can
produce less cluttered output in cases where the URLs are not particularly
important.
=item quotes
Sets the quote marks used to surround CE<lt>> text. If the value is a
single character, it is used as both the left and right quote. Otherwise,
it is split in half, and the first half of the string is used as the left
quote and the second is used as the right quote.
This may also be set to the special value C<none>, in which case no quote
marks are added around CE<lt>> text.
=item sentence
If set to a true value, Pod::Text will assume that each sentence ends in two
spaces, and will try to preserve that spacing. If set to false, all
consecutive whitespace in non-verbatim paragraphs is compressed into a
single space. Defaults to false.
=item stderr
Send error messages about invalid POD to standard error instead of
appending a POD ERRORS section to the generated output. This is
equivalent to setting C<errors> to C<stderr> if C<errors> is not already
set. It is supported for backward compatibility.
=item utf8
By default, Pod::Text uses the same output encoding as the input encoding
of the POD source (provided that Perl was built with PerlIO; otherwise, it
doesn't encode its output). If this option is given, the output encoding
is forced to UTF-8.
Be aware that, when using this option, the input encoding of your POD
source should be properly declared unless it's US-ASCII. Pod::Simple will
attempt to guess the encoding and may be successful if it's Latin-1 or
UTF-8, but it will produce warnings. Use the C<=encoding> command to
declare the encoding. See L<perlpod(1)> for more information.
=item width
The column at which to wrap text on the right-hand side. Defaults to 76.
=back
The standard Pod::Simple method parse_file() takes one argument naming the
POD file to read from. By default, the output is sent to C<STDOUT>, but
this can be changed with the output_fh() method.
The standard Pod::Simple method parse_from_file() takes up to two
arguments, the first being the input file to read POD from and the second
being the file to write the formatted output to.
You can also call parse_lines() to parse an array of lines or
parse_string_document() to parse a document already in memory. As with
parse_file(), parse_lines() and parse_string_document() default to sending
their output to C<STDOUT> unless changed with the output_fh() method.
To put the output from any parse method into a string instead of a file
handle, call the output_string() method instead of output_fh().
See L<Pod::Simple> for more specific details on the methods available to
all derived parsers.
=head1 DIAGNOSTICS
=over 4
=item Bizarre space in item
=item Item called without tag
(W) Something has gone wrong in internal C<=item> processing. These
messages indicate a bug in Pod::Text; you should never see them.
=item Can't open %s for reading: %s
(F) Pod::Text was invoked via the compatibility mode pod2text() interface
and the input file it was given could not be opened.
=item Invalid errors setting "%s"
(F) The C<errors> parameter to the constructor was set to an unknown value.
=item Invalid quote specification "%s"
(F) The quote specification given (the C<quotes> option to the
constructor) was invalid. A quote specification must be either one
character long or an even number (greater than one) characters long.
=item POD document had syntax errors
(F) The POD document being formatted had syntax errors and the C<errors>
option was set to C<die>.
=back
=head1 BUGS
Encoding handling assumes that PerlIO is available and does not work
properly if it isn't. The C<utf8> option is therefore not supported
unless Perl is built with PerlIO support.
=head1 CAVEATS
If Pod::Text is given the C<utf8> option, the encoding of its output file
handle will be forced to UTF-8 if possible, overriding any existing
encoding. This will be done even if the file handle is not created by
Pod::Text and was passed in from outside. This maintains consistency
regardless of PERL_UNICODE and other settings.
If the C<utf8> option is not given, the encoding of its output file handle
will be forced to the detected encoding of the input POD, which preserves
whatever the input text is. This ensures backward compatibility with
earlier, pre-Unicode versions of this module, without large numbers of
Perl warnings.
This is not ideal, but it seems to be the best compromise. If it doesn't
work for you, please let me know the details of how it broke.
=head1 NOTES
This is a replacement for an earlier Pod::Text module written by Tom
Christiansen. It has a revamped interface, since it now uses Pod::Simple,
but an interface roughly compatible with the old Pod::Text::pod2text()
function is still available. Please change to the new calling convention,
though.
The original Pod::Text contained code to do formatting via termcap
sequences, although it wasn't turned on by default and it was problematic to
get it to work at all. This rewrite doesn't even try to do that, but a
subclass of it does. Look for L<Pod::Text::Termcap>.
=head1 AUTHOR
Russ Allbery <rra@cpan.org>, based I<very> heavily on the original
Pod::Text by Tom Christiansen <tchrist@mox.perl.com> and its conversion to
Pod::Parser by Brad Appleton <bradapp@enteract.com>. Sean Burke's initial
conversion of Pod::Man to use Pod::Simple provided much-needed guidance on
how to use Pod::Simple.
=head1 COPYRIGHT AND LICENSE
Copyright 1999-2002, 2004, 2006, 2008-2009, 2012-2016, 2018 Russ Allbery
<rra@cpan.org>
This program is free software; you may redistribute it and/or modify it
under the same terms as Perl itself.
=head1 SEE ALSO
L<Pod::Simple>, L<Pod::Text::Termcap>, L<perlpod(1)>, L<pod2text(1)>
The current version of this module is always available from its web site at
L<https://www.eyrie.org/~eagle/software/podlators/>. It is also part of the
Perl core distribution as of 5.6.0.
=cut
# Local Variables:
# copyright-at-end-flag: t
# End:
Checker.pm 0000644 00000077362 15051135563 0006471 0 ustar 00 #############################################################################
# Pod/Checker.pm -- check pod documents for syntax errors
#
# Copyright (C) 1994-2000 by Bradford Appleton. All rights reserved.
# This is free software; you can redistribute it and/or modify it under the
# same terms as Perl itself.
#############################################################################
package Pod::Checker;
use strict;
use warnings;
our $VERSION = '1.73'; ## Current version of this package
=head1 NAME
Pod::Checker - check pod documents for syntax errors
=head1 SYNOPSIS
use Pod::Checker;
$syntax_okay = podchecker($filepath, $outputpath, %options);
my $checker = Pod::Checker->new(%options);
$checker->parse_from_file($filepath, \*STDERR);
=head1 OPTIONS/ARGUMENTS
C<$filepath> is the input POD to read and C<$outputpath> is
where to write POD syntax error messages. Either argument may be a scalar
indicating a file-path, or else a reference to an open filehandle.
If unspecified, the input-file it defaults to C<\*STDIN>, and
the output-file defaults to C<\*STDERR>.
=head2 podchecker()
This function can take a hash of options:
=over 4
=item B<-warnings> =E<gt> I<val>
Turn warnings on/off. I<val> is usually 1 for on, but higher values
trigger additional warnings. See L<"Warnings">.
=item B<-quiet> =E<gt> I<val>
If C<val> is true, do not print any errors/warnings.
=back
=head1 DESCRIPTION
B<podchecker> will perform syntax checking of Perl5 POD format documentation.
Curious/ambitious users are welcome to propose additional features they wish
to see in B<Pod::Checker> and B<podchecker> and verify that the checks are
consistent with L<perlpod>.
The following checks are currently performed:
=over 4
=item *
Unknown '=xxxx' commands, unknown 'XE<lt>...E<gt>' interior-sequences,
and unterminated interior sequences.
=item *
Check for proper balancing of C<=begin> and C<=end>. The contents of such
a block are generally ignored, i.e. no syntax checks are performed.
=item *
Check for proper nesting and balancing of C<=over>, C<=item> and C<=back>.
=item *
Check for same nested interior-sequences (e.g.
C<LE<lt>...LE<lt>...E<gt>...E<gt>>).
=item *
Check for malformed or non-existing entities C<EE<lt>...E<gt>>.
=item *
Check for correct syntax of hyperlinks C<LE<lt>...E<gt>>. See L<perlpod>
for details.
=item *
Check for unresolved document-internal links. This check may also reveal
misspelled links that seem to be internal links but should be links
to something else.
=back
=head1 DIAGNOSTICS
=head2 Errors
=over 4
=item * empty =headn
A heading (C<=head1> or C<=head2>) without any text? That ain't no
heading!
=item * =over on line I<N> without closing =back
=item * You forgot a '=back' before '=headI<N>'
=item * =over is the last thing in the document?!
The C<=over> command does not have a corresponding C<=back> before the
next heading (C<=head1> or C<=head2>) or the end of the file.
=item * '=item' outside of any '=over'
=item * =back without =over
An C<=item> or C<=back> command has been found outside a
C<=over>/C<=back> block.
=item * Can't have a 0 in =over I<N>
You need to indent a strictly positive number of spaces, not 0.
=item * =over should be: '=over' or '=over positive_number'
Either have an argumentless =over, or have its argument a strictly positive number.
=item * =begin I<TARGET> without matching =end I<TARGET>
A C<=begin> command was found that has no matching =end command.
=item * =begin without a target?
A C<=begin> command was found that is not followed by the formatter
specification.
=item * =end I<TARGET> without matching =begin.
A standalone C<=end> command was found.
=item * '=end' without a target?
'=end' directives need to have a target, just like =begin directives.
=item * '=end I<TARGET>' is invalid.
I<TARGET> needs to be one word
=item * =end I<CONTENT> doesn't match =begin I<TARGET>
I<CONTENT> needs to match =begin's I<TARGET>.
=item * =for without a target?
There is no specification of the formatter after the C<=for> command.
=item * unresolved internal link I<NAME>
The given link to I<NAME> does not have a matching node in the current
POD. This also happened when a single word node name is not enclosed in
C<"">.
=item * Unknown directive: I<CMD>
An invalid POD command has been found. Valid are C<=head1>, C<=head2>,
C<=head3>, C<=head4>, C<=over>, C<=item>, C<=back>, C<=begin>, C<=end>,
C<=for>, C<=pod>, C<=cut>
=item * Deleting unknown formatting code I<SEQ>
An invalid markup command has been encountered. Valid are:
C<BE<lt>E<gt>>, C<CE<lt>E<gt>>, C<EE<lt>E<gt>>, C<FE<lt>E<gt>>,
C<IE<lt>E<gt>>, C<LE<lt>E<gt>>, C<SE<lt>E<gt>>, C<XE<lt>E<gt>>,
C<ZE<lt>E<gt>>
=item * Unterminated I<SEQ>E<lt>E<gt> sequence
An unclosed formatting code
=item * An EE<lt>...E<gt> surrounding strange content
The I<STRING> found cannot be interpreted as a character entity.
=item * An empty EE<lt>E<gt>
=item * An empty C<< LE<lt>E<gt> >>
=item * An empty XE<lt>E<gt>
There needs to be content inside E, L, and X formatting codes.
=item * A non-empty ZE<lt>E<gt>
The C<ZE<lt>E<gt>> sequence is supposed to be empty.
=item * Spurious text after =pod / =cut
The commands C<=pod> and C<=cut> do not take any arguments.
=item * =back doesn't take any parameters, but you said =back I<ARGUMENT>
The C<=back> command does not take any arguments.
=item * =pod directives shouldn't be over one line long! Ignoring all I<N> lines of content
Self explanatory
=item * =cut found outside a pod block.
A '=cut' directive found in the middle of non-POD
=item * Invalid =encoding syntax: I<CONTENT>
Syntax error in =encoding directive
=back
=head2 Warnings
These may not necessarily cause trouble, but indicate mediocre style.
=over 4
=item * nested commands I<CMD>E<lt>...I<CMD>E<lt>...E<gt>...E<gt>
Two nested identical markup commands have been found. Generally this
does not make sense.
=item * multiple occurrences (I<N>) of link target I<name>
The POD file has some C<=item> and/or C<=head> commands that have
the same text. Potential hyperlinks to such a text cannot be unique then.
This warning is printed only with warning level greater than one.
=item * line containing nothing but whitespace in paragraph
There is some whitespace on a seemingly empty line. POD is very sensitive
to such things, so this is flagged. B<vi> users switch on the B<list>
option to avoid this problem.
=item * =item has no contents
There is a list C<=item> that has no text contents. You probably want to delete
empty items.
=item * You can't have =items (as at line I<N>) unless the first thing after the =over is an =item
A list introduced by C<=over> starts with a text or verbatim paragraph,
but continues with C<=item>s. Move the non-item paragraph out of the
C<=over>/C<=back> block.
=item * Expected '=item I<EXPECTED VALUE>'
=item * Expected '=item *'
=item * Possible =item type mismatch: 'I<x>' found leading a supposed definition =item
A list started with e.g. a bullet-like C<=item> and continued with a
numbered one. This is obviously inconsistent. For most translators the
type of the I<first> C<=item> determines the type of the list.
=item * You have '=item x' instead of the expected '=item I<N>'
Erroneous numbering of =item numbers; they need to ascend consecutively.
=item * Unknown E content in EE<lt>I<CONTENT>E<gt>
A character entity was found that does not belong to the standard
ISO set or the POD specials C<verbar> and C<sol>. I<Currently, this warning
only appears if a character entity was found that does not have a Unicode
character. This should be fixed to adhere to the original warning.>
=item * empty =over/=back block
The list opened with C<=over> does not contain anything.
=item * empty section in previous paragraph
The previous section (introduced by a C<=head> command) does not contain
any valid content. This usually indicates that something is missing. Note: A
C<=head1> followed immediately by C<=head2> does not trigger this warning.
=item * Verbatim paragraph in NAME section
The NAME section (C<=head1 NAME>) should consist of a single paragraph
with the script/module name, followed by a dash `-' and a very short
description of what the thing is good for.
=item * =headI<n> without preceding higher level
For example if there is a C<=head2> in the POD file prior to a
C<=head1>.
=back
=head2 Hyperlinks
There are some warnings with respect to malformed hyperlinks:
=over 4
=item * ignoring leading/trailing whitespace in link
There is whitespace at the beginning or the end of the contents of
LE<lt>...E<gt>.
=item * alternative text/node '%s' contains non-escaped | or /
The characters C<|> and C</> are special in the LE<lt>...E<gt> context.
Although the hyperlink parser does its best to determine which "/" is
text and which is a delimiter in case of doubt, one ought to escape
these literal characters like this:
/ E<sol>
| E<verbar>
=back
Note that the line number of the error/warning may refer to the line number of
the start of the paragraph in which the error/warning exists, not the line
number that the error/warning is on. This bug is present in errors/warnings
related to formatting codes. I<This should be fixed.>
=head1 RETURN VALUE
B<podchecker> returns the number of POD syntax errors found or -1 if
there were no POD commands at all found in the file.
=head1 EXAMPLES
See L</SYNOPSIS>
=head1 SCRIPTS
The B<podchecker> script that comes with this distribution is a lean wrapper
around this module. See the online manual with
podchecker -help
podchecker -man
=head1 INTERFACE
While checking, this module collects document properties, e.g. the nodes
for hyperlinks (C<=headX>, C<=item>) and index entries (C<XE<lt>E<gt>>).
POD translators can use this feature to syntax-check and get the nodes in
a first pass before actually starting to convert. This is expensive in terms
of execution time, but allows for very robust conversions.
Since v1.24 the B<Pod::Checker> module uses only the B<poderror>
method to print errors and warnings. The summary output (e.g.
"Pod syntax OK") has been dropped from the module and has been included in
B<podchecker> (the script). This allows users of B<Pod::Checker> to
control completely the output behavior. Users of B<podchecker> (the script)
get the well-known behavior.
v1.45 inherits from Pod::Simple as opposed to all previous versions
inheriting from Pod::Parser. Do B<not> use Pod::Simple's interface when
using Pod::Checker unless it is documented somewhere on this page. I
repeat, DO B<NOT> USE POD::SIMPLE'S INTERFACE.
=cut
#############################################################################
#use diagnostics;
use Carp qw(croak);
use Exporter 'import';
use base qw/Pod::Simple::Methody/;
our @EXPORT = qw(&podchecker);
##---------------------------------
## Function definitions begin here
##---------------------------------
sub podchecker {
my ($infile, $outfile, %options) = @_;
local $_;
## Set defaults
$infile ||= \*STDIN;
$outfile ||= \*STDERR;
## Now create a pod checker
my $checker = Pod::Checker->new(%options);
## Now check the pod document for errors
$checker->parse_from_file($infile, $outfile);
## Return the number of errors found
return $checker->num_errors();
}
##---------------------------------------------------------------------------
##-------------------------------
## Method definitions begin here
##-------------------------------
##################################
=over 4
=item C<Pod::Checker-E<gt>new( %options )>
Return a reference to a new Pod::Checker object that inherits from
Pod::Simple and is used for calling the required methods later. The
following options are recognized:
C<-warnings =E<gt> num>
Print warnings if C<num> is true. The higher the value of C<num>,
the more warnings are printed. Currently there are only levels 1 and 2.
C<-quiet =E<gt> num>
If C<num> is true, do not print any errors/warnings. This is useful
when Pod::Checker is used to munge POD code into plain text from within
POD formatters.
=cut
sub new {
my $new = shift->SUPER::new(@_);
$new->{'output_fh'} ||= *STDERR{IO};
# Set options
my %opts = @_;
$new->{'-warnings'} = defined $opts{'-warnings'} ?
$opts{'-warnings'} : 1; # default on
$new->{'-quiet'} = $opts{'-quiet'} || 0; # default off
# Initialize number of errors/warnings
$new->{'_NUM_ERRORS'} = 0;
$new->{'_NUM_WARNINGS'} = 0;
# 'current' also means 'most recent' in the follow comments
$new->{'_thispara'} = ''; # current POD paragraph
$new->{'_line'} = 0; # current line number
$new->{'_head_num'} = 0; # current =head level (set to 0 to make
# logic easier down the road)
$new->{'_cmds_since_head'} = 0; # num of POD directives since prev. =headN
$new->{'_nodes'} = []; # stack for =head/=item nodes
$new->{'_fcode_stack'} = []; # stack for nested formatting codes
$new->{'_fcode_pos'} = []; # stack for position in paragraph of fcodes
$new->{'_begin_stack'} = []; # stack for =begins: [line #, target]
$new->{'_links'} = []; # stack for hyperlinks to external entities
$new->{'_internal_links'} = []; # set of linked-to internal sections
$new->{'_index'} = []; # stack for text in X<>s
$new->accept_targets('*'); # check all =begin/=for blocks
$new->cut_handler( \&handle_pod_and_cut ); # warn if text after =cut
$new->pod_handler( \&handle_pod_and_cut ); # warn if text after =pod
$new->whiteline_handler( \&handle_whiteline ); # warn if whiteline
$new->parse_empty_lists(1); # warn if they are empty
return $new;
}
##################################
=item C<$checker-E<gt>poderror( @args )>
=item C<$checker-E<gt>poderror( {%opts}, @args )>
Internal method for printing errors and warnings. If no options are given,
simply prints "@_". The following options are recognized and used to form
the output:
-msg
A message to print prior to C<@args>.
-line
The line number the error occurred in.
-file
The file (name) the error occurred in. Defaults to the name of the current
file being processed.
-severity
The error level, should be 'WARNING' or 'ERROR'.
=cut
# Invoked as $self->poderror( @args ), or $self->poderror( {%opts}, @args )
sub poderror {
my $self = shift;
my %opts = (ref $_[0]) ? %{shift()} : ();
## Retrieve options
chomp( my $msg = ($opts{'-msg'} || '')."@_" );
my $line = (exists $opts{'-line'}) ? " at line $opts{'-line'}" : '';
my $file = ' in file ' . ((exists $opts{'-file'})
? $opts{'-file'}
: ((defined $self->source_filename)
? $self->source_filename
: "???"));
unless (exists $opts{'-severity'}) {
## See if can find severity in message prefix
$opts{'-severity'} = $1 if ( $msg =~ s/^\**\s*([A-Z]{3,}):\s+// );
}
my $severity = (exists $opts{'-severity'}) ? "*** $opts{-severity}: " : '';
## Increment error count and print message "
++($self->{'_NUM_ERRORS'})
if(!%opts || ($opts{-severity} && $opts{'-severity'} eq 'ERROR'));
++($self->{'_NUM_WARNINGS'})
if(!%opts || ($opts{-severity} && $opts{'-severity'} eq 'WARNING'));
unless($self->{'-quiet'}) {
my $out_fh = $self->{'output_fh'} || \*STDERR;
print $out_fh ($severity, $msg, $line, $file, "\n")
if($self->{'-warnings'} || !%opts || $opts{'-severity'} ne 'WARNING');
}
}
##################################
=item C<$checker-E<gt>num_errors()>
Set (if argument specified) and retrieve the number of errors found.
=cut
sub num_errors {
return (@_ > 1) ? ($_[0]->{'_NUM_ERRORS'} = $_[1]) : $_[0]->{'_NUM_ERRORS'};
}
##################################
=item C<$checker-E<gt>num_warnings()>
Set (if argument specified) and retrieve the number of warnings found.
=cut
sub num_warnings {
return (@_ > 1) ? ($_[0]->{'_NUM_WARNINGS'} = $_[1]) :
$_[0]->{'_NUM_WARNINGS'};
}
##################################
=item C<$checker-E<gt>name()>
Set (if argument specified) and retrieve the canonical name of POD as
found in the C<=head1 NAME> section.
=cut
sub name {
return (@_ > 1 && $_[1]) ?
($_[0]->{'_pod_name'} = $_[1]) : $_[0]->{'_pod_name'};
}
##################################
=item C<$checker-E<gt>node()>
Add (if argument specified) and retrieve the nodes (as defined by C<=headX>
and C<=item>) of the current POD. The nodes are returned in the order of
their occurrence. They consist of plain text, each piece of whitespace is
collapsed to a single blank.
=cut
sub node {
my ($self,$text) = @_;
if(defined $text) {
$text =~ s/\s+$//s; # strip trailing whitespace
$text =~ s/\s+/ /gs; # collapse whitespace
# add node, order important!
push(@{$self->{'_nodes'}}, $text);
# keep also a uniqueness counter
$self->{'_unique_nodes'}->{$text}++ if($text !~ /^\s*$/s);
return $text;
}
@{$self->{'_nodes'}};
}
##################################
=item C<$checker-E<gt>idx()>
Add (if argument specified) and retrieve the index entries (as defined by
C<XE<lt>E<gt>>) of the current POD. They consist of plain text, each piece
of whitespace is collapsed to a single blank.
=cut
# set/return index entries of current POD
sub idx {
my ($self,$text) = @_;
if(defined $text) {
$text =~ s/\s+$//s; # strip trailing whitespace
$text =~ s/\s+/ /gs; # collapse whitespace
# add node, order important!
push(@{$self->{'_index'}}, $text);
# keep also a uniqueness counter
$self->{'_unique_nodes'}->{$text}++ if($text !~ /^\s*$/s);
return $text;
}
@{$self->{'_index'}};
}
##################################
# add a hyperlink to the list of those of the current POD; returns current
# list after the addition has been done
sub hyperlink {
my $self = shift;
push(@{$self->{'_links'}}, $_[0]);
return $_[0];
}
=item C<$checker-E<gt>hyperlinks()>
Retrieve an array containing the hyperlinks to things outside
the current POD (as defined by C<LE<lt>E<gt>>).
Each is an instance of a class with the following methods:
=cut
sub hyperlinks {
@{shift->{'_links'}};
}
##################################
# override Pod::Simple's whine() and scream() to use poderror()
# Note:
# Ignore $self->{'no_whining'} b/c $self->{'quiet'} takes care of it in poderror
# Don't bother incrementing $self->{'errors_seen'} -- it's not used
# Don't bother pushing to $self->{'errata'} b/c poderror() outputs immediately
# We don't need to set $self->no_errata_section(1) b/c of these overrides
sub whine {
my ($self, $line, $complaint) = @_;
my $severity = 'ERROR';
if (0) {
# XXX: Let's standardize what's a warning and what's an error. Let's not
# move stuff up and down the severity tree. -- rjbs, 2013-04-12
# Convert errors in Pod::Simple that are warnings in Pod::Checker
# XXX Do differently so the $complaint can be reworded without this breaking
$severity = 'WARNING' if
$complaint =~ /^Expected '=item .+?'$/ ||
$complaint =~ /^You can't have =items \(as at line .+?\) unless the first thing after the =over is an =item$/ ||
$complaint =~ /^You have '=item .+?' instead of the expected '=item .+?'$/;
}
$self->poderror({ -line => $line,
-severity => $severity,
-msg => $complaint });
return 1; # assume everything is peachy keen
}
sub scream {
my ($self, $line, $complaint) = @_;
$self->poderror({ -line => $line,
-severity => 'ERROR', # consider making severity 'FATAL'
-msg => $complaint });
return 1;
}
##################################
# Some helper subroutines
sub _init_event { # assignments done at the start of most events
$_[0]{'_thispara'} = '';
$_[0]{'_line'} = $_[1]{'start_line'};
$_[0]{'_cmds_since_head'}++;
}
sub _check_fcode {
my ($self, $inner, $outers) = @_;
# Check for an fcode inside another of the same fcode
# XXX line number is the line of the start of the paragraph that the warning
# is in, not the line that the warning is on. Fix this
# Later versions of Pod::Simple forbid nested L<>'s
return if $inner eq 'L' && $Pod::Simple::VERSION ge '3.33';
if (grep { $_ eq $inner } @$outers) {
$self->poderror({ -line => $self->{'_line'},
-severity => 'WARNING',
-msg => "nested commands $inner<...$inner<...>...>"});
}
}
##################################
sub handle_text { $_[0]{'_thispara'} .= $_[1] }
# whiteline is a seemingly blank line that matches /[^\S\r\n]/
sub handle_whiteline {
my ($line, $line_n, $self) = @_;
$self->poderror({
-line => $line_n,
-severity => 'WARNING',
-msg => 'line containing nothing but whitespace in paragraph'});
}
######## Directives
sub handle_pod_and_cut {
my ($line, $line_n, $self) = @_;
$self->{'_cmds_since_head'}++;
if ($line =~ /=(pod|cut)\s+\S/) {
$self->poderror({ -line => $line_n,
-severity => 'ERROR',
-msg => "Spurious text after =$1"});
}
}
sub start_Para { shift->_init_event(@_); }
sub end_Para {
my $self = shift;
# Get the NAME of the pod document
if ($self->{'_head_num'} == 1 && $self->{'_head_text'} eq 'NAME') {
if ($self->{'_thispara'} =~ /^\s*(\S+?)\s*[,-]/) {
$self->{'_pod_name'} = $1 unless defined $self->{'_pod_name'};
}
}
}
sub start_Verbatim {
my $self = shift;
$self->_init_event(@_);
if ($self->{'_head_num'} == 1 && $self->{'_head_text'} eq 'NAME') {
$self->poderror({ -line => $self->{'_line'},
-severity => 'WARNING',
-msg => 'Verbatim paragraph in NAME section' });
}
}
# Don't need an end_Verbatim
# Do I need to do anything else with this?
sub start_Data { shift->_init_event() }
sub start_head1 { shift->start_head(1, @_) }
sub start_head2 { shift->start_head(2, @_) }
sub start_head3 { shift->start_head(3, @_) }
sub start_head4 { shift->start_head(4, @_) }
sub start_head {
my $self = shift;
my $h = shift;
$self->_init_event(@_);
my $prev_h = $self->{'_head_num'};
$self->{'_head_num'} = $h;
$self->{"_count_head$h"}++;
if ($h > 1 && !$self->{'_count_head'.($h-1)}) {
$self->poderror({ -line => $self->{'_line'},
-severity => 'WARNING',
-msg => "=head$h without preceding higher level"});
}
# If this is the first =head of the doc, $prev_h is 0, thus less than $h
if ($self->{'_cmds_since_head'} == 1 && $prev_h >= $h) {
$self->poderror({ -line => $self->{'_line'},
-severity => 'WARNING',
-msg => 'empty section in previous paragraph'});
}
}
sub end_head1 { shift->end_head(@_) }
sub end_head2 { shift->end_head(@_) }
sub end_head3 { shift->end_head(@_) }
sub end_head4 { shift->end_head(@_) }
sub end_head {
my $self = shift;
my $arg = $self->{'_thispara'};
$arg =~ s/\s+$//;
$self->{'_head_text'} = $arg;
$self->{'_cmds_since_head'} = 0;
my $h = $self->{'_head_num'};
$self->node($arg); # remember this node
if ($arg eq '') {
$self->poderror({ -line => $self->{'_line'},
-severity => 'ERROR',
-msg => "empty =head$h" });
}
}
sub start_over_bullet { shift->start_over(@_, 'bullet') }
sub start_over_number { shift->start_over(@_, 'number') }
sub start_over_text { shift->start_over(@_, 'definition') }
sub start_over_block { shift->start_over(@_, 'block') }
sub start_over_empty {
my $self = shift;
$self->start_over(@_, 'empty');
$self->poderror({ -line => $self->{'_line'},
-severity => 'WARNING',
-msg => 'empty =over/=back block' });
}
sub start_over {
my $self = shift;
my $type = pop;
$self->_init_event(@_);
}
sub start_item_bullet { shift->_init_event(@_) }
sub start_item_number { shift->_init_event(@_) }
sub start_item_text { shift->_init_event(@_) }
sub end_item_bullet { shift->end_item('bullet') }
sub end_item_number { shift->end_item('number') }
sub end_item_text { shift->end_item('definition') }
sub end_item {
my $self = shift;
my $type = shift;
# If there is verbatim text in this item, it will show up as part of
# 'paras', and not part of '_thispara'. If the first para after this is a
# verbatim one, it actually will be (part of) the contents for this item.
if ( $self->{'_thispara'} eq ''
&& ( ! @{$self->{'paras'}}
|| $self->{'paras'}[0][0] !~ /Verbatim/i))
{
$self->poderror({ -line => $self->{'_line'},
-severity => 'WARNING',
-msg => '=item has no contents' });
}
$self->node($self->{'_thispara'}); # remember this node
}
sub start_for { # =for and =begin directives
my ($self, $flags) = @_;
$self->_init_event($flags);
push @{$self->{'_begin_stack'}}, [$self->{'_line'}, $flags->{'target'}];
}
sub end_for {
my ($self, $flags) = @_;
my ($line, $target) = @{pop @{$self->{'_begin_stack'}}};
if ($flags->{'fake-closer'}) { # meaning Pod::Simple generated this =end
$self->poderror({ -line => $line,
-severity => 'ERROR',
-msg => "=begin $target without matching =end $target"
});
}
}
sub end_Document {
# Some final error checks
my $self = shift;
# no POD found here
$self->num_errors(-1) && return unless $self->content_seen;
my %nodes;
for ($self->node()) {
$nodes{$_} = 1;
if(/^(\S+)\s+\S/) {
# we have more than one word. Use the first as a node, too.
# This is used heavily in perlfunc.pod
$nodes{$1} ||= 2; # derived node
}
}
for ($self->idx()) {
$nodes{$_} = 3; # index node
}
# XXX update unresolved internal link POD -- single word not enclosed in ""?
# I don't know what I was thinking when I made the above TODO, and I don't
# know what it means...
for my $link (@{ $self->{'_internal_links'} }) {
my ($name, $line) = @$link;
unless ( $nodes{$name} ) {
$self->poderror({ -line => $line,
-severity => 'ERROR',
-msg => "unresolved internal link '$name'"});
}
}
# check the internal nodes for uniqueness. This pertains to
# =headX, =item and X<...>
if ($self->{'-warnings'} > 1 ) {
for my $node (sort keys %{ $self->{'_unique_nodes'} }) {
my $count = $self->{'_unique_nodes'}{$node};
if ($count > 1) { # not unique
$self->poderror({
-line => '-',
-severity => 'WARNING',
-msg => "multiple occurrences ($count) of link target ".
"'$node'"});
}
}
}
}
######## Formatting codes
sub start_B { shift->start_fcode('B') }
sub start_C { shift->start_fcode('C') }
sub start_F { shift->start_fcode('F') }
sub start_I { shift->start_fcode('I') }
sub start_S { shift->start_fcode('S') }
sub start_fcode {
my ($self, $fcode) = @_;
unshift @{$self->{'_fcode_stack'}}, $fcode;
}
sub end_B { shift->end_fcode() }
sub end_C { shift->end_fcode() }
sub end_F { shift->end_fcode() }
sub end_I { shift->end_fcode() }
sub end_S { shift->end_fcode() }
sub end_fcode {
my $self = shift;
$self->_check_fcode(shift @{$self->{'_fcode_stack'}}, # current fcode removed
$self->{'_fcode_stack'}); # previous fcodes
}
sub start_L {
my ($self, $flags) = @_;
$self->start_fcode('L');
my $link = Pod::Checker::Hyperlink->new($flags, $self);
if ($link) {
if ( $link->type eq 'pod'
&& $link->node
# It's an internal-to-this-page link if no page is given, or
# if the given one is to our NAME.
&& (! $link->page || ( $self->{'_pod_name'}
&& $link->page eq $self->{'_pod_name'})))
{
push @{ $self->{'_internal_links'} }, [ $link->{'-raw_node'}, $link->line ];
}
else {
$self->hyperlink($link);
}
}
}
sub end_L {
my $self = shift;
$self->end_fcode();
}
sub start_X {
my $self = shift;
$self->start_fcode('X');
# keep track of where X<> starts in the paragraph
# (this is a stack so nested X<>s are handled correctly)
push @{$self->{'_fcode_pos'}}, length $self->{'_thispara'};
}
sub end_X {
my $self = shift;
# extract contents of X<> and replace with ''
my $start = pop @{$self->{'_fcode_pos'}}; # start at the beginning of X<>
my $end = length($self->{'_thispara'}) - $start; # end at end of X<>
my $x = substr($self->{'_thispara'}, $start, $end, '');
if ($x eq "") {
$self->poderror({ -line => $self->{'_line'},
-severity => 'ERROR',
-msg => "An empty X<>" });
}
$self->idx($x); # remember this node
$self->end_fcode();
}
package Pod::Checker::Hyperlink;
# This class is used to represent L<> link structures, so that the individual
# elements are easily accessible. It is based on code in Pod::Hyperlink
sub new {
my ($class,
$simple_link, # The link structure returned by Pod::Simple
$caller # The caller class
) = @_;
my $self = +{};
bless $self, $class;
$self->{'-line'} ||= $caller->{'_line'};
$self->{'-type'} ||= $simple_link->{'type'};
# Force stringification of page and node. (This expands any E<>.)
$self->{'-page'} = exists $simple_link->{'to'} ? "$simple_link->{'to'}" : "";
$self->{'-node'} = exists $simple_link->{'section'} ? "$simple_link->{'section'}" : "";
# Save the unmodified node text, as the .t files are expecting the message
# for internal link failures to include it (hence this preserves backward
# compatibility).
$self->{'-raw_node'} = $self->{'-node'};
# Remove leading/trailing white space. Pod::Simple already warns about
# these, so if the only error is this, and the link is otherwise correct,
# only the Pod::Simple warning will be output, avoiding unnecessary
# confusion.
$self->{'-page'} =~ s/ ^ \s+ //x;
$self->{'-page'} =~ s/ \s+ $ //x;
$self->{'-node'} =~ s/ ^ \s+ //x;
$self->{'-node'} =~ s/ \s+ $ //x;
# Pod::Simple warns about L<> and L< >, but not L</>
if ($self->{'-page'} eq "" && $self->{'-node'} eq "") {
$caller->poderror({ -line => $caller->{'_line'},
-severity => 'WARNING',
-msg => 'empty link'});
return;
}
return $self;
}
=item line()
Returns the approximate line number in which the link was encountered
=cut
sub line {
return $_[0]->{-line};
}
=item type()
Returns the type of the link; one of:
C<"url"> for things like
C<http://www.foo>, C<"man"> for man pages, or C<"pod">.
=cut
sub type {
return $_[0]->{-type};
}
=item page()
Returns the linked-to page or url.
=cut
sub page {
return $_[0]->{-page};
}
=item node()
Returns the anchor or node within the linked-to page, or an empty string
(C<"">) if none appears in the link.
=back
=cut
sub node {
return $_[0]->{-node};
}
=head1 AUTHOR
Please report bugs using L<http://rt.cpan.org>.
Brad Appleton E<lt>bradapp@enteract.comE<gt> (initial version),
Marek Rouchal E<lt>marekr@cpan.orgE<gt>,
Marc Green E<lt>marcgreen@cpan.orgE<gt> (port to Pod::Simple)
Ricardo Signes E<lt>rjbs@cpan.orgE<gt> (more porting to Pod::Simple)
Karl Williamson E<lt>khw@cpan.orgE<gt> (more porting to Pod::Simple)
Based on code for B<Pod::Text::pod2text()> written by
Tom Christiansen E<lt>tchrist@mox.perl.comE<gt>
=cut
1
Select.pm 0000644 00000057672 15051135563 0006346 0 ustar 00 #############################################################################
# Pod/Select.pm -- function to select portions of POD docs
#
# Copyright (C) 1996-2000 by Bradford Appleton. All rights reserved.
# This file is part of "PodParser". PodParser is free software;
# you can redistribute it and/or modify it under the same terms
# as Perl itself.
#############################################################################
package Pod::Select;
use strict;
use vars qw($VERSION @ISA @EXPORT $MAX_HEADING_LEVEL %myData @section_headings @selected_sections);
$VERSION = '1.63'; ## Current version of this package
require 5.005; ## requires this Perl version or later
#############################################################################
=head1 NAME
Pod::Select, podselect() - extract selected sections of POD from input
=head1 SYNOPSIS
use Pod::Select;
## Select all the POD sections for each file in @filelist
## and print the result on standard output.
podselect(@filelist);
## Same as above, but write to tmp.out
podselect({-output => "tmp.out"}, @filelist):
## Select from the given filelist, only those POD sections that are
## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
podselect({-sections => ["NAME|SYNOPSIS", "OPTIONS"]}, @filelist):
## Select the "DESCRIPTION" section of the PODs from STDIN and write
## the result to STDERR.
podselect({-output => ">&STDERR", -sections => ["DESCRIPTION"]}, \*STDIN);
or
use Pod::Select;
## Create a parser object for selecting POD sections from the input
$parser = new Pod::Select();
## Select all the POD sections for each file in @filelist
## and print the result to tmp.out.
$parser->parse_from_file("<&STDIN", "tmp.out");
## Select from the given filelist, only those POD sections that are
## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
$parser->select("NAME|SYNOPSIS", "OPTIONS");
for (@filelist) { $parser->parse_from_file($_); }
## Select the "DESCRIPTION" and "SEE ALSO" sections of the PODs from
## STDIN and write the result to STDERR.
$parser->select("DESCRIPTION");
$parser->add_selection("SEE ALSO");
$parser->parse_from_filehandle(\*STDIN, \*STDERR);
=head1 REQUIRES
perl5.005, Pod::Parser, Exporter, Carp
=head1 EXPORTS
podselect()
=head1 DESCRIPTION
B<NOTE: This module is considered legacy; modern Perl releases (5.18 and
higher) are going to remove Pod-Parser from core and use L<Pod-Simple>
for all things POD.>
B<podselect()> is a function which will extract specified sections of
pod documentation from an input stream. This ability is provided by the
B<Pod::Select> module which is a subclass of B<Pod::Parser>.
B<Pod::Select> provides a method named B<select()> to specify the set of
POD sections to select for processing/printing. B<podselect()> merely
creates a B<Pod::Select> object and then invokes the B<podselect()>
followed by B<parse_from_file()>.
=head1 SECTION SPECIFICATIONS
B<podselect()> and B<Pod::Select::select()> may be given one or more
"section specifications" to restrict the text processed to only the
desired set of sections and their corresponding subsections. A section
specification is a string containing one or more Perl-style regular
expressions separated by forward slashes ("/"). If you need to use a
forward slash literally within a section title you can escape it with a
backslash ("\/").
The formal syntax of a section specification is:
=over 4
=item *
I<head1-title-regex>/I<head2-title-regex>/...
=back
Any omitted or empty regular expressions will default to ".*".
Please note that each regular expression given is implicitly
anchored by adding "^" and "$" to the beginning and end. Also, if a
given regular expression starts with a "!" character, then the
expression is I<negated> (so C<!foo> would match anything I<except>
C<foo>).
Some example section specifications follow.
=over 4
=item *
Match the C<NAME> and C<SYNOPSIS> sections and all of their subsections:
C<NAME|SYNOPSIS>
=item *
Match only the C<Question> and C<Answer> subsections of the C<DESCRIPTION>
section:
C<DESCRIPTION/Question|Answer>
=item *
Match the C<Comments> subsection of I<all> sections:
C</Comments>
=item *
Match all subsections of C<DESCRIPTION> I<except> for C<Comments>:
C<DESCRIPTION/!Comments>
=item *
Match the C<DESCRIPTION> section but do I<not> match any of its subsections:
C<DESCRIPTION/!.+>
=item *
Match all top level sections but none of their subsections:
C</!.+>
=back
=begin _NOT_IMPLEMENTED_
=head1 RANGE SPECIFICATIONS
B<podselect()> and B<Pod::Select::select()> may be given one or more
"range specifications" to restrict the text processed to only the
desired ranges of paragraphs in the desired set of sections. A range
specification is a string containing a single Perl-style regular
expression (a regex), or else two Perl-style regular expressions
(regexs) separated by a ".." (Perl's "range" operator is "..").
The regexs in a range specification are delimited by forward slashes
("/"). If you need to use a forward slash literally within a regex you
can escape it with a backslash ("\/").
The formal syntax of a range specification is:
=over 4
=item *
/I<start-range-regex>/[../I<end-range-regex>/]
=back
Where each the item inside square brackets (the ".." followed by the
end-range-regex) is optional. Each "range-regex" is of the form:
=cmd-expr text-expr
Where I<cmd-expr> is intended to match the name of one or more POD
commands, and I<text-expr> is intended to match the paragraph text for
the command. If a range-regex is supposed to match a POD command, then
the first character of the regex (the one after the initial '/')
absolutely I<must> be a single '=' character; it may not be anything
else (not even a regex meta-character) if it is supposed to match
against the name of a POD command.
If no I<=cmd-expr> is given then the text-expr will be matched against
plain textblocks unless it is preceded by a space, in which case it is
matched against verbatim text-blocks. If no I<text-expr> is given then
only the command-portion of the paragraph is matched against.
Note that these two expressions are each implicitly anchored. This
means that when matching against the command-name, there will be an
implicit '^' and '$' around the given I<=cmd-expr>; and when matching
against the paragraph text there will be an implicit '\A' and '\Z'
around the given I<text-expr>.
Unlike with section-specs, the '!' character does I<not> have any special
meaning (negation or otherwise) at the beginning of a range-spec!
Some example range specifications follow.
=over 4
=item
Match all C<=for html> paragraphs:
C</=for html/>
=item
Match all paragraphs between C<=begin html> and C<=end html>
(note that this will I<not> work correctly if such sections
are nested):
C</=begin html/../=end html/>
=item
Match all paragraphs between the given C<=item> name until the end of the
current section:
C</=item mine/../=head\d/>
=item
Match all paragraphs between the given C<=item> until the next item, or
until the end of the itemized list (note that this will I<not> work as
desired if the item contains an itemized list nested within it):
C</=item mine/../=(item|back)/>
=back
=end _NOT_IMPLEMENTED_
=cut
#############################################################################
#use diagnostics;
use Carp;
use Pod::Parser 1.04;
@ISA = qw(Pod::Parser);
@EXPORT = qw(&podselect);
## Maximum number of heading levels supported for '=headN' directives
*MAX_HEADING_LEVEL = \3;
#############################################################################
=head1 OBJECT METHODS
The following methods are provided in this module. Each one takes a
reference to the object itself as an implicit first parameter.
=cut
##---------------------------------------------------------------------------
## =begin _PRIVATE_
##
## =head1 B<_init_headings()>
##
## Initialize the current set of active section headings.
##
## =cut
##
## =end _PRIVATE_
sub _init_headings {
my $self = shift;
local *myData = $self;
## Initialize current section heading titles if necessary
unless (defined $myData{_SECTION_HEADINGS}) {
local *section_headings = $myData{_SECTION_HEADINGS} = [];
for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
$section_headings[$i] = '';
}
}
}
##---------------------------------------------------------------------------
=head1 B<curr_headings()>
($head1, $head2, $head3, ...) = $parser->curr_headings();
$head1 = $parser->curr_headings(1);
This method returns a list of the currently active section headings and
subheadings in the document being parsed. The list of headings returned
corresponds to the most recently parsed paragraph of the input.
If an argument is given, it must correspond to the desired section
heading number, in which case only the specified section heading is
returned. If there is no current section heading at the specified
level, then C<undef> is returned.
=cut
sub curr_headings {
my $self = shift;
$self->_init_headings() unless (defined $self->{_SECTION_HEADINGS});
my @headings = @{ $self->{_SECTION_HEADINGS} };
return (@_ > 0 and $_[0] =~ /^\d+$/) ? $headings[$_[0] - 1] : @headings;
}
##---------------------------------------------------------------------------
=head1 B<select()>
$parser->select($section_spec1,$section_spec2,...);
This method is used to select the particular sections and subsections of
POD documentation that are to be printed and/or processed. The existing
set of selected sections is I<replaced> with the given set of sections.
See B<add_selection()> for adding to the current set of selected
sections.
Each of the C<$section_spec> arguments should be a section specification
as described in L<"SECTION SPECIFICATIONS">. The section specifications
are parsed by this method and the resulting regular expressions are
stored in the invoking object.
If no C<$section_spec> arguments are given, then the existing set of
selected sections is cleared out (which means C<all> sections will be
processed).
This method should I<not> normally be overridden by subclasses.
=cut
sub select {
my ($self, @sections) = @_;
local *myData = $self;
local $_;
### NEED TO DISCERN A SECTION-SPEC FROM A RANGE-SPEC (look for m{^/.+/$}?)
##---------------------------------------------------------------------
## The following is a blatant hack for backward compatibility, and for
## implementing add_selection(). If the *first* *argument* is the
## string "+", then the remaining section specifications are *added*
## to the current set of selections; otherwise the given section
## specifications will *replace* the current set of selections.
##
## This should probably be fixed someday, but for the present time,
## it seems incredibly unlikely that "+" would ever correspond to
## a legitimate section heading
##---------------------------------------------------------------------
my $add = ($sections[0] eq '+') ? shift(@sections) : '';
## Reset the set of sections to use
unless (@sections) {
delete $myData{_SELECTED_SECTIONS} unless ($add);
return;
}
$myData{_SELECTED_SECTIONS} = []
unless ($add && exists $myData{_SELECTED_SECTIONS});
local *selected_sections = $myData{_SELECTED_SECTIONS};
## Compile each spec
for my $spec (@sections) {
if ( defined($_ = _compile_section_spec($spec)) ) {
## Store them in our sections array
push(@selected_sections, $_);
}
else {
carp qq{Ignoring section spec "$spec"!\n};
}
}
}
##---------------------------------------------------------------------------
=head1 B<add_selection()>
$parser->add_selection($section_spec1,$section_spec2,...);
This method is used to add to the currently selected sections and
subsections of POD documentation that are to be printed and/or
processed. See <select()> for replacing the currently selected sections.
Each of the C<$section_spec> arguments should be a section specification
as described in L<"SECTION SPECIFICATIONS">. The section specifications
are parsed by this method and the resulting regular expressions are
stored in the invoking object.
This method should I<not> normally be overridden by subclasses.
=cut
sub add_selection {
my $self = shift;
return $self->select('+', @_);
}
##---------------------------------------------------------------------------
=head1 B<clear_selections()>
$parser->clear_selections();
This method takes no arguments, it has the exact same effect as invoking
<select()> with no arguments.
=cut
sub clear_selections {
my $self = shift;
return $self->select();
}
##---------------------------------------------------------------------------
=head1 B<match_section()>
$boolean = $parser->match_section($heading1,$heading2,...);
Returns a value of true if the given section and subsection heading
titles match any of the currently selected section specifications in
effect from prior calls to B<select()> and B<add_selection()> (or if
there are no explicitly selected/deselected sections).
The arguments C<$heading1>, C<$heading2>, etc. are the heading titles of
the corresponding sections, subsections, etc. to try and match. If
C<$headingN> is omitted then it defaults to the current corresponding
section heading title in the input.
This method should I<not> normally be overridden by subclasses.
=cut
sub match_section {
my $self = shift;
my (@headings) = @_;
local *myData = $self;
## Return true if no restrictions were explicitly specified
my $selections = (exists $myData{_SELECTED_SECTIONS})
? $myData{_SELECTED_SECTIONS} : undef;
return 1 unless ((defined $selections) && @{$selections});
## Default any unspecified sections to the current one
my @current_headings = $self->curr_headings();
for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
(defined $headings[$i]) or $headings[$i] = $current_headings[$i];
}
## Look for a match against the specified section expressions
for my $section_spec ( @{$selections} ) {
##------------------------------------------------------
## Each portion of this spec must match in order for
## the spec to be matched. So we will start with a
## match-value of 'true' and logically 'and' it with
## the results of matching a given element of the spec.
##------------------------------------------------------
my $match = 1;
for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
my $regex = $section_spec->[$i];
my $negated = ($regex =~ s/^\!//);
$match &= ($negated ? ($headings[$i] !~ /${regex}/)
: ($headings[$i] =~ /${regex}/));
last unless ($match);
}
return 1 if ($match);
}
return 0; ## no match
}
##---------------------------------------------------------------------------
=head1 B<is_selected()>
$boolean = $parser->is_selected($paragraph);
This method is used to determine if the block of text given in
C<$paragraph> falls within the currently selected set of POD sections
and subsections to be printed or processed. This method is also
responsible for keeping track of the current input section and
subsections. It is assumed that C<$paragraph> is the most recently read
(but not yet processed) input paragraph.
The value returned will be true if the C<$paragraph> and the rest of the
text in the same section as C<$paragraph> should be selected (included)
for processing; otherwise a false value is returned.
=cut
sub is_selected {
my ($self, $paragraph) = @_;
local $_;
local *myData = $self;
$self->_init_headings() unless (defined $myData{_SECTION_HEADINGS});
## Keep track of current sections levels and headings
$_ = $paragraph;
if (/^=((?:sub)*)(?:head(?:ing)?|sec(?:tion)?)(\d*)\s+(.*?)\s*$/)
{
## This is a section heading command
my ($level, $heading) = ($2, $3);
$level = 1 + (length($1) / 3) if ((! length $level) || (length $1));
## Reset the current section heading at this level
$myData{_SECTION_HEADINGS}->[$level - 1] = $heading;
## Reset subsection headings of this one to empty
for (my $i = $level; $i < $MAX_HEADING_LEVEL; ++$i) {
$myData{_SECTION_HEADINGS}->[$i] = '';
}
}
return $self->match_section();
}
#############################################################################
=head1 EXPORTED FUNCTIONS
The following functions are exported by this module. Please note that
these are functions (not methods) and therefore C<do not> take an
implicit first argument.
=cut
##---------------------------------------------------------------------------
=head1 B<podselect()>
podselect(\%options,@filelist);
B<podselect> will print the raw (untranslated) POD paragraphs of all
POD sections in the given input files specified by C<@filelist>
according to the options given in C<\%options>.
If any argument to B<podselect> is a reference to a hash
(associative array) then the values with the following keys are
processed as follows:
=over 4
=item B<-output>
A string corresponding to the desired output file (or ">&STDOUT"
or ">&STDERR"), or a filehandle to write on. The default is to use
standard output.
=item B<-sections>
A reference to an array of sections specifications (as described in
L<"SECTION SPECIFICATIONS">) which indicate the desired set of POD
sections and subsections to be selected from input. If no section
specifications are given, then all sections of the PODs are used.
=begin _NOT_IMPLEMENTED_
=item B<-ranges>
A reference to an array of range specifications (as described in
L<"RANGE SPECIFICATIONS">) which indicate the desired range of POD
paragraphs to be selected from the desired input sections. If no range
specifications are given, then all paragraphs of the desired sections
are used.
=end _NOT_IMPLEMENTED_
=back
All other arguments are optional and should correspond to filehandles to
read from or the names of input files containing POD sections. A file name
of "", "-" or "<&STDIN" will be interpreted to mean standard input (which
is the default if no arguments are given).
=cut
sub podselect {
my(@argv) = @_;
my %defaults = ();
my $pod_parser = new Pod::Select(%defaults);
my $num_inputs = 0;
my $output = '>&STDOUT';
my %opts;
local $_;
for (@argv) {
my $ref = ref($_);
if ($ref && $ref eq 'HASH') {
%opts = (%defaults, %{$_});
##-------------------------------------------------------------
## Need this for backward compatibility since we formerly used
## options that were all uppercase words rather than ones that
## looked like Unix command-line options.
## to be uppercase keywords)
##-------------------------------------------------------------
%opts = map {
my ($key, $val) = (lc $_, $opts{$_});
$key =~ s/^(?=\w)/-/;
$key =~ /^-se[cl]/ and $key = '-sections';
#! $key eq '-range' and $key .= 's';
($key => $val);
} (keys %opts);
## Process the options
(exists $opts{'-output'}) and $output = $opts{'-output'};
## Select the desired sections
$pod_parser->select(@{ $opts{'-sections'} })
if ( (defined $opts{'-sections'})
&& ((ref $opts{'-sections'}) eq 'ARRAY') );
#! ## Select the desired paragraph ranges
#! $pod_parser->select(@{ $opts{'-ranges'} })
#! if ( (defined $opts{'-ranges'})
#! && ((ref $opts{'-ranges'}) eq 'ARRAY') );
}
elsif(!$ref || $ref eq 'GLOB') {
$pod_parser->parse_from_file($_, $output);
++$num_inputs;
}
else {
croak "Input from $ref reference not supported!\n";
}
}
$pod_parser->parse_from_file('-') unless ($num_inputs > 0);
}
#############################################################################
=head1 PRIVATE METHODS AND DATA
B<Pod::Select> makes uses a number of internal methods and data fields
which clients should not need to see or use. For the sake of avoiding
name collisions with client data and methods, these methods and fields
are briefly discussed here. Determined hackers may obtain further
information about them by reading the B<Pod::Select> source code.
Private data fields are stored in the hash-object whose reference is
returned by the B<new()> constructor for this class. The names of all
private methods and data-fields used by B<Pod::Select> begin with a
prefix of "_" and match the regular expression C</^_\w+$/>.
=cut
##---------------------------------------------------------------------------
=begin _PRIVATE_
=head1 B<_compile_section_spec()>
$listref = $parser->_compile_section_spec($section_spec);
This function (note it is a function and I<not> a method) takes a
section specification (as described in L<"SECTION SPECIFICATIONS">)
given in C<$section_sepc>, and compiles it into a list of regular
expressions. If C<$section_spec> has no syntax errors, then a reference
to the list (array) of corresponding regular expressions is returned;
otherwise C<undef> is returned and an error message is printed (using
B<carp>) for each invalid regex.
=end _PRIVATE_
=cut
sub _compile_section_spec {
my ($section_spec) = @_;
my (@regexs, $negated);
## Compile the spec into a list of regexs
local $_ = $section_spec;
s{\\\\}{\001}g; ## handle escaped backward slashes
s{\\/}{\002}g; ## handle escaped forward slashes
## Parse the regexs for the heading titles
@regexs = split(/\//, $_, $MAX_HEADING_LEVEL);
## Set default regex for omitted levels
for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
$regexs[$i] = '.*' unless ((defined $regexs[$i])
&& (length $regexs[$i]));
}
## Modify the regexs as needed and validate their syntax
my $bad_regexs = 0;
for (@regexs) {
$_ .= '.+' if ($_ eq '!');
s{\001}{\\\\}g; ## restore escaped backward slashes
s{\002}{\\/}g; ## restore escaped forward slashes
$negated = s/^\!//; ## check for negation
eval "m{$_}"; ## check regex syntax
if ($@) {
++$bad_regexs;
carp qq{Bad regular expression /$_/ in "$section_spec": $@\n};
}
else {
## Add the forward and rear anchors (and put the negator back)
$_ = '^' . $_ unless (/^\^/);
$_ = $_ . '$' unless (/\$$/);
$_ = '!' . $_ if ($negated);
}
}
return (! $bad_regexs) ? [ @regexs ] : undef;
}
##---------------------------------------------------------------------------
=begin _PRIVATE_
=head2 $self->{_SECTION_HEADINGS}
A reference to an array of the current section heading titles for each
heading level (note that the first heading level title is at index 0).
=end _PRIVATE_
=cut
##---------------------------------------------------------------------------
=begin _PRIVATE_
=head2 $self->{_SELECTED_SECTIONS}
A reference to an array of references to arrays. Each subarray is a list
of anchored regular expressions (preceded by a "!" if the expression is to
be negated). The index of the expression in the subarray should correspond
to the index of the heading title in C<$self-E<gt>{_SECTION_HEADINGS}>
that it is to be matched against.
=end _PRIVATE_
=cut
#############################################################################
=head1 SEE ALSO
L<Pod::Parser>
=head1 AUTHOR
Please report bugs using L<http://rt.cpan.org>.
Brad Appleton E<lt>bradapp@enteract.comE<gt>
Based on code for B<pod2text> written by
Tom Christiansen E<lt>tchrist@mox.perl.comE<gt>
B<Pod::Select> is part of the L<Pod::Parser> distribution.
=cut
1;
# vim: ts=4 sw=4 et
PlainText.pm 0000644 00000061760 15051135563 0007030 0 ustar 00 # Pod::PlainText -- Convert POD data to formatted ASCII text.
# $Id: Text.pm,v 2.1 1999/09/20 11:53:33 eagle Exp $
#
# Copyright 1999-2000 by Russ Allbery <rra@stanford.edu>
#
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.
#
# This module is intended to be a replacement for Pod::Text, and attempts to
# match its output except for some specific circumstances where other
# decisions seemed to produce better output. It uses Pod::Parser and is
# designed to be very easy to subclass.
############################################################################
# Modules and declarations
############################################################################
package Pod::PlainText;
use strict;
require 5.005;
use Carp qw(carp croak);
use Pod::Select ();
use vars qw(@ISA %ESCAPES $VERSION);
# We inherit from Pod::Select instead of Pod::Parser so that we can be used
# by Pod::Usage.
@ISA = qw(Pod::Select);
$VERSION = '2.07';
BEGIN {
if ($] < 5.006) {
require Symbol;
import Symbol;
}
}
############################################################################
# Table of supported E<> escapes
############################################################################
# This table is taken near verbatim from Pod::PlainText in Pod::Parser,
# which got it near verbatim from the original Pod::Text. It is therefore
# credited to Tom Christiansen, and I'm glad I didn't have to write it. :)
%ESCAPES = (
'amp' => '&', # ampersand
'lt' => '<', # left chevron, less-than
'gt' => '>', # right chevron, greater-than
'quot' => '"', # double quote
"Aacute" => "\xC1", # capital A, acute accent
"aacute" => "\xE1", # small a, acute accent
"Acirc" => "\xC2", # capital A, circumflex accent
"acirc" => "\xE2", # small a, circumflex accent
"AElig" => "\xC6", # capital AE diphthong (ligature)
"aelig" => "\xE6", # small ae diphthong (ligature)
"Agrave" => "\xC0", # capital A, grave accent
"agrave" => "\xE0", # small a, grave accent
"Aring" => "\xC5", # capital A, ring
"aring" => "\xE5", # small a, ring
"Atilde" => "\xC3", # capital A, tilde
"atilde" => "\xE3", # small a, tilde
"Auml" => "\xC4", # capital A, dieresis or umlaut mark
"auml" => "\xE4", # small a, dieresis or umlaut mark
"Ccedil" => "\xC7", # capital C, cedilla
"ccedil" => "\xE7", # small c, cedilla
"Eacute" => "\xC9", # capital E, acute accent
"eacute" => "\xE9", # small e, acute accent
"Ecirc" => "\xCA", # capital E, circumflex accent
"ecirc" => "\xEA", # small e, circumflex accent
"Egrave" => "\xC8", # capital E, grave accent
"egrave" => "\xE8", # small e, grave accent
"ETH" => "\xD0", # capital Eth, Icelandic
"eth" => "\xF0", # small eth, Icelandic
"Euml" => "\xCB", # capital E, dieresis or umlaut mark
"euml" => "\xEB", # small e, dieresis or umlaut mark
"Iacute" => "\xCD", # capital I, acute accent
"iacute" => "\xED", # small i, acute accent
"Icirc" => "\xCE", # capital I, circumflex accent
"icirc" => "\xEE", # small i, circumflex accent
"Igrave" => "\xCD", # capital I, grave accent
"igrave" => "\xED", # small i, grave accent
"Iuml" => "\xCF", # capital I, dieresis or umlaut mark
"iuml" => "\xEF", # small i, dieresis or umlaut mark
"Ntilde" => "\xD1", # capital N, tilde
"ntilde" => "\xF1", # small n, tilde
"Oacute" => "\xD3", # capital O, acute accent
"oacute" => "\xF3", # small o, acute accent
"Ocirc" => "\xD4", # capital O, circumflex accent
"ocirc" => "\xF4", # small o, circumflex accent
"Ograve" => "\xD2", # capital O, grave accent
"ograve" => "\xF2", # small o, grave accent
"Oslash" => "\xD8", # capital O, slash
"oslash" => "\xF8", # small o, slash
"Otilde" => "\xD5", # capital O, tilde
"otilde" => "\xF5", # small o, tilde
"Ouml" => "\xD6", # capital O, dieresis or umlaut mark
"ouml" => "\xF6", # small o, dieresis or umlaut mark
"szlig" => "\xDF", # small sharp s, German (sz ligature)
"THORN" => "\xDE", # capital THORN, Icelandic
"thorn" => "\xFE", # small thorn, Icelandic
"Uacute" => "\xDA", # capital U, acute accent
"uacute" => "\xFA", # small u, acute accent
"Ucirc" => "\xDB", # capital U, circumflex accent
"ucirc" => "\xFB", # small u, circumflex accent
"Ugrave" => "\xD9", # capital U, grave accent
"ugrave" => "\xF9", # small u, grave accent
"Uuml" => "\xDC", # capital U, dieresis or umlaut mark
"uuml" => "\xFC", # small u, dieresis or umlaut mark
"Yacute" => "\xDD", # capital Y, acute accent
"yacute" => "\xFD", # small y, acute accent
"yuml" => "\xFF", # small y, dieresis or umlaut mark
"lchevron" => "\xAB", # left chevron (double less than)
"rchevron" => "\xBB", # right chevron (double greater than)
);
############################################################################
# Initialization
############################################################################
# Initialize the object. Must be sure to call our parent initializer.
sub initialize {
my $self = shift;
$$self{alt} = 0 unless defined $$self{alt};
$$self{indent} = 4 unless defined $$self{indent};
$$self{loose} = 0 unless defined $$self{loose};
$$self{sentence} = 0 unless defined $$self{sentence};
$$self{width} = 76 unless defined $$self{width};
$$self{INDENTS} = []; # Stack of indentations.
$$self{MARGIN} = $$self{indent}; # Current left margin in spaces.
return $self->SUPER::initialize;
}
############################################################################
# Core overrides
############################################################################
# Called for each command paragraph. Gets the command, the associated
# paragraph, the line number, and a Pod::Paragraph object. Just dispatches
# the command to a method named the same as the command. =cut is handled
# internally by Pod::Parser.
sub command {
my $self = shift;
my $command = shift;
return if $command eq 'pod';
return if ($$self{EXCLUDE} && $command ne 'end');
if (defined $$self{ITEM}) {
$self->item ("\n");
local $_ = "\n";
$self->output($_) if($command eq 'back');
}
$command = 'cmd_' . $command;
return $self->$command (@_);
}
# Called for a verbatim paragraph. Gets the paragraph, the line number, and
# a Pod::Paragraph object. Just output it verbatim, but with tabs converted
# to spaces.
sub verbatim {
my $self = shift;
return if $$self{EXCLUDE};
$self->item if defined $$self{ITEM};
local $_ = shift;
return if /^\s*$/;
s/^(\s*\S+)/(' ' x $$self{MARGIN}) . $1/gme;
return $self->output($_);
}
# Called for a regular text block. Gets the paragraph, the line number, and
# a Pod::Paragraph object. Perform interpolation and output the results.
sub textblock {
my $self = shift;
return if $$self{EXCLUDE};
if($$self{VERBATIM}) {
$self->output($_[0]);
return;
}
local $_ = shift;
my $line = shift;
# Perform a little magic to collapse multiple L<> references. This is
# here mostly for backwards-compatibility. We'll just rewrite the whole
# thing into actual text at this part, bypassing the whole internal
# sequence parsing thing.
s{
(
L< # A link of the form L</something>.
/
(
[:\w]+ # The item has to be a simple word...
(\(\))? # ...or simple function.
)
>
(
,?\s+(and\s+)? # Allow lots of them, conjuncted.
L<
/
(
[:\w]+
(\(\))?
)
>
)+
)
} {
local $_ = $1;
s%L</([^>]+)>%$1%g;
my @items = split /(?:,?\s+(?:and\s+)?)/;
my $string = "the ";
my $i;
for ($i = 0; $i < @items; $i++) {
$string .= $items[$i];
$string .= ", " if @items > 2 && $i != $#items;
$string .= " and " if ($i == $#items - 1);
}
$string .= " entries elsewhere in this document";
$string;
}gex;
# Now actually interpolate and output the paragraph.
$_ = $self->interpolate ($_, $line);
s/\s*$/\n/s;
if (defined $$self{ITEM}) {
$self->item ($_ . "\n");
} else {
$self->output ($self->reformat ($_ . "\n"));
}
}
# Called for an interior sequence. Gets the command, argument, and a
# Pod::InteriorSequence object and is expected to return the resulting text.
# Calls code, bold, italic, file, and link to handle those types of
# sequences, and handles S<>, E<>, X<>, and Z<> directly.
sub interior_sequence {
my $self = shift;
my $command = shift;
local $_ = shift;
return '' if ($command eq 'X' || $command eq 'Z');
# Expand escapes into the actual character now, carping if invalid.
if ($command eq 'E') {
return $ESCAPES{$_} if defined $ESCAPES{$_};
carp "Unknown escape: E<$_>";
return "E<$_>";
}
# For all the other sequences, empty content produces no output.
return if $_ eq '';
# For S<>, compress all internal whitespace and then map spaces to \01.
# When we output the text, we'll map this back.
if ($command eq 'S') {
s/\s{2,}/ /g;
tr/ /\01/;
return $_;
}
# Anything else needs to get dispatched to another method.
if ($command eq 'B') { return $self->seq_b ($_) }
elsif ($command eq 'C') { return $self->seq_c ($_) }
elsif ($command eq 'F') { return $self->seq_f ($_) }
elsif ($command eq 'I') { return $self->seq_i ($_) }
elsif ($command eq 'L') { return $self->seq_l ($_) }
else { carp "Unknown sequence $command<$_>" }
}
# Called for each paragraph that's actually part of the POD. We take
# advantage of this opportunity to untabify the input.
sub preprocess_paragraph {
my $self = shift;
local $_ = shift;
1 while s/^(.*?)(\t+)/$1 . ' ' x (length ($2) * 8 - length ($1) % 8)/me;
return $_;
}
############################################################################
# Command paragraphs
############################################################################
# All command paragraphs take the paragraph and the line number.
# First level heading.
sub cmd_head1 {
my $self = shift;
local $_ = shift;
s/\s+$//s;
$_ = $self->interpolate ($_, shift);
if ($$self{alt}) {
$self->output ("\n==== $_ ====\n\n");
} else {
$_ .= "\n" if $$self{loose};
$self->output ($_ . "\n");
}
}
# Second level heading.
sub cmd_head2 {
my $self = shift;
local $_ = shift;
s/\s+$//s;
$_ = $self->interpolate ($_, shift);
if ($$self{alt}) {
$self->output ("\n== $_ ==\n\n");
} else {
$_ .= "\n" if $$self{loose};
$self->output (' ' x ($$self{indent} / 2) . $_ . "\n");
}
}
# third level heading - not strictly perlpodspec compliant
sub cmd_head3 {
my $self = shift;
local $_ = shift;
s/\s+$//s;
$_ = $self->interpolate ($_, shift);
if ($$self{alt}) {
$self->output ("\n= $_ =\n");
} else {
$_ .= "\n" if $$self{loose};
$self->output (' ' x ($$self{indent}) . $_ . "\n");
}
}
# fourth level heading - not strictly perlpodspec compliant
# just like head3
*cmd_head4 = \&cmd_head3;
# Start a list.
sub cmd_over {
my $self = shift;
local $_ = shift;
unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
push (@{ $$self{INDENTS} }, $$self{MARGIN});
$$self{MARGIN} += ($_ + 0);
}
# End a list.
sub cmd_back {
my $self = shift;
$$self{MARGIN} = pop @{ $$self{INDENTS} };
unless (defined $$self{MARGIN}) {
carp 'Unmatched =back';
$$self{MARGIN} = $$self{indent};
}
}
# An individual list item.
sub cmd_item {
my $self = shift;
if (defined $$self{ITEM}) { $self->item }
local $_ = shift;
s/\s+$//s;
$$self{ITEM} = $self->interpolate ($_);
}
# Begin a block for a particular translator. Setting VERBATIM triggers
# special handling in textblock().
sub cmd_begin {
my $self = shift;
local $_ = shift;
my ($kind) = /^(\S+)/ or return;
if ($kind eq 'text') {
$$self{VERBATIM} = 1;
} else {
$$self{EXCLUDE} = 1;
}
}
# End a block for a particular translator. We assume that all =begin/=end
# pairs are properly closed.
sub cmd_end {
my $self = shift;
$$self{EXCLUDE} = 0;
$$self{VERBATIM} = 0;
}
# One paragraph for a particular translator. Ignore it unless it's intended
# for text, in which case we treat it as a verbatim text block.
sub cmd_for {
my $self = shift;
local $_ = shift;
my $line = shift;
return unless s/^text\b[ \t]*\r?\n?//;
$self->verbatim ($_, $line);
}
# just a dummy method for the time being
sub cmd_encoding {
return;
}
############################################################################
# Interior sequences
############################################################################
# The simple formatting ones. These are here mostly so that subclasses can
# override them and do more complicated things.
sub seq_b { return $_[0]{alt} ? "``$_[1]''" : $_[1] }
sub seq_c { return $_[0]{alt} ? "``$_[1]''" : "`$_[1]'" }
sub seq_f { return $_[0]{alt} ? "\"$_[1]\"" : $_[1] }
sub seq_i { return '*' . $_[1] . '*' }
# The complicated one. Handle links. Since this is plain text, we can't
# actually make any real links, so this is all to figure out what text we
# print out.
sub seq_l {
my $self = shift;
local $_ = shift;
# Smash whitespace in case we were split across multiple lines.
s/\s+/ /g;
# If we were given any explicit text, just output it.
if (/^([^|]+)\|/) { return $1 }
# Okay, leading and trailing whitespace isn't important; get rid of it.
s/^\s+//;
s/\s+$//;
# Default to using the whole content of the link entry as a section
# name. Note that L<manpage/> forces a manpage interpretation, as does
# something looking like L<manpage(section)>. The latter is an
# enhancement over the original Pod::Text.
my ($manpage, $section) = ('', $_);
if (/^(?:https?|ftp|news):/) {
# a URL
return $_;
} elsif (/^"\s*(.*?)\s*"$/) {
$section = '"' . $1 . '"';
} elsif (m/^[-:.\w]+(?:\(\S+\))?$/) {
($manpage, $section) = ($_, '');
} elsif (m{/}) {
($manpage, $section) = split (/\s*\/\s*/, $_, 2);
}
my $text = '';
# Now build the actual output text.
if (!length $section) {
$text = "the $manpage manpage" if length $manpage;
} elsif ($section =~ /^[:\w]+(?:\(\))?/) {
$text .= 'the ' . $section . ' entry';
$text .= (length $manpage) ? " in the $manpage manpage"
: ' elsewhere in this document';
} else {
$section =~ s/^\"\s*//;
$section =~ s/\s*\"$//;
$text .= 'the section on "' . $section . '"';
$text .= " in the $manpage manpage" if length $manpage;
}
return $text;
}
############################################################################
# List handling
############################################################################
# This method is called whenever an =item command is complete (in other
# words, we've seen its associated paragraph or know for certain that it
# doesn't have one). It gets the paragraph associated with the item as an
# argument. If that argument is empty, just output the item tag; if it
# contains a newline, output the item tag followed by the newline.
# Otherwise, see if there's enough room for us to output the item tag in the
# margin of the text or if we have to put it on a separate line.
sub item {
my $self = shift;
local $_ = shift;
my $tag = $$self{ITEM};
unless (defined $tag) {
carp 'item called without tag';
return;
}
undef $$self{ITEM};
my $indent = $$self{INDENTS}[-1];
unless (defined $indent) { $indent = $$self{indent} }
my $space = ' ' x $indent;
$space =~ s/^ /:/ if $$self{alt};
if (!$_ || /^\s+$/ || ($$self{MARGIN} - $indent < length ($tag) + 1)) {
my $margin = $$self{MARGIN};
$$self{MARGIN} = $indent;
my $output = $self->reformat ($tag);
$output =~ s/[\r\n]*$/\n/;
$self->output ($output);
$$self{MARGIN} = $margin;
$self->output ($self->reformat ($_)) if /\S/;
} else {
$_ = $self->reformat ($_);
s/^ /:/ if ($$self{alt} && $indent > 0);
my $tagspace = ' ' x length $tag;
s/^($space)$tagspace/$1$tag/ or carp 'Bizarre space in item';
$self->output ($_);
}
}
############################################################################
# Output formatting
############################################################################
# Wrap a line, indenting by the current left margin. We can't use
# Text::Wrap because it plays games with tabs. We can't use formline, even
# though we'd really like to, because it screws up non-printing characters.
# So we have to do the wrapping ourselves.
sub wrap {
my $self = shift;
local $_ = shift;
my $output = '';
my $spaces = ' ' x $$self{MARGIN};
my $width = $$self{width} - $$self{MARGIN};
while (length > $width) {
if (s/^([^\r\n]{0,$width})\s+// || s/^([^\r\n]{$width})//) {
$output .= $spaces . $1 . "\n";
} else {
last;
}
}
$output .= $spaces . $_;
$output =~ s/\s+$/\n\n/;
return $output;
}
# Reformat a paragraph of text for the current margin. Takes the text to
# reformat and returns the formatted text.
sub reformat {
my $self = shift;
local $_ = shift;
# If we're trying to preserve two spaces after sentences, do some
# munging to support that. Otherwise, smash all repeated whitespace.
if ($$self{sentence}) {
s/ +$//mg;
s/\.\r?\n/. \n/g;
s/[\r\n]+/ /g;
s/ +/ /g;
} else {
s/\s+/ /g;
}
return $self->wrap($_);
}
# Output text to the output device.
sub output { $_[1] =~ tr/\01/ /; print { $_[0]->output_handle } $_[1] }
############################################################################
# Backwards compatibility
############################################################################
# The old Pod::Text module did everything in a pod2text() function. This
# tries to provide the same interface for legacy applications.
sub pod2text {
my @args;
# This is really ugly; I hate doing option parsing in the middle of a
# module. But the old Pod::Text module supported passing flags to its
# entry function, so handle -a and -<number>.
while ($_[0] =~ /^-/) {
my $flag = shift;
if ($flag eq '-a') { push (@args, alt => 1) }
elsif ($flag =~ /^-(\d+)$/) { push (@args, width => $1) }
else {
unshift (@_, $flag);
last;
}
}
# Now that we know what arguments we're using, create the parser.
my $parser = Pod::PlainText->new (@args);
# If two arguments were given, the second argument is going to be a file
# handle. That means we want to call parse_from_filehandle(), which
# means we need to turn the first argument into a file handle. Magic
# open will handle the <&STDIN case automagically.
if (defined $_[1]) {
my $infh;
if ($] < 5.006) {
$infh = gensym();
}
unless (open ($infh, $_[0])) {
croak ("Can't open $_[0] for reading: $!\n");
}
$_[0] = $infh;
return $parser->parse_from_filehandle (@_);
} else {
return $parser->parse_from_file (@_);
}
}
############################################################################
# Module return value and documentation
############################################################################
1;
__END__
=head1 NAME
Pod::PlainText - Convert POD data to formatted ASCII text
=head1 SYNOPSIS
use Pod::PlainText;
my $parser = Pod::PlainText->new (sentence => 0, width => 78);
# Read POD from STDIN and write to STDOUT.
$parser->parse_from_filehandle;
# Read POD from file.pod and write to file.txt.
$parser->parse_from_file ('file.pod', 'file.txt');
=head1 DESCRIPTION
B<NOTE: This module is considered legacy; modern Perl releases (5.18 and
higher) are going to remove Pod-Parser from core and use L<Pod-Simple>
for all things POD.>
Pod::PlainText is a module that can convert documentation in the POD format (the
preferred language for documenting Perl) into formatted ASCII. It uses no
special formatting controls or codes whatsoever, and its output is therefore
suitable for nearly any device.
As a derived class from Pod::Parser, Pod::PlainText supports the same methods and
interfaces. See L<Pod::Parser> for all the details; briefly, one creates a
new parser with C<Pod::PlainText-E<gt>new()> and then calls either
parse_from_filehandle() or parse_from_file().
new() can take options, in the form of key/value pairs, that control the
behavior of the parser. The currently recognized options are:
=over 4
=item alt
If set to a true value, selects an alternate output format that, among other
things, uses a different heading style and marks C<=item> entries with a
colon in the left margin. Defaults to false.
=item indent
The number of spaces to indent regular text, and the default indentation for
C<=over> blocks. Defaults to 4.
=item loose
If set to a true value, a blank line is printed after a C<=headN> headings.
If set to false (the default), no blank line is printed after C<=headN>.
This is the default because it's the expected formatting for manual pages;
if you're formatting arbitrary text documents, setting this to true may
result in more pleasing output.
=item sentence
If set to a true value, Pod::PlainText will assume that each sentence ends in two
spaces, and will try to preserve that spacing. If set to false, all
consecutive whitespace in non-verbatim paragraphs is compressed into a
single space. Defaults to true.
=item width
The column at which to wrap text on the right-hand side. Defaults to 76.
=back
The standard Pod::Parser method parse_from_filehandle() takes up to two
arguments, the first being the file handle to read POD from and the second
being the file handle to write the formatted output to. The first defaults
to STDIN if not given, and the second defaults to STDOUT. The method
parse_from_file() is almost identical, except that its two arguments are the
input and output disk files instead. See L<Pod::Parser> for the specific
details.
=head1 DIAGNOSTICS
=over 4
=item Bizarre space in item
(W) Something has gone wrong in internal C<=item> processing. This message
indicates a bug in Pod::PlainText; you should never see it.
=item Can't open %s for reading: %s
(F) Pod::PlainText was invoked via the compatibility mode pod2text() interface
and the input file it was given could not be opened.
=item Unknown escape: %s
(W) The POD source contained an C<EE<lt>E<gt>> escape that Pod::PlainText didn't
know about.
=item Unknown sequence: %s
(W) The POD source contained a non-standard internal sequence (something of
the form C<XE<lt>E<gt>>) that Pod::PlainText didn't know about.
=item Unmatched =back
(W) Pod::PlainText encountered a C<=back> command that didn't correspond to an
C<=over> command.
=back
=head1 RESTRICTIONS
Embedded Ctrl-As (octal 001) in the input will be mapped to spaces on
output, due to an internal implementation detail.
=head1 NOTES
This is a replacement for an earlier Pod::Text module written by Tom
Christiansen. It has a revamped interface, since it now uses Pod::Parser,
but an interface roughly compatible with the old Pod::Text::pod2text()
function is still available. Please change to the new calling convention,
though.
The original Pod::Text contained code to do formatting via termcap
sequences, although it wasn't turned on by default and it was problematic to
get it to work at all. This rewrite doesn't even try to do that, but a
subclass of it does. Look for L<Pod::Text::Termcap|Pod::Text::Termcap>.
=head1 SEE ALSO
B<Pod::PlainText> is part of the L<Pod::Parser> distribution.
L<Pod::Parser|Pod::Parser>, L<Pod::Text::Termcap|Pod::Text::Termcap>,
pod2text(1)
=head1 AUTHOR
Please report bugs using L<http://rt.cpan.org>.
Russ Allbery E<lt>rra@stanford.eduE<gt>, based I<very> heavily on the
original Pod::Text by Tom Christiansen E<lt>tchrist@mox.perl.comE<gt> and
its conversion to Pod::Parser by Brad Appleton
E<lt>bradapp@enteract.comE<gt>.
=cut
ParseLink.pm 0000644 00000014373 15051135563 0007006 0 ustar 00 # Parse an L<> formatting code in POD text.
#
# This module implements parsing of the text of an L<> formatting code as
# defined in perlpodspec. It should be suitable for any POD formatter. It
# exports only one function, parselink(), which returns the five-item parse
# defined in perlpodspec.
#
# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl
##############################################################################
# Modules and declarations
##############################################################################
package Pod::ParseLink;
use 5.006;
use strict;
use warnings;
use vars qw(@EXPORT @ISA $VERSION);
use Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(parselink);
$VERSION = '4.11';
##############################################################################
# Implementation
##############################################################################
# Parse the name and section portion of a link into a name and section.
sub _parse_section {
my ($link) = @_;
$link =~ s/^\s+//;
$link =~ s/\s+$//;
# If the whole link is enclosed in quotes, interpret it all as a section
# even if it contains a slash.
return (undef, $1) if ($link =~ /^"\s*(.*?)\s*"$/);
# Split into page and section on slash, and then clean up quoting in the
# section. If there is no section and the name contains spaces, also
# guess that it's an old section link.
my ($page, $section) = split (/\s*\/\s*/, $link, 2);
$section =~ s/^"\s*(.*?)\s*"$/$1/ if $section;
if ($page && $page =~ / / && !defined ($section)) {
$section = $page;
$page = undef;
} else {
$page = undef unless $page;
$section = undef unless $section;
}
return ($page, $section);
}
# Infer link text from the page and section.
sub _infer_text {
my ($page, $section) = @_;
my $inferred;
if ($page && !$section) {
$inferred = $page;
} elsif (!$page && $section) {
$inferred = '"' . $section . '"';
} elsif ($page && $section) {
$inferred = '"' . $section . '" in ' . $page;
}
return $inferred;
}
# Given the contents of an L<> formatting code, parse it into the link text,
# the possibly inferred link text, the name or URL, the section, and the type
# of link (pod, man, or url).
sub parselink {
my ($link) = @_;
$link =~ s/\s+/ /g;
my $text;
if ($link =~ /\|/) {
($text, $link) = split (/\|/, $link, 2);
}
if ($link =~ /\A\w+:[^:\s]\S*\Z/) {
my $inferred;
if (defined ($text) && length ($text) > 0) {
return ($text, $text, $link, undef, 'url');
} else {
return ($text, $link, $link, undef, 'url');
}
} else {
my ($name, $section) = _parse_section ($link);
my $inferred;
if (defined ($text) && length ($text) > 0) {
$inferred = $text;
} else {
$inferred = _infer_text ($name, $section);
}
my $type = ($name && $name =~ /\(\S*\)/) ? 'man' : 'pod';
return ($text, $inferred, $name, $section, $type);
}
}
##############################################################################
# Module return value and documentation
##############################################################################
# Ensure we evaluate to true.
1;
__END__
=for stopwords
markup Allbery URL
=head1 NAME
Pod::ParseLink - Parse an LE<lt>E<gt> formatting code in POD text
=head1 SYNOPSIS
use Pod::ParseLink;
my $link = get_link();
my ($text, $inferred, $name, $section, $type) = parselink($link);
=head1 DESCRIPTION
This module only provides a single function, parselink(), which takes the
text of an LE<lt>E<gt> formatting code and parses it. It returns the
anchor text for the link (if any was given), the anchor text possibly
inferred from the name and section, the name or URL, the section if any,
and the type of link. The type will be one of C<url>, C<pod>, or C<man>,
indicating a URL, a link to a POD page, or a link to a Unix manual page.
Parsing is implemented per L<perlpodspec>. For backward compatibility,
links where there is no section and name contains spaces, or links where the
entirety of the link (except for the anchor text if given) is enclosed in
double-quotes are interpreted as links to a section (LE<lt>/sectionE<gt>).
The inferred anchor text is implemented per L<perlpodspec>:
L<name> => L<name|name>
L</section> => L<"section"|/section>
L<name/section> => L<"section" in name|name/section>
The name may contain embedded EE<lt>E<gt> and ZE<lt>E<gt> formatting codes,
and the section, anchor text, and inferred anchor text may contain any
formatting codes. Any double quotes around the section are removed as part
of the parsing, as is any leading or trailing whitespace.
If the text of the LE<lt>E<gt> escape is entirely enclosed in double
quotes, it's interpreted as a link to a section for backward
compatibility.
No attempt is made to resolve formatting codes. This must be done after
calling parselink() (since EE<lt>E<gt> formatting codes can be used to
escape characters that would otherwise be significant to the parser and
resolving them before parsing would result in an incorrect parse of a
formatting code like:
L<verticalE<verbar>barE<sol>slash>
which should be interpreted as a link to the C<vertical|bar/slash> POD page
and not as a link to the C<slash> section of the C<bar> POD page with an
anchor text of C<vertical>. Note that not only the anchor text will need to
have formatting codes expanded, but so will the target of the link (to deal
with EE<lt>E<gt> and ZE<lt>E<gt> formatting codes), and special handling of
the section may be necessary depending on whether the translator wants to
consider markup in sections to be significant when resolving links. See
L<perlpodspec> for more information.
=head1 AUTHOR
Russ Allbery <rra@cpan.org>.
=head1 COPYRIGHT AND LICENSE
Copyright 2001, 2008, 2009, 2014, 2018 Russ Allbery <rra@cpan.org>
This program is free software; you may redistribute it and/or modify it
under the same terms as Perl itself.
=head1 SEE ALSO
L<Pod::Parser>
The current version of this module is always available from its web site at
L<https://www.eyrie.org/~eagle/software/podlators/>.
=cut
# Local Variables:
# copyright-at-end-flag: t
# End:
InputObjects.pm 0000644 00000065572 15051135563 0007536 0 ustar 00 #############################################################################
# Pod/InputObjects.pm -- package which defines objects for input streams
# and paragraphs and commands when parsing POD docs.
#
# Copyright (C) 1996-2000 by Bradford Appleton. All rights reserved.
# This file is part of "PodParser". PodParser is free software;
# you can redistribute it and/or modify it under the same terms
# as Perl itself.
#############################################################################
package Pod::InputObjects;
use strict;
use vars qw($VERSION);
$VERSION = '1.63'; ## Current version of this package
require 5.005; ## requires this Perl version or later
#############################################################################
=head1 NAME
Pod::InputObjects - objects representing POD input paragraphs, commands, etc.
=head1 SYNOPSIS
use Pod::InputObjects;
=head1 REQUIRES
perl5.004, Carp
=head1 EXPORTS
Nothing.
=head1 DESCRIPTION
B<NOTE: This module is considered legacy; modern Perl releases (5.18 and
higher) are going to remove Pod-Parser from core and use L<Pod-Simple>
for all things POD.>
This module defines some basic input objects used by B<Pod::Parser> when
reading and parsing POD text from an input source. The following objects
are defined:
=begin __PRIVATE__
=over 4
=item package B<Pod::InputSource>
An object corresponding to a source of POD input text. It is mostly a
wrapper around a filehandle or C<IO::Handle>-type object (or anything
that implements the C<getline()> method) which keeps track of some
additional information relevant to the parsing of PODs.
=back
=end __PRIVATE__
=over 4
=item package B<Pod::Paragraph>
An object corresponding to a paragraph of POD input text. It may be a
plain paragraph, a verbatim paragraph, or a command paragraph (see
L<perlpod>).
=item package B<Pod::InteriorSequence>
An object corresponding to an interior sequence command from the POD
input text (see L<perlpod>).
=item package B<Pod::ParseTree>
An object corresponding to a tree of parsed POD text. Each "node" in
a parse-tree (or I<ptree>) is either a text-string or a reference to
a B<Pod::InteriorSequence> object. The nodes appear in the parse-tree
in the order in which they were parsed from left-to-right.
=back
Each of these input objects are described in further detail in the
sections which follow.
=cut
#############################################################################
package Pod::InputSource;
##---------------------------------------------------------------------------
=begin __PRIVATE__
=head1 B<Pod::InputSource>
This object corresponds to an input source or stream of POD
documentation. When parsing PODs, it is necessary to associate and store
certain context information with each input source. All of this
information is kept together with the stream itself in one of these
C<Pod::InputSource> objects. Each such object is merely a wrapper around
an C<IO::Handle> object of some kind (or at least something that
implements the C<getline()> method). They have the following
methods/attributes:
=end __PRIVATE__
=cut
##---------------------------------------------------------------------------
=begin __PRIVATE__
=head2 B<new()>
my $pod_input1 = Pod::InputSource->new(-handle => $filehandle);
my $pod_input2 = new Pod::InputSource(-handle => $filehandle,
-name => $name);
my $pod_input3 = new Pod::InputSource(-handle => \*STDIN);
my $pod_input4 = Pod::InputSource->new(-handle => \*STDIN,
-name => "(STDIN)");
This is a class method that constructs a C<Pod::InputSource> object and
returns a reference to the new input source object. It takes one or more
keyword arguments in the form of a hash. The keyword C<-handle> is
required and designates the corresponding input handle. The keyword
C<-name> is optional and specifies the name associated with the input
handle (typically a file name).
=end __PRIVATE__
=cut
sub new {
## Determine if we were called via an object-ref or a classname
my $this = shift;
my $class = ref($this) || $this;
## Any remaining arguments are treated as initial values for the
## hash that is used to represent this object. Note that we default
## certain values by specifying them *before* the arguments passed.
## If they are in the argument list, they will override the defaults.
my $self = { -name => '(unknown)',
-handle => undef,
-was_cutting => 0,
@_ };
## Bless ourselves into the desired class and perform any initialization
bless $self, $class;
return $self;
}
##---------------------------------------------------------------------------
=begin __PRIVATE__
=head2 B<name()>
my $filename = $pod_input->name();
$pod_input->name($new_filename_to_use);
This method gets/sets the name of the input source (usually a filename).
If no argument is given, it returns a string containing the name of
the input source; otherwise it sets the name of the input source to the
contents of the given argument.
=end __PRIVATE__
=cut
sub name {
(@_ > 1) and $_[0]->{'-name'} = $_[1];
return $_[0]->{'-name'};
}
## allow 'filename' as an alias for 'name'
*filename = \&name;
##---------------------------------------------------------------------------
=begin __PRIVATE__
=head2 B<handle()>
my $handle = $pod_input->handle();
Returns a reference to the handle object from which input is read (the
one used to contructed this input source object).
=end __PRIVATE__
=cut
sub handle {
return $_[0]->{'-handle'};
}
##---------------------------------------------------------------------------
=begin __PRIVATE__
=head2 B<was_cutting()>
print "Yes.\n" if ($pod_input->was_cutting());
The value of the C<cutting> state (that the B<cutting()> method would
have returned) immediately before any input was read from this input
stream. After all input from this stream has been read, the C<cutting>
state is restored to this value.
=end __PRIVATE__
=cut
sub was_cutting {
(@_ > 1) and $_[0]->{-was_cutting} = $_[1];
return $_[0]->{-was_cutting};
}
##---------------------------------------------------------------------------
#############################################################################
package Pod::Paragraph;
##---------------------------------------------------------------------------
=head1 B<Pod::Paragraph>
An object representing a paragraph of POD input text.
It has the following methods/attributes:
=cut
##---------------------------------------------------------------------------
=head2 Pod::Paragraph-E<gt>B<new()>
my $pod_para1 = Pod::Paragraph->new(-text => $text);
my $pod_para2 = Pod::Paragraph->new(-name => $cmd,
-text => $text);
my $pod_para3 = new Pod::Paragraph(-text => $text);
my $pod_para4 = new Pod::Paragraph(-name => $cmd,
-text => $text);
my $pod_para5 = Pod::Paragraph->new(-name => $cmd,
-text => $text,
-file => $filename,
-line => $line_number);
This is a class method that constructs a C<Pod::Paragraph> object and
returns a reference to the new paragraph object. It may be given one or
two keyword arguments. The C<-text> keyword indicates the corresponding
text of the POD paragraph. The C<-name> keyword indicates the name of
the corresponding POD command, such as C<head1> or C<item> (it should
I<not> contain the C<=> prefix); this is needed only if the POD
paragraph corresponds to a command paragraph. The C<-file> and C<-line>
keywords indicate the filename and line number corresponding to the
beginning of the paragraph
=cut
sub new {
## Determine if we were called via an object-ref or a classname
my $this = shift;
my $class = ref($this) || $this;
## Any remaining arguments are treated as initial values for the
## hash that is used to represent this object. Note that we default
## certain values by specifying them *before* the arguments passed.
## If they are in the argument list, they will override the defaults.
my $self = {
-name => undef,
-text => (@_ == 1) ? shift : undef,
-file => '<unknown-file>',
-line => 0,
-prefix => '=',
-separator => ' ',
-ptree => [],
@_
};
## Bless ourselves into the desired class and perform any initialization
bless $self, $class;
return $self;
}
##---------------------------------------------------------------------------
=head2 $pod_para-E<gt>B<cmd_name()>
my $para_cmd = $pod_para->cmd_name();
If this paragraph is a command paragraph, then this method will return
the name of the command (I<without> any leading C<=> prefix).
=cut
sub cmd_name {
(@_ > 1) and $_[0]->{'-name'} = $_[1];
return $_[0]->{'-name'};
}
## let name() be an alias for cmd_name()
*name = \&cmd_name;
##---------------------------------------------------------------------------
=head2 $pod_para-E<gt>B<text()>
my $para_text = $pod_para->text();
This method will return the corresponding text of the paragraph.
=cut
sub text {
(@_ > 1) and $_[0]->{'-text'} = $_[1];
return $_[0]->{'-text'};
}
##---------------------------------------------------------------------------
=head2 $pod_para-E<gt>B<raw_text()>
my $raw_pod_para = $pod_para->raw_text();
This method will return the I<raw> text of the POD paragraph, exactly
as it appeared in the input.
=cut
sub raw_text {
return $_[0]->{'-text'} unless (defined $_[0]->{'-name'});
return $_[0]->{'-prefix'} . $_[0]->{'-name'} .
$_[0]->{'-separator'} . $_[0]->{'-text'};
}
##---------------------------------------------------------------------------
=head2 $pod_para-E<gt>B<cmd_prefix()>
my $prefix = $pod_para->cmd_prefix();
If this paragraph is a command paragraph, then this method will return
the prefix used to denote the command (which should be the string "="
or "==").
=cut
sub cmd_prefix {
return $_[0]->{'-prefix'};
}
##---------------------------------------------------------------------------
=head2 $pod_para-E<gt>B<cmd_separator()>
my $separator = $pod_para->cmd_separator();
If this paragraph is a command paragraph, then this method will return
the text used to separate the command name from the rest of the
paragraph (if any).
=cut
sub cmd_separator {
return $_[0]->{'-separator'};
}
##---------------------------------------------------------------------------
=head2 $pod_para-E<gt>B<parse_tree()>
my $ptree = $pod_parser->parse_text( $pod_para->text() );
$pod_para->parse_tree( $ptree );
$ptree = $pod_para->parse_tree();
This method will get/set the corresponding parse-tree of the paragraph's text.
=cut
sub parse_tree {
(@_ > 1) and $_[0]->{'-ptree'} = $_[1];
return $_[0]->{'-ptree'};
}
## let ptree() be an alias for parse_tree()
*ptree = \&parse_tree;
##---------------------------------------------------------------------------
=head2 $pod_para-E<gt>B<file_line()>
my ($filename, $line_number) = $pod_para->file_line();
my $position = $pod_para->file_line();
Returns the current filename and line number for the paragraph
object. If called in a list context, it returns a list of two
elements: first the filename, then the line number. If called in
a scalar context, it returns a string containing the filename, followed
by a colon (':'), followed by the line number.
=cut
sub file_line {
my @loc = ($_[0]->{'-file'} || '<unknown-file>',
$_[0]->{'-line'} || 0);
return (wantarray) ? @loc : join(':', @loc);
}
##---------------------------------------------------------------------------
#############################################################################
package Pod::InteriorSequence;
##---------------------------------------------------------------------------
=head1 B<Pod::InteriorSequence>
An object representing a POD interior sequence command.
It has the following methods/attributes:
=cut
##---------------------------------------------------------------------------
=head2 Pod::InteriorSequence-E<gt>B<new()>
my $pod_seq1 = Pod::InteriorSequence->new(-name => $cmd
-ldelim => $delimiter);
my $pod_seq2 = new Pod::InteriorSequence(-name => $cmd,
-ldelim => $delimiter);
my $pod_seq3 = new Pod::InteriorSequence(-name => $cmd,
-ldelim => $delimiter,
-file => $filename,
-line => $line_number);
my $pod_seq4 = new Pod::InteriorSequence(-name => $cmd, $ptree);
my $pod_seq5 = new Pod::InteriorSequence($cmd, $ptree);
This is a class method that constructs a C<Pod::InteriorSequence> object
and returns a reference to the new interior sequence object. It should
be given two keyword arguments. The C<-ldelim> keyword indicates the
corresponding left-delimiter of the interior sequence (e.g. 'E<lt>').
The C<-name> keyword indicates the name of the corresponding interior
sequence command, such as C<I> or C<B> or C<C>. The C<-file> and
C<-line> keywords indicate the filename and line number corresponding
to the beginning of the interior sequence. If the C<$ptree> argument is
given, it must be the last argument, and it must be either string, or
else an array-ref suitable for passing to B<Pod::ParseTree::new> (or
it may be a reference to a Pod::ParseTree object).
=cut
sub new {
## Determine if we were called via an object-ref or a classname
my $this = shift;
my $class = ref($this) || $this;
## See if first argument has no keyword
if (((@_ <= 2) or (@_ % 2)) and $_[0] !~ /^-\w/) {
## Yup - need an implicit '-name' before first parameter
unshift @_, '-name';
}
## See if odd number of args
if ((@_ % 2) != 0) {
## Yup - need an implicit '-ptree' before the last parameter
splice @_, $#_, 0, '-ptree';
}
## Any remaining arguments are treated as initial values for the
## hash that is used to represent this object. Note that we default
## certain values by specifying them *before* the arguments passed.
## If they are in the argument list, they will override the defaults.
my $self = {
-name => (@_ == 1) ? $_[0] : undef,
-file => '<unknown-file>',
-line => 0,
-ldelim => '<',
-rdelim => '>',
@_
};
## Initialize contents if they haven't been already
my $ptree = $self->{'-ptree'} || new Pod::ParseTree();
if ( ref $ptree =~ /^(ARRAY)?$/ ) {
## We have an array-ref, or a normal scalar. Pass it as an
## an argument to the ptree-constructor
$ptree = new Pod::ParseTree($1 ? [$ptree] : $ptree);
}
$self->{'-ptree'} = $ptree;
## Bless ourselves into the desired class and perform any initialization
bless $self, $class;
return $self;
}
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<cmd_name()>
my $seq_cmd = $pod_seq->cmd_name();
The name of the interior sequence command.
=cut
sub cmd_name {
(@_ > 1) and $_[0]->{'-name'} = $_[1];
return $_[0]->{'-name'};
}
## let name() be an alias for cmd_name()
*name = \&cmd_name;
##---------------------------------------------------------------------------
## Private subroutine to set the parent pointer of all the given
## children that are interior-sequences to be $self
sub _set_child2parent_links {
my ($self, @children) = @_;
## Make sure any sequences know who their parent is
for (@children) {
next unless (length and ref and ref ne 'SCALAR');
if (UNIVERSAL::isa($_, 'Pod::InteriorSequence') or
UNIVERSAL::can($_, 'nested'))
{
$_->nested($self);
}
}
}
## Private subroutine to unset child->parent links
sub _unset_child2parent_links {
my $self = shift;
$self->{'-parent_sequence'} = undef;
my $ptree = $self->{'-ptree'};
for (@$ptree) {
next unless (length and ref and ref ne 'SCALAR');
$_->_unset_child2parent_links()
if UNIVERSAL::isa($_, 'Pod::InteriorSequence');
}
}
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<prepend()>
$pod_seq->prepend($text);
$pod_seq1->prepend($pod_seq2);
Prepends the given string or parse-tree or sequence object to the parse-tree
of this interior sequence.
=cut
sub prepend {
my $self = shift;
$self->{'-ptree'}->prepend(@_);
_set_child2parent_links($self, @_);
return $self;
}
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<append()>
$pod_seq->append($text);
$pod_seq1->append($pod_seq2);
Appends the given string or parse-tree or sequence object to the parse-tree
of this interior sequence.
=cut
sub append {
my $self = shift;
$self->{'-ptree'}->append(@_);
_set_child2parent_links($self, @_);
return $self;
}
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<nested()>
$outer_seq = $pod_seq->nested || print "not nested";
If this interior sequence is nested inside of another interior
sequence, then the outer/parent sequence that contains it is
returned. Otherwise C<undef> is returned.
=cut
sub nested {
my $self = shift;
(@_ == 1) and $self->{'-parent_sequence'} = shift;
return $self->{'-parent_sequence'} || undef;
}
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<raw_text()>
my $seq_raw_text = $pod_seq->raw_text();
This method will return the I<raw> text of the POD interior sequence,
exactly as it appeared in the input.
=cut
sub raw_text {
my $self = shift;
my $text = $self->{'-name'} . $self->{'-ldelim'};
for ( $self->{'-ptree'}->children ) {
$text .= (ref $_) ? $_->raw_text : $_;
}
$text .= $self->{'-rdelim'};
return $text;
}
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<left_delimiter()>
my $ldelim = $pod_seq->left_delimiter();
The leftmost delimiter beginning the argument text to the interior
sequence (should be "<").
=cut
sub left_delimiter {
(@_ > 1) and $_[0]->{'-ldelim'} = $_[1];
return $_[0]->{'-ldelim'};
}
## let ldelim() be an alias for left_delimiter()
*ldelim = \&left_delimiter;
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<right_delimiter()>
The rightmost delimiter beginning the argument text to the interior
sequence (should be ">").
=cut
sub right_delimiter {
(@_ > 1) and $_[0]->{'-rdelim'} = $_[1];
return $_[0]->{'-rdelim'};
}
## let rdelim() be an alias for right_delimiter()
*rdelim = \&right_delimiter;
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<parse_tree()>
my $ptree = $pod_parser->parse_text($paragraph_text);
$pod_seq->parse_tree( $ptree );
$ptree = $pod_seq->parse_tree();
This method will get/set the corresponding parse-tree of the interior
sequence's text.
=cut
sub parse_tree {
(@_ > 1) and $_[0]->{'-ptree'} = $_[1];
return $_[0]->{'-ptree'};
}
## let ptree() be an alias for parse_tree()
*ptree = \&parse_tree;
##---------------------------------------------------------------------------
=head2 $pod_seq-E<gt>B<file_line()>
my ($filename, $line_number) = $pod_seq->file_line();
my $position = $pod_seq->file_line();
Returns the current filename and line number for the interior sequence
object. If called in a list context, it returns a list of two
elements: first the filename, then the line number. If called in
a scalar context, it returns a string containing the filename, followed
by a colon (':'), followed by the line number.
=cut
sub file_line {
my @loc = ($_[0]->{'-file'} || '<unknown-file>',
$_[0]->{'-line'} || 0);
return (wantarray) ? @loc : join(':', @loc);
}
##---------------------------------------------------------------------------
=head2 Pod::InteriorSequence::B<DESTROY()>
This method performs any necessary cleanup for the interior-sequence.
If you override this method then it is B<imperative> that you invoke
the parent method from within your own method, otherwise
I<interior-sequence storage will not be reclaimed upon destruction!>
=cut
sub DESTROY {
## We need to get rid of all child->parent pointers throughout the
## tree so their reference counts will go to zero and they can be
## garbage-collected
_unset_child2parent_links(@_);
}
##---------------------------------------------------------------------------
#############################################################################
package Pod::ParseTree;
##---------------------------------------------------------------------------
=head1 B<Pod::ParseTree>
This object corresponds to a tree of parsed POD text. As POD text is
scanned from left to right, it is parsed into an ordered list of
text-strings and B<Pod::InteriorSequence> objects (in order of
appearance). A B<Pod::ParseTree> object corresponds to this list of
strings and sequences. Each interior sequence in the parse-tree may
itself contain a parse-tree (since interior sequences may be nested).
=cut
##---------------------------------------------------------------------------
=head2 Pod::ParseTree-E<gt>B<new()>
my $ptree1 = Pod::ParseTree->new;
my $ptree2 = new Pod::ParseTree;
my $ptree4 = Pod::ParseTree->new($array_ref);
my $ptree3 = new Pod::ParseTree($array_ref);
This is a class method that constructs a C<Pod::Parse_tree> object and
returns a reference to the new parse-tree. If a single-argument is given,
it must be a reference to an array, and is used to initialize the root
(top) of the parse tree.
=cut
sub new {
## Determine if we were called via an object-ref or a classname
my $this = shift;
my $class = ref($this) || $this;
my $self = (@_ == 1 and ref $_[0]) ? $_[0] : [];
## Bless ourselves into the desired class and perform any initialization
bless $self, $class;
return $self;
}
##---------------------------------------------------------------------------
=head2 $ptree-E<gt>B<top()>
my $top_node = $ptree->top();
$ptree->top( $top_node );
$ptree->top( @children );
This method gets/sets the top node of the parse-tree. If no arguments are
given, it returns the topmost node in the tree (the root), which is also
a B<Pod::ParseTree>. If it is given a single argument that is a reference,
then the reference is assumed to a parse-tree and becomes the new top node.
Otherwise, if arguments are given, they are treated as the new list of
children for the top node.
=cut
sub top {
my $self = shift;
if (@_ > 0) {
@{ $self } = (@_ == 1 and ref $_[0]) ? ${ @_ } : @_;
}
return $self;
}
## let parse_tree() & ptree() be aliases for the 'top' method
*parse_tree = *ptree = \⊤
##---------------------------------------------------------------------------
=head2 $ptree-E<gt>B<children()>
This method gets/sets the children of the top node in the parse-tree.
If no arguments are given, it returns the list (array) of children
(each of which should be either a string or a B<Pod::InteriorSequence>.
Otherwise, if arguments are given, they are treated as the new list of
children for the top node.
=cut
sub children {
my $self = shift;
if (@_ > 0) {
@{ $self } = (@_ == 1 and ref $_[0]) ? ${ @_ } : @_;
}
return @{ $self };
}
##---------------------------------------------------------------------------
=head2 $ptree-E<gt>B<prepend()>
This method prepends the given text or parse-tree to the current parse-tree.
If the first item on the parse-tree is text and the argument is also