[net.micro.pc] where are you after a batch file

johnhi@tekig5.UUCP (John Higley) (01/25/86)

Where are you after a batch file completes?  Wherever it chooses to leave
you.  Where do you want to be?  Back where you started.  How can you get
there automatically?

I have just written a c program that reads the current working directory and
outputs it.  This output is just right for a batch file to return you to
where you want to be.  If any one is interested, send me e-mail.

John Higley
...tektronix!tekig5!johnhi

keifer@uiucdcs.CS.UIUC.EDU (01/28/86)

You can get the current directory by using the CD (CHDIR) command
without any arguments.   You get something like

C:\TEMP

or whatever.

hes@ecsvax.UUCP (01/28/86)

> Where are you after a batch file completes?  Wherever it chooses to leave
> you.  Where do you want to be?  Back where you started.  How can you get
> there automatically?
> ... 
   In pc-dos 2.1 - if you do a cd in the  .bat file you are left in that
directory, otherwise you stay in the same directory.  (Am I missing something?)

> John Higley
> ...tektronix!tekig5!johnhi

--henry schaffer

connery@bnrmtv.UUCP (Glenn Connery) (01/28/86)

> Where are you after a batch file completes?  Wherever it chooses to leave
> you.  Where do you want to be?  Back where you started.  How can you get
> there automatically?
> 
> I have just written a c program that reads the current working directory and
> outputs it.  This output is just right for a batch file to return you to
> where you want to be.  If any one is interested, send me e-mail.
> 
> John Higley
> ...tektronix!tekig5!johnhi

But just doing "CD >somefile" gets you that.  What you really want is
programs that PUSH and POP the current directory, so that they can handle
nested calls (I use them both in CED synonyms and in batch files).

Glenn

ray@othervax.UUCP (Raymond D. Dunn) (01/30/86)

For those people who made trite comments about the batch file directory
posting, please think a little before hitting 'f'.  If you have to say
"am I missing something", then yes, you probably are.

The problem being solved by the referenced program is how to return to
the directory current at the start of a batch file which does directory
changes, i.e some sort of pushd and popd.

If anyone thinks this can be done with normal commands without it taking
forever, I for one would be very interested in the solution!

This is a common problem in Dos, particularly when calling (sick)programs
in a batch file which do not understand paths, you have to cd to the
directory of the required file, call the program which uses that file, and
then ... what?  The batch file does not know what its initial current
directory was.

The only solution I know using Dos commands and which I regard as an
unacceptable cludge, is to have a file say xx in a known place which
contains only the characters c, d, and space (no terminating return).

The batch file should now look like:

   copy \dd\xx \pp\popd.bat [ copy the "cd " into file popd.bat, where
                              pp is a directory in your PATH (2.1), or
                              use \pp\popd in the call below (3.1).
                              echo  cd  > popd.bat  can not be used
                              because echo always outputs a terminating
                              return ]
   cd >> \pp\popd.bat       [ append the current directory path to the
                              "cd " ]
   .
   .                        [ the required batch file commands which
   .                          include one or more cd's ]
   .
   popd                     [ which executes the cd to the initial directory.
                              note that if commands are require to follow
                              this in the batch file, it should be:
                              command /c popd ]

As an aside, this is another example of the stupid non-consistency of Dos.
The PATH command with no arguments displays(writes) the line PATH=....., 
however cd with no arguments just displays the directory path with no
initial "cd ".

Ray Dunn  ..philabs!micomvax!othervax!ray

glen@intelca.UUCP (Glen Shires) (01/30/86)

> > Where are you after a batch file completes?  Wherever it chooses to leave
> > you.  Where do you want to be?  Back where you started.  How can you get
> > there automatically?
> > ... 
>    In pc-dos 2.1 - if you do a cd in the  .bat file you are left in that
> directory, otherwise you stay in the same directory.  (Am I missing something?)
> 
> > John Higley
> > ...tektronix!tekig5!johnhi
> 
> --henry schaffer
Often you can get around this by specifying a programs full path name like:
c:\yourdir\yourfile

Also, you can use the DOS "PATH=c:\;c:\yourdir" command

But not always...

For those programs that must run with the current directory elsewhere
here's a hack around your problem:

create a dummy skeleton file in root CDMSG.BAT containing only
   "CD "
 (CD<space>)    NO CARRIAGE RETURN

then put in your batch file:

copy c:\cdmsg.bat c:\zap.bat          copy "CD " shell into zap.bat
cd >>c:\zap.bat                       add current directory "CD C:\NOW\HERE"
cd where\ever\you\want\to\go          now change directories freely
yourprog                              and execute your programs
c:\zap.bat                            now go back to original directory
del c:\zap.bat                        and delete temp file

NOTE: you do not have to place CDMSG.BAT and ZAP.BAT in your root directory,
but you must always place it in the same directory and specify a full
path name

-- 
^ ^    Glen Shires, Intel, Santa Clara, Ca.
O O     Usenet: {ucbvax!amd,pur-ee,hplabs}!intelca!glen
 >      ARPA:   "amd!intelca!glen"@BERKELEY
\-/    --- stay mellow

g-tsang@gumby.UUCP (Michael H. Tsang) (02/03/86)

     In responding to the question of "where are you after a batch file?", I
have written the following programs in Turbo Pascal.  They are "pushd.pas" and 
"popd.pas".  These programs simulate the corresponding pushd and popd commands
in UNIX.  It requires you to set up a file named "dirstack" in the directory
"c:\tmp", but it can be changed by changing the constant StackFileName.

     I would like to see somebody rewriting these programs in assembly in order
to reduce the program size (about 11K for each .COM file now).  A sample batch
file showing how to use these programs are given below: (suppose your applica-
tion program is c:\tools\wordstar\ws.com)

File: ws.bat

echo off
pushd c:\tools\wordstar
ws
popd
echo on

------------------------------CUT HERE-------------------------

{$G512,P512}
program Pushd(input, output);

const
  ProgramName = 'pushd';
  Version = '[v1.01 (c) 2.2.86]';
  StackFileName = 'c:\tmp\dirstack';
type
  Str255 = string[255];
  StackPtr = ^StackRec;
  StackRec =
    record
      Path: Str255;
      Next: StackPtr
    end;
var
  StackFile: text;
  StkTop, StkBot: StackPtr;
  Depth: integer;
  Dirty: boolean;

  procedure BuildStack;
  begin
    new(StkTop);
    StkBot := StkTop;
    GetDir(0, StkTop^.Path);
    Depth := 0;
    assign(StackFile, StackFileName);
    reset(StackFile);
    while not eof(StackFile) do begin
      new(StkBot^.Next);
      StkBot := StkBot^.Next;
      readln(StackFile, StkBot^.Path);
      Depth := Depth + 1
    end;
    StkBot^.Next := nil;
    close(StackFile)
  end; { BuildStack }

  procedure SwapStackTop;
  var
    NewTop: StackPtr;
  begin
    BuildStack;
    if Depth < 1 then
      writeln(ProgramName, ': No other directory')
    else begin
      NewTop := StkTop^.Next;
      StkTop^.Next := NewTop^.Next;
      NewTop^.Next := StkTop;
      StkTop := NewTop;
      Dirty := true
    end
  end; { SwapStackTop }

  procedure RotateStack(NumStr: Str255);
  var
    Cnt, Num, Result: integer;
  begin
    Val(Copy(NumStr, 2, Length(NumStr)-1), Num, Result);
    if (Result <> 0) or (Num <= 0) then
      writeln(ProgramName, ': ', NumStr, ': No such file or directory')
    else begin
      BuildStack;
      if Num > Depth then
        writeln(ProgramName, ': Directory stack not that deep')
      else begin
        StkBot^.Next := StkTop;
        for Cnt := 1 to Num do begin
          StkTop := StkTop^.Next;
          StkBot := StkBot^.Next
        end;
        StkBot^.Next := nil;
        Dirty := true
      end
    end
  end; { RotateStack }

  procedure PushStack(ArgStr: Str255);
  var
    StkNode: StackPtr;
  begin
    BuildStack;
    new(StkNode);
    StkNode^.Path := ArgStr;
    StkNode^.Next := StkTop;
    StkTop := StkNode;
    Dirty := true
  end; { PushStack }

  procedure SaveStack;
  begin
    {$I-}
    ChDir(StkTop^.Path);
    {$I+}
    if IOResult <> 0 then
      writeln(ProgramName, ': ', StkTop^.Path, ': No such file or directory')
    else begin
      assign(StackFile, StackFileName);
      rewrite(StackFile);
      StkTop := StkTop^.Next;
      while StkTop <> nil do begin
        writeln(StackFile, StkTop^.Path);
        StkTop := StkTop^.Next
      end;
      close(StackFile)
    end
  end; { SaveStack }

var
  Argc: integer;
  ArgStr: Str255;
begin { Pushd }
  Argc := ParamCount;
  if Argc > 1 then
    writeln('Usage: ', ProgramName, ' [pathname | +n | -v]')
  else begin
    Dirty := false;
    if Argc = 0 then
      SwapStackTop
    else begin
      ArgStr := ParamStr(1);
      if ArgStr = '-v' then
        writeln(ProgramName, ': ', Version)
      else if ArgStr[1] = '+' then
        RotateStack(ArgStr)
      else
        PushStack(ArgStr)
    end;
    if Dirty then
      SaveStack
  end
end. { Pushd }

-------------------------CUT HERE--------------------------

{$G512,P512}
program Popd(input, output);

const
  ProgramName = 'popd';
  Version = '[v1.01 (c) 2.2.86]';
  StackFileName = 'c:\tmp\dirstack';
type
  Str255 = string[255];
  StackPtr = ^StackRec;
  StackRec =
    record
      Path: Str255;
      Next: StackPtr
    end;
var
  StackFile: text;
  StkTop, StkBot: StackPtr;
  Depth: integer;
  Dirty: boolean;

  procedure BuildStack;
  begin
    new(StkTop);
    StkBot := StkTop;
    GetDir(0, StkTop^.Path);
    Depth := 0;
    assign(StackFile, StackFileName);
    reset(StackFile);
    while not eof(StackFile) do begin
      new(StkBot^.Next);
      StkBot := StkBot^.Next;
      readln(StackFile, StkBot^.Path);
      Depth := Depth + 1
    end;
    StkBot^.Next := nil;
    close(StackFile)
  end; { BuildStack }

  procedure PopStack;
  var
    PathStr: Str255;
    StkNode: StackPtr;
  begin
    BuildStack;
    if Depth < 1 then
      writeln(ProgramName, ': Directory stack empty')
    else begin
      StkTop := StkTop^.Next;
      Dirty := true
    end
  end; { PopStack }

  procedure DeleteStack(NumStr: Str255);
  var
    TmpPtr: StackPtr;
    Cnt, Num, Result: integer;
  begin
    Val(Copy(NumStr, 2, Length(NumStr)-1), Num, Result);
    if (Result <> 0) or (Num <= 0) then
      writeln(ProgramName, ': ', NumStr, ': Bad directory')
    else begin
      BuildStack;
      if Num > Depth then
        writeln(ProgramName, ': Directory stack not that deep')
      else begin
        TmpPtr := StkTop;
        for Cnt := 1 to Num-1 do
          TmpPtr := TmpPtr^.Next;
        TmpPtr^.Next := TmpPtr^.Next^.Next;
        Dirty := true
      end
    end
  end; { DeleteStack }

  procedure SaveStack;
  begin
    {$I-}
    ChDir(StkTop^.Path);
    {$I+}
    if IOResult <> 0 then
      writeln(ProgramName, ': ', StkTop^.Path, ': Bad directory')
    else begin
      assign(StackFile, StackFileName);
      rewrite(StackFile);
      StkTop := StkTop^.Next;
      while StkTop <> nil do begin
        writeln(StackFile, StkTop^.Path);
        StkTop := StkTop^.Next
      end;
      close(StackFile)
    end
  end; { SaveStack }

var
  Argc: integer;
  ArgStr: Str255;
begin { Popd }
  Argc := ParamCount;
  if Argc > 1 then
    writeln('Usage: ', ProgramName, ' [+n | -v]')
  else begin
    Dirty := false;
    if Argc = 0 then
      PopStack
    else begin
      ArgStr := ParamStr(1);
      if ArgStr = '-v' then
        writeln(ProgramName, ': ', Version)
      else if ArgStr[1] = '+' then
        DeleteStack(ArgStr)
      else
        writeln(ProgramName, ': ', ArgStr, ': Bad directory')
    end;
    if Dirty then
      SaveStack
  end
end. { Popd }

--------------------------CUT HERE----------------------------

Have fun with these programs.

Mike Tsang

broehl@watdcsu.UUCP (Bernie Roehl) (02/05/86)

In article <51@gumby.UUCP> g-tsang@gumby.UUCP (Michael H. Tsang) writes:
>
>     In responding to the question of "where are you after a batch file?", I
>have written the following programs in Turbo Pascal.  They are "pushd.pas" and 
>"popd.pas".  These programs simulate the corresponding pushd and popd commands
>in UNIX.  It requires you to set up a file named "dirstack" in the directory
>"c:\tmp", but it can be changed by changing the constant StackFileName.

First, thanks to Michael Tsang for taking time to write and post these
programs.

Now, a suggestion: why doesn't somebody write a program that either (a) keeps
the directory stack in the environment, instead of having to have a writeable
file sitting around on disk and doing disk accesses for directory
pushing/popping?  Another approach would be a tiny program that gets the
current directory and then executes a fresh copy of command.com; when you
exit, the program would restore the current directory and then exit.  This
avoids scratch files and large environments, but takes up a few K of extra
ram for the fresh copy of the command interpreter.

Just some ideas...

connery@bnrmtv.UUCP (Glenn Connery) (02/09/86)

> ...
> 
> Now, a suggestion: why doesn't somebody write a program that either (a) keeps
> the directory stack in the environment, instead of having to have a writeable
> file sitting around on disk and doing disk accesses for directory
> pushing/popping?  Another approach would be a tiny program that gets the
> current directory and then executes a fresh copy of command.com; when you
> exit, the program would restore the current directory and then exit.  This
> avoids scratch files and large environments, but takes up a few K of extra
> ram for the fresh copy of the command interpreter.
> 
> Just some ideas...

The latter is what COMMAND /c should be doing anyway, but I really don't
want to waste the time or memory on this, as well as the fact that it would
mean multiple batch files where I only wanted one.  Also, there are problems
with doing certain things this way--you can't pass back errorlevel across
such things for example.

The former is a great idea, but I've never seen anybody propose a method
for handling this.  You have to remember that when a program is run by
DOS, it is given a COPY of the original environment.  You can write a
program to modify that environment (though it is still unclear how you
know how much space that environment has been allocated, as opposed to how
much it is using).  You could even use Microsoft C 3.0's builtin functions
for doing this.  But when your program exits the old environment will be
restored with none of your changes.

If you were willing to write a shell or something you could do this by
running the program as an overlay instead, but this seems like it would
be tricky, and wouldn't be portable across multiple versions of DOS.  As
well, if you were going to write a shell for this specific purpose, you
might as well just provide the capabilities that DOS left out directly
rather than doing it this way (variables, pushd/popd).

If anybody has any information on this subject I'd be real interested to
hear it.

...Glenn

hamilton@uiucuxc.CSO.UIUC.EDU (02/12/86)

>> Now, a suggestion: why doesn't somebody write a program that either (a) keeps
>> the directory stack in the environment, instead of having to have a writeable
>> file sitting around on disk and doing disk accesses for directory
>> pushing/popping?
>
>[this] is a great idea, but I've never seen anybody propose a method
>for handling this.  You have to remember that when a program is run by
>DOS, it is given a COPY of the original environment.  You can write a
>program to modify that environment (though it is still unclear how you
>know how much space that environment has been allocated, as opposed to how
>much it is using).  You could even use Microsoft C 3.0's builtin functions
>for doing this.  But when your program exits the old environment will be
>restored with none of your changes.

well, there is an ugly way to do this (modify command.com's copy of the
environment).  i did some exploring some time back, and figured how to
scan memory and recognize memory control blocks.  you can also find out
where command.com is (the para is all you want) from one of the several
pointers to it in your psp.  the first memory control block before the
one containing command.com (if i remember right) is the one containing
command.com's environment (i _said_ it was ugly).  the control block
tells you how much space is allocated to the environment, and you parse
to find how much was used.  i wrote a little program using a scan for
control blocks to produce a map of allocated memory; the result is
slightly useful as a substitute for a "ps".

	wayne hamilton
	U of Il and US Army Corps of Engineers CERL
UUCP:	{ihnp4,pur-ee,convex}!uiucdcs!uiucuxc!hamilton
ARPA:	hamilton%uiucuxc@a.cs.uiuc.edu	USMail:	Box 476, Urbana, IL 61801
CSNET:	hamilton%uiucuxc@uiuc.csnet	Phone:	(217)333-8703