//========= Copyright © Valve Corporation, All rights reserved. ============// #include "pch_tier0.h" // This function is marked in the VPC file as always being optimized, even in debug // builds, because this gives a ~7% speedup on debug builds because this function is // used by the debug allocator. #define TOLOWERC( x ) (( ( x >= 'A' ) && ( x <= 'Z' ) )?( x + 32 ) : x ) #if !defined( STATIC_LINK ) #define FDECL extern "C" #else #define FDECL #endif FDECL int V_tier0_stricmp(const char *s1, const char *s2 ) { // A string is always equal to itself. This optimization is // surprisingly valuable. if ( s1 == s2 ) return 0; uint8 const *pS1 = ( uint8 const * ) s1; uint8 const *pS2 = ( uint8 const * ) s2; for(;;) { int c1 = *( pS1++ ); int c2 = *( pS2++ ); if ( c1 == c2 ) { if ( !c1 ) return 0; } else { if ( ! c2 ) { return c1 - c2; } c1 = TOLOWERC( c1 ); c2 = TOLOWERC( c2 ); if ( c1 != c2 ) { return c1 - c2; } } c1 = *( pS1++ ); c2 = *( pS2++ ); if ( c1 == c2 ) { if ( !c1 ) return 0; } else { if ( ! c2 ) { return c1 - c2; } c1 = TOLOWERC( c1 ); c2 = TOLOWERC( c2 ); if ( c1 != c2 ) { return c1 - c2; } } } } FDECL void V_tier0_strncpy( char *a, const char *b, int n ) { Assert( n >= sizeof( *a ) ); // NOTE: Never never use strncpy! Here's what it actually does, which is not what we want! // (from MSDN) // The strncpy function copies the initial count characters of strSource to strDest // and returns strDest. If count is less than or equal to the length of strSource, // a null character is not appended automatically to the copied string. If count // is greater than the length of strSource, the destination string is padded with // null characters up to length count. The behavior of strncpy is undefined // if the source and destination strings overlap. // strncpy( pDest, pSrc, maxLen ); char *pLast = a + n - 1; while ( (a < pLast) && (*b != 0) ) { *a = *b; ++a; ++b; } *a = 0; } FDECL char *V_tier0_strncat( char *pDest, const char *pSrc, int destBufferSize, int max_chars_to_copy ) { int charstocopy = 0; Assert( destBufferSize >= 0 ); int len = (int)strlen(pDest); int srclen = (int)strlen( pSrc ); if ( max_chars_to_copy <= -1 ) { charstocopy = srclen; } else { charstocopy = Min( max_chars_to_copy, (int)srclen ); } if ( len + charstocopy >= destBufferSize ) { charstocopy = destBufferSize - len - 1; } // charstocopy can end up negative if you fill a buffer and then pass in a smaller // buffer size. Yes, this actually happens. // Cast to ptrdiff_t is necessary in order to check for negative (size_t is unsigned) if ( charstocopy <= 0 ) { return pDest; } ANALYZE_SUPPRESS( 6059 ); // warning C6059: : Incorrect length parameter in call to 'strncat'. Pass the number of remaining characters, not the buffer size of 'argument 1' char *pOut = strncat( pDest, pSrc, charstocopy ); return pOut; } FDECL int V_tier0_vsnprintf( char *a, int n, const char *f, va_list l ) { int len = _vsnprintf( a, n, f, l ); if ( ( len < 0 ) || ( n > 0 && len >= n ) ) { len = n - 1; a[n - 1] = 0; } return len; } FDECL int V_tier0_snprintf( char *a, int n, const char *f, ... ) { va_list l; va_start( l, f ); int len = V_tier0_vsnprintf( a, n, f, l ); va_end( l ); return len; }