@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