Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1322 lines
28 KiB

#include "toollib.h"
#ifdef _DEBUG
#define HEAP_CHECK
#endif
int g_tl_argc;
char** g_tl_argv;
int g_tl_byteorder;
int g_tl_dircount;
char** g_tl_dirlist;
int g_tl_start;
int g_tl_abort;
bool g_tl_quiet;
#pragma warning(disable:4311)
#pragma warning(disable:4267)
/*****************************************************************************
TL_Setup
*****************************************************************************/
void TL_Setup(char* appname, int argc, char** argv)
{
const char* buildStr;
g_tl_argc = argc;
g_tl_argv = argv;
g_tl_quiet = (TL_CheckParm("q") > 0) || (TL_CheckParm("quiet") > 0) || (TL_CheckParm("noheader") > 0);
if (appname)
{
TL_printf("\n%s \n",appname);
#ifdef _DEBUG
buildStr = "Debug Build";
#else
buildStr = "Release Build";
#endif
TL_printf("%s - %s %s\n\n", buildStr, __DATE__, __TIME__);
}
g_tl_abort = TL_CheckParm("abort");
g_tl_start = TL_CPUCount();
}
/*****************************************************************************
TL_End
*****************************************************************************/
void TL_End(bool showtime)
{
int end;
if (showtime && !g_tl_quiet)
{
end = TL_CPUCount();
TL_printf("\n%f seconds.\n",TL_CPUTime(g_tl_start,end));
}
}
/*****************************************************************************
TL_Error
*****************************************************************************/
void TL_Error(char* error, ...)
{
va_list argptr;
va_start(argptr,error);
vprintf(error,argptr);
va_end(argptr);
printf("\n");
#if !defined( _X360 )
__asm
{
int 3;
}
#endif
if (g_tl_abort)
abort();
exit(-1);
}
/*****************************************************************************
TL_CheckParm
Returns the argument number (1 to argc-1) or 0 if not present
*****************************************************************************/
int TL_CheckParm(char* check)
{
int i;
char* parm;
for (i=1; i<g_tl_argc; i++)
{
parm = g_tl_argv[i];
if (!isalpha(*parm))
if (!*++parm)
continue;
if (!stricmp(check,parm))
return (i);
}
return (0);
}
/*****************************************************************************
TL_SafeRead
*****************************************************************************/
void TL_SafeRead(int handle, void* buffer, long count)
{
if (_read(handle,buffer,count) != count)
TL_Error("SafeRead(): read failure");
}
/*****************************************************************************
TL_SafeOpenRead
*****************************************************************************/
int TL_SafeOpenRead(const char* filename)
{
int handle;
handle = _open(filename,_O_RDONLY|_O_BINARY);
if (handle == -1)
TL_Error("TL_SafeOpenRead(): Error opening %s: %s",filename,strerror(errno));
return (handle);
}
/*****************************************************************************
TL_SafeOpenWrite
*****************************************************************************/
int TL_SafeOpenWrite(const char* filename)
{
int handle;
handle = _open(filename,_O_RDWR|_O_BINARY|_O_CREAT|_O_TRUNC,0666);
if (handle == -1)
TL_Error("TL_SafeOpenWrite(): Error opening %s: %s",filename,strerror(errno));
return (handle);
}
/*****************************************************************************
TL_SafeWrite
*****************************************************************************/
void TL_SafeWrite(int handle, void* buffer, long count)
{
int status;
status = _write(handle,buffer,count);
if (status != count)
TL_Error("TL_SafeWrite(): write failure %d, errno=%d",status,errno);
}
/*****************************************************************************
TL_SafeClose
*****************************************************************************/
void TL_SafeClose(int handle, int touch)
{
// ensure date and time of modification get set
if (touch)
_futime(handle,NULL);
close(handle);
}
/*****************************************************************************
TL_Malloc
*****************************************************************************/
void* TL_Malloc(int size)
{
void* ptr;
int newsize;
newsize = size + sizeof(tlmem_t);
newsize = (newsize + 3) & ~3;
ptr = malloc(newsize);
if (!ptr)
TL_Error("TL_Malloc(): failure for %lu bytes",size);
memset(ptr,0,newsize);
((tlmem_t*)ptr)->id = TL_MEMID;
((tlmem_t*)ptr)->size = size;
return ((byte_t*)ptr + sizeof(tlmem_t));
}
/*****************************************************************************
TL_Free
*****************************************************************************/
void TL_Free(void* ptr)
{
tlmem_t* memptr;
if (!ptr)
TL_Error("TL_Free(): null pointer");
memptr = (tlmem_t*)((byte_t*)ptr - sizeof(tlmem_t));
if (((u32)memptr) & 3)
TL_Error("TL_Free(): bad pointer %8.8x",ptr);
if (memptr->id != TL_MEMID)
TL_Error("TL_Free(): corrupted pointer %8.8x",ptr);
memptr->id = 0;
memptr->size = 0;
free(memptr);
#ifdef HEAP_CHECK
if (_heapchk() != _HEAPOK)
TL_Error("TL_Free(): heap corrupted");
#endif
}
bool TL_Check(void* ptr)
{
tlmem_t* memptr;
if (!ptr)
return false;
memptr = (tlmem_t*)((byte_t*)ptr - sizeof(tlmem_t));
if (((u32)memptr) & 3)
return false;
if (memptr->id != TL_MEMID)
return false;
return true;
}
/*****************************************************************************
TL_Realloc
*****************************************************************************/
void* TL_Realloc(void* ptr, int newsize)
{
int len;
tlmem_t* oldmemptr;
void* newptr;
if (!ptr)
{
newptr = TL_Malloc(newsize);
return (newptr);
}
oldmemptr = (tlmem_t*)((byte_t*)ptr - sizeof(tlmem_t));
if ((u32)oldmemptr & 3)
TL_Error("TL_Realloc(): bad pointer %8.8x",ptr);
if (oldmemptr->id != TL_MEMID)
TL_Error("TL_Realloc(): corrupted pointer %8.8x",ptr);
newptr = TL_Malloc(newsize);
len = TL_min(newsize,oldmemptr->size);
memcpy(newptr,ptr,len);
TL_Free(ptr);
return (newptr);
}
/*****************************************************************************
TL_strncpyz
Copy up to (N) bytes including appending null.
*****************************************************************************/
void TL_strncpyz(char* dst, char* src, int n)
{
if (n <= 0)
return;
if (n > 1)
strncpy(dst,src,n-1);
dst[n-1] = '\0';
}
/*****************************************************************************
TL_strncatz
Concatenate up to dstsize bytes including appending null.
*****************************************************************************/
void TL_strncatz(char* dst, char* src, int dstsize)
{
int len;
if (dstsize <= 0)
return;
len = (int)strlen(dst);
TL_strncpyz(dst+len,src,dstsize-len);
}
/*****************************************************************************
TL_LoadFile
*****************************************************************************/
long TL_LoadFile(const char* filename, void** bufferptr)
{
int handle;
long length;
char* buffer;
handle = TL_SafeOpenRead(filename);
length = TL_FileLength(handle);
buffer = (char*)TL_Malloc(length+1);
TL_SafeRead(handle,buffer,length);
close(handle);
// for parsing
buffer[length] = '\0';
*bufferptr = (void*)buffer;
return (length);
}
/*****************************************************************************
TL_TouchFile
*****************************************************************************/
void TL_TouchFile(char* filename)
{
int h;
h = _open(filename,_O_RDWR|_O_BINARY,0666);
if (h < 0)
return;
_futime(h,NULL);
_close(h);
}
/*****************************************************************************
TL_SaveFile
*****************************************************************************/
void TL_SaveFile(char* filename, void* buffer, long count)
{
int handle;
handle = TL_SafeOpenWrite(filename);
TL_SafeWrite(handle,buffer,count);
TL_SafeClose(handle,true);
}
/*****************************************************************************
TL_FileLength
*****************************************************************************/
long TL_FileLength(int handle)
{
long pos;
long length;
pos = lseek(handle,0,SEEK_CUR);
length = lseek(handle,0,SEEK_END);
lseek(handle,pos,SEEK_SET);
return (length);
}
/*****************************************************************************
TL_StripFilename
Removes filename from path.
*****************************************************************************/
void TL_StripFilename(char* path)
{
int length;
length = (int)strlen(path)-1;
while ((length > 0) && (path[length] != '\\') && (path[length] != '/') && (path[length] != ':'))
length--;
/* leave possible seperator */
if (!length)
path[0] = '\0';
else
path[length+1] = '\0';
}
/*****************************************************************************
TL_StripExtension
Removes extension from path.
*****************************************************************************/
void TL_StripExtension(char* path)
{
int length;
length = (int)strlen(path)-1;
while (length > 0 && path[length] != '.')
length--;
if (length && path[length] == '.')
path[length] = 0;
}
/*****************************************************************************
TL_StripPath
Removes path from full path.
*****************************************************************************/
void TL_StripPath(char* path, char* dest)
{
char* src;
src = path + strlen(path);
while ((src != path) && (*(src-1) != '\\') && (*(src-1) != '/') && (*(src-1) != ':'))
src--;
strcpy(dest,src);
}
/*****************************************************************************
TL_GetExtension
Gets any extension from the full path.
*****************************************************************************/
void TL_GetExtension(char* path, char* dest)
{
char* src;
src = path + strlen(path) - 1;
// back up until a . or the start
while (src != path && *(src-1) != '.')
src--;
if (src == path)
{
*dest = '\0'; // no extension
return;
}
strcpy(dest,src);
}
/*****************************************************************************
TL_DefaultPath
Adds basepath to head of path.
*****************************************************************************/
void TL_DefaultPath(char* path, char* basepath)
{
char temp[TL_MAXPATH];
char* ptr;
char ch;
if (path[0] == '\\')
{
// path is absolute
return;
}
ptr = path;
while (1)
{
ch = *ptr++;
if (!ch)
break;
if (ch == ':')
{
// path has a device - must be absolute
return;
}
}
// place basepath at head of path
// do intermediate copy to preserve any arg wierdness
strcpy(temp,path);
strcpy(path,basepath);
strcat(path,temp);
}
/*****************************************************************************
TL_AddSeperatorToPath
*****************************************************************************/
void TL_AddSeperatorToPath(char* inpath, char* outpath)
{
int len;
strcpy(outpath,inpath);
len = (int)strlen(outpath);
if (outpath[len-1] != '\\')
{
outpath[len] = '\\';
outpath[len+1] = '\0';
}
}
/*****************************************************************************
TL_DefaultExtension
Adds extension a path that has no extension.
*****************************************************************************/
void TL_DefaultExtension(char* path, char* extension, bool bForce)
{
char* src;
if ( !bForce && path[0] )
{
src = path + strlen(path) - 1;
while ((src != path) && (*src != '\\') && (*src != '/'))
{
if (*src == '.')
return;
src--;
}
}
strcat(path,extension);
}
/*****************************************************************************
TL_ReplaceDosExtension
Handles files of the form xxxx.xxxxxxx.xxxxx.zzz
*****************************************************************************/
void TL_ReplaceDosExtension(char* path, char* extension)
{
int len;
len = (int)strlen(path);
if (!len)
return;
if (path[len-1] == '.')
{
path[len-1] = '\0';
strcat(path,extension);
return;
}
if (len-4 > 0 && path[len-4] == '.')
path[len-4] = '\0';
strcat(path,extension);
}
/*****************************************************************************
TL_ReplaceExtension
Replaces any extension found after '.'
*****************************************************************************/
void TL_ReplaceExtension(const char* inPath, const char* extension, char* outPath)
{
int len;
char* src;
if (outPath != inPath)
strcpy(outPath, inPath);
len = (int)strlen(outPath);
if (!len)
return;
if (outPath[len-1] == '.')
{
outPath[len-1] = '\0';
strcat(outPath, extension);
return;
}
src = outPath + len - 1;
while ((src != outPath) && (*src != '\\') && (*src != '/'))
{
if (*src == '.')
{
*src = '\0';
break;
}
src--;
}
strcat(outPath, extension);
}
/*****************************************************************************
TL_TempFilename
Builds a temporary filename at specified path.
*****************************************************************************/
void TL_TempFilename(char* path)
{
int len;
len = (int)strlen(path);
if (len)
{
/* tack on appending seperator */
if (path[len-1] != '\\')
{
path[len] = '\\';
path[len+1] = '\0';
}
}
strcat(path,tmpnam(NULL));
}
/*****************************************************************************
TL_AlignFile
TL_Aligns data in file to any boundary.
*****************************************************************************/
int TL_AlignFile(int handle, int align)
{
int i;
int pos;
int empty;
int count;
empty = 0;
pos = lseek(handle,0,SEEK_CUR);
count = ((pos+align-1)/align)*align - pos;
for (i=0; i<count; i++)
TL_SafeWrite(handle,&empty,1);
return (pos+count);
}
/*****************************************************************************
TL_GetByteOrder
Gets byte ordering, true is bigendian.
*****************************************************************************/
int TL_GetByteOrder(void)
{
return (g_tl_byteorder);
}
/*****************************************************************************
TL_SetByteOrder
Sets byte ordering, true is bigendian.
*****************************************************************************/
void TL_SetByteOrder(int flag)
{
g_tl_byteorder = flag;
}
/*****************************************************************************
TL_LongSwap
Swap according to set state.
*****************************************************************************/
long TL_LongSwap(long l)
{
if (!g_tl_byteorder)
return (l);
return (TL_BigLong(l));
}
/*****************************************************************************
TL_ShortSwap
Swap according to set state.
*****************************************************************************/
short TL_ShortSwap(short s)
{
if (!g_tl_byteorder)
return (s);
return (TL_BigShort(s));
}
/*****************************************************************************
TL_BigShort
Converts native short to big endian
*****************************************************************************/
short TL_BigShort(short l)
{
byte_t b1;
byte_t b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
/*****************************************************************************
TL_LittleShort
Converts native short to little endian
*****************************************************************************/
short TL_LittleShort(short l)
{
return (l);
}
/*****************************************************************************
TL_BigLong
Converts native long to big endian
*****************************************************************************/
long TL_BigLong(long l)
{
byte_t b1;
byte_t b2;
byte_t b3;
byte_t b4;
b1 = (byte_t)(l&255);
b2 = (byte_t)((l>>8)&255);
b3 = (byte_t)((l>>16)&255);
b4 = (byte_t)((l>>24)&255);
return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4;
}
/*****************************************************************************
TL_LittleLong
Converts native long to little endian
*****************************************************************************/
long TL_LittleLong(long l)
{
return (l);
}
/*****************************************************************************
TL_BigFloat
Converts native float to big endian
*****************************************************************************/
float TL_BigFloat(float f)
{
union
{
float f;
byte_t b[4];
} dat1,dat2;
dat1.f = f;
dat2.b[0] = dat1.b[3];
dat2.b[1] = dat1.b[2];
dat2.b[2] = dat1.b[1];
dat2.b[3] = dat1.b[0];
return (dat2.f);
}
/*****************************************************************************
TL_Exists
Returns TRUE if file exists.
*****************************************************************************/
bool TL_Exists(const char* filename)
{
FILE* test;
if (!filename || !filename[0])
return (false);
if ((test = fopen(filename,"rb")) == NULL)
return (false);
fclose(test);
return (true);
}
/*****************************************************************************
TL_FileTime
Returns a file's time and data word.
*****************************************************************************/
u32 TL_FileTime(char* filename)
{
struct _finddata_t finddata;
intptr_t h;
h = _findfirst(filename, &finddata);
if (h == -1)
return (0);
_findclose(h);
return (finddata.time_write);
}
/*****************************************************************************
TL_SortNames
*****************************************************************************/
int TL_SortNames(const void *a, const void *b)
{
return (strcmp(*((char **)a), *((char **)b)));
}
/*****************************************************************************
TL_FindFiles
*****************************************************************************/
int TL_FindFiles(char* filemask, char*** filenames)
{
struct _finddata_t finddata;
intptr_t h;
char sourcepath[TL_MAXPATH];
int count;
int len;
char** names = NULL;
char* ptr;
h = _findfirst(filemask,&finddata);
if (h == -1)
return (0);
TL_strncpyz(sourcepath,filemask,TL_MAXPATH);
TL_StripFilename(sourcepath);
if (!sourcepath[0])
strcpy(sourcepath,".\\");
else
{
len = (int)strlen(sourcepath);
if (sourcepath[len-1] != '\\')
TL_strncatz(sourcepath,"\\",TL_MAXPATH);
}
count = 0;
do
{
if (finddata.attrib & _A_SUBDIR)
continue;
if (!count)
names = (char**)TL_Malloc(sizeof(char*));
else
names = (char**)TL_Realloc(names,(count+1)*sizeof(char*));
ptr = (char*)TL_Malloc(TL_MAXPATH);
names[count] = ptr;
TL_strncpyz(names[count],sourcepath,TL_MAXPATH);
TL_strncatz(names[count],finddata.name,TL_MAXPATH);
count++;
}
while (!_findnext(h,&finddata));
_findclose(h);
// ascending sort the names
qsort(names,count,sizeof(char*),TL_SortNames);
*filenames = names;
return (count);
}
/*****************************************************************************
TL_GetFileList
*****************************************************************************/
int TL_GetFileList(char* dirpath, char* pattern, tlfile_t*** filelist)
{
struct _finddata_t finddata;
char sourcepath[TL_MAXPATH];
char fullpath[TL_MAXPATH];
char* filename;
intptr_t h;
int filecount;
int finddirs;
int len;
filecount = 0;
strcpy(sourcepath,dirpath);
len = (int)strlen(sourcepath);
if (!len)
strcpy(sourcepath,".\\");
else if (sourcepath[len-1] != '\\')
{
sourcepath[len] = '\\';
sourcepath[len+1] = '\0';
}
strcpy(fullpath,sourcepath);
if (pattern[0] == '\\' && pattern[1] == '\0')
{
// find directories
finddirs = true;
strcat(fullpath,"*");
}
else
{
finddirs = false;
strcat(fullpath,pattern);
}
h = _findfirst(fullpath,&finddata);
if (h == -1)
return (0);
do
{
// dos attribute complexities i.e. _A_NORMAL is 0
if (finddirs)
{
// skip non dirs
if (!(finddata.attrib & _A_SUBDIR))
continue;
}
else
{
// skip dirs
if (finddata.attrib & _A_SUBDIR)
continue;
}
if (!stricmp(finddata.name,"."))
continue;
if (!stricmp(finddata.name,".."))
continue;
if (!filecount)
*filelist = (tlfile_t**)TL_Malloc(sizeof(tlfile_t*));
else
*filelist = (tlfile_t**)TL_Realloc(*filelist,(filecount+1)*sizeof(tlfile_t*));
(*filelist)[filecount] = (tlfile_t*)TL_Malloc(sizeof(tlfile_t));
len = (int)strlen(sourcepath) + (int)strlen(finddata.name) + 1;
filename = (char*)TL_Malloc(len);
strcpy(filename,sourcepath);
strcat(filename,finddata.name);
(*filelist)[filecount]->filename = filename;
(*filelist)[filecount]->time_write = finddata.time_write;
filecount++;
}
while (!_findnext(h,&finddata));
_findclose(h);
return (filecount);
}
/*****************************************************************************
_RecurseFileTree
*****************************************************************************/
void _RecurseFileTree(char* dirpath, int depth)
{
tlfile_t** filelist;
int numfiles;
int i;
int len;
// recurse from source directory
numfiles = TL_GetFileList(dirpath,"\\",&filelist);
if (!numfiles)
{
// add directory name to search tree
if (!g_tl_dircount)
g_tl_dirlist = (char**)TL_Malloc(sizeof(char*));
else
g_tl_dirlist = (char**)TL_Realloc(g_tl_dirlist,(g_tl_dircount+1)*sizeof(char*));
len = (int)strlen(dirpath);
g_tl_dirlist[g_tl_dircount] = (char*)TL_Malloc(len+1);
strcpy(g_tl_dirlist[g_tl_dircount],dirpath);
g_tl_dircount++;
return;
}
for (i=0; i<numfiles; i++)
{
// form new path name
_RecurseFileTree(filelist[i]->filename,depth+1);
}
g_tl_dirlist = (char**)TL_Realloc(g_tl_dirlist,(g_tl_dircount+1)*sizeof(char*));
len = (int)strlen(dirpath);
g_tl_dirlist[g_tl_dircount] = (char*)TL_Malloc(len+1);
strcpy(g_tl_dirlist[g_tl_dircount],dirpath);
g_tl_dircount++;
}
/*****************************************************************************
TL_BuildFileTree
*****************************************************************************/
int TL_BuildFileTree(char* dirpath, char*** dirlist)
{
g_tl_dircount = 0;
g_tl_dirlist = NULL;
_RecurseFileTree(dirpath,0);
*dirlist = g_tl_dirlist;
return (g_tl_dircount);
}
/*****************************************************************************
TL_FindFiles2
*****************************************************************************/
int TL_FindFiles2(char* filemask, bool recurse, tlfile_t*** filelist)
{
char dirpath[TL_MAXPATH];
char pattern[TL_MAXPATH];
char** dirlist;
tlfile_t*** templists;
tlfile_t** list;
int* numfiles;
int numoutfiles;
int count;
int numdirs;
int i;
int j;
int k;
// get path only
strcpy(dirpath,filemask);
TL_StripFilename(dirpath);
// get pattern only
TL_StripPath(filemask,pattern);
numoutfiles = 0;
if (recurse)
{
// get the tree
numdirs = TL_BuildFileTree(dirpath,&dirlist);
if (numdirs)
{
templists = (tlfile_t***)TL_Malloc(numdirs * sizeof(tlfile_t**));
numfiles = (int*)TL_Malloc(numdirs * sizeof(int));
// iterate each directory found
for (i=0; i<numdirs; i++)
numfiles[i] = TL_GetFileList(dirlist[i],pattern,&templists[i]);
// count all the files
numoutfiles = 0;
for (i=0; i<numdirs; i++)
numoutfiles += numfiles[i];
// allocate single list
if (numoutfiles)
{
*filelist = (tlfile_t**)TL_Malloc(numoutfiles*sizeof(tlfile_t*));
k = 0;
for (i=0; i<numdirs; i++)
{
count = numfiles[i];
list = templists[i];
for (j=0; j<count; j++,k++)
{
(*filelist)[k] = list[j];
}
}
}
// free the directory lists
for (i=0; i<numdirs; i++)
{
TL_Free(dirlist[i]);
if (numfiles[i])
TL_Free(templists[i]);
}
TL_Free(dirlist);
TL_Free(templists);
TL_Free(numfiles);
}
}
else
{
numoutfiles = TL_GetFileList(dirpath,pattern,filelist);
}
return (numoutfiles);
}
/*****************************************************************************
TL_FreeFileList
*****************************************************************************/
void TL_FreeFileList(int count, tlfile_t** filelist)
{
int i;
for (i=0; i<count; i++)
{
TL_Free(filelist[i]->filename);
TL_Free(filelist[i]);
}
if (count)
TL_Free(filelist);
}
/*****************************************************************************
TL_CPUCount
*****************************************************************************/
int TL_CPUCount(void)
{
int time;
time = clock();
return (time);
}
/*****************************************************************************
TL_CPUTime
*****************************************************************************/
double TL_CPUTime(int start, int stop)
{
double duration;
duration = (double)(stop - start)/CLOCKS_PER_SEC;
return (duration);
}
/*****************************************************************************
TL_CreatePath
*****************************************************************************/
void TL_CreatePath(const char* inPath)
{
char* ptr;
char dirPath[TL_MAXPATH];
// prime and skip to first seperator
strcpy(dirPath, inPath);
ptr = strchr(dirPath, '\\');
while (ptr)
{
ptr = strchr(ptr+1, '\\');
if (ptr)
{
*ptr = '\0';
mkdir(dirPath);
*ptr = '\\';
}
}
}
/*****************************************************************************
TL_Warning
*****************************************************************************/
void TL_Warning(const char* format, ...)
{
char msg[4096];
va_list argptr;
if (g_tl_quiet)
return;
va_start(argptr, format);
vsprintf(msg, format, argptr);
va_end(argptr);
printf("WARNING: %s", msg);
}
/*****************************************************************************
TL_printf
*****************************************************************************/
void TL_printf(const char* format, ...)
{
char msg[4096];
va_list argptr;
if (g_tl_quiet)
return;
va_start(argptr, format);
vsprintf(msg, format, argptr);
va_end(argptr);
printf(msg);
}
//-----------------------------------------------------------------------------
// TL_IsWildcardMatch
//
// See if a string matches a wildcard specification that uses * or ?
//-----------------------------------------------------------------------------
bool TL_IsWildcardMatch( const char *wildcardString, const char *stringToCheck, bool caseSensitive )
{
char wcChar;
char strChar;
// use the starMatchesZero variable to determine whether an asterisk
// matches zero or more characters ( TRUE ) or one or more characters
// ( FALSE )
bool starMatchesZero = true;
while ( ( strChar = *stringToCheck ) && ( wcChar = *wildcardString ) )
{
// we only want to advance the pointers if we successfully assigned
// both of our char variables, so we'll do it here rather than in the
// loop condition itself
*stringToCheck++;
*wildcardString++;
// if this isn't a case-sensitive match, make both chars uppercase
// ( thanks to David John Fielder ( Konan ) at http://innuendo.ev.ca
// for pointing out an error here in the original code )
if ( !caseSensitive )
{
wcChar = toupper( wcChar );
strChar = toupper( strChar );
}
// check the wcChar against our wildcard list
switch ( wcChar )
{
// an asterisk matches zero or more characters
case '*' :
// do a recursive call against the rest of the string,
// until we've either found a match or the string has
// ended
if ( starMatchesZero )
*stringToCheck--;
while ( *stringToCheck )
{
if ( TL_IsWildcardMatch( wildcardString, stringToCheck++, caseSensitive ) )
return true;
}
break;
// a question mark matches any single character
case '?' :
break;
// if we fell through, we want an exact match
default :
if ( wcChar != strChar )
return false;
break;
}
}
// if we have any asterisks left at the end of the wildcard string, we can
// advance past them if starMatchesZero is TRUE ( so "blah*" will match "blah" )
while ( ( *wildcardString ) && ( starMatchesZero ) )
{
if ( *wildcardString == '*' )
wildcardString++;
else
break;
}
// if we got to the end but there's still stuff left in either of our strings,
// return false; otherwise, we have a match
if ( ( *stringToCheck ) || ( *wildcardString ) )
return false;
else
return true;
}
//-----------------------------------------------------------------------------
// TL_CopyString
//
//-----------------------------------------------------------------------------
char *TL_CopyString( const char* pString )
{
int size = strlen( pString ) + 1;
char *pNewString = (char *)TL_Malloc( size );
memcpy( pNewString, pString, size );
return pNewString;
}