csgo-2018-source/tier0/tier0_strtools.cpp
2021-07-24 21:11:47 -07:00

150 lines
3.3 KiB
C++

//========= 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;
}