http://qs1969.pair.com?node_id=30139
Category: Miscellaneous
Author/Contact Info jcwren
jcwren@jcwren.com
Description: I write a fair number of programs that use interactive commands. I intensely dislike programs that require me to type more than the minimum number of characters to distinguish one command from another. I also dislike have to have special parameters that instruct the command interpeter what portion of the command is unique.

To that end, this snippet takes a hash of commands, keyed by the command name, and the user input, and finds the minimum match. Errors are no matches, or ambiguous matches, in which case an error message with the list of commands is returned. If no error, the full name of the hash is returned.
#!/usr/local/bin/perl -w

use strict;
use Carp;

my %Commands = ('who'      => \&do_who,
                'what'     => \&do_what,
                'why'      => \&do_why,
                'never'    => \&do_never,
                'again'    => \&do_again,
                'answer'   => \&do_answer);

{
   my $userinput = $ARGV[0];

   my ($errmsg, $command) = check_commands (\%Commands, $userinput);

   if ($errmsg)
   {
      print "$errmsg\n";
      exit;
   }

   &{$Commands {$command}};
}

sub check_commands
{
   @_ == 2 or croak "Incorrect number of parameters";
   
   my ($cmdhash, $command) = @_;
   
   my @matches = grep /^$command/i, sort keys %$cmdhash;
   
   if (scalar @matches == 0)
   {
      return ("I don't know what '$command' means", undef);
   }
   elsif (scalar @matches > 1)
   {
      my $lastcmd = pop @matches;

      return ("'$command' is ambigous.  It could mean " . join (', ', 
+@matches) . " or $lastcmd", undef);
   }
   
   return (undef, $matches [0]);
}

sub do_who     {print "Who\n"};
sub do_what    {print "What\n"};
sub do_why     {print "Why\n"};
sub do_never   {print "Never\n"};
sub do_again   {print "Again\n"};
sub do_answer  {print "Answer\n"};