Designing menus in scripts
In we will:

Building the menu:
The menu defines the flow through the script
In menu-driven scripts, each menu choice defines one possible route that the flow of logic can take through the script. It's a good idea to get the menu logic working first, and fill in the code to do each job later. We already have the commented-label outline for the different menu choices in place. There's no code in these sections yet, but we can use dummy task messages for now, to show the right section was reached.
We've covered the groundwork for building a menu with our study of and return codes. Let's remind ourselves about that, and extend our knowledge a little.
Use a Return-code shell to see what's happening
To help see what's going on, we'll work in a Return-code shell. Open a Return-code child shell in the BatchWindow with our RC.BAT script :
Displaying a prompt string with
The command can display a simple text prompt as well as its list of acceptable responses. You simply add the text on the end of the command line, like this:
Try it now, then press Q as your response to the command :
Note We see only because we're in a Return-code shell. Normally, you would see nothing, nor even know a code had been returned. We receive return-code 1 because Q is in the first position in our /c:qab list.
Using the /n switch to suppress response list
When using menus, we shall use to display a list of menu options and each corresponding response. We shan't need the list – [Q,A,B]? – displayed with the
Try it now. Press B as your response to the command :
Note The /n switch means the list of acceptable responses is not shown. It doesn't suppress the text prompt you add to the command line.
Adding the menu to BKSETUP.BAT
Let's add the menu to our script tool. The command line we've just been using is exactly the one we need for BKSETUP.BAT. Part two of the plan is:
Use to display descriptions of choices
We'll need to display descriptions of the options for the user, and also what key to press for each. We'll display these three lines:
This will display each option clearly, with its corresponding reply key next to it.
The list in /c works best if it's in reverse order
It's a good idea to list the letters in the /c switch in the reverse order that we echo the options on the screen. And it's a good idea to list the Q uit option last on the screen, so that it becomes the first in our /c list. The reasons will become clear later in the Lesson.
Open the script by starting Notepad from the BatchWindow , as usual :
Add the option display lines to the script
Let's add the three ECHO lines we need to the :MAINMENU section of our script. Indent each menu option with a Space , as we did for the menu title. Add blank display lines (use ECHO. on its own) both above and below the menu options; this will help space it out on the screen when the script runs :
Add command
Now let's add our choice command line. We'll add another blank display line below it. Again, this blank display line is just to make the display clearer on screen when the script runs :
Make sure changes to the script are saved
Did you remember to click File, Save in Notepad to save the changes? Merely as a check, the :MAINMENU section of our script now looks like this :
Check the script
Run BKSETUP.BAT in the BatchWindow to check it. Reply
Indenting the prompt with Space s
Notice that, unlike our carefully indented text, the prompt, Please choose-, is not indented, so it doesn't line up properly. You can't fix this by inserting Space s in front of the prompt. Let's confirm that. First, type the command (exactly as we have it) in immediate mode, and reply
Simply adding extra Space s won't work
Use the same command line, but this time try putting three extra Space s in front of the prompt :
The prompt must be included in "quotes"
The extra Space s were ignored. To have effect, they (together with the text prompt) need to be in "quotes". Use three extra Space s before the text prompt, as before, but this time use "quotes" around them and the prompt :
Now the text prompt is indented by the number of Space s inside the "quotes".
A right-aligned prompt is easier to use
One leading Space would be enough to left-align the prompt. But, if we use 15 extra Space s, this will right-align the prompt. This makes the menu more intuitive, because the user's input point (the blinking cursor) is just below the column of acceptable replies.
In the script, change the line to enclose the prompt in "quotes", and use 15 extra Space s in front of the
Check the script again
You clicked File, Save, so run the script to check alignment. Reply
The trailing – is no longer needed
We used a trailing – in our prompt so that when Windows displays our reply key, it wasn't placed immediately after the prompting text. Now we're using "quotes" around our prompt, we can simply replace the – with a
Check the script again
You clicked File, Save, so run the script again. Reply
The return-code won't show in normal use
The alignment of the prompt and the reply key options makes the menu easier to use. We shan't see the line in a normal shell, so its alignment isn't relevant.
The flow of logic:
The path through a script
In a simple script, such as LEVEL.BAT, the flow of logic is top to bottom, then stop. The flow of logic means the route Windows takes through a script when the script runs.
In BKSETUP.BAT, the option chosen when the menu appears will decide the flow through the script. This is the outline of how BKSETUP.BAT will work:
BKSETUP.BAT flow
We'll use the reply codes to route the flow correctly through our script.
Testing :
Using the test
Our script must do different things, depending on the option chosen. We've already used the IF ERRORLEVEL is greater than or equal to test to set variables. Now we'll use it to jump to the right section for the option chosen.
Test for Q option
We know that the returned for Q is 1; so when we get this code, we need to jump to the
Our :QUIT label is in place, and we've seen that to jump to a label with a command we omit the colon (but our comment can remain). So the line we need is:
IF ERRORLEVEL 1 GOTO QUIT no further action
Let's add that line. We must put it in the :MAINMENU section just after the command that gets the reply from the user :
Add code for Q option
It's a good idea to send the user a confirming message whenever an option is selected. If, we add those messages now, they'll confirm our jumps are working, which is useful. For the Q for Quit option, we'll just say
Let's put a command to display this in the :QUIT section. We'll indent the text with a Space , as usual :
We need to jump to the :CLEANUP section
At it stands, the script falls through to :JOBDONE. However, after the user has selected Q for Quit, there's no job to report done. So the next place to go is :CLEANUP.
Remember that the variable SRC will have been set (it was expanded to display the menu title). The user won't know about this, but we need to clear it before the script finishes. The
So use a command to route flow through :CLEANUP to finish :
Test the Q option
The :CLEANUP section has a jump to the :EOF (end-of-file) label, so that completes the code for the Q (for quit) option. You remembered to click File, Save in Notepad? Let's test the script. Run it now, and choose Q from the menu :
Note You've grown used to the DVM screen clearing immediately Return is pressed after typing bksetup. We shan't show the split before/after simulation any more, unless there is a special point to demonstrate. Instead, the window simulation will show the DVM screen in the final state only.
The A option
To add the A option, which is second in the /c:qab list, we'll need an test for a return code of 2. You remember that all these tests are for whether or not the current code is greater than or equal to the number you test for, don't you?
Before we add any code to the :ADDFILES section, let's just run the script again, as it is, but we'll reply
The Q test is true for all the other replies, too
We saw the No further action taken message just as if we'd pressed Q . Why does that happen?
We can see the return code was 2, so our A reply was detected properly. The problem is that our test for Q :
IF ERRORLEVEL 1 GOTO QUIT no further action
is really a test for any return code that is greater than or equal to 1, so it's true for a value of 2, as well, and the script jumped straight to :QUIT
An A reply returns a code of 2
We shall need a line to test for the A option (which returns
IF ERRORLEVEL 2 GOTO ADDFILES and make changes
It can't go after our test for return-code 1, because any reply that set a return-code 2 (or higher) would jump on the test for 1 (and so always jump straight to the :QUIT section).
This time tests must be in descending order
The solution is that we must put the test for 2 immediately before the test for 1. This is the opposite of the test order we needed to set our variable in LEVEL.BAT. In that script, all the tests were checked (but some were false).
In a menu script, the first test that is true usually sends the flow off elsewhere, with a command, and so the remaining tests aren't ever reached. With menus, you must test for the return codes in descending order.
Add the A test above the Q test
Add the line to test for the A option above the test for Q , like this :
The same applies to the test for our B option
In the same way, we can't test for B (which will return
The reversed /c list is now reversed again
Now you can see why it's a good idea to put the options in the /c: list in the reverse order their descriptions are displayed. We echoed the descriptions: B A Q , but reversed the order is our /c:qab switch. Since the return codes must be checked in descending order, the checks are in the same order as the descriptions. This makes the script very clear to follow when we read it, as you now see :
Using a task message for A and B options
The two sections, :ADDFILES and :BUILD, don't have any code at the moment. They just fall through to :QUIT.
We'll set a variable, TASK, in each section to hold a task description. To prevent fall through into :QUIT, we'll also add a jump to :JOBDONE.
Task description for the :BUILD section
In the :BUILD section, we'll set TASK to the message
Task description for the :ADDFILES section
In :ADDFILES, we'll set TASK to the message
We can't test the script properly yet
We need to test the lines we've added, but we can't test yet, because we won't see their effect properly. We need to add some code to the :JOBDONE section to report the TASK message. Then we'll know whether the jumps to the different sections of the script are each working properly.
Using TASK message
The actual text message set in TASK will depend on the user. If the user chooses:
TASK is set to
TASK is set to Reporting that the TASK selected has finished
We'll display the content of the variable, by using
Add the line in :JOBDONE now
Each new variable needs cleaning up
We've used a new variable, TASK, so we also need to add a command to clear it again in :CLEANUP. Let's do it now before we forget :
Now we can test the script; test with B
You clicked File, Save so we can test all three options now. We'll see the messages to show that the flow of the script went to the right section each time. Run the script, and choose
If you see errors reported
We've added a lot of code, and it's easy to make typing mistakes. If you see error messages or syntax errors, remember the simple debug technique to use when new lines added are leading to problems:
Test with reply A
Once all is well, run the script again, and choose
And test with Q
Run the script once again, and choose
Add a further blank display line
The task message will be clearer if it's not immediately followed by the system prompt
Check the script in a normal shell
You remembered to click File, Save? To finish off, we'll try out the script in a normal shell (where the return-code message won't be displayed). Exit the Return-code shell now :
Test the script with B
Run the script, and choose
Test the script with A
Run the script again, and choose
Two finishing touches to the menu
There are two more simple tweaks to make to the menu before we test the Q option. They're two good habits to get into, and they make menu operation fail-safe.
1: Can we get a 0 code?
As we know, the reply Q will
However, if any reply did return 0 it wouldn't trigger any of our tests (they're all for 1 or more), and we'd fall straight through into whatever option we happened to code first. Bad idea. But it can't happen; so nothing can possibly go wrong go wrong, can it?
Coding Q uit as default
You don't get far with computer programming before realising that almost anything can go wrong. For example, the command executable file, CHOICE.COM, could be missing or corrupt. Then we wouldn't get a new set, and 0 is the initial when we start a session. Better to code our Q uit option to fail safe:
2: Getting more than 3?
Nothing else can possibly go wrong, because with only three items, we can't receive a reply code of more than 3, can we? It's just as well since any code more than 3 would trigger our first test. Remember the test is for greater-than-or-equal-to, so a reply code of 4 (or more) would test true, and jump to the :BUILD section. But it can't happen.
You don't get far with computer programming ... Exactly. You'll recall that in Lesson 2, Lesson 3, and Lesson 4, we used with an invalid switch
Mistakes are frequent during development
While we're writing a script, it's very easy to alter an existing line by accident. So we'll code a test for greater-than-or-equal-to 4, and make it jump to the :QUIT section. Add it, with a new comment afterwards :
Nothing can go wrong
Now nothing can possibly go wrong (well, not much).
Note problems are rare in Windows 95/98/ME, but much of its Batch syntax is similar to that in Windows NT, so sometimes scripts are "borrowed". And is not a default install in Windows NT and related operating systems, so it's often missing (a version of the command is available for such systems, but it's not loaded by default).
Test the script with Q
With that change saved, run the script once again, and choose
That completes the script flow for the menu
We now have the menu logic fully working. Choosing each option makes the script flow jump to the right section, as confirmed by the messages we put in each section.
Getting the menu working first is a good way to write a complex script, because the menu and its tests and jumps defines the structure of the script. All that remains is to add the code to do the actual work once we've learnt how to! That will come later.
What we have learnt
In this Lesson we have learnt how to: