Initial source commit

This commit is contained in:
Tony Bark 2025-10-03 02:19:59 -04:00
commit f1384c11ee
335 changed files with 52715 additions and 0 deletions

View file

@ -0,0 +1,450 @@
/*
* Modification History
*
* 2003-May-10 Jason Rohrer
* Created.
* Added a tokenization function.
*
* 2003-June-14 Jason Rohrer
* Added a join function.
*
* 2003-June-22 Jason Rohrer
* Added an autoSprintf function.
*
* 2003-July-27 Jason Rohrer
* Fixed bugs in autoSprintf return values for certain cases.
*
* 2003-August-12 Jason Rohrer
* Added a concatonate function.
*
* 2003-September-7 Jason Rohrer
* Changed so that split returns last part, even if it is empty.
*
* 2004-January-15 Jason Rohrer
* Added work-around for MinGW vsnprintf bug.
*
* 2006-June-2 Jason Rohrer
* Added a stringStartsWith function.
*
* 2009-September-7 Jason Rohrer
* Fixed int types.
* Switched away from StringBufferOutputStream to new function in SimpleVector.
*
* 2010-May-14 Jason Rohrer
* String parameters as const to fix warnings.
*/
#include "stringUtils.h"
#include <stdarg.h>
char *stringToLowerCase( const char *inString ) {
unsigned int length = strlen( inString );
char *returnString = stringDuplicate( inString );
for( unsigned int i=0; i<length; i++ ) {
returnString[i] = (char)tolower( returnString[i] );
}
return returnString;
}
char *stringLocateIgnoreCase( const char *inHaystack,
const char *inNeedle ) {
char *lowerHaystack = stringToLowerCase( inHaystack );
char *lowerNeedle = stringToLowerCase( inNeedle );
char *matchPointer = strstr( lowerHaystack, lowerNeedle );
char *returnString = NULL;
if( matchPointer != NULL ) {
unsigned int matchRemainderLength = strlen( matchPointer );
unsigned int haystackIndex =
strlen( inHaystack ) - matchRemainderLength;
returnString = (char*)( &( inHaystack[ haystackIndex ] ) );
}
delete [] lowerHaystack;
delete [] lowerNeedle;
return returnString;
}
int stringCompareIgnoreCase( const char *inStringA,
const char *inStringB ) {
char *lowerA = stringToLowerCase( inStringA );
char *lowerB = stringToLowerCase( inStringB );
int returnVal = strcmp( lowerA, lowerB );
delete [] lowerB;
delete [] lowerA;
return returnVal;
}
char stringStartsWith( const char *inString, const char *inPrefix ) {
unsigned int prefixLength = strlen( inPrefix );
unsigned int stringLength = strlen( inString );
if( prefixLength > stringLength ) {
return false;
}
else {
for( unsigned int i=0; i<prefixLength; i++ ) {
if( inString[i] != inPrefix[i] ) {
return false;
}
}
// all characters, up to prefix length, are equal in both strings
return true;
}
}
char **split( const char *inString, const char *inSeparator,
int *outNumParts ) {
SimpleVector<char *> *parts = new SimpleVector<char *>();
char *workingString = stringDuplicate( inString );
char *workingStart = workingString;
unsigned int separatorLength = strlen( inSeparator );
char *foundSeparator = strstr( workingString, inSeparator );
while( foundSeparator != NULL ) {
// terminate at separator
foundSeparator[0] = '\0';
parts->push_back( stringDuplicate( workingString ) );
// skip separator
workingString = &( foundSeparator[ separatorLength ] );
foundSeparator = strstr( workingString, inSeparator );
}
// add the remaining part, even if it is the empty string
parts->push_back( stringDuplicate( workingString ) );
delete [] workingStart;
*outNumParts = parts->size();
char **returnArray = parts->getElementArray();
delete parts;
return returnArray;
}
char *join( char **inStrings, int inNumParts, const char *inGlue ) {
SimpleVector<char> result;
for( int i=0; i<inNumParts - 1; i++ ) {
result.appendElementString( inStrings[i] );
result.appendElementString( inGlue );
}
// no glue after last string
result.appendElementString( inStrings[ inNumParts - 1 ] );
char *returnString = result.getElementString();
return returnString;
}
char *concatonate( const char *inStringA, const char *inStringB ) {
char **tempArray = new char*[2];
tempArray[ 0 ] = (char *)inStringA;
tempArray[ 1 ] = (char *)inStringB;
char *result = join( tempArray, 2, "" );
delete [] tempArray;
return result;
}
char *replaceOnce( const char *inHaystack, const char *inTarget,
const char *inSubstitute,
char *outFound ) {
char *haystackCopy = stringDuplicate( inHaystack );
char *fieldTargetPointer = strstr( haystackCopy, inTarget );
if( fieldTargetPointer == NULL ) {
// target not found
*outFound = false;
return haystackCopy;
}
else {
// target found
// prematurely terminate haystack copy string at
// start of target occurence
// (okay, since we're working with a copy of the haystack argument)
fieldTargetPointer[0] = '\0';
// pointer to first char after target occurrence
char *fieldPostTargetPointer =
&( fieldTargetPointer[ strlen( inTarget ) ] );
char *returnString = new char[
strlen( inHaystack )
- strlen( inTarget )
+ strlen( inSubstitute ) + 1 ];
sprintf( returnString, "%s%s%s",
haystackCopy,
inSubstitute,
fieldPostTargetPointer );
delete [] haystackCopy;
*outFound = true;
return returnString;
}
}
char *replaceAll( const char *inHaystack, const char *inTarget,
const char *inSubstitute,
char *outFound ) {
// repeatedly replace once until replacing fails
char lastFound = true;
char atLeastOneFound = false;
char *returnString = stringDuplicate( inHaystack );
while( lastFound ) {
char *nextReturnString =
replaceOnce( returnString, inTarget, inSubstitute, &lastFound );
delete [] returnString;
returnString = nextReturnString;
if( lastFound ) {
atLeastOneFound = true;
}
}
*outFound = atLeastOneFound;
return returnString;
}
char *replaceTargetListWithSubstituteList(
const char *inHaystack,
SimpleVector<char *> *inTargetVector,
SimpleVector<char *> *inSubstituteVector ) {
int numTargets = inTargetVector->size();
char *newHaystack = stringDuplicate( inHaystack );
char tagFound;
for( int i=0; i<numTargets; i++ ) {
char *newHaystackWithReplacements
= replaceAll( newHaystack,
*( inTargetVector->getElement( i ) ),
*( inSubstituteVector->getElement( i ) ),
&tagFound );
delete [] newHaystack;
newHaystack = newHaystackWithReplacements;
}
return newHaystack;
}
SimpleVector<char *> *tokenizeString( const char *inString ) {
char *tempString = stringDuplicate( inString );
char *restOfString = tempString;
SimpleVector<char *> *foundTokens = new SimpleVector<char *>();
SimpleVector<char> *currentToken = new SimpleVector<char>();
while( restOfString[0] != '\0' ) {
// characters remain
// skip whitespace
char nextChar = restOfString[0];
while( nextChar == ' ' || nextChar == '\n' ||
nextChar == '\r' || nextChar == '\t' ) {
restOfString = &( restOfString[1] );
nextChar = restOfString[0];
}
if( restOfString[0] != '\0' ) {
// a token
while( nextChar != ' ' && nextChar != '\n' &&
nextChar != '\r' && nextChar != '\t' &&
nextChar != '\0' ) {
// still not whitespace
currentToken->push_back( nextChar );
restOfString = &( restOfString[1] );
nextChar = restOfString[0];
}
// reached end of token
foundTokens->push_back( currentToken->getElementString() );
currentToken->deleteAll();
}
}
delete [] tempString;
delete currentToken;
return foundTokens;
}
char *autoSprintf( const char* inFormatString, ... ) {
unsigned int bufferSize = 50;
va_list argList;
va_start( argList, inFormatString );
char *buffer = new char[ bufferSize ];
int stringLength =
vsnprintf( buffer, bufferSize, inFormatString, argList );
va_end( argList );
if( stringLength != -1 ) {
// follows C99 standard...
// stringLength is the length of the string that would have been
// written if the buffer was big enough
// not room for string and terminating \0 in bufferSize bytes
if( (unsigned int)stringLength >= bufferSize ) {
// need to reprint with a bigger buffer
delete [] buffer;
bufferSize = (unsigned int)( stringLength + 1 );
va_list argList;
va_start( argList, inFormatString );
buffer = new char[ bufferSize ];
// can simply use vsprintf now
vsprintf( buffer, inFormatString, argList );
va_end( argList );
return buffer;
}
else {
// buffer was big enough
// trim the buffer to fit the string
char *returnString = stringDuplicate( buffer );
delete [] buffer;
return returnString;
}
}
else {
// follows old ANSI standard
// -1 means the buffer was too small
// Note that some buggy non-C99 vsnprintf implementations
// (notably MinGW)
// do not return -1 if stringLength equals bufferSize (in other words,
// if there is not enough room for the trailing \0).
// Thus, we need to check for both
// (A) stringLength == -1
// (B) stringLength == bufferSize
// below.
// keep doubling buffer size until it's big enough
while( stringLength == -1 ||
(unsigned int)stringLength == bufferSize ) {
delete [] buffer;
if( (unsigned int)stringLength == bufferSize ) {
// only occurs if vsnprintf implementation is buggy
// might as well use the information, though
// (instead of doubling the buffer size again)
bufferSize = bufferSize + 1;
}
else {
// double buffer size again
bufferSize = 2 * bufferSize;
}
va_list argList;
va_start( argList, inFormatString );
buffer = new char[ bufferSize ];
stringLength =
vsnprintf( buffer, bufferSize, inFormatString, argList );
va_end( argList );
}
// trim the buffer to fit the string
char *returnString = stringDuplicate( buffer );
delete [] buffer;
return returnString;
}
}