Blame lib/Devel/Symdump.pm

Packit b48d6e
package Devel::Symdump;
Packit b48d6e
Packit b48d6e
use 5.003;
Packit b48d6e
use Carp ();
Packit b48d6e
use strict;
Packit b48d6e
use vars qw($Defaults $VERSION *ENTRY $MAX_RECURSION);
Packit b48d6e
Packit b48d6e
$VERSION = '2.18';
Packit b48d6e
$MAX_RECURSION = 97;
Packit b48d6e
Packit b48d6e
$Defaults = {
Packit b48d6e
	     'RECURS'   => 0,
Packit b48d6e
	     'AUTOLOAD' => {
Packit b48d6e
			    'packages'	=> 1,
Packit b48d6e
			    'scalars'	=> 1,
Packit b48d6e
			    'arrays'	=> 1,
Packit b48d6e
			    'hashes'	=> 1,
Packit b48d6e
			    'functions'	=> 1,
Packit b48d6e
			    'ios'	=> 1,
Packit b48d6e
			    'unknowns'	=> 1,
Packit b48d6e
			   },
Packit b48d6e
             'SEEN' => {},
Packit b48d6e
	    };
Packit b48d6e
Packit b48d6e
sub rnew {
Packit b48d6e
    my($class,@packages) = @_;
Packit b48d6e
    no strict "refs";
Packit b48d6e
    my $self = bless {%${"$class\::Defaults"}}, $class;
Packit b48d6e
    $self->{RECURS}++;
Packit b48d6e
    $self->_doit(@packages);
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub new {
Packit b48d6e
    my($class,@packages) = @_;
Packit b48d6e
    no strict "refs";
Packit b48d6e
    my $self = bless {%${"$class\::Defaults"}}, $class;
Packit b48d6e
    $self->_doit(@packages);
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub _doit {
Packit b48d6e
    my($self,@packages) = @_;
Packit b48d6e
    @packages = ("main") unless @packages;
Packit b48d6e
    $self->{RESULT} = $self->_symdump(@packages);
Packit b48d6e
    return $self;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub _symdump {
Packit b48d6e
    my($self,@packages) = @_ ;
Packit b48d6e
    my($key,$val,$num,$pack,@todo,$tmp);
Packit b48d6e
    my $result = {};
Packit b48d6e
    foreach $pack (@packages){
Packit b48d6e
	no strict;
Packit b48d6e
	while (($key,$val) = each(%{*{"$pack\::"}})) {
Packit b48d6e
	    my $gotone = 0;
Packit b48d6e
	    local(*ENTRY) = $val;
Packit b48d6e
	    #### SCALAR ####
Packit b48d6e
	    if (defined $val && defined *ENTRY{SCALAR}) {
Packit b48d6e
		$result->{$pack}{SCALARS}{$key}++;
Packit b48d6e
		$gotone++;
Packit b48d6e
	    }
Packit b48d6e
	    #### ARRAY ####
Packit b48d6e
	    if (defined $val && defined *ENTRY{ARRAY}) {
Packit b48d6e
		$result->{$pack}{ARRAYS}{$key}++;
Packit b48d6e
		$gotone++;
Packit b48d6e
	    }
Packit b48d6e
	    #### HASH ####
Packit b48d6e
	    if (defined $val && defined *ENTRY{HASH} && $key !~ /::/) {
Packit b48d6e
		$result->{$pack}{HASHES}{$key}++;
Packit b48d6e
		$gotone++;
Packit b48d6e
	    }
Packit b48d6e
	    #### PACKAGE ####
Packit b48d6e
	    if (defined $val && defined *ENTRY{HASH} && $key =~ /::$/ &&
Packit b48d6e
                $key ne "main::" && $key ne "<none>::") {
Packit b48d6e
                my($p) = $pack ne "main" ? "$pack\::" : "";
Packit b48d6e
                ($p .= $key) =~ s/::$//;
Packit b48d6e
                $result->{$pack}{PACKAGES}{$p}++;
Packit b48d6e
                $gotone++;
Packit b48d6e
                if (++$self->{SEEN}{*$val} > $Devel::Symdump::MAX_RECURSION){
Packit b48d6e
                    next;
Packit b48d6e
                }
Packit b48d6e
		push @todo, $p;
Packit b48d6e
	    }
Packit b48d6e
	    #### FUNCTION ####
Packit b48d6e
	    if (defined $val && defined *ENTRY{CODE}) {
Packit b48d6e
		$result->{$pack}{FUNCTIONS}{$key}++;
Packit b48d6e
		$gotone++;
Packit b48d6e
	    }
Packit b48d6e
Packit b48d6e
	    #### IO #### had to change after 5.003_10
Packit b48d6e
	    if ($] > 5.003_10){
Packit b48d6e
		if (defined $val && defined *ENTRY{IO}){ # fileno and telldir...
Packit b48d6e
		    $result->{$pack}{IOS}{$key}++;
Packit b48d6e
		    $gotone++;
Packit b48d6e
		}
Packit b48d6e
	    } else {
Packit b48d6e
		#### FILEHANDLE ####
Packit b48d6e
		if (defined fileno(ENTRY)){
Packit b48d6e
		    $result->{$pack}{IOS}{$key}++;
Packit b48d6e
		    $gotone++;
Packit b48d6e
		} elsif (defined telldir(ENTRY)){
Packit b48d6e
		    #### DIRHANDLE ####
Packit b48d6e
		    $result->{$pack}{IOS}{$key}++;
Packit b48d6e
		    $gotone++;
Packit b48d6e
		}
Packit b48d6e
	    }
Packit b48d6e
Packit b48d6e
	    #### SOMETHING ELSE ####
Packit b48d6e
	    unless ($gotone) {
Packit b48d6e
		$result->{$pack}{UNKNOWNS}{$key}++;
Packit b48d6e
	    }
Packit b48d6e
	}
Packit b48d6e
    }
Packit b48d6e
Packit b48d6e
    return (@todo && $self->{RECURS})
Packit b48d6e
		? { %$result, %{$self->_symdump(@todo)} }
Packit b48d6e
		: $result;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub _partdump {
Packit b48d6e
    my($self,$part)=@_;
Packit b48d6e
    my ($pack, @result);
Packit b48d6e
    my $prepend = "";
Packit b48d6e
    foreach $pack (keys %{$self->{RESULT}}){
Packit b48d6e
	$prepend = "$pack\::" unless $part eq 'PACKAGES';
Packit b48d6e
	push @result, map {"$prepend$_"} keys %{$self->{RESULT}{$pack}{$part} || {}};
Packit b48d6e
    }
Packit b48d6e
    return @result;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
# this is needed so we don't try to AUTOLOAD the DESTROY method
Packit b48d6e
sub DESTROY {}
Packit b48d6e
Packit b48d6e
sub as_string {
Packit b48d6e
    my $self = shift;
Packit b48d6e
    my($type,@m);
Packit b48d6e
    for $type (sort keys %{$self->{'AUTOLOAD'}}) {
Packit b48d6e
	push @m, $type;
Packit b48d6e
	push @m, "\t" . join "\n\t", map {
Packit b48d6e
	    s/([\000-\037\177])/ '^' . pack('c', ord($1) ^ 64) /eg;
Packit b48d6e
	    $_;
Packit b48d6e
	} sort $self->_partdump(uc $type);
Packit b48d6e
    }
Packit b48d6e
    return join "\n", @m;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub as_HTML {
Packit b48d6e
    my $self = shift;
Packit b48d6e
    my($type,@m);
Packit b48d6e
    push @m, "";
Packit b48d6e
    for $type (sort keys %{$self->{'AUTOLOAD'}}) {
Packit b48d6e
	push @m, "$type";
Packit b48d6e
	push @m, "" . join ", ", map {
Packit b48d6e
	    s/([\000-\037\177])/ '^' .
Packit b48d6e
		pack('c', ord($1) ^ 64)
Packit b48d6e
		    /eg; $_;
Packit b48d6e
	} sort $self->_partdump(uc $type);
Packit b48d6e
	push @m, "";
Packit b48d6e
    }
Packit b48d6e
    push @m, "";
Packit b48d6e
    return join "\n", @m;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub diff {
Packit b48d6e
    my($self,$second) = @_;
Packit b48d6e
    my($type,@m);
Packit b48d6e
    for $type (sort keys %{$self->{'AUTOLOAD'}}) {
Packit b48d6e
	my(%first,%second,%all,$symbol);
Packit b48d6e
	foreach $symbol ($self->_partdump(uc $type)){
Packit b48d6e
	    $first{$symbol}++;
Packit b48d6e
	    $all{$symbol}++;
Packit b48d6e
	}
Packit b48d6e
	foreach $symbol ($second->_partdump(uc $type)){
Packit b48d6e
	    $second{$symbol}++;
Packit b48d6e
	    $all{$symbol}++;
Packit b48d6e
	}
Packit b48d6e
	my(@typediff);
Packit b48d6e
	foreach $symbol (sort keys %all){
Packit b48d6e
	    next if $first{$symbol} && $second{$symbol};
Packit b48d6e
	    push @typediff, "- $symbol" unless $second{$symbol};
Packit b48d6e
	    push @typediff, "+ $symbol" unless $first{$symbol};
Packit b48d6e
	}
Packit b48d6e
	foreach (@typediff) {
Packit b48d6e
	    s/([\000-\037\177])/ '^' . pack('c', ord($1) ^ 64) /eg;
Packit b48d6e
	}
Packit b48d6e
	push @m, $type, @typediff if @typediff;
Packit b48d6e
    }
Packit b48d6e
    return join "\n", @m;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub inh_tree {
Packit b48d6e
    my($self) = @_;
Packit b48d6e
    return $self->{INHTREE} if ref $self && defined $self->{INHTREE};
Packit b48d6e
    my($inherited_by) = {};
Packit b48d6e
    my($m)="";
Packit b48d6e
    my(@isa) = grep /\bISA$/, Devel::Symdump->rnew->arrays;
Packit b48d6e
    my $isa;
Packit b48d6e
    foreach $isa (sort @isa) {
Packit b48d6e
	$isa =~ s/::ISA$//;
Packit b48d6e
	my($isaisa);
Packit b48d6e
	no strict 'refs';
Packit b48d6e
	foreach $isaisa (@{"$isa\::ISA"}){
Packit b48d6e
	    $inherited_by->{$isaisa}{$isa}++;
Packit b48d6e
	}
Packit b48d6e
    }
Packit b48d6e
    my $item;
Packit b48d6e
    foreach $item (sort keys %$inherited_by) {
Packit b48d6e
	$m .= "$item\n";
Packit b48d6e
	$m .= _inh_tree($item,$inherited_by);
Packit b48d6e
    }
Packit b48d6e
    $self->{INHTREE} = $m if ref $self;
Packit b48d6e
    $m;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub _inh_tree {
Packit b48d6e
    my($package,$href,$depth) = @_;
Packit b48d6e
    return unless defined $href;
Packit b48d6e
    $depth ||= 0;
Packit b48d6e
    $depth++;
Packit b48d6e
    if ($depth > 100){
Packit b48d6e
	warn "Deep recursion in ISA\n";
Packit b48d6e
	return;
Packit b48d6e
    }
Packit b48d6e
    my($m) = "";
Packit b48d6e
    # print "DEBUG: package[$package]depth[$depth]\n";
Packit b48d6e
    my $i;
Packit b48d6e
    foreach $i (sort keys %{$href->{$package}}) {
Packit b48d6e
	$m .= qq{\t} x $depth;
Packit b48d6e
	$m .= qq{$i\n};
Packit b48d6e
	$m .= _inh_tree($i,$href,$depth);
Packit b48d6e
    }
Packit b48d6e
    $m;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub isa_tree{
Packit b48d6e
    my($self) = @_;
Packit b48d6e
    return $self->{ISATREE} if ref $self && defined $self->{ISATREE};
Packit b48d6e
    my(@isa) = grep /\bISA$/, Devel::Symdump->rnew->arrays;
Packit b48d6e
    my($m) = "";
Packit b48d6e
    my($isa);
Packit b48d6e
    foreach $isa (sort @isa) {
Packit b48d6e
	$isa =~ s/::ISA$//;
Packit b48d6e
	$m .= qq{$isa\n};
Packit b48d6e
	$m .= _isa_tree($isa)
Packit b48d6e
    }
Packit b48d6e
    $self->{ISATREE} = $m if ref $self;
Packit b48d6e
    $m;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
sub _isa_tree{
Packit b48d6e
    my($package,$depth) = @_;
Packit b48d6e
    $depth ||= 0;
Packit b48d6e
    $depth++;
Packit b48d6e
    if ($depth > 100){
Packit b48d6e
	warn "Deep recursion in ISA\n";
Packit b48d6e
	return;
Packit b48d6e
    }
Packit b48d6e
    my($m) = "";
Packit b48d6e
    # print "DEBUG: package[$package]depth[$depth]\n";
Packit b48d6e
    my $isaisa;
Packit b48d6e
    no strict 'refs';
Packit b48d6e
    foreach $isaisa (@{"$package\::ISA"}) {
Packit b48d6e
	$m .= qq{\t} x $depth;
Packit b48d6e
	$m .= qq{$isaisa\n};
Packit b48d6e
	$m .= _isa_tree($isaisa,$depth);
Packit b48d6e
    }
Packit b48d6e
    $m;
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
AUTOLOAD {
Packit b48d6e
    my($self,@packages) = @_;
Packit b48d6e
    unless (ref $self) {
Packit b48d6e
	$self = $self->new(@packages);
Packit b48d6e
    }
Packit b48d6e
    no strict "vars";
Packit b48d6e
    (my $auto = $AUTOLOAD) =~ s/.*:://;
Packit b48d6e
Packit b48d6e
    $auto =~ s/(file|dir)handles/ios/;
Packit b48d6e
    my $compat = $1;
Packit b48d6e
Packit b48d6e
    unless ($self->{'AUTOLOAD'}{$auto}) {
Packit b48d6e
	Carp::croak("invalid Devel::Symdump method: $auto()");
Packit b48d6e
    }
Packit b48d6e
Packit b48d6e
    my @syms = $self->_partdump(uc $auto);
Packit b48d6e
    if (defined $compat) {
Packit b48d6e
	no strict 'refs';
Packit b48d6e
        local $^W; # bleadperl@26631 introduced an io warning here
Packit b48d6e
	if ($compat eq "file") {
Packit b48d6e
	    @syms = grep { defined(fileno($_)) } @syms;
Packit b48d6e
	} else {
Packit b48d6e
	    @syms = grep { _is_dirhandle($_) } @syms;
Packit b48d6e
	}
Packit b48d6e
    }
Packit b48d6e
    return @syms; # make sure now it gets context right
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
use Config ();
Packit b48d6e
use constant HAVE_TELLDIR => $Config::Config{d_telldir};
Packit b48d6e
sub _is_dirhandle {
Packit b48d6e
    my ($glob) = @_;
Packit b48d6e
    if ( HAVE_TELLDIR ) {
Packit b48d6e
        return defined(telldir($glob));
Packit b48d6e
    }
Packit b48d6e
    else {
Packit b48d6e
        if ( !ref $glob ) {
Packit b48d6e
            no strict 'refs';
Packit b48d6e
            $glob = \*{$glob};
Packit b48d6e
        }
Packit b48d6e
        require B;
Packit b48d6e
        my $obj = B::svref_2object($glob);
Packit b48d6e
        return if !$obj || !eval{ $obj->IO; $obj->IO->IoTYPE; 1 };
Packit b48d6e
        my $mode = $obj->IO->IoTYPE;
Packit b48d6e
        return $mode eq "\0" ? 1 : 0;
Packit b48d6e
    }
Packit b48d6e
}
Packit b48d6e
Packit b48d6e
1;
Packit b48d6e
Packit b48d6e
__END__
Packit b48d6e
Packit b48d6e
=head1 NAME
Packit b48d6e
Packit b48d6e
Devel::Symdump - dump symbol names or the symbol table
Packit b48d6e
Packit b48d6e
=head1 SYNOPSIS
Packit b48d6e
Packit b48d6e
    # Constructor
Packit b48d6e
    require Devel::Symdump;
Packit b48d6e
    @packs = qw(some_package another_package);
Packit b48d6e
    $obj = Devel::Symdump->new(@packs);        # no recursion
Packit b48d6e
    $obj = Devel::Symdump->rnew(@packs);       # with recursion
Packit b48d6e
Packit b48d6e
    # Methods
Packit b48d6e
    @array = $obj->packages;
Packit b48d6e
    @array = $obj->scalars;
Packit b48d6e
    @array = $obj->arrays;
Packit b48d6e
    @array = $obj->hashes;
Packit b48d6e
    @array = $obj->functions;
Packit b48d6e
    @array = $obj->filehandles;  # deprecated, use ios instead
Packit b48d6e
    @array = $obj->dirhandles;   # deprecated, use ios instead
Packit b48d6e
    @array = $obj->ios;
Packit b48d6e
    @array = $obj->unknowns;     # only perl version < 5.003 had some
Packit b48d6e
Packit b48d6e
    $string = $obj->as_string;
Packit b48d6e
    $string = $obj->as_HTML;
Packit b48d6e
    $string = $obj1->diff($obj2);
Packit b48d6e
Packit b48d6e
    $string = Devel::Symdump->isa_tree;    # or $obj->isa_tree
Packit b48d6e
    $string = Devel::Symdump->inh_tree;    # or $obj->inh_tree
Packit b48d6e
Packit b48d6e
    # Methods with autogenerated objects
Packit b48d6e
    # all of those call new(@packs) internally
Packit b48d6e
    @array = Devel::Symdump->packages(@packs);
Packit b48d6e
    @array = Devel::Symdump->scalars(@packs);
Packit b48d6e
    @array = Devel::Symdump->arrays(@packs);
Packit b48d6e
    @array = Devel::Symdump->hashes(@packs);
Packit b48d6e
    @array = Devel::Symdump->functions(@packs);
Packit b48d6e
    @array = Devel::Symdump->ios(@packs);
Packit b48d6e
    @array = Devel::Symdump->unknowns(@packs);
Packit b48d6e
Packit b48d6e
=head1 DESCRIPTION
Packit b48d6e
Packit b48d6e
This little package serves to access the symbol table of perl.
Packit b48d6e
Packit b48d6e
=over 4
Packit b48d6e
Packit b48d6e
=item C<Devel::Symdump-E<gt>rnew(@packages)>
Packit b48d6e
Packit b48d6e
returns a symbol table object for all subtrees below @packages.
Packit b48d6e
Nested Modules are analyzed recursively. If no package is given as
Packit b48d6e
argument, it defaults to C<main>. That means to get the whole symbol
Packit b48d6e
table, just do a C<rnew> without arguments.
Packit b48d6e
Packit b48d6e
The global variable $Devel::Symdump::MAX_RECURSION limits the
Packit b48d6e
recursion to prevent contention. The default value is set to 97, just
Packit b48d6e
low enough to survive the test suite without a warning about deep
Packit b48d6e
recursion.
Packit b48d6e
Packit b48d6e
=item C<Devel::Symdump-E<gt>new(@packages)>
Packit b48d6e
Packit b48d6e
does not go into recursion and only analyzes the packages that are
Packit b48d6e
given as arguments.
Packit b48d6e
Packit b48d6e
=item packages, scalars, arrays, hashes, functions, ios
Packit b48d6e
Packit b48d6e
The methods packages(), scalars(), arrays(), hashes(), functions(),
Packit b48d6e
ios(), and (for older perls) unknowns() each return an array of fully
Packit b48d6e
qualified symbols of the specified type in all packages that are held
Packit b48d6e
within a Devel::Symdump object, but without the leading C<$>, C<@> or
Packit b48d6e
C<%>. In a scalar context, they will return the number of such
Packit b48d6e
symbols. Unknown symbols are usually either formats or variables that
Packit b48d6e
haven't yet got a defined value.
Packit b48d6e
Packit b48d6e
Note that scalar symbol table entries are a special case.  If a symbol
Packit b48d6e
table entry exists at all, presence of a scalar is currently
Packit b48d6e
unknowable, due to a feature of Perl described in L
Packit b48d6e
References> point 7.  For example, this package will mark a scalar
Packit b48d6e
value C<$foo> as present if any of C<@foo>, C<%foo>, C<&foo> etc. have
Packit b48d6e
been declared or used.
Packit b48d6e
Packit b48d6e
=item as_string
Packit b48d6e
Packit b48d6e
=item as_HTML
Packit b48d6e
Packit b48d6e
As_string() and as_HTML() return a simple string/HTML representations
Packit b48d6e
of the object.
Packit b48d6e
Packit b48d6e
=item diff
Packit b48d6e
Packit b48d6e
Diff() prints the difference between two Devel::Symdump objects in
Packit b48d6e
human readable form. The format is similar to the one used by the
Packit b48d6e
as_string method.
Packit b48d6e
Packit b48d6e
=item isa_tree
Packit b48d6e
Packit b48d6e
=item inh_tree
Packit b48d6e
Packit b48d6e
Isa_tree() and inh_tree() both return a simple string representation
Packit b48d6e
of the current inheritance tree. The difference between the two
Packit b48d6e
methods is the direction from which the tree is viewed: top-down or
Packit b48d6e
bottom-up. As I'm sure, many users will have different expectation
Packit b48d6e
about what is top and what is bottom, I'll provide an example what
Packit b48d6e
happens when the Socket module is loaded:
Packit b48d6e
Packit b48d6e
=item % print Devel::Symdump-E<gt>inh_tree
Packit b48d6e
Packit b48d6e
    AutoLoader
Packit b48d6e
            DynaLoader
Packit b48d6e
                    Socket
Packit b48d6e
    DynaLoader
Packit b48d6e
            Socket
Packit b48d6e
    Exporter
Packit b48d6e
            Carp
Packit b48d6e
            Config
Packit b48d6e
            Socket
Packit b48d6e
Packit b48d6e
The inh_tree method shows on the left hand side a package name and
Packit b48d6e
indented to the right the packages that use the former.
Packit b48d6e
Packit b48d6e
=item % print Devel::Symdump-E<gt>isa_tree
Packit b48d6e
Packit b48d6e
    Carp
Packit b48d6e
            Exporter
Packit b48d6e
    Config
Packit b48d6e
            Exporter
Packit b48d6e
    DynaLoader
Packit b48d6e
            AutoLoader
Packit b48d6e
    Socket
Packit b48d6e
            Exporter
Packit b48d6e
            DynaLoader
Packit b48d6e
                    AutoLoader
Packit b48d6e
Packit b48d6e
The isa_tree method displays from left to right ISA relationships, so
Packit b48d6e
Socket IS A DynaLoader and DynaLoader IS A AutoLoader. (Actually, they
Packit b48d6e
were at the time this manpage was written)
Packit b48d6e
Packit b48d6e
=back
Packit b48d6e
Packit b48d6e
You may call both methods, isa_tree() and inh_tree(), with an
Packit b48d6e
object. If you do that, the object will store the output and retrieve
Packit b48d6e
it when you call the same method again later. The typical usage would
Packit b48d6e
be to use them as class methods directly though.
Packit b48d6e
Packit b48d6e
=head1 SUBCLASSING
Packit b48d6e
Packit b48d6e
The design of this package is intentionally primitive and allows it to
Packit b48d6e
be subclassed easily. An example of a (maybe) useful subclass is
Packit b48d6e
Devel::Symdump::Export, a package which exports all methods of the
Packit b48d6e
Devel::Symdump package and turns them into functions.
Packit b48d6e
Packit b48d6e
=head1 SEE ALSO
Packit b48d6e
Packit b48d6e
Routines for manipulating stashes: C<Package::Stash>; to work with
Packit b48d6e
lexicals: C<PadWalker>.
Packit b48d6e
Packit b48d6e
=head1 AUTHORS
Packit b48d6e
Packit b48d6e
Andreas Koenig F<< <andk@cpan.org> >> and Tom Christiansen
Packit b48d6e
F<< <tchrist@perl.com> >>. Based on the old F<dumpvar.pl> by Larry
Packit b48d6e
Wall.
Packit b48d6e
Packit b48d6e
=head1 COPYRIGHT, LICENSE
Packit b48d6e
Packit b48d6e
This module is
Packit b48d6e
Packit b48d6e
Copyright (c) 1995, 1997, 2000, 2002, 2005, 2006 Andreas Koenig C<< <andk@cpan.org> >>.
Packit b48d6e
Packit b48d6e
All rights reserved.
Packit b48d6e
Packit b48d6e
This library is free software;
Packit b48d6e
you may use, redistribute and/or modify it under the same
Packit b48d6e
terms as Perl itself.
Packit b48d6e
Packit b48d6e
=cut
Packit b48d6e
Packit b48d6e
Packit b48d6e
# Local Variables:
Packit b48d6e
# mode: cperl
Packit b48d6e
# cperl-indent-level: 4
Packit b48d6e
# End: