Create an Interactive Batch File Using ECHO

Ed shows how to use the MS-DOS ECHO command to turn a batch file into a program that will accept input.

By Ed Keefe

[Note: This article begins by letting you stick your toe in the shallows of programming, but ends by asking you to swim in some deep, uncharted waters. If you find yourself getting in over your head, jump out, dry off and lay down in the sun. The programming technique revealed herein has never before been seen in print, as far as I know. If nothing else, it will make this issue of The HP Palmtop Paper a collector's item.]

A batch file is a keystroke saver an unformatted file that lets you run a series of DOS commands. For example, open a blank Memo screen and type in these three lines: d: cd\DOS dir Save this batch file as C:\LIST.BAT and exit to the DOS C:\ prompt by pressing (&...) Dos. Type list and press (ENTER) to run the batch file. The first line of the batch file changes to the D drive, the second line changes to the DOS directory, and the third line executes the DOS dir command, listing the files in that directory.

A normal batch file like the one described above runs a series of DOS commands. Once you start the batch file, it executes the commands one after the other, without accepting any further input from you. For most users, the ability to run a series of DOS commands is all they want out of batch files. However, some users want to be able to do more with batch files. Specifically, they want to make batch files interactive. They want batch files to be able to ask questions of a user, accept his or her answers, and respond accordingly.

Here's a simple example batch file that shows how a batch file can be used to simulate a Yes/No interaction. Open Memo, type in the lines exactly as shown below and save the Memo file as C:\ YESNO.BAT. (All batch, script and .COM files referenced in this article are archived in ECHO.ZIP <See Shareware/Freeware index>.)

ECHO OFF
CLS
REM YesNo.BAT
REM Delete any file named YN
IF EXIST YN DEL YN
REM Prompt the user
ECHO If you want the Yes branch,
ECHO press Any Key followed by
ECHO Ctrl-Z and Enter. If you
ECHO want the No branch, press
ECHO only Ctrl-Z and Enter.
REM Get the response. If only Ctrl-Z REM is pressed,
REM then no YN file will be created.
COPY CON yn > nul
REM If the YN file exists, branch
REM to Yes otherwise branch to No
IF EXIST yn GOTO yes
GOTO no
:yes
ECHO You chose Yes.
GOTO end
:no
ECHO You chose No.
:end
REM Erase YN file, if it exists.
IF EXIST YN del YN

Once you've saved the file as C:\YESNO.BAT, exit to the DOS prompt, type yesno and press (ENTER) to run the program.

This batch file gives you the option of choosing Yes or No. If you choose Yes, a message is displayed telling you that you should chose Yes. If you choose No, you get the opposite message.

The awkwardness of the technique shown in the above example, using the COPY CON command, inspired others to create small, executable files to accomplish the same thing. The batch file would run the executable file. The executable file accepts your input and then runs the rest of the batch file. Eventually, Microsoft included its own input program, CHOICE .COM, in version 6.0 of MS-DOS.

YESNO2.BAT, listed below, is a version of the YesNo batch file, using the MS-DOS CHOICE command.

@echo off
REM CHOOSE.BAT
CHOICE /N Press Y or N:
REM N is the second of two choices, so...
if errorlevel 2 goto NO
echo You chose YES
goto end
:NO
echo You chose NO
:end

This batch file is simpler, but you'll have to have a copy of CHOICE .COM, found in the C:\DOS directory of a PC running DOS 6.0 or greater.

Unfortunately, CHOICE.COM is not found on the HP Palmtop. But read on and you'll see how to create an interactive batch file without using CHOICE.COM.

Creating a stand-alone, interactive batch file using the ECHO command to embed programming code into a batch file

The typical use for the ECHO command is to display a message on the screen. You can also redirect the message to a file. For example, go to the DOS prompt, type echo George and press (ENTER). The word George is displayed on the screen. For another example showing the redirect capability, go to the DOS prompt, type echo George > line.txt and press (ENTER). This command redirects George to a file called LINE.TXT (The > symbol causes the LINE.TXT file to be created.)

A more unusual use for the ECHO command is to have it redirect machine-readable characters (binary computer code) to a .COM file. This technique lets you use the ECHO command to create executable files. When used in a batch file, the batch file can create .COM files on the fly. This can be useful, as you will see.

The process involves: 1. Using the built-in Debug program to assemble a small .COM program; 2. Embedding the binary code from the .COM program into an ECHO statement in a batch file; and 3. Removing the assembler code and the .COM file from your disk.

CREATING THE .COM PROGRAM

The process of creating .COM programs involves the creation of script files and turning the script files into executable .COM files using the built-in Debug program. Script files are nothing more than text files containing lines of computer code. You use the built-in Memo program to create the script file (or any word processor capable of saving a file in plain ASCII format).

The process of using Debug to assemble the script files into .COM programs is described in the sidebar on this page. As mentioned earlier, these programs, as well as the .BAT files described in this issue, are available on the Jan/Feb 96 issue of The Palmtop Paper On Disk, archived in ECHO.ZIP <See Shareware/Freeware index>

 Example 1: A simple "Yes/No" program

 CREATING A .COM PROGRAM

 One of the simplest but most important thing an interactive batch file must do is be able to ask a Yes, No question. Save the Debug script file shown below as YN.SCR and use Debug to turn YN.SCR into the executable program YN.COM as described in the sidebar.

N YN.COM ; Give output a file name
A 100 ; Begin assembling at offset 100hex
XOR AH,AH ; Set AH=0 (Use this rather than
 ; MOV AH,0 to avoid getting any
; 00 hex opcodes in .COM file.)
INT 16 ; Call interrupt 16h, with AH=0, to get
 ; a key and return the scancode and
; ASCII value in AX. We only need
; the high byte, so...
CMP AH,15 ; compare AH with 15 hex (Y)
 ; Ctrl-Y, Alt-Y, Shift-Y will also
 ; yield 15hex. So we don't have to
 ; check for uppercase, etc.
JZ 0110 ; If its a Y, jump to 110
CMP AH,31 ; else compare AH with 31 (N)
JZ 0110 ; If its an N jump to 110, else
JMP 0100 ; jump back to start and try again
 ; 0110 is on the next line
MOV AL,AH ; Copy AH to AL where it will
 ; become known as the errorlevel
MOV AH,4C ; Put 4c in AH
INT 21 ; Call DOS interrupt 21 to exit
 ; End at offset 0116 hex
RCX
16 ; i.e. 0116hex - 0100hex = 16hex
bytes
W ; Write 22 bytes to YN.COM
Q ; Quit

When assembled the YN.COM program will be 22 bytes long.

When YN.COM is run, it waits for the next single keystroke to be entered (Y or N, and no others) and stores the ASCII keycode value in the DOS errorlevel variable buffer. (This is simply a memory location reserved by DOS to store a certain type of information.) This makes it possible to set up a batch file that runs YN.COM, stores the ASCII keycode entered by a user, uses if statements to test for a specific errorlevel variable, and executes different commands based on the input.

The TESTYN.BAT batch file shown below shows how this .COM program works and lets you test the YN.COM program. See the sidebar on page 42 for instructions on creating batch files.

@echo off
:again
echo Do you want to quit? [y/n]
 YN
if errorlevel 49 goto again
if errorlevel 21 goto end
:end
echo Quitting the testyn program

But before running this batch file, please back up everything on your disk. If you're working on the HP 100/200LX, be sure to close all applications.

The batch file begins by turning ECHO off so commands in the batch file are not displayed on the screen as they are executed. Then it displays the question Do you want to quit? [y/n] and calls the YN.COM program. YN.COM stores the ASCII code for the next keystroke you type in, in the DOS errorlevel variable buffer (49 for N, 21 for Y). YN.COM is designed to only accept a Y or N. It will sit there doing nothing until you enter one of those two characters. Errorlevel is really a misnomer, since we're not expecting any errors. Well use the errorlevel memory buffer as a way to store the input from YN.COM and pass it on to TESTYN.BAT. In this case, the errorlevel number can only be 49 or 21 depending on whether you pressed the N or the Y key.

The batch file then tests the errorlevel values with a couple of if errorlevel statements. The first, if errorlevel 49 goto again checks to see if you answered N for no. If you did, the if command sends the batch file back to :again (line 2) and you start over again with the Do you want to quit? message. If you enter Y for yes, you skip by the first if errorlevel line and if errorlevel 21 goto end sends you to :end. From there, the message Quitting the testyn program is displayed and the batch file ends.

Since the if errorlevel statement checks for values that are greater than or equal to a given value, the TESTYN.BAT file is designed to test for the higher value before testing for the lower value.

EMBEDDING YN.COM BINARY CODE IN THE BATCH FILE

We are doing this so we can create a stand-alone batch file that doesn't depend on another program file to work. Once you're satisfied that YN.COM behaves properly, its time to embed its binary code in the TESTYN.BAT file. To do this, you'll need to use a text editor that displays binary data. Memo, on the HP Palmtops, does not display binary data, so you'll have to use a text editor like QEDIT <See Shareware/Freeware index>. The instructions below assume you are using QEDIT.

Load the TESTYN.BAT into QEDIT, go to the 4th line that contains YN and insert a blank line above and below it. On the line above YN, type echo (put a space after ECHO.) Use the editor's block read command to load the YN.COM file onto the same line as ECHO . Then go to the end of the line and append the characters > yn.com .

On the line below YN, add the characters del yn.com and save the file.

When you run the TESTYN .BAT program, the super ECHO statement you just created will use I/O redirection to recreate the YN.COM file. The YN command will run it and the next command will delete it.

Pat yourself on the back. You've just created a simple stand-alone interactive batch file that contains binary code. It creates its own executable .COM file, runs it, and then cleans up after itself by deleting it. Call it a stupid DOS trick, but it turns out to be very useful, as you'll see below.

Example 2: Create a simple menu system for your Palmtop

Here's a way to use the trick we just learned to create a simple batch file menu system. Key the following script file into a text editor and save it with the file name ETCESC.SCR (don't forget the blank line at the very end).

 N ETCesc.com
A 100
XOR AH,AH ; Use int 16h, function #0
; to get a keystroke.
INT 16
CMP AH,12 ; If this key is an E
JZ 11a ; then jump to exit
CMP AH,2E ; else if its a C
JZ 11a ; then jump to exit
CMP AH,14 ; else if its a T
JZ 11a ; then jump to exit
CMP AH,1 ; else if its an ESC
JZ 11a ; then jump to exit
JMP 0100 ; else jump to the start
;<011A> exit
MOV AL,AH ; put the ASCII code in AL
MOV AH,4C ; put 4c in AH
INT 21 ; return to DOS
;<0120> end
RCX
20 ; 0120h - 0100h = 20h bytes
w ; write the ETCesc.com file
q ; quit

Then use the command: debug < etcesc.scr to generate the ETCESC .COM program.

This executable .COM file accepts a keystroke for one of the characters: E, T, C or ESC, and then stores the ASCII value of that key in the errorlevel variable buffer.

The MENU.BAT file, shown below lets you check out the performance of ETCESC.COM, and begins to set up the menu system.

@echo off
echo Programming Options : [E]dit [C]ompile [T]est
echo [ESC]
ECTesc
if errorlevel 46 goto compile
if errorlevel 20 goto test
if errorlevel 18 goto edit
if errorlevel 1 goto quit
:compile
echo Pretending to run compiler
goto end
:test
echo Pretending to test the program
goto end
:edit echo Pretending to edit the file
goto end
:quit
echo Pretending to quit the batch file
:end

The first thing the batch file does is to turn ECHO off and display the message: Programming Options : [E]dit [C]ompile [T]est [ESC]. Depending on which key is pressed (E,T,C, or ESC), the batch file will display one of the following messages:

Pretending to run compiler

Pretending to test the program

Pretending to edit the file

Pretending to quit the batch file

We haven't yet set the batch file up to run any programs, so were just pretending at this point.

When you're convinced that the batch file and ETCESC.COM file are working properly, load the MENU.BAT file into QEDIT and insert the word echo (make sure its followed by a blank space) on a new line before line 3 (the one containing ETCesc). Append the ETCESC.COM file to that ECHO command as described in the previous example. Then add >etcesc .com to the end of the line. Put the command del etcesc.com on a blank line after ETCESC and save the batch file. MENU.BAT is now a stand-alone interactive file. Let's turn it into a real menuing system.

Example 3: "Stuffing" the keyboard

Suppose you wanted to set up the MENU.BAT file described above so that one of the programs in the menu was Borland's C Compiler (BCC). One of the simplest things to do would be to enter a command line in MENU.BAT containing the program name followed by the file you wanted to compile (for the C Compiler example you would replace echo Pretending to run compiler with bcc filename .cpp). Unfortunately, this would cause the batch file to remain in memory while the Borland C Compiler program is running. The batch program won't quit until it can jump to the end of its code.

The third script file, PUTCR .SCR, can be used to create the PUTCR.COM program. Key in the script file below and create PUTCR.COM using Debug as described earlier.

N PUTCR.COM ; Name the output file.
A 100
XOR BH,BH ; Put 0081 in BX. Use two
 ; instructions to avoid having
MOV BL,81 ; 00 in the binary code
MOV CL,[BX] ; Copy whatevers pointed to
 ; by BX into CL
MOV AL,0C ; Set AL = 0D hex. Use two
 ; instructions to avoid having
INC AL ; 0D hex in the binary code.
CMP CL,AL ; Compare CL and AL
JZ 0125 ; If CL=AL then jump to 0125
INC BX ; else add 1 to BX
MOV CL,[BX] ; and get the next character
 ; from the PSP
MOV AL,0C ; Look for 0D hex again.
INC AL
CMP CL,AL ; Find 0D hex, jump to 0125
JZ 0125 ; Otherwise use INT 16,
MOV AH,05 ; function #5 to stuff the
XOR AL,AL ; character into the keyboard
XOR CH,CH ; buffer.
INT 16
JMP 010E ; repeat the loop again
xor ax,ax
;<0125> exi t ; Just before quitting, stuff 0D
mov ah,05 ; hex into the keyboard buffer.
xor al,al
 xor ch,ch
 mov cl,0c ; Let C=0C hex and then add
 ; 1 to CL : all to avoid getting
inc cl ; 0D hex in the binary code.
int 16
XOR AL,AL
MOV AH,4C
INT 21
;<0137> END
RCX
37
 W
q

 This program takes the character or command string on the command line and stuffs it into the keyboard buffer along with the code for the ENTER (carriage return) key. If you use PUTCR .COM in a batch file, you can execute a DOS command after the batch file ends.

This strategy can help us launch a program from the menu system after the batch file has ended. Replace echo Pretending to run compiler with putcr bcc filename.cpp (instead of bcc filename.cpp). This stuffs bcc filename.cpp into the keyboard buffer, the batch file then jumps to the end of its code. As soon as the batch file ends, the characters in the keystroke buffer are executed. The batch file will be out of the way and won't take up any memory.

Traps and workarounds

"OFF-LIMIT CHARACTERS" Using the ECHO statement to create a .COM file has its limitations. It works fine as long as the string of binary code does not contain any of the characters:

Nul Ascii 00 hex

Tab Ascii 09 hex

NewLine Ascii 0A hex

Enter Ascii 0D hex

> Ascii 3C hex

< Ascii 3E hex

| Ascii 7C hex

The ECHO command will interpret these codes rather than display them.

For example, if ECHO encounters < , it will try to read from a file rather than display <. And when it fails, it will respond with File not found.

Likewise, the Nul byte (ASCII 0) will be interpreted as a space (ASCII 32) and the Tab character may be interpreted as 8 spaces, depending on how your editor deals with the Tab character.

One way to check for the presence of these off-limit characters in a .COM file is to load the COM file into Debug and use the U command to unassemble the program. The listing will look something like this.

xxxx:0100 30E4XORAH,AH
xxxx:0102 CD16INT16
xxxx:0104 80FC15CMPAH,15
xxxx:0107 7407JZ0110
xxxx:0109 80FC31CMPAH,31
xxxx:010C 7402JZ0110
xxxx:010E EBF0JMP0100
xxxx:0110 88E0MOVAL,AH
xxxx:0112 B44CMOVAH,4C
xxxx:0114 CD21INT21

The column to the left of the assembler instructions contains opcodes for the instructions. The opcodes will reveal if Debug generated any of the off-limit codes: 00, 09, 0A, 0D, 3C, 3E, or 7C. If you find any of these opcodes, you'll need to rewrite the instruction to eliminate them.

 For example, in the above listing, the first line could have been MOV AH,0. However that would have produced an opcode of 00. Using the equivalent instruction, XOR AH,AH, produces a different pair of opcodes. They have the same effect, namely setting the AH variable to zero.

 The PUTCR.SCR file shown on page 44 has some other work-arounds. This file uses three commands XOR CH,CH, MOV CL,0C, INC CL, to do the same thing as the single command MOV CX,000D. This bit twiddling is needed, if you want to use the binary code in the ECHO command. To put this another way: if you don't eliminate these opcodes from the final COM file, you risk hanging the computer or, getting error messages that say File not found, etc.

Example 4: A DOS READLN Command

One of the commands found in many programming languages, but missing from the DOS batch language, is READLN (read a line). This command reads input from the keyboard and appends a new line character at the end of the input. With a slight modification, READLN can read its input from a disk file rather than from the keyboard. For example, in the Pascal programming language, the command READLN (name) activates the keyboard and lets you type in a string of characters. When you press (ENTER), the string of characters is stored in a variable called name. The MS-DOS batch language doesn't have any such command.

 Most often, the COPY CON filename command is used as a work-around. The only problem I have with COPY CON is that I always forget to press (CTRL)-(Z) to end the input.

The script file shown immediately below will generate READLN .COM. This program adds READLN capability. Like the other script files in this package, READLN.SCR has been optimized to eliminate any off-limit opcodes.

N READLN.COM ; Name the output file
A 100 ; Begin assembling at offset 100 hex
MOV AL,80 ; Put 80 hex in AL
MOV SI,AX ; Put AX (0080h) in SI
LODSB ; Load a string (i.e. point at the output
ADD SI,AX ; file name.
MOV [SI],AH ; Put nul byte at end of filename
MOV AX,3B02 ; Put 3b02h in AX, and
INC AH ; increment 3b to avoid 3C as opcode
XOR CX,CX ; Set normal file attribute
XOR DH,DH ;
MOV DL,82 ; Point at start of the filename
INT 21 ; Create the file
MOV DI ,AX ; Save the file handle
MOV AX,203D ; Put 203Dh in AX. Incr AL so
INC AL ; to avoid an opcode of 3E
XOR BX,BX ; Point at location 82h in PSP
MOV BL,82 ;
 MOV [BX],AX ; Put > in the PSP
MOV BL,02 ; Set output to stderr
MOV CL,01 ; Write one character
MOV DL,82 ; from PSP location 82h
MOV AH,40 ;
INT 21 ;
MOV SI,DX ; Put 82h in SI
MOV BYTE PTR [SI],72 ; The max length of
 ; input is 114 bytes
MOV AX,4C4A ; Put 0C0A in AX
SUB AX,4040
INT 21 ; Clear buffer and do a buffered
read
INC SI ; Point to the number of characters
read
LODSB
AND AL,AL ; If AL is 0 then no characters
JZ 0168 ; Jump to exit routine
XOR CH,CH ;
MOV CL,AL ; Put string length in CX
INC CX ; to include an ending CR
ADD SI,CX
MOV BYTE PTR [SI],08
INC BYTE PTR [SI]
INC BYTE PTR [SI] ; Add 0Ah, a line feed
INC CX
MOV AH,40 ; Write to file function
MOV BX,DI ; Put file handle in BX
MOV DL,84 ;
INT 21 ; Write the string
DEC SI ; SI now points at terminating
CR,LF
MOV AH,40 ; Write to file handle
SUB BH,BH
MOV BL,01 ; Set file handle to stdout
XOR CH,CH
MOV CL,02 ; Number of bytes to write
MOV DX,SI ; String to output
INT 21 ; Write CR,LF
JMP 0118 ; Jump to top of input/output loop
MOV AH,4C ; Exit routine
XOR AL,AL
INT 21 ; DOS terminate program
;<016E> END ;
RCX
6e ; Write 110 bytes to READLN.COM
W
q ; Quit DEBUG

This version of READLN.COM is mostly the work of Dave Vickers, who wrote the file input/output parts of the code. It will work either at the DOS prompt or when run from FILER.

The TESTRDLN.BAT file shown below shows how to use the READLN.COM program.

@echo off
echo Enter commands. Use Enter alone to quit.
readln $.bat
call $
del $.bat

After shutting off ECHO, the batch file displays the following prompt: Enter commands. Use Enter alone to quit. Then the batch file calls the READLN program. The READLN command must contain the name of a batch file on its command line. Failure to name an output file will cause READLN to send its output to the COM port, or to some other place in your computer, and may lock up your system and require you to reboot your machine. When READLN runs, it puts a > prompt on the screen. From this prompt you may enter any DOS command, such as DIR /W, and press (ENTER). Another > prompt will appear. Key in pause and press (ENTER). At the next > prompt type CHKDSK c: and press (ENTER). Finally, at the > prompt, just press (ENTER) and the three commands will be executed via the CALL $ command. The $.BAT file will be deleted and the TESTRDLN .BAT file will end.

A second batch file, TESTSET.BAT, shows how you might use READLN .COM, along with the ECHONL.COM program, from a previous issue of The HP Palmtop Paper, to get a user's name and store it in a DOS environment variable for use by the TESTSET program.

@echo off
echo Enter your name and press Enter twice.
echonl set name=>$1.bat
readln $2.bat
copy $1.bat+$2.bat $.bat >nul
call $
del $*.*
echo Hello, %name%
set name=
pause

As before, you can use your text editor to embed the binary code for READLN.COM in an ECHO statement and redirect the output to a file, $READLN.COM. Use the command $READLN $.BAT and you can delete both the COM and BAT files with a single command, DEL $*.*.

Hope this gives you some food for thought. Until next time: Happy Programming!
 
 

Using Debug to create COM programs from .SCR files