walkingthecow has asked for the wisdom of the Perl Monks concerning the following question:

Hey Monks!

I currently have about 30 scripts that I am trying to build a menu system for, but having a VERY difficult time doing so. Basically, the menu system builds the command and calls each script. Each script works like so: "scriptWrapper.pl -infile File -script Script". The menu needs to define the script and build the infile.

For example, the menu starts at a main menu, from there lets say you choose account menu, that displays and you choose addUser. In the addUser portion you can load an infile and then it gets validated. If a line in the infile is not valid, it takes you to manually edit the option. If you do not have an infile you can manually add users and build an infile. This returns an infile and the script. The problem is, I am unsure really how to do this. Sample code is below:

Main Menu
sub mainMenu { my ($choice,$notice); while (1) { system("clear"); $choice=displayMenu("main",$notice); if ($choice =~ /a/i) { accountMenu(); last; } elsif ($choice =~ /s/i) { serverMenu(); last; } elsif ($choice =~ /m/i) { miscMenu(); last; } else { $notice="INVALID OPTION!"; next; } } }
Account Menu
sub accountMenu { my ($notice,$choice); while (1) { $choice=displayMenu("accountMenu",$notice) if ($choice == 1) { changePassword(); last; } elsif ($choice == 2) { addAccount(); last; } else { $notice="INVALID OPTION"; } } }
addAccount
sub addAccount { while (1) { displayMenu("add"); if ($choice == 1) { my $tempInFile=getInput("PLEASE ENTER FULL PATH TO INPUT F +ILE > "); my $csv = Text::CSV->new(); open (CSV, "<$tempInFile") or die "COULD NOT OPEN $tempInF +ile ($!)\n"; while (<CSV>) { if ($csv->parse($_)) { my @columns = $csv->fields(); validateOptions("add","$infile",@columns); } else { my $err = $csv->error_input; print "Failed to parse line: $err"; } } close CSV; last; } elsif ($choice == 2) { manuallyEnterUser("add"," "); last; } elsif ($choice =~ /a/i) { accountMenu(); } elsif ($choice =~ /m/i) { mainMenu(); } elsif ($choice =~ /e/i) { exit(0); } else { $notice="INVALID OPTION"; next; } } }
As you can see right now the code is not returning the script or infile, but really at this point I have so many function calls for just one option that I am just completely lost here. Is there a better way to do this? A good module anyone can recommend? Anything??

Replies are listed 'Best First'.
Re: Building a Perl Menu
by Utilitarian (Vicar) on Apr 28, 2009 at 10:03 UTC
    The snippet below comes from an old menu based script I wrote when learning Perl, it offers a less sprawling approach, each menu option has an associated string and sub_name, you then call the sub with the same index as the "friendly" name.
    @menu_array=("User Operations","Domain Operations","Exit this script") +; @sub_array=qw(userMenu domainMenu sub_quit); print "Which type of operation do you wish to perform"; for ($index=0;$index<$#menu_array;$index++){ print "\n\t$index)$menu_array[$index]"; } $index=&getReply; $return_value=&{$sub_array[$index]}; return($return_value);
    UPDATE: Looking back on this, a generic menu sub should be implemented, to take a list
    &menuSub($friendly_prompts_array_ref, $sub_routine_array_ref,$question +)
Re: Building a Perl Menu
by leocharre (Priest) on Apr 28, 2009 at 15:01 UTC
Re: Building a Perl Menu
by Bloodnok (Vicar) on Apr 28, 2009 at 17:02 UTC
    You don't identify the OS, nor the version of perl, but assuming they're compatible and that you don't want to re-invent the wheel again, is Curses of any use to you ??

    A user level that continues to overstate my experience :-))
      Sorry all, the OS is Solaris 8 and the version of Perl is 5.005_03. I know, it's outdated, trust me I know this, but there is nothing I am able to do about it.

      A little more about the script... Basically, it is entirely command line. You ssh into the server and then you load up the menu. There is no X session at all. It is entirely command line. Now, basically the idea is that we start with a menu and we end with a $script and $infile variable, which are then passed to another script. So we're building a command line is all the menu is really doing. However, there is a lot of input and the menu changes based on user input. Again, a little revised version here, but this is what I have thus far:
      #!/usr/bin/perl use strict; use Menu; my $username=getlogin(); my $infile="/tmp/$username.inFile"; my ($script,$infile=mainMenu($infile);
      sub mainMenu { my $infile=shift; my ($choice,$notice); while (1) { system("clear"); print BOLD BLUE <<EOF; PLEASE CHOOSE AN OPTION FROM BELOW EOF print GREEN <<EOF; (A) Account Administration ------------------------------- EOF if ($notice ne "") { print RED "\n\n$notice\n\n"; $notice=""; } my $choice=getInput("Please enter your choice > "); if ($choice =~ /a/i) { accountMenu($infile); last; } else { $notice="INVALID OPTION!"; next; } } } sub accountMenu { my $infile=shift; my ($notice,$choice); while (1) { system("clear"); print BOLD BLUE <<EOF; PLEASE CHOOSE AN OPTION FROM BELOW EOF print GREEN <<EOF; (1) Add Account(s). ------------------------------------------------- (M) Back to Main Menu. EOF if ($choice == 1) { addAccount($infile); last; } else { $notice="INVALID OPTION"; next; } }
      sub getInput { my $message = shift; my $return; print "$message"; chomp($return=<STDIN>); return $return; }
      sub addAccount { my $infile = shift; while (1) { system("clear"); print BOLD BLUE <<EOF; PLEASE CHOOSE AN OPTION FROM BELOW EOF print RED <<EOF; (1) Load User File. (2) Manually Enter Each User. ------------------------------------------------- (A) Back to Account Administration Menu. (M) Back to Main Menu. (E) Exit. EOF if ($notice ne "") { print RED "\n\n$notice\n\n"; $notice=""; } my $choice=getInput("Please enter your choice > "); if ($choice == 1) { loadFile(); last; } elsif ($choice == 2) { manuallyEnterUser(); last; } elsif ($choice =~ /a/i) { accountMenu(); } elsif ($choice =~ /m/i) { mainMenu(); } elsif ($choice =~ /e/i) { exit(0); } else { $notice="INVALID OPTION"; next; } } }
      Now, the user can then load a file, at which point they type in full path to file, and then all options are validated and if file is good then their infile gets returned as the infile, and script gets returned. If a line in user infile is not valid then they must fix the error. Anyway, this is a huge convuluted way of doing a simple task, and I just know there is an easier way of doing this.
        I sympathise with your predicament - sounds like an MOD engagement I was involved with a coupla years ago...

        If it is really command line, then the simplest solution would surely be the select command within the Korn shell e.g.

        #! /bin/ksh PS3="Select an item:" select ITEM in opt1 opt2 opt3 opt4 ; do case "$ITEM" in opt1) ... ;; opt2) ... ;; opt3) ... ;; opt4) ... ;; *) echo "Bad call" ;; esac done
        A user level that continues to overstate my experience :-))