From 02485a3c853295e3b885cb337fcb99a00668f768 Mon Sep 17 00:00:00 2001 From: Dora <45337750+ddorab@users.noreply.github.com> Date: Sun, 10 Sep 2023 13:43:07 +0300 Subject: [PATCH] Update CUtlString & obsolete utlstring.cpp --- public/tier1/utlstring.h | 322 ++++++++-------- tier1/utlstring.cpp | 767 --------------------------------------- 2 files changed, 172 insertions(+), 917 deletions(-) delete mode 100644 tier1/utlstring.cpp diff --git a/public/tier1/utlstring.h b/public/tier1/utlstring.h index 7d698fec..15fad8fc 100644 --- a/public/tier1/utlstring.h +++ b/public/tier1/utlstring.h @@ -42,7 +42,7 @@ inline size_t strnlen(const char *s, size_t n) class CUtlStringToken { - unsigned int m_nHashCode; + unsigned int m_nHashCode; }; //----------------------------------------------------------------------------- @@ -59,168 +59,177 @@ public: } TUtlStringPattern; public: - CUtlString(); - CUtlString( const char *pString ); - CUtlString( const char *pString, int length ); - CUtlString( const CUtlString& string ); + // Defining AltArgumentType_t hints that associative container classes should + // also implement Find/Insert/Remove functions that take const char* params. + typedef const char* AltArgumentType_t; -#ifdef MOVE_CONSTRUCTOR_SUPPORT - // Support moving of CUtlString objects. Long live C++11 - // This move constructor will get called when appropriate, such as when - // returning objects from functions, or otherwise copying from temporaries - // which are about to be destroyed. It can also be explicitly invoked with - // std::move(). - // Move constructor: - CUtlString( CUtlString&& rhs ) - { - // Move the string pointer from the source to this -- be sure to - // zero out the source to avoid double frees. - m_pString = rhs.m_pString; - rhs.m_pString = 0; - } - // Move assignment operator: - CUtlString& operator=( CUtlString&& rhs ) - { - // Move the string pointer from the source to this -- be sure to - // zero out the source to avoid double frees. - m_pString = rhs.m_pString; - rhs.m_pString = 0; - return *this; - } -#endif + CUtlString(); + CUtlString(const char *pString); + CUtlString(const char *pString, int length); + CUtlString(const CUtlString &string); + DLL_CLASS_IMPORT CUtlString(const CBufferString &string); ~CUtlString(); - const char *Get( ) const; - void Set( const char *pValue ); - operator const char*() const; + DLL_CLASS_IMPORT CUtlString &operator=(const CBufferString &src); + CUtlString &operator=(const CUtlString &src); + CUtlString &operator=(const char *src); + + // Test for equality, both are case sensitive + DLL_CLASS_IMPORT bool operator==(const CUtlString &src) const; + DLL_CLASS_IMPORT bool operator==(const CBufferString &src) const; + + bool operator!=(const CUtlString &src) const { return !operator==(src); } + bool operator!=(const CBufferString &src) const { return !operator==(src); } + + DLL_CLASS_IMPORT char operator[](int i) const; + + DLL_CLASS_IMPORT CUtlString operator+(const char *pOther) const; + DLL_CLASS_IMPORT CUtlString operator+(const CUtlString &other) const; + DLL_CLASS_IMPORT CUtlString operator+(int rhs) const; + + DLL_CLASS_IMPORT CUtlString &operator+=(const CUtlString &rhs); + DLL_CLASS_IMPORT CUtlString &operator+=(const CBufferString &rhs); + DLL_CLASS_IMPORT CUtlString &operator+=(char c); + DLL_CLASS_IMPORT CUtlString &operator+=(int rhs); + DLL_CLASS_IMPORT CUtlString &operator+=(double rhs); + DLL_CLASS_IMPORT CUtlString &operator+=(const char *rhs); + + const char *Get() const; + operator const char *() const { return Get(); } + const char *String() const { return Get(); } + + DLL_CLASS_IMPORT void Set(const char *pValue); + + // Get this string as an absolute path (calls right through to V_MakeAbsolutePathBuffer). + DLL_CLASS_IMPORT CUtlString AbsPath(const char *pStartingDir = NULL) const; + + // Calls CBufferString::EnsureOwnedAllocation + // If the second parameter is true it will set UNK4 from EAllocationOption_t + // Always uses ALLOW_HEAP_ALLOCATION + DLL_CLASS_IMPORT void Acquire(CBufferString *pBufferString, bool bUNK4); + + DLL_CLASS_IMPORT void Append(const char *pchAddition); + DLL_CLASS_IMPORT void Append(const char *pAddition, int nChars); + + DLL_CLASS_IMPORT void Convert(wchar_t *string); + + // Uses CBufferString::ExtractFilePath + // Returns the root path to the provided directory "a/b/c/" -> "a/b" + DLL_CLASS_IMPORT CUtlString DirName() const; + + // Appends the string starting with a dot "file".DottedAppend("test") -> "file.test" + DLL_CLASS_IMPORT CUtlString DottedAppend(const char *string) const; + + // Chops the string to fit the nChop length, appending "..." as a last symbols (inclusive) + // Works only with nChop amount >= 3, otherwise string would be returned as is + DLL_CLASS_IMPORT CUtlString Ellipsify(int nChop); + + DLL_CLASS_IMPORT void FixSlashes(char cSeparator = CORRECT_PATH_SEPARATOR); + DLL_CLASS_IMPORT void FixupPathName(); + + DLL_CLASS_IMPORT int Format(const char *pFormat, ...) FMTFUNCTION(2, 3); + DLL_CLASS_IMPORT int FormatV(const char *pFormat, va_list marker); + + // Get a string with the base filename (with CBufferString::ExtractFileBase). + DLL_CLASS_IMPORT CUtlString GetBaseFilename() const; + // Empty string for those times when you need to return an empty string and + // either don't want to pay the construction cost, or are returning a + // const CUtlString& and cannot just return "". + DLL_CLASS_IMPORT static const CUtlString &GetEmptyString(); + // Get a string with the file extension + DLL_CLASS_IMPORT CUtlString GetExtensionAlloc() const; + + DLL_CLASS_IMPORT char *GetForModify(); + + DLL_CLASS_IMPORT bool IsEqual_CaseSensitive(const char *src) const; + DLL_CLASS_IMPORT bool IsEqual_FastCaseInsensitive(const char *src) const; + + // case SENSITIVE, use * for wildcard in pattern string + // nFlags checks for PATTERN_DIRECTORY + DLL_CLASS_IMPORT bool MatchesPattern(const CUtlString &Pattern, int nFlags = 0) const; + + // Works like V_ComposeFileName. + DLL_CLASS_IMPORT static CUtlString PathJoin(const char *pStr1, const char *pStr2); + + // These can be used for utlvector sorts. + static int __cdecl SortCaseInsensitive(const CUtlString *pString1, const CUtlString *pString2); + static int __cdecl SortCaseSensitive(const CUtlString *pString1, const CUtlString *pString2); + + DLL_CLASS_IMPORT void Purge(); + void Clear() { Purge(); } + + DLL_CLASS_IMPORT CUtlString Remove(const char *string, bool bCaseSensitive = true) const; + DLL_CLASS_IMPORT void RemoveDotSlashes(char replacement); + DLL_CLASS_IMPORT CUtlString RemoveFromStart(const char *search, bool bCaseSensitive = true) const; + + // Replaces all instances of specified char with a char + DLL_CLASS_IMPORT CUtlString Replace(char cSearch, char cReplace) const; + // Replaces all instances of specified char with a string + DLL_CLASS_IMPORT CUtlString Replace(const char cSearch, const char *pszReplacement) const; + // Replaces all instances of specified string with another string + DLL_CLASS_IMPORT CUtlString Replace(const char *pszSearch, const char *pszReplacement, bool bCaseSensitive = true) const; + + // Get a substring starting from the right side. + DLL_CLASS_IMPORT CUtlString Right(int32 nChars) const; + // Get a substring starting from the left side. + DLL_CLASS_IMPORT CUtlString Left(int32 nChars) const; // Set directly and don't look for a null terminator in pValue. // nChars does not include the nul and this will only copy // at most nChars (even if pValue is longer). If nChars // is >strlen(pValue) it will copy past the end, don't do it // Does nothing if pValue == String() - void SetDirect( const char *pValue, int nChars ); - - // for compatibility switching items from UtlSymbol - const char *String() const { return Get(); } - - // Returns strlen - int Length() const; - // IsEmpty() is more efficient than Length() == 0 - bool IsEmpty() const; - + DLL_CLASS_IMPORT void SetDirect(const char *pValue, int nChars); // Sets the length (used to serialize into the buffer ) // Note: If nLen != 0, then this adds an extra byte for a null-terminator. - void SetLength( int nLen ); - char *GetForModify(); - void Clear(); - void Purge(); - - // Case Change - void ToLower(); - void ToUpper(); - void Append( const char *pAddition, int nChars ); - - void Append( const char *pchAddition ); - void Append( const char chAddition ) { char temp[2] = { chAddition, 0 }; Append( temp ); } - // Strips the trailing slash - void StripTrailingSlash(); - void FixSlashes( char cSeparator = CORRECT_PATH_SEPARATOR ); - - // Trim whitespace - void TrimLeft( char cTarget ); - void TrimLeft( const char *szTargets = "\t\r\n " ); - void TrimRight( char cTarget ); - void TrimRight( const char *szTargets = "\t\r\n " ); - void Trim( char cTarget ); - void Trim( const char *szTargets = "\t\r\n " ); - - bool IsEqual_CaseSensitive( const char *src ) const; - bool IsEqual_CaseInsensitive( const char *src ) const; - - CUtlString &operator=( const CUtlString &src ); - CUtlString &operator=( const char *src ); - - // Test for equality - bool operator==( const CUtlString &src ) const; - bool operator!=( const CUtlString &src ) const { return !operator==( src ); } - - CUtlString &operator+=( const CUtlString &rhs ); - CUtlString &operator+=( const char *rhs ); - CUtlString &operator+=( char c ); - CUtlString &operator+=( int rhs ); - CUtlString &operator+=( double rhs ); - - CUtlString operator+( const char *pOther ) const; - CUtlString operator+( const CUtlString &other ) const; - CUtlString operator+( int rhs ) const; - - bool MatchesPattern( const CUtlString &Pattern, int nFlags = 0 ) const; // case SENSITIVE, use * for wildcard in pattern string - - char operator[]( int i ) const; - - int Format( const char *pFormat, ... ) FMTFUNCTION( 2, 3 ); - int FormatV( const char *pFormat, va_list marker ); - - // Defining AltArgumentType_t hints that associative container classes should - // also implement Find/Insert/Remove functions that take const char* params. - typedef const char *AltArgumentType_t; + DLL_CLASS_IMPORT void SetLength(int nLen); // Get a copy of part of the string. // If you only specify nStart, it'll go from nStart to the end. // You can use negative numbers and it'll wrap around to the start. - CUtlString Slice( int32 nStart=0, int32 nEnd=INT_MAX ) const; + DLL_CLASS_IMPORT CUtlString Slice(int32 nStart = 0, int32 nEnd = INT_MAX) const; - // Get a substring starting from the left or the right side. - CUtlString Left( int32 nChars ) const; - CUtlString Right( int32 nChars ) const; + // Get a string with the extension removed + DLL_CLASS_IMPORT CUtlString StripExtension() const; + // Get a string with the filename removed (doesn't strip the trailing slash, looks like it was intentional) + DLL_CLASS_IMPORT CUtlString StripFilename() const; + DLL_CLASS_IMPORT CUtlString StripFirstDirectory() const; + DLL_CLASS_IMPORT void StripTrailingSlash(); - // Get a string with all instances of one character replaced with another. - CUtlString Replace( char cFrom, char cTo ) const; + // Swaps this object with target + DLL_CLASS_IMPORT void Swap(CUtlString &target); - // Replace all instances of specified string with another. - CUtlString Replace( const char *pszFrom, const char *pszTo ) const; + // Case Change + DLL_CLASS_IMPORT void ToLowerFast(); + DLL_CLASS_IMPORT void ToUpperFast(); - // Get this string as an absolute path (calls right through to V_MakeAbsolutePath). - CUtlString AbsPath( const char *pStartingDir=NULL ) const; + // Trim whitespace + DLL_CLASS_IMPORT void Trim(char cTarget); + DLL_CLASS_IMPORT void Trim(const char *szTargets = "\t\r\n "); + DLL_CLASS_IMPORT void TrimLeft(char cTarget); + DLL_CLASS_IMPORT void TrimLeft(const char *szTargets = "\t\r\n "); + DLL_CLASS_IMPORT void TrimRight(char cTarget); + DLL_CLASS_IMPORT void TrimRight(const char *szTargets = "\t\r\n "); + + // param1's least significant 4 bits (param1 & 0xf) are used in a switch in V_UnicodeCaseConvert + // return value is also dependant on V_UnicodeCaseConvert + DLL_CLASS_IMPORT int UnicodeCaseConvert(int param1, EStringConvertErrorPolicy eErrorPolicy); // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt). - CUtlString UnqualifiedFilename() const; - - // Gets a string with one directory removed. Uses V_StripLastDir but strips the last slash also! - CUtlString DirName() const; + DLL_CLASS_IMPORT CUtlString UnqualifiedFilenameAlloc() const; - // Get a string with the extension removed (with V_StripExtension). - CUtlString StripExtension() const; - - // Get a string with the filename removed (uses V_UnqualifiedFileName and also strips the last slash) - CUtlString StripFilename() const; - - // Get a string with the base filename (with V_FileBase). - CUtlString GetBaseFilename() const; - - // Get a string with the file extension (with V_FileBase). - CUtlString GetExtension() const; - - // Works like V_ComposeFileName. - static CUtlString PathJoin( const char *pStr1, const char *pStr2 ); - - // These can be used for utlvector sorts. - static int __cdecl SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 ); - static int __cdecl SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 ); - - // Empty string for those times when you need to return an empty string and - // either don't want to pay the construction cost, or are returning a - // const CUtlString& and cannot just return "". - static const CUtlString &GetEmptyString(); + // Returns strlen + int Length() const; + // IsEmpty() is more efficient than Length() == 0 + bool IsEmpty() const; private: - // INTERNALS // AllocMemory allocates enough space for length characters plus a terminating zero. // Previous characters are preserved, the buffer is null-terminated, but new characters // are not touched. - void *AllocMemory( uint32 length ); + DLL_CLASS_IMPORT void *AllocMemoryBlock(uint32 length); + DLL_CLASS_IMPORT void FreeMemoryBlock(); // If m_pString is not NULL, it points to the start of the string, and the memory allocation. char *m_pString; @@ -232,13 +241,25 @@ private: // inline friend bool operator==( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) == 0; } // inline friend bool operator!=( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) != 0; } +inline CUtlString &CUtlString::operator=( const CUtlString &src ) +{ + SetDirect( src.Get(), src.Length() ); + return *this; +} + +inline CUtlString &CUtlString::operator=( const char *src ) +{ + Set( src ); + return *this; +} + inline bool operator==( const char *pString, const CUtlString &utlString ) { return utlString.IsEqual_CaseSensitive( pString ); } inline bool operator!=( const char *pString, const CUtlString &utlString ) -{ +{ return !utlString.IsEqual_CaseSensitive( pString ); } @@ -252,30 +273,28 @@ inline bool operator!=( const CUtlString &utlString, const char *pString ) return !utlString.IsEqual_CaseSensitive( pString ); } - - //----------------------------------------------------------------------------- // Inline methods //----------------------------------------------------------------------------- inline CUtlString::CUtlString() -: m_pString( NULL ) + : m_pString( NULL ) { } inline CUtlString::CUtlString( const char *pString ) -: m_pString( NULL ) + : m_pString( NULL ) { Set( pString ); } inline CUtlString::CUtlString( const char *pString, int length ) -: m_pString( NULL ) + : m_pString( NULL ) { SetDirect( pString, length ); } -inline CUtlString::CUtlString( const CUtlString& string ) -: m_pString( NULL ) +inline CUtlString::CUtlString( const CUtlString &string ) + : m_pString( NULL ) { Set( string.Get() ); } @@ -285,9 +304,18 @@ inline CUtlString::~CUtlString() Purge(); } +inline const char *CUtlString::Get() const +{ + if(!m_pString) + { + return ""; + } + return m_pString; +} + inline int CUtlString::Length() const { - if (m_pString) + if(m_pString) { return V_strlen( m_pString ); } @@ -309,12 +337,6 @@ inline int __cdecl CUtlString::SortCaseSensitive( const CUtlString *pString1, co return V_strcmp( pString1->String(), pString2->String() ); } -// Converts to c-strings -inline CUtlString::operator const char*() const -{ - return Get(); -} - //----------------------------------------------------------------------------- diff --git a/tier1/utlstring.cpp b/tier1/utlstring.cpp deleted file mode 100644 index 300766b9..00000000 --- a/tier1/utlstring.cpp +++ /dev/null @@ -1,767 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//============================================================================= - -#define __STDC_LIMIT_MACROS -#include - -#include "tier1/utlstring.h" -#include "tier1/strtools.h" -#include - -// NOTE: This has to be the last file included! -#include "tier0/memdbgon.h" - -//----------------------------------------------------------------------------- -// Simple string class. -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Either allocates or reallocates memory to the length -// -// Allocated space for length characters. It automatically adds space for the -// nul and the cached length at the start of the memory block. Will adjust -// m_pString and explicitly set the nul at the end before returning. -void *CUtlString::AllocMemory( uint32 length ) -{ - void *pMemoryBlock; - if ( m_pString ) - { - pMemoryBlock = realloc( m_pString, length + 1 ); - } - else - { - pMemoryBlock = malloc( length + 1 ); - } - m_pString = (char*)pMemoryBlock; - m_pString[ length ] = 0; - - return pMemoryBlock; -} - -//----------------------------------------------------------------------------- -void CUtlString::SetDirect( const char *pValue, int nChars ) -{ - if ( pValue && nChars > 0 ) - { - if ( pValue == m_pString ) - { - AssertMsg( nChars == Q_strlen(m_pString), "CUtlString::SetDirect does not support resizing strings in place." ); - return; // Do nothing. Realloc in AllocMemory might move pValue's location resulting in a bad memcpy. - } - - Assert( nChars <= Min( strnlen(pValue, nChars) + 1, nChars ) ); - AllocMemory( nChars ); - Q_memcpy( m_pString, pValue, nChars ); - } - else - { - Purge(); - } - -} - - -void CUtlString::Set( const char *pValue ) -{ - int length = pValue ? V_strlen( pValue ) : 0; - SetDirect( pValue, length ); -} - -// Sets the length (used to serialize into the buffer ) -void CUtlString::SetLength( int nLen ) -{ - if ( nLen > 0 ) - { -#ifdef _DEBUG - int prevLen = m_pString ? Length() : 0; -#endif - AllocMemory( nLen ); -#ifdef _DEBUG - if ( nLen > prevLen ) - { - V_memset( m_pString + prevLen, 0xEB, nLen - prevLen ); - } -#endif - } - else - { - Purge(); - } -} - -const char *CUtlString::Get( ) const -{ - if (!m_pString) - { - return ""; - } - return m_pString; -} - -char *CUtlString::GetForModify() -{ - if ( !m_pString ) - { - // In general, we optimise away small mallocs for empty strings - // but if you ask for the non-const bytes, they must be writable - // so we can't return "" here, like we do for the const version - jd - void *pMemoryBlock = malloc( 1 ); - m_pString = (char *)pMemoryBlock; - *m_pString = 0; - } - - return m_pString; -} - -char CUtlString::operator[]( int i ) const -{ - if ( !m_pString ) - return '\0'; - - if ( i >= Length() ) - { - return '\0'; - } - - return m_pString[i]; -} - -void CUtlString::Clear() -{ - Purge(); -} - -void CUtlString::Purge() -{ - free( m_pString ); - m_pString = NULL; -} - -bool CUtlString::IsEqual_CaseSensitive( const char *src ) const -{ - if ( !src ) - { - return (Length() == 0); - } - return ( V_strcmp( Get(), src ) == 0 ); -} - -bool CUtlString::IsEqual_CaseInsensitive( const char *src ) const -{ - if ( !src ) - { - return (Length() == 0); - } - return ( V_stricmp( Get(), src ) == 0 ); -} - - -void CUtlString::ToLower() -{ - if ( !m_pString ) - { - return; - } - - V_strlower( m_pString ); -} - -void CUtlString::ToUpper() -{ - if ( !m_pString ) - { - return; - } - - V_strupr( m_pString ); -} - -CUtlString &CUtlString::operator=( const CUtlString &src ) -{ - SetDirect( src.Get(), src.Length() ); - return *this; -} - -CUtlString &CUtlString::operator=( const char *src ) -{ - Set( src ); - return *this; -} - -bool CUtlString::operator==( const CUtlString &src ) const -{ - if ( IsEmpty() ) - { - if ( src.IsEmpty() ) - { - return true; - } - - return false; - } - else - { - if ( src.IsEmpty() ) - { - return false; - } - - return Q_strcmp( m_pString, src.m_pString ) == 0; - } -} - -CUtlString &CUtlString::operator+=( const CUtlString &rhs ) -{ - const int lhsLength( Length() ); - const int rhsLength( rhs.Length() ); - - if (!rhsLength) - { - return *this; - } - - const int requestedLength( lhsLength + rhsLength ); - - AllocMemory( requestedLength ); - Q_memcpy( m_pString + lhsLength, rhs.m_pString, rhsLength ); - - return *this; -} - -CUtlString &CUtlString::operator+=( const char *rhs ) -{ - const int lhsLength( Length() ); - const int rhsLength( V_strlen( rhs ) ); - const int requestedLength( lhsLength + rhsLength ); - - if (!requestedLength) - { - return *this; - } - - AllocMemory( requestedLength ); - Q_memcpy( m_pString + lhsLength, rhs, rhsLength ); - - return *this; -} - -CUtlString &CUtlString::operator+=( char c ) -{ - const int lhsLength( Length() ); - - AllocMemory( lhsLength + 1 ); - m_pString[ lhsLength ] = c; - - return *this; -} - -CUtlString &CUtlString::operator+=( int rhs ) -{ - Assert( sizeof( rhs ) == 4 ); - - char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ] - V_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs ); - tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0'; - - return operator+=( tmpBuf ); -} - -CUtlString &CUtlString::operator+=( double rhs ) -{ - char tmpBuf[ 256 ]; // How big can doubles be??? Dunno. - V_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs ); - tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0'; - - return operator+=( tmpBuf ); -} - -bool CUtlString::MatchesPattern( const CUtlString &Pattern, int nFlags ) const -{ - const char *pszSource = String(); - const char *pszPattern = Pattern.String(); - bool bExact = true; - - while( 1 ) - { - if ( ( *pszPattern ) == 0 ) - { - return ( (*pszSource ) == 0 ); - } - - if ( ( *pszPattern ) == '*' ) - { - pszPattern++; - - if ( ( *pszPattern ) == 0 ) - { - return true; - } - - bExact = false; - continue; - } - - int nLength = 0; - - while( ( *pszPattern ) != '*' && ( *pszPattern ) != 0 ) - { - nLength++; - pszPattern++; - } - - while( 1 ) - { - const char *pszStartPattern = pszPattern - nLength; - const char *pszSearch = pszSource; - - for( int i = 0; i < nLength; i++, pszSearch++, pszStartPattern++ ) - { - if ( ( *pszSearch ) == 0 ) - { - return false; - } - - if ( ( *pszSearch ) != ( *pszStartPattern ) ) - { - break; - } - } - - if ( pszSearch - pszSource == nLength ) - { - break; - } - - if ( bExact == true ) - { - return false; - } - - if ( ( nFlags & PATTERN_DIRECTORY ) != 0 ) - { - if ( ( *pszPattern ) != '/' && ( *pszSource ) == '/' ) - { - return false; - } - } - - pszSource++; - } - - pszSource += nLength; - } -} - - -int CUtlString::Format( const char *pFormat, ... ) -{ - va_list marker; - - va_start( marker, pFormat ); - int len = FormatV( pFormat, marker ); - va_end( marker ); - - return len; -} - -//-------------------------------------------------------------------------------------------------- -// This can be called from functions that take varargs. -//-------------------------------------------------------------------------------------------------- - -int CUtlString::FormatV( const char *pFormat, va_list marker ) -{ - char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer - - //va_start( marker, pFormat ); - int len = V_vsprintf_safe( tmpBuf, pFormat, marker ); - //va_end( marker ); - Set( tmpBuf ); - return len; -} - -//----------------------------------------------------------------------------- -// Strips the trailing slash -//----------------------------------------------------------------------------- -void CUtlString::StripTrailingSlash() -{ - if ( IsEmpty() ) - return; - - int nLastChar = Length() - 1; - char c = m_pString[ nLastChar ]; - if ( c == '\\' || c == '/' ) - { - SetLength( nLastChar ); - } -} - -void CUtlString::FixSlashes( char cSeparator/*=CORRECT_PATH_SEPARATOR*/ ) -{ - if ( m_pString ) - { - V_FixSlashes( m_pString, cSeparator ); - } -} - -//----------------------------------------------------------------------------- -// Trim functions -//----------------------------------------------------------------------------- -void CUtlString::TrimLeft( char cTarget ) -{ - int nIndex = 0; - - if ( IsEmpty() ) - { - return; - } - - while( m_pString[nIndex] == cTarget ) - { - ++nIndex; - } - - // We have some whitespace to remove - if ( nIndex > 0 ) - { - memcpy( m_pString, &m_pString[nIndex], Length() - nIndex ); - SetLength( Length() - nIndex ); - } -} - - -void CUtlString::TrimLeft( const char *szTargets ) -{ - int i; - - if ( IsEmpty() ) - { - return; - } - - for( i = 0; m_pString[i] != 0; i++ ) - { - bool bWhitespace = false; - - for( int j = 0; szTargets[j] != 0; j++ ) - { - if ( m_pString[i] == szTargets[j] ) - { - bWhitespace = true; - break; - } - } - - if ( !bWhitespace ) - { - break; - } - } - - // We have some whitespace to remove - if ( i > 0 ) - { - memcpy( m_pString, &m_pString[i], Length() - i ); - SetLength( Length() - i ); - } -} - - -void CUtlString::TrimRight( char cTarget ) -{ - const int nLastCharIndex = Length() - 1; - int nIndex = nLastCharIndex; - - while ( nIndex >= 0 && m_pString[nIndex] == cTarget ) - { - --nIndex; - } - - // We have some whitespace to remove - if ( nIndex < nLastCharIndex ) - { - m_pString[nIndex + 1] = 0; - SetLength( nIndex + 2 ); - } -} - - -void CUtlString::TrimRight( const char *szTargets ) -{ - const int nLastCharIndex = Length() - 1; - int i; - - for( i = nLastCharIndex; i > 0; i-- ) - { - bool bWhitespace = false; - - for( int j = 0; szTargets[j] != 0; j++ ) - { - if ( m_pString[i] == szTargets[j] ) - { - bWhitespace = true; - break; - } - } - - if ( !bWhitespace ) - { - break; - } - } - - // We have some whitespace to remove - if ( i < nLastCharIndex ) - { - m_pString[i + 1] = 0; - SetLength( i + 2 ); - } -} - - -void CUtlString::Trim( char cTarget ) -{ - TrimLeft( cTarget ); - TrimRight( cTarget ); -} - - -void CUtlString::Trim( const char *szTargets ) -{ - TrimLeft( szTargets ); - TrimRight( szTargets ); -} - - -CUtlString CUtlString::Slice( int32 nStart, int32 nEnd ) const -{ - int length = Length(); - if ( length == 0 ) - { - return CUtlString(); - } - - if ( nStart < 0 ) - nStart = length - (-nStart % length); - else if ( nStart >= length ) - nStart = length; - - if ( nEnd == INT32_MAX ) - nEnd = length; - else if ( nEnd < 0 ) - nEnd = length - (-nEnd % length); - else if ( nEnd >= length ) - nEnd = length; - - if ( nStart >= nEnd ) - return CUtlString(); - - const char *pIn = String(); - - CUtlString ret; - ret.SetDirect( pIn + nStart, nEnd - nStart ); - return ret; -} - -// Grab a substring starting from the left or the right side. -CUtlString CUtlString::Left( int32 nChars ) const -{ - return Slice( 0, nChars ); -} - -CUtlString CUtlString::Right( int32 nChars ) const -{ - return Slice( -nChars ); -} - -CUtlString CUtlString::Replace( char cFrom, char cTo ) const -{ - if (!m_pString) - { - return CUtlString(); - } - - CUtlString ret = *this; - int len = ret.Length(); - for ( int i=0; i < len; i++ ) - { - if ( ret.m_pString[i] == cFrom ) - ret.m_pString[i] = cTo; - } - - return ret; -} - -CUtlString CUtlString::Replace( const char *pszFrom, const char *pszTo ) const -{ - Assert( pszTo ); // Can be 0 length, but not null - Assert( pszFrom && *pszFrom ); // Must be valid and have one character. - - - const char *pos = V_strstr( String(), pszFrom ); - if ( !pos ) - { - return *this; - } - - const char *pFirstFound = pos; - - // count number of search string - int nSearchCount = 0; - int nSearchLength = V_strlen( pszFrom ); - while ( pos ) - { - nSearchCount++; - int nSrcOffset = ( pos - String() ) + nSearchLength; - pos = V_strstr( String() + nSrcOffset, pszFrom ); - } - - // allocate the new string - int nReplaceLength = V_strlen( pszTo ); - int nAllocOffset = nSearchCount * ( nReplaceLength - nSearchLength ); - size_t srcLength = Length(); - CUtlString strDest; - size_t destLength = srcLength + nAllocOffset; - strDest.SetLength( destLength ); - - // find and replace the search string - pos = pFirstFound; - int nDestOffset = 0; - int nSrcOffset = 0; - while ( pos ) - { - // Found an instance - int nCurrentSearchOffset = pos - String(); - int nCopyLength = nCurrentSearchOffset - nSrcOffset; - V_strncpy( strDest.GetForModify() + nDestOffset, String() + nSrcOffset, nCopyLength + 1 ); - nDestOffset += nCopyLength; - V_strncpy( strDest.GetForModify() + nDestOffset, pszTo, nReplaceLength + 1 ); - nDestOffset += nReplaceLength; - - nSrcOffset = nCurrentSearchOffset + nSearchLength; - pos = V_strstr( String() + nSrcOffset, pszFrom ); - } - - // making sure that the left over string from the source is the same size as the left over dest buffer - Assert( destLength - nDestOffset == srcLength - nSrcOffset ); - if ( destLength - nDestOffset > 0 ) - { - V_strncpy( strDest.GetForModify() + nDestOffset, String() + nSrcOffset, destLength - nDestOffset + 1 ); - } - - return strDest; -} - -CUtlString CUtlString::AbsPath( const char *pStartingDir ) const -{ - char szNew[MAX_PATH]; - V_MakeAbsolutePath( szNew, sizeof( szNew ), this->String(), pStartingDir ); - return CUtlString( szNew ); -} - -CUtlString CUtlString::UnqualifiedFilename() const -{ - const char *pFilename = V_UnqualifiedFileName( this->String() ); - return CUtlString( pFilename ); -} - -CUtlString CUtlString::DirName() const -{ - CUtlString ret( this->String() ); - V_StripLastDir( (char*)ret.Get(), ret.Length() + 1 ); - V_StripTrailingSlash( (char*)ret.Get() ); - return ret; -} - -CUtlString CUtlString::StripExtension() const -{ - char szTemp[MAX_PATH]; - V_StripExtension( String(), szTemp, sizeof( szTemp ) ); - return CUtlString( szTemp ); -} - -CUtlString CUtlString::StripFilename() const -{ - const char *pFilename = V_UnqualifiedFileName( Get() ); // NOTE: returns 'Get()' on failure, never NULL - int nCharsToCopy = pFilename - Get(); - CUtlString result; - result.SetDirect( Get(), nCharsToCopy ); - result.StripTrailingSlash(); - return result; -} - -CUtlString CUtlString::GetBaseFilename() const -{ - char szTemp[MAX_PATH]; - V_FileBase( String(), szTemp, sizeof( szTemp ) ); - return CUtlString( szTemp ); -} - -CUtlString CUtlString::GetExtension() const -{ - char szTemp[MAX_PATH]; - V_ExtractFileExtension( String(), szTemp, sizeof( szTemp ) ); - return CUtlString( szTemp ); -} - - -CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 ) -{ - char szPath[MAX_PATH]; - V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) ); - return CUtlString( szPath ); -} - -CUtlString CUtlString::operator+( const char *pOther ) const -{ - CUtlString s = *this; - s += pOther; - return s; -} - -CUtlString CUtlString::operator+( const CUtlString &other ) const -{ - CUtlString s = *this; - s += other; - return s; -} - -CUtlString CUtlString::operator+( int rhs ) const -{ - CUtlString ret = *this; - ret += rhs; - return ret; -} - -//----------------------------------------------------------------------------- -// Purpose: concatenate the provided string to our current content -//----------------------------------------------------------------------------- -void CUtlString::Append( const char *pchAddition ) -{ - (*this) += pchAddition; -} - -void CUtlString::Append( const char *pchAddition, int nChars ) -{ - nChars = Min( nChars, V_strlen( pchAddition ) ); - - const int lhsLength( Length() ); - const int rhsLength( nChars ); - const int requestedLength( lhsLength + rhsLength ); - - AllocMemory( requestedLength ); - const int allocatedLength( requestedLength ); - const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength ); - memcpy( GetForModify() + lhsLength, pchAddition, copyLength ); - m_pString[ allocatedLength ] = '\0'; -} - -// Shared static empty string. -const CUtlString &CUtlString::GetEmptyString() -{ - static const CUtlString s_emptyString; - - return s_emptyString; -}