campo-sirio/arch/objname.cpp

755 lines
20 KiB
C++
Executable File

//
// OBJNAME.CPP
//
// Source file for ArchiveLib 1.0
//
// Copyright (c) Greenleaf Software, Inc. 1994
// All Rights Reserved
//
// CONTENTS
//
// ALName::operator new()
// ALName::operator+()
// ALName::ALName( const char *, ALCase )
// ALName::ALName( const ALName & )
// ALName::operator=( const char * )
// ALName::operator = ( const ALName & )
// ALName::~ALName()
// ALName::ChangeExtension()
// ALName::ChangeTrailingChar()
// ALName::GetSafeName()
// ALName::GetSafeOldName()
// ALName::operator char *()
// ALName::StripFileName()
// ALName::StripPath()
// ALName::WildCardMatch()
// ALName::Strcpy()
//
// DESCRIPTION
//
// This file contains all the source code to support class ALName.
// Class ALName doesn't really do much outside of ALStorage, where
// it shows up as the mName data member. It does make cameo appearances
// elsewhere, such as in the wild card expansion code, but those
// are pretty limited.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
//
#include "arclib.h"
#pragma hdrstop
#include <string.h>
#include <ctype.h>
#include "_match.h"
//
// void * ALName::operator new( size_t size )
//
// ARGUMENTS:
//
// size : The number of bytes needed to create a new ALName 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 ALName::operator new( size_t size )
{
return ::new char[ size ];
}
#endif
//
// ALName ALName::operator+( const char *rhs )
//
// ARGUMENTS:
//
// rhs : The character pointer that is going to be added to the
// ALName object. This will often be the string component
// of another ALName object, cast to type const char *.
//
// RETURNS
//
// A newly created ALName object. This disappears quickly, but can
// be copied into a result object using either the assignment operator
// or the copy constructor.
//
// DESCRIPTION
//
// This is one of those C++ functions that makes converts out of C
// programmers. It allows me to add two strings together to create
// a third. I really like that.
//
// The implementation is pretty easy. I allocate a new character buffer of
// the correct length, the copy the two strings into it. I use this
// result as the initializer for a new ALName object, and return that.
//
// Note that the new string will have the same case sensitivity as this.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
ALName ALName::operator+( const char AL_DLL_FAR *rhs )
{
int l1 = ( rhs ) ? strlen( rhs ) : 0;
int l2 = ( mszName ) ? strlen( mszName ) : 0;
char *p = new char[ l1 + l2 + 1 ];
if ( p ) {
strcpy( p, mszName );
if ( rhs )
strcat( p, rhs );
}
ALName result( p, mCase );
if ( p )
delete p;
return result;
}
//
// ALName::ALName( const char *s = "", ALCase name_case = AL_MIXED )
//
// ARGUMENTS:
//
// s : The initial string value of the new object. Note that
// you can pass a null pointer here and all will still be okay.
//
// name_case: The case sensitivity of the new ALName object. Will its
// contents be mixed, or will it always be forced to upper
// or lower.
//
// RETURNS
//
// Nothing, a constructor.
//
// DESCRIPTION
//
// This constructor first initializes the mCase member in an initializer.
// mCase is a const member, which is nice, because you can make it public.
// But, it means you can't initialize it *in* the constructor, you have
// to do it before the body.
//
// Things are pretty easy after that. We allocate enough space to hold
// the initializer string and copy it in. The old name gets set to 0, since
// this name hasn't been around long enough to have been renamed.
// And that's it.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
AL_PROTO ALName::ALName( const char AL_DLL_FAR *s /* = "" */,
ALCase name_case /* = AL_MIXED */ )
: mCase( name_case )
{
mszName = new AL_DLL_FAR char[ strlen( s ) + 1 ];
if ( mszName )
Strcpy( s );
mszOldName = 0;
}
//
// ALName::ALName( const ALName &rhs )
//
// ARGUMENTS:
//
// rhs : A reference to another ALName object. This is the ALName
// we are going to copy.
//
// RETURNS
//
// Nothing, a constructor.
//
// DESCRIPTION
//
// This is the copy constructor. It is very nearly the same as the
// other constructor.
//
// This constructor first initializes the mCase member in an initializer.
// mCase is a const member, which is nice, because you can make it public.
// But, it means you can't initialize it *in* the constructor, you have
// to do it before the body.
//
// Things are pretty easy after that. We allocate enough space to hold
// a copy of the string in the rhs, and then copy it. The old name gets
// set to 0, since this name hasn't been around long enough to have been
// renamed. We could have copied the old name from the rhs, but I think
// this way makes more sense.
// And that's it.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
AL_PROTO ALName::ALName( const ALName AL_DLL_FAR &rhs )
: mCase( rhs.mCase )
{
const char *s = rhs.GetSafeName();
mszName = new AL_DLL_FAR char[ strlen( s ) + 1 ];
if ( mszName )
Strcpy( s );
mszOldName = 0;
}
//
// ALName & ALName::operator = ( const char * rhs )
//
// ARGUMENTS:
//
// rhs : This is the character string that we are going to assign to this.
//
// RETURNS
//
// A reference to this. We need to do it that way so we can do:
//
// a = b = c = "test";
//
// DESCRIPTION
//
// This function performs roughly the same function as the first
// constructor, but there is a twist. When we assign a new name to
// an ALName object, we also make a copy of fit and place it in
// the old name data member.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
ALName AL_DLL_FAR & AL_PROTO ALName::
operator = ( const char AL_DLL_FAR * rhs )
{
if ( rhs == 0 )
rhs = "";
if ( rhs == mszName ) // Pathological?
return *this;
char AL_DLL_FAR *new_name = new AL_DLL_FAR char[ strlen( rhs ) + 1 ];
if ( new_name ) {
if ( mszOldName )
delete[] mszOldName;
mszOldName = mszName;
mszName = new_name;
Strcpy( rhs );
} else {
if ( mszOldName )
delete[] mszOldName;
mszOldName = mszName;
mszName = 0;
}
return *this;
}
//
// ALName & ALName::operator = ( const ALName & rhs )
//
// ARGUMENTS:
//
// rhs : The right hand side of the assignment operator.
//
// RETURNS
//
// A reference to this. Like in the above function, we do this so
// that you can stack assignments:
//
// a = b = c = "Dummy";
//
// DESCRIPTION
//
//
// This function is very similar to the copy constructor, but it has
// one additional twist. When we copy the rhs string value into our
// string, we move our old name into the backup copy member,
// mszOldName. That way, if we change our mind, we can easily
// switch back to the old name.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
ALName AL_DLL_FAR & AL_PROTO ALName::
operator = ( const ALName AL_DLL_FAR & rhs )
{
return *this = rhs.GetName();
}
//
// ALName::~ALName()
//
// ARGUMENTS:
//
// None, this is a destructor.
//
// RETURNS
//
// None, destructor.
//
// DESCRIPTION
//
// All this function has to do is free up the two pieces of
// dynamic memory. I just can't get out of that old C habit of
// checking a pointer for NULL before deleting it.
//
// In debug mode, I check the state of this before and after freeing
// the dynamically allocated memory, in hopes of catching any
// heap errors near their source.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
AL_PROTO ALName::~ALName()
{
AL_ASSERT( GoodTag(), "~ALName: attempt to delete invalid object" );
if ( mszName )
delete[] mszName;
if ( mszOldName )
delete[] mszOldName;
AL_ASSERT( GoodTag(), "~ALName: attempt to delete invalid object" );
}
//
// ALName & ALName::ChangeExtension( const char *new_extension = ".bak" )
//
// ARGUMENTS:
//
// new_extension : The new extension you want to apply to the name.
//
// RETURNS
//
// A reference to this. This is nice, because it lets you do things
// like this:
//
// fopen( name.ChangeExtension( ".OBJ" ), "rb" );
//
// DESCRIPTION
//
// This function is used to change the extension of a filename stored
// in an ALName object. A lot of times you will want to do this
// in order to create a backup. For example, you could change
// TEMP.DAT to TEMP.BAK.
//
// This function makes a copy of the current name in mszOldName, so we
// can keep track of it later. It then searches for the '.' character
// in the new file name, and sticks the new extension there.
//
// If you apply this function to a filename, you can then rename the file
// by calling ALStorage::Rename() with no argument. When you do this,
// the rename function uses the saved OldName and current name as its
// arguments for the rename() function.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
//
// I need to fix this code up to handle extensions with and without a
// leading '.' character. Maybe you can use a leading character
// other than '.' to indicate a different type of extension?
//
ALName AL_DLL_FAR & AL_PROTO ALName::
ChangeExtension( const char AL_DLL_FAR *new_extension /* = ".bak" */ )
{
AL_ASSERT( new_extension != 0, "ChangeExtension: new extension is null" );
AL_ASSERT( mszName, "ChangeExtension: current name is null" );
char *file_name = new char[ strlen( mszName ) + strlen( new_extension ) + 1 ];
if ( mszOldName )
delete[] mszOldName;
mszOldName = mszName;
mszName = file_name;
if ( !file_name )
return *this;
strcpy( mszName, mszOldName );
char *p = strrchr( file_name, '.' );
if ( p )
strcpy( p, new_extension );
else
strcat( mszName, new_extension );
switch ( mCase ) {
case AL_UPPER : strupr( mszName ); break;
case AL_LOWER : strlwr( mszName ); break;
}
return *this;
}
//
// ALName & ALName::ChangeTrailingChar( char new_char = '@' )
//
// ARGUMENTS:
//
// new_char : The new character to use as the last name of the file
// name.
//
// RETURNS
//
// A reference to this. This is nice, because it lets you do things
// like this:
//
// fopen( name.ChangeTrailingChar(), "rb" );
//
// DESCRIPTION
//
// This function is used to change the the last character of the extension
// in filename stored in an ALName object. A lot of times you will want to
// do this in order to create a backup. For example, you could change
// TEMP.DAT to TEMP.DA@.
//
// This function makes a copy of the current name in mszOldName, so we
// can keep track of it later. It then searches for the end of the
// current file name, and changes it.
//
// Note that if the filename doesn't have an extension, we do something
// funny. Instead of just changing the last character, we create a
// new extension, and append that instead. So if the filename is
// "TEST", the new name will be "TEST.@".
//
// If you apply this function to a filename, you can then rename the file
// by calling ALStorage::Rename() with no argument. When you do this,
// the rename function uses the saved OldName and current name as its
// arguments for the rename() function.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
ALName AL_DLL_FAR & AL_PROTO ALName::
ChangeTrailingChar( char new_char /* = '@' */ )
{
AL_ASSERT( mszName != 0, "ChangeTrailingChar: current name is null" );
char *file_name = new char[ strlen( mszName ) + 2 ];
if ( mszOldName )
delete[] mszOldName;
mszOldName = mszName;
mszName = file_name;
switch ( mCase ) {
case AL_UPPER : new_char = (char) toupper( new_char ); break;
case AL_LOWER : new_char = (char) tolower( new_char ); break;
}
if ( !file_name )
return *this;
strcpy( mszName, mszOldName );
char *p;
if ( ( p = strrchr( mszName, '.' ) ) != 0 ) {
if ( p[ 1 ] == '0' ) {
p[ 1 ] = new_char;
p[ 2 ] = '\0';
} else
mszName[ strlen( mszName ) - 1 ] = new_char;
} else {
char new_extension[ 3 ];
new_extension[ 0 ] ='.';
new_extension[ 1 ] = new_char;
new_extension[ 2 ] = 0;
strcat( mszName, new_extension );
}
return *this;
}
//
// const char * ALName::GetSafeName() const
//
// ARGUMENTS:
//
// None.
//
// RETURNS
//
// This function normally returns the value of mszName. However, if
// mszName is currently a null pointer, we return a pointer to an
// empty string instead. This means you can use the return value from
// this function anywhere you want without checking for its NULLity.
//
// DESCRIPTION
//
// See above.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
const char AL_DLL_FAR * AL_PROTO ALName::GetSafeName() const
{
if ( mszName )
return mszName;
else
return "";
}
//
// const char * ALName::GetSafeOldName() const
//
// ARGUMENTS:
//
// None.
//
// RETURNS
//
// This function normally returns the value of mszOldName. However, if
// mszOldName is currently a null pointer, we return a pointer to an
// empty string instead. This means you can use the return value from
// this function anywhere you want without checking for its NULLity.
//
// DESCRIPTION
//
// See above.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
const char AL_DLL_FAR * AL_PROTO ALName::GetSafeOldName() const
{
if ( mszOldName )
return mszOldName;
else
return "";
}
//
// ALName::operator const char *() const
//
// ARGUMENTS:
//
// None.
//
// RETURNS
//
// A pointer to the string inside the object. If the string is
// presently a null pointer, we return a pointer to an empty string
// instead. See ALName::GetSafeName() for an explanation of why
// this is.
//
// DESCRIPTION
//
// This is the casting operator that pretty much lets me use
// an ALName object anywhere I use a char *. There are some strange
// Microsoft compiler problems that make me use this goofy STRINGF
// typedef instead of char *, but it all adds up the same in
// the wash.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
#if defined( AL_MICROSOFT ) && ( AL_MICROSOFT < 800 ) && defined( AL_BUILDING_DLL ) //??????
AL_PROTO ALName::operator char *() const
#else
AL_PROTO ALName::operator const STRINGF() const
#endif
{
if ( mszName )
return mszName;
else
return "";
}
//
// ALName & ALName::StripFileName()
//
// ARGUMENTS:
//
// None.
//
// RETURNS
//
// A reference to this. This is nice, because you can strip the
// file name from an object and use it in the same operation.
//
// DESCRIPTION
//
// In the wildcard parsing code, sometimes I need to get the path
// of a file, which means stripping off the filename and extension.
// This is pretty easy to do, I just find the right spot and stick
// a string termination character in that position.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
ALName AL_DLL_FAR & AL_PROTO ALName::StripFileName()
{
if ( mszName ) {
char *p = strrchr( mszName, '\\' );
if ( p == 0 )
p = strrchr( mszName, ':' );
if ( p )
p[ 1 ] = '\0';
else
mszName[ 0 ] = '\0';
}
return *this;
}
//
// ALName & ALName::StripPath()
//
// ARGUMENTS:
//
// None.
//
// RETURNS
//
// A reference to this. This is nice, because you can strip the
// file name from an object and use it in the same operation.
//
// DESCRIPTION
//
// In the wildcard parsing code, sometimes I need to get just the
// filename and extension of a file, which means stripping off the
// drive and path information. This is pretty easy to do, I just find
// the start of the filename, and move it up to the start of the string.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
ALName AL_DLL_FAR & AL_PROTO ALName::StripPath()
{
if ( mszName ) {
char *p = strrchr( mszName, '\\' );
if ( p == 0 )
p = strrchr( mszName, ':' );
if ( p ) {
p++;
char *s = mszName;
while( ( *s++ = *p++ ) != 0 )
;
*s = '\0';
} //If not p, path is already stripped
}
return *this;
}
//
// int ALName::WildCardMatch( const char *pattern )
//
// ARGUMENTS:
//
// pattern : A pointer to a regular expression, including wildcards
// and sets. It can get pretty complicated.
//
// RETURNS
//
// 0 if the pattern doesn't match the object name, 1 if it does.
//
// DESCRIPTION
//
// This is a super-duper powerful function. It is used to compare
// a regular expression to the contents of an ALName. The real meat
// here is in the public domain string matching code found in _MATCH.CPP.
//
// The tricky bit here is that we have to make a comparison based
// on the case sensitivity of this. Rather than trying to modify
// the code in _MATCH.CPP, I just make a new copy of the pattern, and
// mangle the case according to what this expects.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
int AL_PROTO ALName::WildCardMatch( const char AL_DLL_FAR *pattern )
{
int error;
int result;
char *p = new char[ strlen( pattern ) + 1 ];
if ( !p )
return 0;
strcpy( p, pattern );
switch ( mCase ) {
case AL_UPPER : strupr( p ); break;
case AL_LOWER : strlwr( p ); break;
}
if ( !is_valid_pattern( p, &error ) )
result = 0;
else if ( matche( p, mszName ) == MATCH_VALID )
result = 1;
else
result = 0;
delete p;
return result;
}
// PROTECTED MEMBER FUNCTION.
//
// void ALName::Strcpy( const char *s )
//
// ARGUMENTS:
//
// s : A character string to be copied into mszName.
//
// RETURNS
//
// Nothing.
//
// DESCRIPTION
//
// Whenever I am going to copy a string into mszName, I need to convert
// it to the case that this object expects. If it is AL_UPPER or
// AL_LOWER, that means copying and then converting to either all upper
// case or all lower case. I do that here.
//
// REVISION HISTORY
//
// May 26, 1994 1.0A : First release
//
void AL_PROTO ALName::Strcpy( const char *s )
{
strcpy( mszName, s );
switch ( mCase ) {
case AL_UPPER : strupr( mszName ); break;
case AL_LOWER : strlwr( mszName ); break;
}
}