The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/local/bin/perl -w

use strict;

use File::Basename;
use Getopt::Std;

use vars qw($VERSION);
$VERSION = q$Revision: 1.2 $ =~ /Revision:\s*(\S*)/;

use vars qw($opt_w $opt_m);

getopts('w:m:') || die "Bad options.\n";

my $dir = dirname($0);
my $wordlist = $opt_w || "$dir/wordlist";

unless (@ARGV) {
    warn "usage: $0 [-w <word-file>] [-m <min-length>] <letters>\n";
    exit;
}

my $minlen = $opt_m || 0;                # minimum word length

if ($minlen =~ /\D/) {
    die "$0: <min-length> must be a whole number\n";
}

open(DICT, $wordlist) or                 # open word list
    die "Unable to open $wordlist: $!\n";

$| = 1;

my $letters = shift;
my $words = 0;

my %letters;

$letters = lc $letters;              # convert to lowercase
$letters =~ tr/a-z//cd;              # strip non-letter characters

foreach (split(//, $letters)) {      # store letter counts
    $letters{$_}++;
}

my($word);
WORD:
while (defined($word = <DICT>)) {
                                     # for each word in list
    chomp($word);

    next WORD if (length($word) < $minlen);
                                     # verify length
    next WORD if ($word =~ /[^$letters]/o);
                                     # verify letters used
                                     # comments also skipped here

    my %word;
    foreach (split(//, $word)) {     # verify letter counts
        $word{$_}++;
        next WORD if ($word{$_} > $letters{$_});
    }

    print "$word\n";                 # success - print word
    $words++;

} # WORD: while (defined($word = <DICT>))

__END__

=pod

=head1 NAME

B<words> -- find words which can be made from a string of letters

=head1 SYNOPSIS

B<words> [B<-w> I<word-file>] [B<-m> I<min-length>] I<letters>

=head1 DESCRIPTION

B<words> prints all the uncapitalized words in the word list that can
be made from the string of letters.  Each letter can appear in a word
once for each time it appears in the string.

=head2 OPTIONS

B<words> accepts the following options:

=over 4

=item B<-w> I<word-file>

By default, B<words> looks for a word-file named 'wordlist' in the
same directory as the executable.  Use the B<-w> option to specify the
path to an alternate word list.

=item B<-m> I<min-length>

By default, B<words> prints words of any length that can be made from
the string of letters.  Use the B<-m> option to specify the minimum
length of each word.  B<words> will skip any words that are less than
the specified length.

=back

=head1 FILES

=over 4

=item F<wordlist>

The list of words, found with the executable.

For a comprehensive word list, the author recommends the ENABLE word
list, with more than 172,000 words, which can be found at
http://personal.riverusers.com/~thegrendel/software.html.

=back

=head1 BUGS

This implementation of B<words> has no known bugs.

=head1 REVISION HISTORY

    $Log: words,v $
    Revision 1.2  2004/08/05 14:17:44  cwest
    cleanup, new version number on website

    Revision 1.4  2003/06/06 02:27:35  rjk
    trivial changes to POD
    new email address

    Revision 1.3  1999/08/26 17:10:32  rjk
    Removed L<> from around link in pod - pod2html doesn't handle L<> properly

    Revision 1.2  1999/06/22 02:20:13  rjk
    added /o to regex which verifies letters used
      (regex is constant in this implementation of words)
    added link to ENABLE word list in POD
    added $VERSION

    Revision 1.1  1999/06/14 02:28:41  rjk
    Initial revision

=head1 AUTHOR

This implementation of B<words> in Perl was written by Ronald J Kimball,
I<rjk-perl@tamias.net>.

=head1 COPYRIGHT and LICENSE

This program is copyright 1999 by Ronald J Kimball.

This program is free and open software.  You may use, modify, or
distribute this program (and any modified variants) in any way you
wish, provided you do not restrict others from doing the same.

=cut