subcommand within Perl script

S

Slickuser

I am trying to use Getopt::Long to get user input arguments.
game.pl start mode:easy
game.pl stop
game.pl start mode:hard
game.pl exit

If user input game.pl start mode:easy it will go to the start function
with mode:easy for options.

I'm not sure how to start it. Can you guys give me some hints. I have
some code below.


use strict;
use warnings;
use Getopt::Long;

&main;

sub main
{
my (@CMDS);

my $subcmds =
{
#game start -mode:easy
"start" =>
{
'sub' => \&subcmd_start,
'getopt' => ["-mode|m=s"],
},

";" =>
{
'sub' => \&subcmd_no_func,
}

};


foreach my $arg_func (@ARGV)
{
if (exists $subcmds->{$arg_func})
{
push(@CMDS, [$arg_func]);
next;
}
#else
#{
# print "AAAAAAA \n";
#}
}

foreach my $cmd (@CMDS)
{
#&exe_cmd($subcmds, $cmd->[0], $cmd->[1]);
}


return 1;
}

sub exe_cmd
{


}

sub subcmd_start
{
print "Starting... \n";

}


sub subcmd_no_func
{
print "No sub function... \n";

}
 
T

Ted Zlatanov

S> I am trying to use Getopt::Long to get user input arguments.
S> If user input game.pl start mode:easy it will go to the start function
S> with mode:easy for options.

S> I'm not sure how to start it. Can you guys give me some hints. I have
S> some code below.

You're not using Getopt::Long in your code, you just import it.

Since -mode will imply you want to start, you can get rid of -start:

# untested but copied from working code

my %options =
(
# put your defaults here
);

GetOptions (
\%options,
"mode|m=s",
"stop",
"exit",
);

if (exists $options{stop})
{
.... stop logic ...
}

if (exists $options{exit})
{
.... exit logic ...
}

if (exists $options{mode})
{
.... start logic with $options{mode} ...
}
 
B

Ben Morrow

Quoth Slickuser said:
I am trying to use Getopt::Long to get user input arguments.

If you want options looking like that, you don't want Getopt::Long :).
If user input game.pl start mode:easy it will go to the start function
with mode:easy for options.

I'm not sure how to start it. Can you guys give me some hints. I have
some code below.


use strict;
use warnings;
use Getopt::Long;

&main;

Don't call subs with & unless you need to.
sub main
{
my (@CMDS);

my $subcmds =
{
#game start -mode:easy
"start" =>
{
'sub' => \&subcmd_start,
'getopt' => ["-mode|m=s"],
},

OK, you're building a dispatch table: that's a good start. Personally I
would put the subs directly in the table, like

my $subcmds = {
start => {
getopt => ['-mode|m=s'],
sub => sub {
# contents of &subcmd_start here
},
},
};

rather than giving them separate names, but that's not important.

I'm not sure what this entry is for: are you expecting users to invoke
the program like

game ";"

?
foreach my $arg_func (@ARGV)

I don't think you want a for loop here. AFAICT, you just want to
dispatch on the first argument, and pass the rest; this looks like

my $cmd = shift @ARGV;
$subcmds->{$cmd} or die "no such command: $cmd\n";
$subcmds->{$cmd}{sub}->(@ARGV);

Ben
 
S

Slickuser

game.pl start -mode:easy
game.pl stop
game.pl start -mode:hard
game.pl exit

I would like to use multiple arguments, how would that work?
Such as:

game.pl start -mode:easy -cheat:eek:ff -player:3 -name:"Jen,Josh,Kim"

All these are optional: -mode:easy -cheat:eek:ff -player:3 -
name:"Jen,Josh,Kim".
By default it will start with easy, cheat off, player 1, Ben.

Thanks.
 
T

Ted Zlatanov

S> If user input game.pl start mode:easy it will go to the start function
S> with mode:easy for options.S> I'm not sure how to start it. Can you guys give me some hints. I have
S> some code below.
S> game.pl start -mode:easy
S> game.pl stop
S> game.pl start -mode:hard
S> game.pl exit

S> I would like to use multiple arguments, how would that work?
S> Such as:

S> game.pl start -mode:easy -cheat:eek:ff -player:3 -name:"Jen,Josh,Kim"

S> All these are optional: -mode:easy -cheat:eek:ff -player:3 -
S> name:"Jen,Josh,Kim".
S> By default it will start with easy, cheat off, player 1, Ben.

Please don't top-post.

You can add any options to the GetOptions parameters, e.g. add
"player=i" to have a "-player 3" option. Put "player => 1" in %options
if you want a default player value. If you want colons to set the
options, as your examples show, you'll have to look at the Getopt::Long
docs or write your own parser.

If I understand your player example, what you really want there is
"player|p=s@" which will put multiple players in an array reference in
%options. So you'll be able to say

my $player_one = $options{player}->[0];

Please see the Getopt::Long documentation. "Options with multiple
values" is right after the introduction.

Ted
 
S

Slickuser

Ben,

Thanks for the suggestion. I will follow that method and ignore that
module.
Once I'm in the function, I can search for the options.

How can I fixed this error?
Use of uninitialized value in hash element at C:\game.pl line 30.
Use of uninitialized value in hash element at C:\game.pl line 31.
No sub function...
game.pl start -mode:easy
Starting...
The rest are options: -mode:easy


use strict;
use warnings;

my @CMDS = @ARGV;

main();

sub main
{

my $subcmds =
{
#game start -mode:easy
"start" =>
{
'sub' => \&subcmd_start,
'getopt' => ["-mode|m=s"],
},

"" =>
{
'sub' => \&subcmd_no_func,
}

};


my $cmd = shift @CMDS;
$subcmds->{$cmd} or die "no such command: $cmd\n";
$subcmds->{$cmd}{sub}->(@CMDS);

return 1;
}


sub subcmd_start
{
print "Starting... \n";

print "The rest are options: @CMDS \n";



}


sub subcmd_no_func
{
print "No sub function... \n";

}
 
B

Ben Morrow

Quoth Slickuser said:
Ben,

Thanks for the suggestion. I will follow that method and ignore that
module.
Once I'm in the function, I can search for the options.

You can use Getopt::Long to do this, within each function, if you like.
You could also use G:L to process the remainder of @ARGV before you call
the sub, and pass the parsed options.
How can I fixed this error?

Use of uninitialized value in hash element at C:\game.pl line 30.
Use of uninitialized value in hash element at C:\game.pl line 31.

If you pass no arguments, then @ARGV has no values, and when you try to
shift one off you get undef. There are several ways to fix this:

my $cmd = (shift @ARGV || '');

will default to using the empty string; however, then both

game.pl ""

and

game.pl 0

will be treated as 'no arguments', since 0 is a false value in Perl. If
you're OK with the former but not the latter, you can use

my $cmd = shift @ARGV;
defined $cmd or $cmd = '';

or (if you are using 5.10)

my $cmd = (shift @ARGV // '');

If neither is OK, you can use

@ARGV or return subcmd_no_func();
my $cmd = shift @ARGV;

which will only call subcmd_no_func if no arguments are supplied.

Ben
 
S

Slickuser

I will follow this model. Thanks..

use strict;
use warnings;
use Getopt::Long;

main();

sub main
{

my $subcmds =
{
#game start -mode "easy"
"start" =>
{
'sub' => \&subcmd_start,
'getopt' => ["-mode|m=s"],
},

"" =>
{
'sub' => \&subcmd_no_func,
}

};


my $cmd = shift @ARGV;
defined $cmd or $cmd = '';
$subcmds->{$cmd} or die "no such command: $cmd\n";
$subcmds->{$cmd}{sub}->(@ARGV);

return 1;
}


sub subcmd_start
{
GetOptions(
'mode:s' => \my $opt_mode,
'name:s' => \my $opt_name,
'player:i' => \my $opt_player,
'cheat:s' => \my $opt_cheat
);

print "Starting... \n";

if (defined $opt_cheat)
{
print "Cheat: $opt_cheat \n";
}

}


sub subcmd_no_func
{
print "No sub function... \n";

}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top