The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl
# pminst -- find modules whose names match this pattern
# tchrist@perl.com

BEGIN { $^W = 1 }

use Getopt::Std qw(getopts);
use File::Find;

getopts('ls') || die "bad usage";

if (@ARGV == 0) {
    @ARGV = ('.');
} 

die "usage: $0 [-l] [-s] pattern\n" unless @ARGV == 1;

$pattern = shift();
$pattern =~ s,::,/,g;

no lib '.';

use vars qw($opt_l $opt_s);

for $startdir (@INC) { 
    find(\&wanted, $startdir);
}

sub wanted {
    if (-d && /^[a-z]/) { 
	# this is so we don't go down site_perl etc too early
	$File::Find::prune = 1;
	return;
    }
    return unless /\.pm$/;
    local $_ = $File::Find::name;
    ($tmpname = $_) =~ s{^\Q$startdir/}{};
    return unless $tmpname =~ /$pattern/o;

    if ($opt_l) { 
	s{^(\Q$startdir\E)/}{$1 } if $opt_s;
    } 
    else {
	s{^\Q$startdir/}{};  
	s/\.pm$//;
	s{/}{::}g;
	print "$startdir " if $opt_s;
    } 

    print $_, "\n";
} 

__END__

=head1 NAME

pminst - find modules whose names match this pattern

=head1 SYNOPSIS

pminst [B<-s>] [B<-l>] [I<pattern>]

=head1 DESCRIPTION

Without argumnets, show the names of all installed modules.  Given a
pattern, show all module names that match it.  The B<-l> flag will show
the full pathname.  The B<-s> flag will separate the base directory from
@INC from the module portion itself.


=head1 EXAMPLES

    $ pminst
    (lists all installed modules)

    $ pminst Carp
    CGI::Carp
    Carp

    $ pminst ^IO::
    IO::Socket::INET
    IO::Socket::UNIX
    IO::Select
    IO::Socket
    IO::Poll
    IO::Handle
    IO::Pipe
    IO::Seekable
    IO::Dir
    IO::File

    $ pminst '(?i)io'
    IO::Socket::INET
    IO::Socket::UNIX
    IO::Select
    IO::Socket
    IO::Poll
    IO::Handle
    IO::Pipe
    IO::Seekable
    IO::Dir
    IO::File
    IO
    Pod::Functions

  The -s flag provides output with the directory separated
  by a space:

    $ pminst -s | sort +1
    (lists all modules, sorted by name, but with where they 
     came from)

    $ oldperl -S pminst -s IO
    /usr/lib/perl5/i386-linux/5.00404 IO::File
    /usr/lib/perl5/i386-linux/5.00404 IO::Handle
    /usr/lib/perl5/i386-linux/5.00404 IO::Pipe
    /usr/lib/perl5/i386-linux/5.00404 IO::Seekable
    /usr/lib/perl5/i386-linux/5.00404 IO::Select
    /usr/lib/perl5/i386-linux/5.00404 IO::Socket
    /usr/lib/perl5/i386-linux/5.00404 IO
    /usr/lib/perl5/site_perl LWP::IO
    /usr/lib/perl5/site_perl LWP::TkIO
    /usr/lib/perl5/site_perl Tk::HTML::IO
    /usr/lib/perl5/site_perl Tk::IO
    /usr/lib/perl5/site_perl IO::Stringy
    /usr/lib/perl5/site_perl IO::Wrap
    /usr/lib/perl5/site_perl IO::ScalarArray
    /usr/lib/perl5/site_perl IO::Scalar
    /usr/lib/perl5/site_perl IO::Lines
    /usr/lib/perl5/site_perl IO::WrapTie
    /usr/lib/perl5/site_perl IO::AtomicFile

  The -l flag gives full paths:

    $ filsperl -S pminst -l Thread
    /usr/local/filsperl/lib/5.00554/i686-linux-thread/Thread/Queue.pm
    /usr/local/filsperl/lib/5.00554/i686-linux-thread/Thread/Semaphore.pm
    /usr/local/filsperl/lib/5.00554/i686-linux-thread/Thread/Signal.pm
    /usr/local/filsperl/lib/5.00554/i686-linux-thread/Thread/Specific.pm
    /usr/local/filsperl/lib/5.00554/i686-linux-thread/Thread.pm

=head1 AUTHOR and COPYRIGHT

Copyright (c) 1999 Tom Christiansen

This is free software.  You may modify it and distribute it 
under Perl's Artistic Licence.  Modified versions must be
clearly indicated.