 @echo off
:: Copyright 1998, Ted Davis - all rights reserved
:: Note: directory names must be fully qualified, must end with a backslash,
:: and must not be quoted.  The name of this file *must* be ENTER.BAT.
:: vector to start-up or later pass
 if not %pass%!==! goto %pass%
:: Initialize variables
:: PASS contains the label to which future invocations of this program
:: should jump to.  It is both at flag and a value.
 set pass=pass2
:: count is a bang counter variable - variables will be named for the various
:: states assumed by this variable - initialze it to two bangs (the first 
:: case is handled outside the loop that manages COUNT)
 set count=!!
:: FLAG will either be null or a " character, depending on whether or not
:: there are spaces in the given directory.  Initially, it is null.
 set flag=
:: pattern holds the original arguments - the directory spec being examined
 set pattern=
:: realdir is the name of the subdirectory currently being tested
 set realdir=
:: testdir is the name of the directory under test
 set testdir=
:: olddircmd holds any existing DIRCMD switches - we need a switchless DIR
:: so we have to clear any existing switches and put them back later
 set olddircmd=%dircmd%
:: Clear the existing switches, if any
 set dircmd=
:: A is a temporary variable used as a scratchpad.
 set a=
:: since NT has a different format for it's DATE error message, one bit of
:: code must be made variable depending on the OS in use.  OSTYPE is 
:: a flag that controls that.
 set ostype=DOS
 if %OS%!==Windows_NT! set ostype=NT
 set null=nul
 if %ostype%==NT set null=
:: build the pattern from the arguments - assume one space between arguments
:: also assume that patterns containing long directory names are quoted
:: a loop is used here to rebuild the given string that was parsed into
:: separate arguments
:: note that PATTERN is initially empty - the first pass through the loop
:: sets it to just the first argument

:: If the string contains spaces, we will need to add quotes around it to 
:: keep DIR from barfing.  We'll use the FLAG variable to control this
 :loop0
 set pattern=%pattern%%1
:: test whether there is another argument pending - exit the loop if not
 if %2!==! goto cont0
:: if there is at least one more argument, a space must be added to PATTERN
:: note that the following line ends with a space
 set pattern=%pattern% 
:: realign the arguments so that the next argument becomes %1
 shift
:: Since this code doesn't execute unless there is a space in the given
:: directory, this is a good place to set FLAG to "
 set flag="
:: reenter the loop so that the next argument can be appended
 goto loop0
 :cont0
:: This is the first point when we can make a sanity check on the given
:: string - it must exist and be in proper form.  Note that a trailing
:: backslash must alread exist.
 if not exist %flag%%pattern%%null%%flag% goto error
:: Later, we will need a copy of the pattern in a file, so we
:: can perform a sort of backwards FIND on it - this is a good place to
:: create the file
 echo %pattern%> }1{.dat
:: now we must extract the first element in the directory specificfication
:: the first element is the drive letter, ;, and \ and must be handled
:: separately because it is not included in any directory listing

:: the drive letter can be obtained from the "Volume in drive ..." line
:: of a directory listing of the pattern assume that there are fewer
:: subdirectories than files and DIR just the directories - pipe the
:: result through FIND to isolate the "Volume in drive ..." line
:: put the isolated line into a transient batch file
 dir %flag%%pattern%*.*%flag% /a:d | find "Volume in drive" > }2{.bat
:: create another transient batch file that has a name matching the first
:: field in the string just placed in }2{.bat: "volume"
:: this batch file will set the first element to the drive letter
 echo set !=%%3> volume.bat
:: By CALLing the first transient batch file, we have it jump to the
:: second, then the second will honor the pending return from the CALL
 call }2{
:: at this point, the variable named ! contains the drive letter - we get
:: to add the :\ ourselves. We also need to initialize the working 
:: strings to the first element.
 set !=%!%:\
::  set workingpattern=%!%:
 set realdir=%!%
:: Now ! contains the first element in the directory spec to be parsed and
:: we can deal with the others with nested loops.
:: The outer loop executes once for each level of subdirectories under the
:: root; the inner loop executes once for each subdirectory in the current
:: level above and including the one we need (in the DIR listing) at 
:: each level - this is where things get "interesting", and very difficult
:: to write and debug, and to understand.  The idea is to begin with the
:: root and recursively explore the branch, looking for directories at each
:: level that are part of the string we are trying to analyse.  We build 
:: strings from what we already have and the pieces at each level, and 
:: discard all the strings that aren't part of the one we want to match.
:: since the first element is unique (it contains s ':'), the matches are 
:: necessarily for the leading part of the pattern.
:: This batch file is going to be invoking itself a number of times to use
:: the code in the inner loop - the entry point is the pass2 label.  We
:: do this by setting the PASS variable to that label so that the second line
:: of the program will vector there.
 :outerloop
:: DIR foo /a:d /b returns a list of just the names - long names in Win95 
:: and NT4, short (only) names in real MSDOS - of the directories in foo.
:: We need to add a backslash to the working pattern.
 dir %flag%%realdir%*.*%flag% /a:d /b > }3{.dat
:: We will use error responses from DATE to prefix each of the enteries
:: with - guess what - the name of this program: "Enter" (there is some other
:: stuff added as well, but we can ignore it).  This does have the restriction
:: that none of the directories can be have names that are valid dates.  It also
:: restricts the length of the individual directory names to somewhat less than 
:: the maximum length of a command line, but this should not be a problem in
:: practice.  The lines we want begin "Enter ...".
:: However, we also have to give DATE something it likes in order to terminate
:: it - a blank line will do.
 echo.>> }3{.dat
 date < }3{.dat | find "En" > }4{.dat
:: }4{.DAT now contains the list of directories in the current directory
:: currently specified in the WORKINGPATTERN variable, and one line with
:: no directory name.  Now we have to get this back into this batch file,
:: which we do by feedind it into an executable program that executes its
:: input: COMMAND.COM - to make sure it has enough environment space for 
:: the code to work, we specify an arbitrary environment size that is 
:: large enough in most cases: 1Kb.  The output of COMMAND is redirected
:: to the null device to suppress the screen display.
:: There is one more thing - vitally important - that we must do: we must
:: provide a way to return from the secondary command processor.  We do that
:: by appending an EXIT command to its input file.
 echo exit>> }4{.dat
 command /e:1024 < }4{.dat >> nul
:: The inner loop wrote a batch file to set the environment variables that
:: are needed for the next pass - we need to CALL it
 call }5{.bat
:: now we need to make a case insensitive comparison between the pattern
:: and the string so far.  This is somewhere on the impossible side of very
:: difficult, so we will take advantage of the fact that we know that the
:: string is in the pattern and will now see if the pattern is in the string -
:: if it is, then the strings are identical except for case
 echo %realdir%> }6{.dat
 find /i "%pattern%" }6{.dat > nul
:: If the strings are a case insensitive match, then we are done and can
:: display the results - otherwise we need to loop again.
 if not errorlevel 1 goto display
:: Increment the bang counter.
if %count%==!!!!!!!! goto end
 set count=%count%!
 goto outerloop
 :pass2
:: In order to skip the line without a directory at the end of the file, 
:: we test for it here and abort if it's found - the directory name starts
:: with the fourth (fifth in NT) argument. 
 if %ostype%==NT goto nt1
 if %4!==! goto end
 goto cont11
 :nt1
 if %5!==! goto end
 :cont11
:: Note that since we are in a secondary command processor, what we do to 
:: existing variables will not be seen by the previous command processor, 
:: and therefore not by the outer loop or the rest of the base level program. 
:: Except for some oddities with Win95, that is. To be on the safe side, we 
:: will use temporary variables.
 set a=%realdir%
:: Since we want no caryover with TESTDIR, we null it here.
 set testdir=
 :innerloop
 if %ostype%==DOS set a=%a%%4
 if %ostype%==NT set a=%a%%5
 if %ostype%==DOS set testdir=%testdir%%4
 if %ostype%==NT set testdir=%testdir%%5
:: Realign the arguments down one place.
 shift
:: If the argument is null, the directory name has no more pieces.
 if %ostype%==NT goto nt2
 if %4!==! goto cont1
 goto cont12
 :nt2
 if %5!==! goto cont1
 :cont12
:: Note the trailing spaces on the next three SET lines
 set a=%a% 
 set testdir=%testdir% 
 goto innerloop
 :cont1
:: Test the composite of the known elements and the current one - if there is no
:: match, terminate this pass.
:: Here we get a bit fancy - we need to FIND the working pattern in the master
:: pattern, which is why we put a copy of it in a file.  The output is 
:: suppressed by redirection to the null device - we need just the ERRORLEVEL.
:: Use a case insensitive search.  We must also add a backslash
:: to prevent problems where one directory name is a part of what we are
:: looking for.
 set a=%a%\
 find /i "%a%" }1{.dat > nul
:: If ERRORLEVEL is 0, the working pattern is a substring of the master pattern
:: otherwise it isn't and we can terminate this pass.
 if errorlevel 1 goto end
:: At this point, REALDIR and WOORKING PATTERN contain copies of the string as
:: validated so far, and TESTDIR contains the name of the current element.  We
:: need to put copies of both back into the parent environment, which requires
:: using a transient file that can reveive the current values from this 
:: environment and later, in the parent command processor, set them to those
:: values.
 echo set %count%=%testdir%> }5{.bat
 echo set realdir=%a%>> }5{.bat
:: echo set workingpattern=%b%>> }5{.bat
 goto end
 :display
 :cleanup
:: Restore any DIRCMD switches the user may have set
 set dircmd=%olddircmd%
:: Clear the variables we used, including the ones created dynamically.
:: It is convenient to merge the display and part of the cleanup code here.
 set maxcount=%count%
 set count=!
 echo The elements in %pattern% are
 :cleancountloop
 set %count%=
 if %count%==%maxcount% goto cleancont
 set count=%count%!
 echo echo %%%count%%%>}5{.bat
 call }5{
 set %count%=
 goto cleancountloop
 :cleancont
 set pass=
 set ostype=
 set count=
 set maxcount=
 set pattern=
 set realdir=
 set testdir=
 set a=
 set flag=
 set olddircmd=
 del }1{.dat
 del }2{.bat
 del }3{.dat
 del }4{.dat
 del }5{.bat
 del }6{.dat
 goto end
 :error
 echo.
 echo.
 echo ERROR Report: %pattern% 
 echo does not exist, lacks a trailing '\' or has some other error.
 :end