Designing menus in scripts

In we will:

 Note  Each Lesson relies on your files from the previous one. It's better to use your own files, but if you can't, download a copy of files as they were at the end of Lesson 5 and click instructions. Remember you can if you prefer.

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:

choice /c:qab Please choose-

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 Please choose- text. We've previously used the /n switch to suppress the list, and that's what is needed here. Our command line becomes:

choice /c:qab /n Please choose-

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:

  1. Main menu - user chooses an option:

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:

 Build fresh test folder.....B
 Add files and make changes..A
 Quit (no further action)....Q

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  Q  :

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  Q  :

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 Please choose- text :

Check the script again

You clicked File, Save, so run the script to check alignment. Reply  Q  :

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  Space  :

Check the script again

You clicked File, Save, so run the script again. Reply  Q  :

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

Study the flow and notice how each option needs to jump over the code for the other options, so that only that code for the selected option actually runs.

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 :QUIT no further action section.

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 No further action taken.

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 :CLEANUP section already has the code to clear SRC for us.

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  A  :

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 2) and it will look like this:

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 3) after our other two tests. The  B  test must go first. The code is similar to the other lines, so add it now :

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 Build fresh test folder, and add the jump to :JOBDONE :

Task description for the :ADDFILES section

In :ADDFILES, we'll set TASK to the message Add files and make changes, and add the jump to :JOBDONE :

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:

Then (with code we have yet to add) the right section of the script will perform the task. Afterwards, in either case, we jump to :JOBDONE. If we put a single command there to display whatever is in TASK, it will display the task description that was set.

Reporting that the TASK selected has finished

We'll display the content of the variable, by using %TASK%, plus a message that it's finished. By this stage in the completed script, the task will be finished, and the confirming message will be useful to us while we write the code.

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  B  :

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  A  :

And test with  Q 

Run the script once again, and choose  Q  :

Add a further blank display line

The task message will be clearer if it's not immediately followed by the system prompt RCode C:\CSW>_. We can add a blank display line to our :CLEANUP section, since the code there is always executed just before the script finishes. Remember, the code for a blank display line is ECHO. on its own, so add it now :

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  B  :

Test the script with  A 

Run the script again, and choose  A  :

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 return 1, because it's the first letter in our /c list. All other replies return a higher code (they're further down the list). So we can't get a 0.

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:

Then, if is missing, our script will quit. We've already coded in the jump, all we need to do is take out the test from in front of the GOTO QUIT :

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 (/x) to return 255.

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  Q  :

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:

The Index has the Syllabus for the next Lesson, where we cover a lot of new ground. We learn to redirect the output of commands, and capture it in files. See you then.

© Copyright 2003- Allen & Company. All rights reserved ©