CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Pass Aurgment When sub is called in menu

 



SSBN743
New User

May 3, 2016, 11:23 AM

Post #1 of 14 (4217 views)
Pass Aurgment When sub is called in menu Can't Post

Hey guys – I’m wondering if I can get a little help here. I’m, decent with Perl but seem to have stumbled into something above my knowledge level.

I have a proprietary application that can test traffic on different network ports. So, it works like this: `call application (SOURCE IP) (DEST IP):(PORT)` (Basically, just like nc without the source)

There are a number of different values for each of the above parameters. So, I want to build a simple menu to allow an operator to answer applicable questions and build the appropriate command – not too hard right? I’ve already done the same thing in Bash, but the Bash script is so slow that I set out to do it in Perl instead and I’ve hit a roadblock that I can’t get by for 3 days now.

So, here’s what I have:


Code
my ($menu1, $menu2, $menu3) 
my @DEST;
push(@DEST, value1);
push(@DEST, value2);
push(@DEST, value3);
push(@DEST, valueX (etc…));

my @SRC;
push(@SRC, value1);
push(@SRC, value2);
push(@SRC, value3);
push(@SRC, valueX (etc…));

my @PORT;
push(@PORT, value1);
push(@PORT, value2);
push(@PORT, value3);
push(@PORT, valueX(etc…));

$menu1 = [
“menu 1”
[ option 1, \&SOURCE ],
[ option 2, \&SOURCE ],
[ quit ],
];
$menu2 = [
“menu 2”
[ option 1, \&DST ],
[ option 2, \&DST ],
[ quit ],
];
$menu3 = [
“menu 3”
[ option 1, \&PRT ],
[ option 2, \&PRT ],
[ quit ],
];

sub menu {
my $m=shift;
my $choice;
while (1) {
print “$m->[0]?\n\n”;
print map { “\t$_. $m->[$_][0]\n } (1..$#$m) ;
print >
chomp ($choice<>) ;
last if (blah)
}
&m->[$choice][1]|} ;

sub SOURCE {
$SOURCE=$SOURCE[$the problem]
&menu($menu2) ;}

Everything else below is the same with different variable names, before

&menu($menu1);
System(application $SOURCE $DEST:$PORT) ;



I’m trying to pass an argument in when option 1 is selected and use to call an element in each array – but because it all executes at runtime – no matter which option is selected in the menu, the last entry in every array is the result.

So, I’ve been through several iterations of passing an argument in when the sub is called – but that’s going nowhere. I think it’s because of the runtime issue. Basically, it seems to me like what I’m trying to do can’t be done with the menu method above – but there has to be a way to do this very simply idea right?

I have got it to work by calling a unique sub for each choice in the menu, as that way I don’t have to pass anything and each sub can be dedicated to whatever value I want. But, I have a total of 35 different options of the @PORT array alone; I really don’t want to have to do 50 some odd subs – however, that does work.

i.e:

Code
sub SOURCE1 { 
$SOURCE=$SOURCE[0];
&menu($menu2);}
sub SOURCE 2{
$SOURCE=$SOURCE[1];
&menu($menu2);}


Does anyone have any suggestions?


(This post was edited by FishMonger on May 3, 2016, 1:16 PM)


FishMonger
Veteran / Moderator

May 3, 2016, 1:35 PM

Post #2 of 14 (4202 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

That code is incomplete and has syntax errors so I can't test it.

Please post a short but complete test script which demonstrates the problem.

Don't use & when calling your subs.

You probably, if not definitely, should be using a dispatch table and possibly even one of the cpan modules for outputting the menu.
http://search.cpan.org/~dconway/IO-Prompt-0.997003/lib/IO/Prompt.pm
http://search.cpan.org/~dconway/IO-Prompter-0.004014/lib/IO/Prompter.pm
A few minutes searching cpan will probably reveal a couple other choices.


(This post was edited by FishMonger on May 3, 2016, 1:35 PM)


BillKSmith
Veteran

May 3, 2016, 1:37 PM

Post #3 of 14 (4200 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

Nearly every thread in this forum encourages programmers to always use strict and warnings. Your code tries to use bare words and symbolic references, neither of which are allowed under strict.

Place the following at the start of your script:

Code
use strict; 
use warnings;


Fix all the errors and warnings which perl reports. There is a fair chance you can fix your problem yourself. If not, post code that we can actually run and duplicate the problem (and verify any solution we may propose).
Good Luck,
Bill


SSBN743
New User

May 3, 2016, 2:47 PM

Post #4 of 14 (4197 views)
Re: [BillKSmith] Pass Aurgment When sub is called in menu [In reply to] Can't Post

OK thanks - I'll check those links out

BTW - I am using strict and warnings - I just don't have my code on the Internet equipped system and can't get it over there - so I just banged out a quick once-over of what I was doing in a Word doc and posted it.


SSBN743
New User

May 3, 2016, 3:52 PM

Post #5 of 14 (4192 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post


Code
#!/usr/bin/perl –w 

use strict;
use warnings;

my ($menu1, $menu2, $menu3)
my @DEST;
push(@DEST, Tom);
push(@DEST, Sam);
push(@DEST, Adrian);
my $d;
my $DEST;

my @SRC;
push(@SRC, Josh);
push(@SRC, Bill);
push(@SRC, Cody);
my $s ;
my $SOURCE ;

my @PORT;
push(@PORT, Baseball);
push(@PORT, Football);
push(@PORT, Hockey);
my $p;
my $PORT;

$menu1 = [
“menu 1”
[ option 1, \&SOURCE, $s=0],
[ option 2, \&SOURCE, $s=1 ],
[ quit ],
];
$menu2 = [
“menu 2”
[ option 1, \&DST, $d=0 ],
[ option 2, \&DST, $d=1 ],
[ quit ],
];
$menu3 = [
“menu 3”
[ option 1, \&PRT, $p=0 ],
[ option 2, \&PRT, $p=1 ],
[ quit ],
];

sub menu {
my $m=shift;
my $choice;
while (1) {
print “$m->[0]?\n\n”;
print map { “\t$_. $m->[$_][0]\n } (1..$#$m) ;
print “>”;
chomp ($choice<>) ;
last if ( ($choice > 0 ) && ($choice <= $#$m ));
print “You chose ‘$choice’. Which is not a valid option.\n\n”;
}
&m->[$choice][1]|} ;

sub SOURCE {
$SOURCE=$SOURCE[$s];
&menu($menu2) ;}
sub DST {
$DEST=$DEST[$d];
&menu($menu3);}
sub PRT {
$PORT=$PORT[$p];}

&menu($menu1)
system(`echo $SOURCE $DEST:$PORT`)


This should be pretty close to what I actually have - hopefully there are not too many errors, I know how Word love to capitalize things.

Anyway, this should illustrate the problem - no matter what selection you make in the menus, the last element of each array will be the result.


(This post was edited by FishMonger on May 3, 2016, 6:18 PM)


FishMonger
Veteran / Moderator

May 3, 2016, 7:07 PM

Post #6 of 14 (4185 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

NEVER use a word processor to write code, even if it's just to post an example. Use a plain text editor.

Why do you have

Quote
“menu 1”

, and the like, in your array ref assignment? Are they supposed to be comments, or elements of the array?

Why are you doing var assignments inside the assignments of the array refs?

Your code block indentation is wrong and makes it harder to read/follow the code. You need to use proper indentation.


FishMonger
Veteran / Moderator

May 3, 2016, 7:29 PM

Post #7 of 14 (4182 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

You have too many errors in that code for me to determine with any certainty what the real code looks like.

Please find a way to post your actual code, not a sloppy representation of it.


BillKSmith
Veteran

May 3, 2016, 8:53 PM

Post #8 of 14 (4179 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

As soon as I succeeded in correcting all the errors that perl reported, your code worked the way I think you intend. If you had done what FishMonger and I requested, you would have solved the problem yourself.

What made you think your code did not work right. You could not possibly have run it with that many syntax errors.

Code
#!/usr/bin/perl –w  

use strict;
use warnings;

my ($menu1, $menu2, $menu3);
my @DEST;
push(@DEST, 'Tom');
push(@DEST, 'Sam');
push(@DEST, 'Adrian');
my $d;
my $DEST;

my @SRC;
push(@SRC, 'Josh');
push(@SRC, 'Bill');
push(@SRC, 'Cody');
my $s ;
my $SOURCE ;

my @PORT;
push(@PORT, 'Baseball');
push(@PORT, 'Football');
push(@PORT, 'Hockey');
my $p;
my $PORT;

$menu1 = [
"menu 1",
[ 'option 1', \&SOURCE, $s=0 ],
[ 'option 2', \&SOURCE, $s=1 ],
[ 'option 3', \&SOURCE, $s=2 ],
[ 'quit' ],
];
$menu2 = [
"menu 2",
[ 'option 1', \&DST, $d=0 ],
[ 'option 2', \&DST, $d=1 ],
[ 'option 3', \&DST, $d=2 ],
[ 'quit' ],
];
$menu3 = [
"menu 3",
[ 'option 1', \&PRT, $p=0 ],
[ 'option 2', \&PRT, $p=1 ],
[ 'option 3', \&PRT, $p=2 ],
[ 'quit' ],
];

sub menu {
my $m=shift;
my $choice;
while (1) {
print "$m->[0]?\n\n";
print map { "\t$_ $m->[$_][0]\n" } (1..$#$m) ;
print ">";
chomp ($choice=<>) ;
last if ( ($choice > 0 ) && ($choice <= $#$m ));
print "You chose ‘$choice’. Which is not a valid option.\n\n";
}
&{$m->[$choice][1]} ;
}

sub SOURCE {
$SOURCE=$SRC[$s];
&menu($menu2) ;}
sub DST {
$DEST=$DEST[$d];
&menu($menu3);}
sub PRT {
$PORT=$PORT[$p];}

menu($menu1);
system("echo $SOURCE $DEST:$PORT");

Good Luck,
Bill


BillKSmith
Veteran

May 4, 2016, 7:13 AM

Post #9 of 14 (4169 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

You can accomplish the same thing with much simpler code. A prompt module is a big help.


Code
use strict; 
use warnings;
use IO::Prompt::Hooked;
use Readonly;

Readonly::Scalar my $MENU1 => <<'END_MENU_1';
1 option 1
2 option 2
3 option 3
4 quit

SOURCE?
END_MENU_1

Readonly::Array my @DEST => qw( Tom Sam Adrian );


Readonly::Scalar my $MENU2 => <<'END_MENU_2';
1 option 1
2 option 2
3 option 3
4 quit

DESTINATION:
END_MENU_2

Readonly::Array my @SRC => qw( Josh Bill Cody );

Readonly::Scalar my $MENU3 => <<'END_MENU_3';
1 option 1
2 option 2
3 option 3
4 quit

PORT?
END_MENU_3

Readonly::Array my @PORT => => qw( Baseball Football Hockey );

Readonly::Hash my %OPTS => (
validate => qr/^[1-4]$/,
error => "Invalid option. Try again\n",
);

my $choice;

$choice = prompt(message => $MENU1, %OPTS);
die "Aborted by user\n" if $choice == 4;
my $source = $SRC[ $choice - 1 ];

$choice = prompt(message => $MENU2, %OPTS);
die "Aborted by user\n" if $choice == 4;
my $dest = $DEST[ $choice -1 ];

$choice = prompt(message => $MENU3, %OPTS);
die "Aborted by user\n" if $choice == 4;
my $port = $PORT[ $choice -1 ];

system "echo $source $dest:$port";


This version is much shorter than yours. It has better error handling and it is easier to understand. Readonly is not required. I have used it only to tell the reader that these "variables" never change.

You probably want to make changes. Go ahead. My objective was to make that as easy as possible.
Good Luck,
Bill


FishMonger
Veteran / Moderator

May 4, 2016, 7:54 AM

Post #10 of 14 (4168 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post


Code
#!/usr/bin/perl 

use strict;
use warnings FATAL => 'all';
use IO::Prompter;

my @source = ( qw(src1 src2 src3) );
my @dest = ( qw(dest1 dest2 dest3) );
my @port = ( qw(port1 port2 port3) );

my $src = prompt 'Source IP', -menu => \@source;
my $dest = prompt 'Destination IP', -menu => \@dest;
my $port = prompt 'Port', -menu => \@port;

print "$src $dest:$port";


c:\test>Perl-1.pl

Code
Source IP 
a. src1
b. src2
c. sr3

a
Destination IP
a. dest1
b. dest2
c. dest3

b
Port
a. port1
b. port2
c. port3

c
src1 dest2:port3



(This post was edited by FishMonger on May 4, 2016, 7:58 AM)


FishMonger
Veteran / Moderator

May 4, 2016, 8:33 AM

Post #11 of 14 (4159 views)
Re: [FishMonger] Pass Aurgment When sub is called in menu [In reply to] Can't Post

I intentionally kept that example to its minimum to show how easy and clean it could be with a proper module. Your code used numbers for selecting menu items and that could easily be done in the code I used by adding the -i option parameter the the prompt calls.


Code
my $src  = prompt 'Source IP',      -i, -menu => \@source; 
my $dest = prompt 'Destination IP', -i, -menu => \@dest;
my $port = prompt 'Port', -i, -menu => \@port;


If your menu choices are limited, then hard coding them in the script is fine, but if you have a lot of items, it would be best to have them in a config file (such as an ini file) or in a database and retrieve them as needed.


SSBN743
New User

May 4, 2016, 11:15 AM

Post #12 of 14 (4146 views)
Re: [FishMonger] Pass Aurgment When sub is called in menu [In reply to] Can't Post

Thanks for the replies - that is a whole lot easier and better looking. Unfortunately, I don't have the IO::Prompter module even though I hoped I might.

I work in a secure environment that is at least 10 years behind, is there any alternative to IO::Prompter?


FishMonger
Veteran / Moderator

May 4, 2016, 1:20 PM

Post #13 of 14 (4135 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

Your best option would be to install one of the prompt modules.

If you don't want to do that, then you'll have to write your own menu prompt subs, but don't use what you've shown us. Start over from scratch and do it cleanly.

I don't have time right now to give a non-module example.


Laurent_R
Veteran / Moderator

May 4, 2016, 3:10 PM

Post #14 of 14 (4130 views)
Re: [SSBN743] Pass Aurgment When sub is called in menu [In reply to] Can't Post

It is of course better to install a module with the right installation tools provided with the module, but if you can't do it the standard way, the IO::Prompter module is, if I am not wrong, a Perl-only module. At the very least, you should be able to install it just in the same way as you will install your own program (i.e. copy it to the right directory). You'll probably have a couple of dependencies to handle, but it should still be quite easy.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives