campo-sirio/arch/wildcard.cpp

595 lines
21 KiB
C++
Executable File

//
// WILDCARD.CPP
//
// Source file for ArchiveLib 1.0
//
// Copyright (c) Greenleaf Software, Inc. 1994
// All Rights Reserved
//
// CONTENTS
//
// ALWildCardExpander::operator new()
// ALWildCardExpander::ALWildCardExpander()
// ALWildCardExpander::~ALWildCardExpander()
// ALWildCardExpander::GetNextWildName()
// ALWildCardExpander::GetNextFile()
//
// DESCRIPTION
//
// This file contains all the source code for the nifty class
// ALWildCardExpander. The wild card expansion code is a state
// drive routine, which keeps track of its entire state between
// calls. So you can call it once to get a new file name, then
// do some processing. When you call it again later, you will
// get the next file name in the sequence.
//
// There is a little difference between the NT version and the DOS
// version, because the function calls for get first/get next
// are different. A minor difference is created by the fact
// that under NT you can't specify attributes in a search, so when
// you want to look for subdirectories, you have to search all files
// and see if any of your matches turn out to be directories.
//
// The way the wild card class handles searching through subdirectories
// is by keeping a link pointer to a subdirectory search. When it
// is time to open up a subdirectory search, we create a new file
// expander, and assign its pointer to our link pointer. As long as
// the link is active, we keep searching there. When the link runs
// out of files to return, we continue searching in our own directory.
//
// A lot of this code is easier to deal with because we use the
// ALName class. That makes it easy to strip file names and
// paths apart, and even easier to put them back together again.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
//
#include "arclib.h"
#pragma hdrstop
#include <stdlib.h>
#ifdef __BORLANDC__
#include <dir.h>
#endif
#include "wildcard.h"
//
// void * ALWildCardExpander::operator new( size_t size )
//
// ARGUMENTS:
//
// size : The number of bytes needed to create a new ALWildCardExpander
// object.
//
// RETURNS
//
// A pointer to the newly allocated storage area, or 0 if no storage
// was available.
//
// DESCRIPTION
//
// When using a DLL, it is easy to get into a dangerous situation when
// creating objects whose ctor and dtor are both in the DLL. The problem
// arises because when you create an object using new, the memory for
// the object will be allocated from the EXE. However, when you destroy
// the object using delete, the memory is freed inside the DLL. Since
// the DLL doesn't really own that memory, bad things can happen.
//
// But, you say, won't the space just go back to the Windows heap regardless
// of who tries to free it? Maybe, but maybe not. If the DLL is using
// a subsegment allocation scheme, it might do some sort of local free
// before returning the space to the windows heap. That is the point where
// you could conceivably cook your heap.
//
// By providing our own version of operator new inside this class, we
// ensure that all memory allocation for the class will be done from
// inside the DLL, not the EXE calling the DLL.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
#if defined( AL_BUILDING_DLL )
void AL_DLL_FAR * AL_PROTO ALWildCardExpander::operator new( size_t size )
{
return ::new char[ size ];
}
#endif
//
// ALWildCardExpander::ALWildCardExpander( const char *file_list,
// int traverse_flag = 0,
// ALCase name_case = AL_LOWER )
//
// ARGUMENTS:
//
// file_list : A list of wild card file specifications, separated
// by commas, semicolons, or spaces, maybe looking
// something like this: "*.CPP, BOB.DAT, *.*"
//
// traverse_flag : A flag that indicates whether you want to traverse
// all subdirectories under the current path.
//
// name_case : An indicator of whether you want all the returned
// file names forced to a certain case.
//
// RETURNS
//
// No returns.
//
// DESCRIPTION
//
// The constructor for the expander has to set up a bunch of data members
// that will all be used during the expansion process. The mCase
// member is easy to understand. All of the objname objects that
// we create are going to be force to a certain case by this
// using this data member. miTraverseFlag is just our copy of the
// input parameter. And the mState variable keeps track of what we
// are doing in between function calls. We set it to GET_NEXT_WILD_NAME,
// which means we will be doing that the first time we get called.
//
// mInputLine is where we keep a copy of the list of wild card file
// specifications passed by the calling program. Each time we take
// a new file name out of mInputLine, we remove it from the ALName
// object, making mInputLine just a little shorter.
//
// The mResultFileName member is the storage area where we keep a copy
// of the file name created by the expander. This is our local copy,
// when it gets returned to the calling program they need to make
// their own copy of it and leave ours alone.
//
// Every time we get asked to get a new file, the very first thing
// we do is check to see if the mpNextExpander member is pointing
// to a new expander object. If it is, we ask him to provide
// the next file name, instead of giving it ourselves. When he
// doesn't have any file names left to give, we destroy him and
// set that pointer back to 0. Here in the constructor, the smart
// thing to do is set him to 0 for starters.
//
// The final data member differs between NT and DOS. The structure
// NT uses to expand directories is store in mFindFileHandle. The
// DOS version is stored in mpFfblk. Both of these are presently
// in an invalid state, but will get initialized when the user
// calls the member function.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
AL_PROTO ALWildCardExpander::ALWildCardExpander(
const char AL_DLL_FAR *file_list,
int traverse_flag /* = 0 */,
ALCase name_case /* = AL_LOWER */ )
: mCase( name_case ),
mResultFileName( "", name_case )
{
mInputLine = file_list;
mState = GET_NEXT_WILD_NAME;
mpNextExpander = 0;
miTraverseFlag = traverse_flag;
#if defined( AL_WIN32S )
mFindFileHandle = INVALID_HANDLE_VALUE;
#else
mpFfblk = new find_t;
#endif
}
//
// ALWildCardExpander::~ALWildCardExpander()
//
// ARGUMENTS:
//
// None, destructors don't get any.
//
// RETURNS
//
// None, destructor.
//
// DESCRIPTION
//
// There are a couple of big deals we need to worry about in the
// destructor an ALWildCardExpander. First, we have to worry about
// any additional handlers we created to search subdirectories. If
// this destructor is being called before our search is done, we
// may have some of those expander objects just hanging around out
// there. We take care of the by checking the mpNextExpander member.
// If it isn't set to 0, we delete the dynamically created expander.
//
// Under NT we also have to worry about our mpFindFileHandle. Under
// NT, the file expansion algorithm isn't just a get first/get next
// deal. Instead, it is get first/get next/terminate. The termination
// is done using the FindClose() call. If we still had a search in progress
// we call that function.
//
// Under DOS, we just have to delete the dynamically created
// mpFfblk structure. I wanted to make that a data member of this
// class, instead of a pointer, but one of our compilers wasn't happy
// about putting this C struct in a class, it complained about something.
// So, to expedite, we made it a pointer.
//
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
AL_PROTO ALWildCardExpander::~ALWildCardExpander()
{
if ( mpNextExpander )
delete mpNextExpander;
#if defined( AL_WIN32S )
if ( mFindFileHandle != INVALID_HANDLE_VALUE )
FindClose( mFindFileHandle );
#else
if ( mpFfblk )
delete mpFfblk;
#endif
}
// PROTECTED MEMBER FUNCTION
//
// int ALWildCardExpander::GetNextWildName()
//
// ARGUMENTS:
//
// None.
//
// RETURNS
//
// 1 if it got a new file spec, 0 if it didn't.
//
// DESCRIPTION
//
// This function is called internally to get the next file spec out of
// the input line. This is simply a matter of parsing past all the
// delimiter characters. The resulting file spec is stored in
// data member mFullWildName. That member will be the one used to
// kick off the next wild card search.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
int AL_PROTO ALWildCardExpander::GetNextWildName()
{
char wild_spec[ _MAX_PATH ];
int i = 0;
char *p = mInputLine;
for ( ; ; p++ ) {
int c = *p;
if ( c != ' ' && c != ',' && c != '\t' )
break;
}
for ( ; ; p++ ) {
int c = *p;
if ( c == ' ' || c == ',' || c == '\t' || c == '\0' )
break;
wild_spec[ i++ ] = (char) c;
if ( i >= ( _MAX_PATH - 2 ) )
return 0;
}
wild_spec[ i++ ] = '\0';
if ( i <= 1 )
return 0;
mFullWildName = wild_spec;
mInputLine = p;
return 1;
}
//
// char * ALWildCardExpander::GetNextFile()
//
// ARGUMENTS:
//
// None.
//
// RETURNS
//
// In the event that this routine is able to come up with a new
// file name, it returns a character pointer to the name, which
// is kept in member variable mResultFileName. If no new file
// name could be cooked up, we return a 0, which means you are
// done.
//
// DESCRIPTION
//
// There are two wild card expander routines. One for NT, and one
// for DOS. They are both very similar in structure, but they weren't
// quite close enough to combine into a single routine. However, the
// both share a common structure, which is being described here.
//
// The ALWildCardExpander has what amounts to six different internal
// states. They are:
//
// Searching subdirectories, using another object
//
// Extracting the next wild spec from the input line
//
// Expanding the wild card to get the first matching file
//
// Expanding the wild card to get the next matching file
//
// Looking for the first subdirectory
//
// Looking for the next subdirectory
//
// For the most part, we keep track of the state using the mState
// variable. However, we keep track of whether we are searching
// subdirectories by examining the pointer to the next expander. If
// it is non-null, it means we are in that state.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
#if defined( AL_WIN32S )
//
// This is the NT version. It has to use FindFirstFile() and
// FindNextFile() to get file names. Note that this is implemented
// as a giant loop. This means we may go through several states
// inside this routine until we finally come up with a filename.
//
char AL_DLL_FAR * AL_PROTO ALWildCardExpander::GetNextFile()
{
for ( ; ; ) {
//
// If the pointer to the next expander is set, it means we are working
// on a subdirectory, so I have to let him do the work. If the subdirectory
// search fails, I continue right back where I was when interrupted.
//
if ( mpNextExpander ) {
char *p = mpNextExpander->GetNextFile();
if ( p )
return p; // Return the name if he found one
delete mpNextExpander; // If not, he is toast
mpNextExpander = 0;
}
switch ( mState ) {
//
// This is where I get the next wild spec from the input line. If
// there aren't any more, I return 0, because we are done. If there
// is one, I set up the member variable that will be used in the
// rest of the search, and set up the state so that next I will get
// get the first file name.
//
case GET_NEXT_WILD_NAME :
if ( GetNextWildName() == 0 )
return 0;
mWildPathOnly = mFullWildName;
mWildPathOnly.StripFileName();
mWildNameOnly = mFullWildName;
mWildNameOnly.StripPath();
mState = GET_FIRST_FILE_NAME;
break;
//
// Once I have a wild spec, time to start getting file names.
// FindFirstFile() does it for me. if there aren't any files, I
// either go on to search directories, or go the the next wild
// name in the input line. If there is a name, I return it to
// the calling procedure.
//
case GET_FIRST_FILE_NAME :
mFindFileHandle = FindFirstFile( mFullWildName, &mFindFileData );
if ( mFindFileHandle == INVALID_HANDLE_VALUE ) {
if ( miTraverseFlag )
mState = GET_FIRST_DIRECTORY;
else
mState = GET_NEXT_WILD_NAME;
break;
}
mState = GET_NEXT_FILE_NAME;
if ( mFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
break;
mResultFileName = ALName( mWildPathOnly + mFindFileData.cFileName );
return mResultFileName;
//
// Time to get another file name with FindNextFile(). If there aren't
// any more, I clean up, and either get the next name for the input
// line or start searching subdirectories. If there was a name, I return
// it to the calling procedure.
//
case GET_NEXT_FILE_NAME :
if ( !FindNextFile( mFindFileHandle, &mFindFileData ) ) {
FindClose( mFindFileHandle );
mFindFileHandle = INVALID_HANDLE_VALUE;
if ( miTraverseFlag )
mState = GET_FIRST_DIRECTORY;
else
mState = GET_NEXT_WILD_NAME;
break;
}
if ( mFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
break;
mResultFileName = ALName( mWildPathOnly + mFindFileData.cFileName );
return mResultFileName;
//
// The procedure to get the first subdirectory is an awful lot like that
// we use to get the first file. If we find a valid subdirectory, we create
// a new expander to deal with its wildcards. If we find a file, but
// it isn't a subdirectory, we keep on searching. If we don't find
// anything, we are going to go back and check out the next file spec
// from the input line.
//
case GET_FIRST_DIRECTORY :
mFindFileHandle = FindFirstFile( mWildPathOnly + "*.*", &mFindFileData );
if ( mFindFileHandle == INVALID_HANDLE_VALUE ) {
mState = GET_NEXT_WILD_NAME;
break;
}
mState = GET_NEXT_DIRECTORY;
if ( mFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
if ( strcmp( mFindFileData.cFileName, ".." ) == 0 )
break;
if ( strcmp( mFindFileData.cFileName, "." ) == 0 )
break;
mpNextExpander = new ALWildCardExpander( mWildPathOnly + mFindFileData.cFileName + "\\" + (char *) mWildNameOnly, 1, mCase );
}
break;
//
// This works the same as the state where I get the first directory.
// The only difference here is that if I run out of file names in the
// directory, I have to call FindClose() to clean up after myself.
//
case GET_NEXT_DIRECTORY :
if ( !FindNextFile( mFindFileHandle, &mFindFileData ) ) {
FindClose( mFindFileHandle );
mFindFileHandle = INVALID_HANDLE_VALUE;
mState = GET_NEXT_WILD_NAME;
break;
}
if ( mFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
if ( strcmp( mFindFileData.cFileName, ".." ) == 0 )
break;
if ( strcmp( mFindFileData.cFileName, "." ) == 0 )
break;
mpNextExpander = new ALWildCardExpander( mWildPathOnly + mFindFileData.cFileName + "\\" + (char *) mWildNameOnly, 1 );
}
break;
default :
return 0;
}
}
}
#else
//
// This is the MS-DOS version of the file expander. In structure,
// it is almost identical to the NT version.
//
char AL_DLL_FAR * AL_PROTO ALWildCardExpander::GetNextFile()
{
//
// mpFfblk is the pointer to my structure used by _dos_findfirst()
// and _dos_findnext(). If for some reason this is a null pointer,
// I need to quit. The only reason this should be null is a memory
// allocation failure.
//
if ( mpFfblk == 0 )
return 0;
for ( ; ; ) {
//
// If the pointer to the next expander is non-zero, it means I am in
// the middle of a subdirectory search. If that is the case, I call
// the next expander to see if it can come up with a file name. if
// it does, we return it. If it doesn't, it means it is done, and
// I can delete it and try my luck with the next subdirectory.
//
if ( mpNextExpander ) {
char *p = mpNextExpander->GetNextFile();
if ( p )
return p;
delete mpNextExpander;
mpNextExpander = 0;
}
switch ( mState ) {
//
// This is where I start, and this is where I end up after completely
// processing one of the input wild specs. I get the next name from
// the input line here. If there aren't any more names, I can return
// 0, meaning the whole thing is done.
//
case GET_NEXT_WILD_NAME :
if ( GetNextWildName() == 0 )
return 0;
mWildPathOnly = mFullWildName;
mWildPathOnly.StripFileName();
mWildNameOnly = mFullWildName;
mWildNameOnly.StripPath();
mState = GET_FIRST_FILE_NAME;
break;
//
// Once I have a file name, I start parsing using _dos_findfirst().
// If that doesn't return a name, I have struck out on my first swing.
// if that is the case, I either move on to start searching subdirectories,
// or go back and look for another name from the input line. On the
// other hand, if I get a name, I return it to the caller.
//
case GET_FIRST_FILE_NAME :
if ( _dos_findfirst( mFullWildName, 0, mpFfblk ) ) {
if ( miTraverseFlag )
mState = GET_FIRST_DIRECTORY;
else
mState = GET_NEXT_WILD_NAME;
break;
}
mState = GET_NEXT_FILE_NAME;
mResultFileName = ALName( mWildPathOnly + mpFfblk->name );
return mResultFileName;
//
// This state is identical to GET_FIRST_FILE_NAME, except it has to
// use _dos_findnext() instead of _dos_findfirst()
//
case GET_NEXT_FILE_NAME :
if ( _dos_findnext( mpFfblk ) ) {
if ( miTraverseFlag )
mState = GET_FIRST_DIRECTORY;
else
mState = GET_NEXT_WILD_NAME;
break;
}
mResultFileName = mWildPathOnly + mpFfblk->name;
return mResultFileName;
//
// After getting all of the file names that a wildspec expands into,
// we can start searching subdirectories, if needed. Unlike with NT,
// we can set our search up to look for directories only. that means
// we don't have to check the status of the file returned from _dos_findxxxx().
// However, we always do have to check to make sure it isn't one of the
// two bogus directory entries, "." or "..".
//
// If we score here, we create a new ALWildCardExpander, and put him to
// work. If we strike out, time to go back and get our next input
// file name.
//
case GET_FIRST_DIRECTORY :
if ( _dos_findfirst( mWildPathOnly + "*.*", _A_SUBDIR, mpFfblk ) ) {
mState = GET_NEXT_WILD_NAME;
break;
}
mState = GET_NEXT_DIRECTORY;
if ( mpFfblk->attrib & _A_SUBDIR ) {
if ( strcmp( mpFfblk->name, ".." ) == 0 )
break;
if ( strcmp( mpFfblk->name, "." ) == 0 )
break;
mpNextExpander = new ALWildCardExpander( mWildPathOnly + mpFfblk->name + "\\" + (char *) mWildNameOnly, 1, mCase );
}
break;
//
// This is just like GET_FIRST_DIRECTORY, except it gets to call
// _dos_findnext() instead of _dos_findfirst().
//
case GET_NEXT_DIRECTORY :
if ( _dos_findnext( mpFfblk ) ) {
mState = GET_NEXT_WILD_NAME;
break;
}
if ( mpFfblk->attrib & _A_SUBDIR ) {
if ( strcmp( mpFfblk->name, ".." ) == 0 )
break;
if ( strcmp( mpFfblk->name, "." ) == 0 )
break;
mpNextExpander = new ALWildCardExpander( mWildPathOnly + mpFfblk->name + "\\" + (char *) mWildNameOnly, 1 );
}
break;
default :
return 0;
}
}
#if defined( AL_MICROSOFT ) && ( AL_MICROSOFT < 800 )
return 0; //MSC 7.0 thinks I need this return path. No way to get here!
#endif
}
#endif // #if defined( AL_WIN32S )... #else