Search code examples
batch-filedos

Problems in real DOS with mixed "goto" and "call" commands in a batch menu


I'm creating a batch menu in MS-DOS 6.22 and I need to use if errorlevel with mixed goto and call commands. I'm having some issues with the order because they are not executed as expected.
I can't start the other batch files without using call with the exception of file6.bat because I need to preserve environment variables.

This is an example of the menu:

:MENU
@echo off
echo [1] Choice 1
echo [2] Choice 2
echo [3] Choice 3
echo [4] Choice 4
echo [5] Choice 5
echo [6] Choice 6
echo [7] Choice 7
echo [8] Choice 8
echo [Y] Choice Y
echo [Z] Choice Z
choice /c12345678YZ /n /m "Select an option"

if errorlevel 10 call file7.bat
if errorlevel 9 file6.bat
if errorlevel 8 call file5.bat
if errorlevel 7 call file4.bat
if errorlevel 6 call file3.bat
if errorlevel 5 call file2.bat
if errorlevel 4 goto menu3
if errorlevel 3 goto menu2
if errorlevel 2 goto menu1
if errorlevel 1 call file1.bat

That's the behaviour:

  • If I choose 1, it executes the 4th [goto menu3].
  • If I choose 2, 3, 4, 5, Y and Z, it responds properly.
  • If I choose 6, 7 and 8, nothing happens.

Could you please help me understand how to fix this problem?


Solution

  • Three facts are important here:

    1. COMMAND.COM of MS-DOS 6.22 processes one line after the other from top to bottom of a batch file, except the command GOTO is used to continue batch file processing not on next line, but on line below the line with the label specified as parameter for command GOTO.

    2. The DOS command processor continues processing of a batch file on another batch file without returning ever back to current batch file if the other batch file is specified on a command line without usage of command CALL.

    3. The condition if errorlevel X means IF ERRORLEVEL IS GREATER OR EQUAL 1. It is necessary to use two conditions to check if exit code of a command or application is equal a specific number. The necessary syntax is: if errorlevel X if not errorlevel X+1 command. That is like IF ERRORLEVEL IS EQUAL X because of ERRORLEVEL must be GREATER OR EQUAL X AND LESS THAN X+1. These two conditions are only true IF ERRORLEVEL IS EQUAL X. Example: if errorlevel 6 if not errorlevel 7 call file3.bat results in calling file3.bat only IF ERRORLEVEL IS EQUAL 6.

    Let us look together on the use cases defined by the key pressed by the user.

    Use case 1: The user presses key Z.

    1. CHOICE.COM exits with value 10 assigned to ERRORLEVEL.
    2. The first condition if errorlevel 10 is true and therefore batch file file7.bat is called by command processor.
    3. COMMAND.COM continues on next IF condition line after finishing processing of file7.bat, except it contains the command EXIT which results in exiting the command process independent on the calling hierarchy on being really executed.
    4. The second condition if errorlevel 9 evaluates not the exit code of CHOICE.COM, but the exit code returned by batch file file7.bat to the main batch file. The exit code returned by file7.bat is most likely 0 and therefore this second condition and all other below are evaluating to false.

    Use case 2: The user presses key Y.

    1. CHOICE.COM exits with value 9 assigned to ERRORLEVEL.
    2. The first condition if errorlevel 10 is false.
    3. The second condition if errorlevel 9 is true resulting in execution of file6.bat. The command CALL is not used here. For that reason COMMAND.COM does not return back to main batch file after finishing processing of file6.bat. For that reason everything below if errorlevel 9 file6.bat does not matter on this condition being true because of batch file processing ends with finishing processing of file6.bat.

    Use case 3: The user presses key 8.

    1. CHOICE.COM exits with value 8 assigned to ERRORLEVEL.
    2. The first condition if errorlevel 10 is false.
    3. The second condition if errorlevel 9 is false.
    4. The third condition if errorlevel 8 is true and therefore batch file file5.bat is called by command processor.
    5. COMMAND.COM continues on next IF condition line after finishing processing of file5.bat, except it contains the command EXIT and which is also executed.
    6. The fourth condition if errorlevel 7 evaluates the exit code returned by batch file file5.bat to the main batch file which is most likely 0 and therefore this fourth condition and all other below are evaluating to false.

    The behavior is more or less the same on user pressing key 7, 6 or 5.

    Use case 4: The user presses key 4.

    1. CHOICE.COM exits with value 4 assigned to ERRORLEVEL.
    2. The first six conditions evaluate all to false.
    3. The seventh condition if errorlevel 4 is true and therefore command GOTO is executed resulting in continuation of batch file processing on the line below the line with the label menu3. So the other IF conditions do not matter on this use case.

    The behavior is more or less the same on user pressing key 3 or 2.

    Use case 5: The user presses key 1.

    1. CHOICE.COM exits with value 1 assigned to ERRORLEVEL.
    2. The first nine conditions evaluate all to false.
    3. The last condition if errorlevel 9 is true and therefore batch file file1.bat is called by command processor.
    4. COMMAND.COM continues on line after finishing processing of file1.bat, except the command EXIT is executed during processing of file1.bat.

    There are at least three potential problems with this code:

    1. The last exit code of an executed command or application of a called batch file determines the processing behavior in main batch file. That is not really wanted here.
    2. If none of the commands in a called batch file modifies value of ERRORLEVEL like called batch file containing only a series of set variable=value, the next IF condition below the IF condition resulting in calling the other batch file is also true which results in calling one more batch file or continuation of batch file processing on code for menu3.
    3. The code below the last condition if errorlevel 1 determines what happens next on any other batch file called from within this main batch file in case of all those batch files exit with value 0.

    The third problem can be easily solved by writing next in main batch file after last condition if errorlevel 1 either goto MENU to continue batch file processing at top with printing again the menu or goto ENDBAT with last line in main batch file being :ENDBAT to continue processing the batch file at end of the batch file which means finishing the processing of this batch file.

    But it is necessary for the potential problems 1 and 2 to make sure that processing of main batch file continues not on next command line after calling other batch file, but for example with the menu.

    @echo off
    :MainMenu
    cls
    echo [1] Choice 1
    echo [2] Choice 2
    echo [3] Choice 3
    echo [4] Choice 4
    echo [5] Choice 5
    echo [6] Choice 6
    echo [7] Choice 7
    echo [8] Choice 8
    echo [Y] Choice Y
    echo [Z] Choice Z
    choice /C:12345678YZ /N /M "Select an option:"
    
    if errorlevel 10 set BatFile=7
    if errorlevel 9 if not errorlevel 10 file6.bat
    if errorlevel 8 if not errorlevel 9 set BatFile=5
    if errorlevel 7 if not errorlevel 8 set BatFile=4
    if errorlevel 6 if not errorlevel 7 set BatFile=3
    if errorlevel 5 if not errorlevel 6 set BatFile=2
    if errorlevel 4 if not errorlevel 5 goto Menu3
    if errorlevel 3 if not errorlevel 4 goto Menu2
    if errorlevel 2 if not errorlevel 3 goto Menu1
    if errorlevel 1 if not errorlevel 2 set BatFile=1
    
    call file%BatFile%.bat
    set BatFile=
    goto MainMenu
    
    :Menu3
    echo Here would be shown menu 3.
    goto ENDBAT
    
    :Menu2
    echo Here would be shown menu 2.
    goto ENDBAT
    
    :Menu1
    echo Here would be shown menu 1.
    goto ENDBAT
    
    :ENDBAT
    

    The goal for every called batch file is to continue with showing again the main menu after finishing processing of called batch file. For that reason it is enough to define an environment variable like BatFile with the number of the batch file to call and make sure that always only one IF condition is true according to errorlevel set by CHOICE.COM.

    The code above results in execution of file6.bat on user pressing key Y with ignoring the remaining lines in this main batch file. The batch file processing continues with pressing key 2, 3 or 4 on appropriate code for the submenu 1, 2 or 3. But for the keys 1, 5 to 8 and 7 is called the appropriate batch file, then defined environment variable BatFile is undefined and batch file processing continues with printing again the main menu and let the user take one more choice.

    It is of course also possible to assign complete file name of the batch file to call to environment variable BatFile instead of just its number if the batch files to call have different file names and just file extension is the same for all batch files to call. In this case the command line with CALL would be call %BatFile%.bat.