#!/usr/pkg/bin/perl -wl
# finbin - find binaries in the user's PATH
# See the POD at the end of the file for documentation.
use strict;
use Getopt::Std;

my %opts;
our $VERSION = 1.2;
getopts('fFp:qx', \%opts) || exit 2;

argLoop: for (@ARGV) {
for my $d (split /:/, $opts{p} || $ENV{PATH}) {
 $d = '.' if $d eq '';
 for (grep { -e && (!$opts{x} || -x) } glob "$d/$_") {
  # The `-e' is for when the glob() fails to find a match.
  exit 0 if $opts{q};
  print;
  exit 0 if $opts{f};
  next argLoop if $opts{F};
 }
}
}
exit 1 if $opts{q};

sub HELP_MESSAGE {
select shift;
print <<EOT;
Usage: $0 [-F | -f | -q] [-x] [-p path] pattern ...
Type `man finbin` for more information.
EOT
exit 0;
}

__END__

=pod

=head1 NAME

B<finbin> - find binaries in the user's PATH

=head1 SYNOPSIS

B<finbin> [B<-F> | B<-f> | B<-q>] [B<-x>] [B<-p> I<path>] I<pattern> ...

=head1 DESCRIPTION

B<finbin> searches the user's PATH for any files matching the given I<pattern>
and prints the results to standard output.  It is intended as a replacement for
the inconsistently implemented L<which(1)> and L<whereis(1)> commands.

If B<finbin> is given more than one operand, it searches for each one
individually and prints out the results as it finds them.  Each operand is
interpreted as a shell wildcard pattern to match against the contents of each
directory in the PATH.  If no wildcards are present in an operand, it is
treated as the basename of a program to look for; if wildcards are present,
they may have to be escaped or quoted in order to avoid interpolation by one's
shell.

=head1 OPTIONS

=over

=item B<-F>

Print out only the first match found for each operand.

=item B<-f>

Exit immediately after finding the first match.

=item B<-p> I<path>

Use I<path> as the path to search rather than the user's PATH environment
variable.  Directories in I<path> must be separated by colons.  An empty string
in I<path> is interpreted as referring to the current directory.

=item B<-q>

Do not print anything; instead, exit with a status of 0 if any matches were
found, 1 otherwise.

=item B<-x>

Only find matches that the user has execute permission for.

=back

=head1 RESTRICTIONS

Due to Getopt::Std's parsing of all options at once, rather than parsing them
one at a time as L<getopt(3)> does, mutually exclusive options (i.e., B<-F>,
B<-f>, and B<-q>) that are given on the command line cannot be resolved by
seeing which comes last.  Instead, a set of built-in precedences is used: B<-q>
overrides B<-f>, which overrides B<-F>.

This program is implemented as a L<perl(1)> script, which means that non-ARPA
members on SDF cannot run it.  An attempt was made to convert it to a shell
script, but problems were encountered in dealing with wildcards in operands.

Wildcard matching is implemented using Perl's C<glob> function, which may or
may not support whatever non-standard patterns you desire.

=head1 SEE ALSO

L<command(1)>, L<whereis(1)>, L<which(1)>

=head1 AUTHOR

John T. Wodder II <[email protected]>

=head1 LICENSE

Feel free to do whatever the Tartarus you want with this.

=head1 HISTORY

B<finbin> was originally written 15 Oct 2008 by John T. Wodder II.  It was last
edited 14 Dec 2008 by John Wodder.

=cut