[comp.sys.ibm.pc] Interactive BAT files: here's how

birdsall@manana.dec.com (10/04/88)

> Subject: Interactive BAT files: HOW?
> Posted: 29 Sep 88 00:19:14 GMT
> Organization: Evans & Sutherland, Salt Lake City, Utah
 
> I would like to alter my AUTOEXEC.BAT file (or another BAT file)
> to accept interactive input.  I want it to ask me a question
> (such as who I am), and based on the answer, perform a system setup.
> Alas, I cannot find anything in my eMeSS-DOS (3.3) manual or elsewhere
> that tells me how to do this.  Is it possible?  If so, how, and which
> book(s) describe it?
 
Is it "possible"? Why of course! All things are possible under MS-DOS ... 
but it can be painful ...

Try this:

First write a C program that asks you questions and returns some value based on 
your answer.

	if (strcmp (Input_Buffer, "one") == 0)
	    return (1);

Now write a BAT file. Include your C program at the top. It will return its
value in ERRORLEVEL. Then write some BAT statements that branch on ERRORLEVEL
(consult your DOS reference manual ). The syntax is a bit obscure but this is
how you branch on a specific errorlevel using a BAT file IF statement: 

	if errorlevel 1 if not errorlevel 2 goto one:
	if errorlevel 2 if not errorlevel 3 goto two:
	goto exit:
	:one
		one statements 
		...
		goto exit
	:two
		two statements
		...
		goto exit
	:and_so_on 
		...
	:exit

Here is a sample C and sample BAT file. Cut, compile, link, and then modify to
suit your application.

=============ASK.C  (cut here) ===========
/*
 * compile and link as ASK.EXE (done under MSC 5.0)
 */
   #include <conio.h>
   char buffer[20];

   main()
   {
   int status;

   cprintf("Please enter user name: "); /* get a name from the user           */
   scanf("%19s", buffer);
   status = 0;                          /* reset status to 0                  */

   if (strcmp (buffer, "tom") == 0)     /* is it tom?                         */
     status = 1;                        /* yes. return a 1                    */

   if (strcmp (buffer, "dick") == 0)    /* is it dick?                        */
     status = 2;                        /* yes. return a 2                    */

   if (strcmp (buffer, "harry") == 0)   /* is it harry?                       */
     status = 3;                        /* yes. return a 3                    */

     return(status);

   }
==================================

Now load and run the following BAT file:

================== INQUIRE.BAT  (cut here) ===================
echo off
ask
if errorlevel 0 if not errorlevel 1 goto zilch:
if errorlevel 1 if not errorlevel 2 goto tom:
if errorlevel 2 if not errorlevel 3 goto dick:
if errorlevel 3 if not errorlevel 4 goto harry:
:tom
echo Matched on tom
goto exit
:dick
echo Matched on dick
goto exit
:harry
echo Matched on harry
goto exit
:zilch
echo No Name Was Matched
:exit

====================================================

Have fun!

walt

hollen@spot.megatek.uucp (Dion Hollenbeck) (10/05/88)

From article <8810040015.AA21729@decwrl.dec.com>, by birdsall@manana.dec.com:
>> Subject: Interactive BAT files: HOW?
>> Posted: 29 Sep 88 00:19:14 GMT
>> Organization: Evans & Sutherland, Salt Lake City, Utah
>  
>> I would like to alter my AUTOEXEC.BAT file (or another BAT file)
>> to accept interactive input.  [...stuff deleted...]
>  
> Is it "possible"? Why of course! All things are possible under MS-DOS ... 
> but it can be painful ...
> 
> Try this:
>   [...stuff deleted...]
> (consult your DOS reference manual ). The syntax is a bit obscure but this is
> how you branch on a specific errorlevel using a BAT file IF statement: 
> 
> 	if errorlevel 1 if not errorlevel 2 goto one:
> 	if errorlevel 2 if not errorlevel 3 goto two:
> 	goto exit:
> 	:one
> 		one statements 
> 		...
> 		goto exit
> 	:two

Walt has got approximately the right idea here and everything else he
says about he C programs is accurate.  

CAUTION!!
	If the above return values are tested in ascending order, when
the (implied) test "if errorlevel >= 1"  is made, it will be true,
even if the program returned 2 or 3 as the errorlevel.

FIX!!!
	Make sure all errorlevel numeric  tests test descendingly:

 	if errorlevel 2 if not errorlevel 3 goto two:
 	if errorlevel 1 if not errorlevel 2 goto one:

By the time you get to testing for 1, you have eliminated all values
above 1 and the true branch will indeed be true.



	Dion Hollenbeck             (619) 455-5590 x2814
	Megatek Corporation, 9645 Scranton Road, San Diego, CA  92121

                                seismo!s3sun!megatek!hollen
                                ames!scubed/

dave@westmark.UUCP (Dave Levenson) (10/10/88)

In article <1317@micomvax.UUCP>, ray@micomvax.UUCP (Ray Dunn) writes:
...
> In MS C, setting environment variables is easy.  You use the putenv library
> call,  putenv("arg1=fred");, sets arg1 to "fred", whether arg1 existed
> before or not.

Setting the program's own environment variables is, in deed, easy. 
But the putenv() function only modifies its caller's own
environment.  What the original article requires is that the C
program modify the environment of its parent process.  Putenv() does
not do this.  No documented MS-DOS function does this.

-- 
Dave Levenson
Westmark, Inc.		The Man in the Mooney
Warren, NJ USA
{rutgers | att}!westmark!dave

dmurdoch@watdcsu.waterloo.edu ( D. Murdoch - Statistics ) (10/11/88)

In article <1317@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes:

[ a lot of completely correct information, then...]

>... it is easy
>to write a general purpose C program which will return the user input
>through standard environment variables (e.g. arg1, arg2, arg3....).  This
>can then be used in all .bat files that require the facility, and the tests
>can be like:
>
>if %arg1%==reply goto label
>
>In MS C, setting environment variables is easy.  You use the putenv library
>call,  putenv("arg1=fred");, sets arg1 to "fred", whether arg1 existed
>before or not.

Doesn't putenv only affect the environment of the C program (and its children)?
The parent environment remains unchanged.  To change it, you need one of
those routines that uses undocumented (i.e. unreliable) methods to find the
parent environment, and patches the changes in there.  

Duncan Murdoch

ltf@killer.DALLAS.TX.US (Lance Franklin) (10/13/88)

In article <5137@watdcsu.waterloo.edu> dmurdoch@watdcsu.waterloo.edu ( D. Murdoch - Statistics ) writes:
>In article <1317@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes:
>>In MS C, setting environment variables is easy.  You use the putenv library
>>call,  putenv("arg1=fred");, sets arg1 to "fred", whether arg1 existed
>>before or not.
>Doesn't putenv only affect the environment of the C program (and its children)?
>The parent environment remains unchanged.  To change it, you need one of
>those routines that uses undocumented (i.e. unreliable) methods to find the
>parent environment, and patches the changes in there.  

This is true...putenv only changes YOUR program's copy of the environment (and
any child process's copy).  However, it is possible to change the parent's
copy, with a little work, at least under 3.xx.  It involves...

    a) getting your process's psp address (available via the _psp external
       variable)...actually, this is an unsigned int that contains the
       segment that contains the psp.

    b) get the word at offset 16h in this segment...this is the segment that
       contains the parent process's psp.

    c) now get the word at offset 2ch of the parent's psp...this is a pointer
       to the parent's environment, or at least it is under 3.30.  Under 3.10,
       if the parent is the copy of COMMAND.COM that was started up on bootup,
       this value, I have found, is always zero (but not under subsequent
       copies of COMMAND.COM, and not under 3.30...don't ask me why).  In this
       case, the environment area seems to be at a constant offset of 0c1h
       paragraphs from the start of COMMAND.COM's psp.  (1 paragraph = 16 bytes)
       Of course, I can't guarentee this...it works on my copy of 3.10 though.
       3.30 seems to be much more logically constructed in this area.  By the
       way, if there are more than one layer of process between your program
       and COMMAND.COM, you can repeat the process from (b) to (c) to follow
       the chain down...when you get to the closest COMMAND.COM, you'll find
       that the pointer to the parent's psp points to itself...don't bother
       to go further. :-)

    d) now that you have the address of the parent's environment, make a copy
       of it locally, do what you have to, and prepare to write it back to the
       original address...but first, make sure that you have enough space.  The
       length of the environment's buffer is 1 paragraph before the start of
       the environment area + 3 bytes, and is a single byte indicating the 
       number of paragraphs available for the environment.  Don't try to write
       more than that number of paragraphs!  You won't like the results!
       Incidently, this was the hardest bit of information for me to find...
       NOBODY documents this little bit of information, I had to bring up
       COMMAND.COM under codeview and trace thru a set command to find out
       what the length is.  Oh, and by the way, 3.10 has another problem, I've
       found...no matter WHAT you do, you cannot get any more environment 
       space for new invocations of COMMAND.COM than the amount of space that
       the current enviroment variables take (rounded to the next paragraph)
       plus 1 paragraph.  Apparently, only the bootup copy of COMMAND.COM
       accepts the /E:xx parameter.  If anybody knows a way to get around 
       this, PLEASE let me know...right now, I do a set PAD=<lots of chars>
       in AUTOEXEC.BAT, so I can free up some space when I need it...not the
       best solution.

Please remember that most of this information was gleaned from trial and error,
and I won't guarentee that it'll work for everybody...it works on my copies of
PC-DOS 3.10 and 3.30, has not been tested on 2.xx or 3.20 or 4.xx or under the
MicroSoft versions...only PC-DOS.  If anybody knows any cases where it will
NOT work, or whether 3.20 works more like 3.10 or 3.30, please let me know...
I've worked out several routines that makes working with batch files much more
acceptable, and I'd like to try and make them work on all versions...right now,
I'll only guarentee PC-DOS 3.10 and 3.30.  If there's any interest, I'll post
the routines, and the common code that reads, modifies and writes a parent's
environment.
 
Lance
 

-- 
+-------------------------+ +-----------------------------------------------+
| Lance T Franklin        | | I never said that! It must be some kind of a  |
| ltf@killer.DALLAS.TX.US | | forgery...I gotta change that password again. |
+-------------------------+ +-----------------------------------------------+

craig@trsvax.UUCP (10/15/88)

->/*Written7:15 pm Oct 3,1988 by manana.dec.com!birdsall in comp.sys.ibm.pc */
->/* ---------- "Interactive BAT files: here's how" ---------- */
->> Subject: Interactive BAT files: HOW?
->> Posted: 29 Sep 88 00:19:14 GMT
->> Organization: Evans & Sutherland, Salt Lake City, Utah
-> 
->> I would like to alter my AUTOEXEC.BAT file (or another BAT file)
->> to accept interactive input.  I want it to ask me a question
->> (such as who I am), and based on the answer, perform a system setup.
->> Alas, I cannot find anything in my eMeSS-DOS (3.3) manual or elsewhere
->> that tells me how to do this.  Is it possible?  If so, how, and which
->> book(s) describe it?
-> 
->Is it "possible"? Why of course! All things are possible under MS-DOS ... 
->but it can be painful ...
->
->Try this:
->
->First write a C program that asks you questions and returns some value based on 
->your answer.
->
	[Other good stuff deleted]
->
->====================================================
->
->Have fun!
->
->walt
->/* End of text from comp.sys.ibm.pc */

You're posting has some good information for a novice user, but you're
making this process too difficult.  It can all be done with batch files and
subdirectories.  Try this:
	Create a subdirectory called `\STARTUP'
	Put the following lines in your AUTOEXEC.BAT file:
		ECHO OFF
		CLS
		CD \STARTUP
		PROMPT=     Enter Choice (1 or 2):
		ECHO.
		ECHO.
		ECHO	1)  TOM
		ECHO	2)  FRED
		ECHO.
	In the '\STARTUP' subdirectory, create a 1.BAT and a 2.BAT file
	   with the appropriate commands depending on the user's choice.
	   The first few lines in both files should be something like:
		ECHO OFF
		CLS
		PROMPT=$P$G
		CD \

Advantages: doesn't require purchasing a programming language;  easier to
	    implement and understand
Disadvantages: leaves extra files laying around on your disk; not as pretty
-----------------------------------------------------------------------
If you don't care where you are         |	Craig Fleece
then you aren't lost.			|	craig@trsvax
                                        |	ninja!sys1!trsvax!craig
<This information is provided by an individual and is not nor should be
 construed as being provided by my employer.  My employer has no obligation
 to support the information provided in  any way. > 

ray@micomvax.UUCP (Ray Dunn) (10/26/88)

I recently gave myself a red face by pontificating on how you should use
putenv to set interactively given values to environment variables from
inside a 'C' program.  It was correctly pointed out that this only affects a
*copy* of the variables.

I promised a solution, so... after putting up real money within my group as
a challenge, Eric Anderson (anderson@micomvax) who otherwise is usually very
usefully employed, came up with the following solution (:-).

He is the proud winner of exactly $2.10 (dont ask).

The batch file (any suitable name):

    if "%1"=="runbatch" goto runbatch
    getinput
    setinput %0
    rem   The name of this file (%0) is passed to setinp so can be re-executed
    rem   Control does not return here from the batchfile setinput
    :runbatch
    rem   Here you put the "real" commands you want the batch file to run
    rem   including the use of the environment variables defined in the
    rem   getinput/setinput mechanism


The 'C' program, getinp.exe, interacts with the user and generates the file
setinput.bat, which should be in the form:

    set var1=required value
    set var2=required value
    etc
    %1 runbatch

The set statements should reflect the user's responses as required.  The
last line calls the first batch file again, with parameter runbatch.

The code of getinp is very application specific, is simple, and is left as
an exercise for the reader.

The mechanism should be self-evident, and has the effect of running the batch
commands at the :runbatch label after the environment variables are
interactively defined.

With this basic mechanism understood, many variations and expansions can be
envisaged, one of which could be passing a question-string and a response
environment variable name to getinput etc.  Excrutiating contortions
involving multiple calls of getinput with different "runbatch" labels are
possible!

All donations to reimburse the $2.10 gladly accepted!

The mechanism shall be known as the Anderson Kludge.

Now the only question is, does Eric deserve promotion or should he be
condemned to eternally generating increasingly more and more obscure MS-DOS
batch files!!!

-- 
Ray Dunn.                      |   UUCP: ..!philabs!micomvax!ray
Philips Electronics Ltd.       |   TEL : (514) 744-8200   Ext: 2347
600 Dr Frederik Philips Blvd   |   FAX : (514) 744-6455
St Laurent. Quebec.  H4M 2S9   |   TLX : 05-824090