//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //===========================================================================// #ifndef TIER1_STRTOOLS_H #define TIER1_STRTOOLS_H #include "../tier0/platform.h" #include #include #ifdef _WIN32 #pragma once #elif POSIX #include #include #include #endif #include #include #ifdef _WIN64 #define str_size unsigned int #else #define str_size size_t #endif template class CUtlMemory; template class CUtlVector; //----------------------------------------------------------------------------- // Portable versions of standard string functions //----------------------------------------------------------------------------- void _V_memset(const char *file, int line, void *dest, int fill, int count); void _V_memcpy(const char *file, int line, void *dest, const void *src, int count); void _V_memmove(const char *file, int line, void *dest, const void *src, int count); int _V_memcmp(const char *file, int line, const void *m1, const void *m2, int count); int _V_strlen(const char *file, int line, const char *str); void _V_strcpy(const char *file, int line, char *dest, const char *src); char *_V_strrchr(const char *file, int line, const char *s, char c); int _V_strcmp(const char *file, int line, const char *s1, const char *s2); int _V_wcscmp(const char *file, int line, const wchar_t *s1, const wchar_t *s2); char *_V_strstr(const char *file, int line, const char *s1, const char *search); int _V_wcslen(const char *file, int line, const wchar_t *pwch); wchar_t *_V_wcslower(const char *file, int line, wchar_t *start); wchar_t *_V_wcsupr(const char *file, int line, wchar_t *start); // ASCII-optimized functions which fall back to CRT only when necessary char *V_strupr(char *start); char *V_strlower(char *start); int V_stricmp(const char *s1, const char *s2); // int V_strncmp( const char *s1, const char *s2, int count ); #define V_strncmp strncmp int V_strnicmp(const char *s1, const char *s2, int n); #ifdef POSIX inline char *strupr(char *start) { return V_strupr(start); } inline char *strlwr(char *start) { return V_strlower(start); } inline wchar_t *_wcslwr(wchar_t *start) { wchar_t *str = start; while (str && *str) { *str = (wchar_t)towlower(static_cast(*str)); str++; } return start; }; inline wchar_t *_wcsupr(wchar_t *start) { wchar_t *str = start; while (str && *str) { *str = (wchar_t)towupper(static_cast(*str)); str++; } return start; }; #endif // POSIX #ifdef _DEBUG #define V_memset(dest, fill, count) \ _V_memset(__FILE__, __LINE__, (dest), (fill), (count)) #define V_memcpy(dest, src, count) \ _V_memcpy(__FILE__, __LINE__, (dest), (src), (count)) #define V_memmove(dest, src, count) \ _V_memmove(__FILE__, __LINE__, (dest), (src), (count)) #define V_memcmp(m1, m2, count) \ _V_memcmp(__FILE__, __LINE__, (m1), (m2), (count)) #define V_strlen(str) _V_strlen(__FILE__, __LINE__, (str)) #define V_strcpy(dest, src) _V_strcpy(__FILE__, __LINE__, (dest), (src)) #define V_strrchr(s, c) _V_strrchr(__FILE__, __LINE__, (s), (c)) #define V_strcmp(s1, s2) _V_strcmp(__FILE__, __LINE__, (s1), (s2)) #define V_wcscmp(s1, s2) _V_wcscmp(__FILE__, __LINE__, (s1), (s2)) #define V_strstr(s1, search) _V_strstr(__FILE__, __LINE__, (s1), (search)) #define V_wcslen(pwch) _V_wcslen(__FILE__, __LINE__, (pwch)) #define V_wcslower(start) _V_wcslower(__FILE__, __LINE__, (start)) #define V_wcsupr(start) _V_wcsupr(__FILE__, __LINE__, (start)) #else inline void V_memset(void *dest, int fill, int count) { memset(dest, fill, count); } inline void V_memcpy(void *dest, const void *src, int count) { memcpy(dest, src, count); } inline void V_memmove(void *dest, const void *src, int count) { memmove(dest, src, count); } inline int V_memcmp(const void *m1, const void *m2, int count) { return memcmp(m1, m2, count); } inline int V_strlen(const char *str) { return (int)strlen(str); } inline void V_strcpy(char *dest, const char *src) { strcpy(dest, src); } inline int V_wcslen(const wchar_t *pwch) { return (int)wcslen(pwch); } inline char *V_strrchr(const char *s, char c) { return (char *)strrchr(s, c); } inline int V_strcmp(const char *s1, const char *s2) { return strcmp(s1, s2); } inline int V_wcscmp(const wchar_t *s1, const wchar_t *s2) { return wcscmp(s1, s2); } inline char *V_strstr(const char *s1, const char *search) { return (char *)strstr(s1, search); } inline wchar_t *V_wcslower(wchar_t *start) { return _wcslwr(start); } inline wchar_t *V_wcsupr(wchar_t *start) { return _wcsupr(start); } #endif int V_atoi(const char *str); int64 V_atoi64(const char *str); uint64 V_atoui64(const char *str); float V_atof(const char *str); char *V_stristr(char *pStr, const char *pSearch); const char *V_stristr(const char *pStr, const char *pSearch); // const char* V_strnistr( const char* pStr, const char* pSearch, int n ); #define V_strnistr 0 const char *V_strnchr(const char *pStr, char c, int n); inline int V_strcasecmp(const char *s1, const char *s2) { return V_stricmp(s1, s2); } inline int V_strncasecmp(const char *s1, const char *s2, int n) { return V_strnicmp(s1, s2, n); } void V_qsort_s(void *base, size_t num, size_t width, int(__cdecl *compare)(void *, const void *, const void *), void *context); // returns string immediately following prefix, (ie str+strlen(prefix)) or NULL // if prefix not found const char *StringAfterPrefix(const char *str, const char *prefix); const char *StringAfterPrefixCaseSensitive(const char *str, const char *prefix); inline bool StringHasPrefix(const char *str, const char *prefix) { return StringAfterPrefix(str, prefix) != NULL; } inline bool StringHasPrefixCaseSensitive(const char *str, const char *prefix) { return StringAfterPrefixCaseSensitive(str, prefix) != NULL; } template inline bool _V_strEndsWithInner(const char *pStr, const char *pSuffix) { int nSuffixLen = V_strlen(pSuffix); int nStringLen = V_strlen(pStr); if (nSuffixLen == 0) return true; // All strings end with the empty string (matches Java & // .NET behaviour) if (nStringLen < nSuffixLen) return false; pStr += nStringLen - nSuffixLen; if (CASE_SENSITIVE) return !V_strcmp(pStr, pSuffix); else return !V_stricmp(pStr, pSuffix); } // Does 'pStr' end with 'pSuffix'? (case sensitive/insensitive variants) inline bool V_strEndsWith(const char *pStr, const char *pSuffix) { return _V_strEndsWithInner(pStr, pSuffix); } inline bool V_striEndsWith(const char *pStr, const char *pSuffix) { return _V_strEndsWithInner(pStr, pSuffix); } // Normalizes a float string in place. // (removes leading zeros, trailing zeros after the decimal point, and the // decimal point itself where possible) void V_normalizeFloatString(char *pFloat); // this is locale-unaware and therefore faster version of standard isdigit() // It also avoids sign-extension errors. inline bool V_isdigit(char c) { return c >= '0' && c <= '9'; } // The islower/isdigit/etc. functions all expect a parameter that is either // 0-0xFF or EOF. It is easy to violate this constraint simply by passing // 'char' to these functions instead of unsigned char. // The V_ functions handle the char/unsigned char mismatch by taking a // char parameter and casting it to unsigned char so that chars with the // sign bit set will be zero extended instead of sign extended. // Not that EOF cannot be passed to these functions. // // These functions could also be used for optimizations if locale // considerations make some of the CRT functions slow. //#undef isdigit // In case this is implemented as a macro //#define isdigit use_V_isdigit_instead_of_isdigit inline bool V_isalpha(char c) { return isalpha((unsigned char)c) != 0; } //#undef isalpha //#define isalpha use_V_isalpha_instead_of_isalpha inline bool V_isalnum(char c) { return isalnum((unsigned char)c) != 0; } //#undef isalnum //#define isalnum use_V_isalnum_instead_of_isalnum inline bool V_isprint(char c) { return isprint((unsigned char)c) != 0; } //#undef isprint //#define isprint use_V_isprint_instead_of_isprint inline bool V_isxdigit(char c) { return isxdigit((unsigned char)c) != 0; } //#undef isxdigit //#define isxdigit use_V_isxdigit_instead_of_isxdigit inline bool V_ispunct(char c) { return ispunct((unsigned char)c) != 0; } //#undef ispunct //#define ispunct use_V_ispunct_instead_of_ispunct inline bool V_isgraph(char c) { return isgraph((unsigned char)c) != 0; } //#undef isgraph //#define isgraph use_V_isgraph_instead_of_isgraph inline bool V_isupper(char c) { return isupper((unsigned char)c) != 0; } //#undef isupper //#define isupper use_V_isupper_instead_of_isupper inline bool V_islower(char c) { return islower((unsigned char)c) != 0; } //#undef islower //#define islower use_V_islower_instead_of_islower inline bool V_iscntrl(char c) { return iscntrl((unsigned char)c) != 0; } //#undef iscntrl //#define iscntrl use_V_iscntrl_instead_of_iscntrl inline bool V_isspace(char c) { return isspace((unsigned char)c) != 0; } //#undef isspace //#define isspace use_V_isspace_instead_of_isspace // These are versions of functions that guarantee NULL termination. // // maxLen is the maximum number of bytes in the destination string. // pDest[maxLen-1] is always NULL terminated if pSrc's length is >= maxLen. // // This means the last parameter can usually be a sizeof() of a string. #define V_strncpy strncpy // Ultimate safe strcpy function, for arrays only -- buffer size is inferred by // the compiler template void V_strcpy_safe(OUT_Z_ARRAY char (&pDest)[maxLenInChars], const char *pSrc) { V_strncpy(pDest, pSrc, (int)maxLenInChars); } // A function which duplicates a string using new[] to allocate the new string. inline char *V_strdup(const char *pSrc) { int nLen = V_strlen(pSrc); char *pResult = new char[nLen + 1]; V_memcpy(pResult, pSrc, nLen + 1); return pResult; } void V_wcsncpy(OUT_Z_BYTECAP(maxLenInBytes) wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes); template void V_wcscpy_safe(OUT_Z_ARRAY wchar_t (&pDest)[maxLenInChars], wchar_t const *pSrc) { V_wcsncpy(pDest, pSrc, maxLenInChars * sizeof(*pDest)); } #define COPY_ALL_CHARACTERS -1 char *V_strncat(INOUT_Z_CAP(cchDest) char *pDest, const char *pSrc, size_t cchDest, int max_chars_to_copy = COPY_ALL_CHARACTERS); template char *V_strcat_safe(INOUT_Z_ARRAY char (&pDest)[cchDest], const char *pSrc, int nMaxCharsToCopy = COPY_ALL_CHARACTERS) { return V_strncat(pDest, pSrc, (int)cchDest, nMaxCharsToCopy); } wchar_t *V_wcsncat(INOUT_Z_CAP(cchDest) wchar_t *pDest, const wchar_t *pSrc, size_t cchDest, int nMaxCharsToCopy = COPY_ALL_CHARACTERS); template wchar_t *V_wcscat_safe(INOUT_Z_ARRAY wchar_t (&pDest)[cchDest], const wchar_t *pSrc, int nMaxCharsToCopy = COPY_ALL_CHARACTERS) { return V_wcsncat(pDest, pSrc, (int)cchDest, nMaxCharsToCopy); } char *V_strnlwr(INOUT_Z_CAP(cchBuf) char *pBuf, size_t cchBuf); template char *V_strlwr_safe(INOUT_Z_ARRAY char (&pBuf)[cchDest]) { return _V_strnlwr(pBuf, (int)cchDest); } // Unicode string conversion policies - what to do if an illegal sequence is // encountered enum EStringConvertErrorPolicy { _STRINGCONVERTFLAG_SKIP = 1, _STRINGCONVERTFLAG_FAIL = 2, _STRINGCONVERTFLAG_ASSERT = 4, STRINGCONVERT_REPLACE = 0, STRINGCONVERT_SKIP = _STRINGCONVERTFLAG_SKIP, STRINGCONVERT_FAIL = _STRINGCONVERTFLAG_FAIL, STRINGCONVERT_ASSERT_REPLACE = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_REPLACE, STRINGCONVERT_ASSERT_SKIP = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_SKIP, STRINGCONVERT_ASSERT_FAIL = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_FAIL, }; // Unicode (UTF-8, UTF-16, UTF-32) fundamental conversion functions. bool Q_IsValidUChar32(uchar32 uValue); int Q_UChar32ToUTF8Len(uchar32 uValue); int Q_UChar32ToUTF8(uchar32 uValue, char *pOut); int Q_UChar32ToUTF16Len(uchar32 uValue); int Q_UChar32ToUTF16(uchar32 uValue, uchar16 *pOut); // Validate that a Unicode string is well-formed and contains only valid code // points bool Q_UnicodeValidate(const char *pUTF8); bool Q_UnicodeValidate(const uchar16 *pUTF16); bool Q_UnicodeValidate(const uchar32 *pUTF32); // Returns length of string in Unicode code points (printed glyphs or // non-printing characters) int Q_UnicodeLength(const char *pUTF8); int Q_UnicodeLength(const uchar16 *pUTF16); int Q_UnicodeLength(const uchar32 *pUTF32); // Returns length of string in elements, not characters! These are analogous to // Q_strlen and Q_wcslen inline int Q_strlen16(const uchar16 *puc16) { int nElems = 0; while (puc16[nElems]) ++nElems; return nElems; } inline int Q_strlen32(const uchar32 *puc32) { int nElems = 0; while (puc32[nElems]) ++nElems; return nElems; } // Repair invalid Unicode strings by dropping truncated characters and fixing // improperly-double-encoded UTF-16 sequences. Unlike conversion functions which // replace with '?' by default, a repair operation assumes that you know that // something is wrong with the string (eg, mid-sequence truncation) and you just // want to do the best possible job of cleaning it up. You can pass a REPLACE or // FAIL policy if you would prefer to replace characters with '?' or clear the // entire string. Returns nonzero on success, or 0 if the policy is FAIL and an // invalid sequence was found. int Q_UnicodeRepair(char *pUTF8, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP); int Q_UnicodeRepair(uchar16 *pUTF16, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP); int Q_UnicodeRepair(uchar32 *pUTF32, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_SKIP); // Advance pointer forward by N Unicode code points (printed glyphs or // non-printing characters), stopping at terminating null if encountered. char *Q_UnicodeAdvance(char *pUTF8, int nCharacters); uchar16 *Q_UnicodeAdvance(uchar16 *pUTF16, int nCharactersnCharacters); uchar32 *Q_UnicodeAdvance(uchar32 *pUTF32, int nChars); inline const char *Q_UnicodeAdvance(const char *pUTF8, int nCharacters) { return Q_UnicodeAdvance((char *)pUTF8, nCharacters); } inline const uchar16 *Q_UnicodeAdvance(const uchar16 *pUTF16, int nCharacters) { return Q_UnicodeAdvance((uchar16 *)pUTF16, nCharacters); } inline const uchar32 *Q_UnicodeAdvance(const uchar32 *pUTF32, int nCharacters) { return Q_UnicodeAdvance((uchar32 *)pUTF32, nCharacters); } // Truncate to maximum of N Unicode code points (printed glyphs or non-printing // characters) inline void Q_UnicodeTruncate(char *pUTF8, int nCharacters) { *Q_UnicodeAdvance(pUTF8, nCharacters) = 0; } inline void Q_UnicodeTruncate(uchar16 *pUTF16, int nCharacters) { *Q_UnicodeAdvance(pUTF16, nCharacters) = 0; } inline void Q_UnicodeTruncate(uchar32 *pUTF32, int nCharacters) { *Q_UnicodeAdvance(pUTF32, nCharacters) = 0; } // Conversion between Unicode string types (UTF-8, UTF-16, UTF-32). Deals with // bytes, not element counts, to minimize harm from the programmer mistakes // which continue to plague our wide-character string code. Returns the number // of bytes written to the output, or if output is NULL, the number of bytes // required. int Q_UTF8ToUTF16( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF8ToUTF32( const char *pUTF8, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF16ToUTF8( const uchar16 *pUTF16, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF16ToUTF32( const uchar16 *pUTF16, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF32ToUTF8( const uchar32 *pUTF32, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF32ToUTF16( const uchar32 *pUTF32, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); // This is disgusting and exist only easily to facilitate having 16-bit and // 32-bit wchar_t's on different platforms int Q_UTF32ToUTF32( const uchar32 *pUTF32Source, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32Dest, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); // Conversion between count-limited UTF-n character arrays, including any // potential NULL characters. Output has a terminating NULL for safety; strip // the last character if you want an unterminated string. Returns the number of // bytes written to the output, or if output is NULL, the number of bytes // required. int Q_UTF8CharsToUTF16( const char *pUTF8, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF8CharsToUTF32( const char *pUTF8, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF16CharsToUTF8( const uchar16 *pUTF16, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF16CharsToUTF32( const uchar16 *pUTF16, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF32CharsToUTF8( const uchar32 *pUTF32, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); int Q_UTF32CharsToUTF16( const uchar32 *pUTF32, int nElements, OUT_Z_BYTECAP(cubDestSizeInBytes) uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy = STRINGCONVERT_ASSERT_REPLACE); // Decode a single UTF-8 character to a uchar32, returns number of UTF-8 bytes // parsed int Q_UTF8ToUChar32(const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut); // Decode a single UTF-16 character to a uchar32, returns number of UTF-16 // characters (NOT BYTES) consumed int Q_UTF16ToUChar32(const uchar16 *pUTF16, uchar32 &uValueOut, bool &bErrorOut); // NOTE: WString means either UTF32 or UTF16 depending on the platform and // compiler settings. #if defined(_MSC_VER) || defined(_WIN32) #define Q_UTF8ToWString Q_UTF8ToUTF16 #define Q_UTF8CharsToWString Q_UTF8CharsToUTF16 #define Q_UTF32ToWString Q_UTF32ToUTF16 #define Q_WStringToUTF8 Q_UTF16ToUTF8 #define Q_WStringCharsToUTF8 Q_UTF16CharsToUTF8 #define Q_WStringToUTF32 Q_UTF16ToUTF32 #else #define Q_UTF8ToWString Q_UTF8ToUTF32 #define Q_UTF8CharsToWString Q_UTF8CharsToUTF32 #define Q_UTF32ToWString Q_UTF32ToUTF32 #define Q_WStringToUTF8 Q_UTF32ToUTF8 #define Q_WStringCharsToUTF8 Q_UTF32CharsToUTF8 #define Q_WStringToUTF32 Q_UTF32ToUTF32 #endif // These are legacy names which don't make a lot of sense but are used // everywhere. Prefer the WString convention wherever possible #define V_UTF8ToUnicode Q_UTF8ToWString #define V_UnicodeToUTF8 Q_WStringToUTF8 #ifdef WIN32 // This function is ill-defined as it relies on the current ANSI code page. // Currently Win32 only for tools. int Q_LocaleSpecificANSIToUTF8(const char *pANSI, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes); #endif // Windows-1252 is mostly the same as ISO Latin-1, and probably what you want if // you are saddled with an 8-bit ANSI string that originated on a Windows // system. int Q_Windows1252CharsToUTF8(const char *pchSrc, int cchSrc, OUT_Z_BYTECAP(cchDestUTF8) char *pchDestUTF8, int cchDestUTF8); // CP 437 is used for VGA console text and some old-school file formats such as // ZIP. It is also known as the "IBM PC OEM code page" and various related // names. You probably don't want to use this function unless you know for a // fact that you're dealing with old-school OEM code pages. Otherwise try the // Windows-1252 function above. int Q_CP437CharsToUTF8(const char *pchSrc, int cchSrc, OUT_Z_BYTECAP(cchDestUTF8) char *pchDestUTF8, int cchDestUTF8); // replaces characters in a UTF8 string with their identical-looking equivalent // (non-roundtrippable) // // older version of API uses a small homoglyph table; newer version uses a // larger one // // strings using old version are baked into the database, so we won't toss it // quite yet, but don't use it for new features. int Q_NormalizeUTF8Old(const char *pchSrc, OUT_Z_CAP(cchDest) char *pchDest, int cchDest); int Q_NormalizeUTF8(const char *pchSrc, OUT_Z_CAP(cchDest) char *pchDest, int cchDest); //----------------------------------------------------------------------------- // Purpose: replaces characters in a UTF8 string with similar-looking // equivalents. Only replaces with ASCII characters.. non-recognized characters // will be replaced with ? This operation is destructive (i.e. you can't // roundtrip through the normalized form). //----------------------------------------------------------------------------- template int Q_NormalizeUTF8ToASCII(OUT_Z_ARRAY char (&pchDest)[maxLenInChars], const char *pchSrc) { int nResult = Q_NormalizeUTF8(pchSrc, pchDest, maxLenInChars); // replace non ASCII characters with ? for (int i = 0; i < nResult; i++) { if (pchDest[i] > 127 || pchDest[i] < 0) { pchDest[i] = '?'; } } return nResult; } // UNDONE: Find a non-compiler-specific way to do this #ifdef _WIN32 #ifndef _VA_LIST_DEFINED #ifdef _M_ALPHA struct va_list { char *a0; /* pointer to first homed integer argument */ int offset; /* byte offset of next parameter */ }; #else // !_M_ALPHA typedef char *va_list; #endif // !_M_ALPHA #define _VA_LIST_DEFINED #endif // _VA_LIST_DEFINED #elif POSIX #include #endif #ifdef _WIN32 #define CORRECT_PATH_SEPARATOR '\\' #define CORRECT_PATH_SEPARATOR_S "\\" #define INCORRECT_PATH_SEPARATOR '/' #define INCORRECT_PATH_SEPARATOR_S "/" #elif POSIX #define CORRECT_PATH_SEPARATOR '/' #define CORRECT_PATH_SEPARATOR_S "/" #define INCORRECT_PATH_SEPARATOR '\\' #define INCORRECT_PATH_SEPARATOR_S "\\" #endif int V_vsnprintf(OUT_Z_CAP(maxLenInCharacters) char *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char *pFormat, va_list params); template int V_vsprintf_safe(OUT_Z_ARRAY char (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char *pFormat, va_list params) { return V_vsnprintf(pDest, maxLenInCharacters, pFormat, params); } #define V_snprintf snprintf // int V_snprintf( OUT_Z_CAP(maxLenInChars) char *pDest, int maxLenInChars, // PRINTF_FORMAT_STRING const char *pFormat, ... ) FMTFUNCTION( 3, 4 ); // gcc insists on only having format annotations on declarations, not // definitions, which is why I have both. template int V_sprintf_safe(OUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ...) FMTFUNCTION(2, 3); template int V_sprintf_safe(OUT_Z_ARRAY char (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const char *pFormat, ...) { va_list params; va_start(params, pFormat); int result = V_vsnprintf(pDest, maxLenInChars, pFormat, params); va_end(params); return result; } int V_vsnwprintf(OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, va_list params); template int V_vswprintf_safe(OUT_Z_ARRAY wchar_t (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const wchar_t *pFormat, va_list params) { return V_vsnwprintf(pDest, maxLenInCharacters, pFormat, params); } int V_vsnprintfRet(OUT_Z_CAP(maxLenInCharacters) char *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const char *pFormat, va_list params, bool *pbTruncated); template int V_vsprintfRet_safe(OUT_Z_ARRAY char (&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char *pFormat, va_list params, bool *pbTruncated) { return V_vsnprintfRet(pDest, maxLenInCharacters, pFormat, params, pbTruncated); } // FMTFUNCTION can only be used on ASCII functions, not wide-char functions. int V_snwprintf(OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, ...); template int V_swprintf_safe(OUT_Z_ARRAY wchar_t (&pDest)[maxLenInChars], PRINTF_FORMAT_STRING const wchar_t *pFormat, ...) { va_list params; va_start(params, pFormat); int result = V_vsnwprintf(pDest, maxLenInChars, pFormat, params); va_end(params); return result; } // Prints out a pretified memory counter string value ( e.g., 7,233.27 Mb, // 1,298.003 Kb, 127 bytes ) char *V_pretifymem(float value, int digitsafterdecimal = 2, bool usebinaryonek = false); // Prints out a pretified integer with comma separators (eg, 7,233,270,000) char *V_pretifynum(int64 value); int _V_UCS2ToUnicode(const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, int cubDestSizeInBytes); template inline int V_UCS2ToUnicode(const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) wchar_t *pUnicode, T cubDestSizeInBytes) { return _V_UCS2ToUnicode(pUCS2, pUnicode, static_cast(cubDestSizeInBytes)); } int _V_UCS2ToUTF8(const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, int cubDestSizeInBytes); template inline int V_UCS2ToUTF8(const ucs2 *pUCS2, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUTF8, T cubDestSizeInBytes) { return _V_UCS2ToUTF8(pUCS2, pUTF8, static_cast(cubDestSizeInBytes)); } int _V_UnicodeToUCS2(const wchar_t *pUnicode, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, int cubDestSizeInBytes); template inline int V_UnicodeToUCS2(const wchar_t *pUnicode, T cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) char *pUCS2, U cubDestSizeInBytes) { return _V_UnicodeToUCS2(pUnicode, static_cast(cubSrcInBytes), pUCS2, static_cast(cubDestSizeInBytes)); } int _V_UTF8ToUCS2(const char *pUTF8, int cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, int cubDestSizeInBytes); template inline int V_UTF8ToUCS2(const char *pUTF8, T cubSrcInBytes, OUT_Z_BYTECAP(cubDestSizeInBytes) ucs2 *pUCS2, U cubDestSizeInBytes) { return _V_UTF8ToUCS2(pUTF8, static_cast(cubSrcInBytes), pUCS2, static_cast(cubDestSizeInBytes)); } // strips leading and trailing whitespace; returns true if any characters were // removed. UTF-8 and UTF-16 versions. bool Q_StripPrecedingAndTrailingWhitespace(char *pch); bool Q_StripPrecedingAndTrailingWhitespaceW(wchar_t *pwch); // strips leading and trailing whitespace, also taking "aggressive" characters // like punctuation spaces, non-breaking spaces, composing characters, and so on bool Q_AggressiveStripPrecedingAndTrailingWhitespace(char *pch); bool Q_AggressiveStripPrecedingAndTrailingWhitespaceW(wchar_t *pwch); bool Q_RemoveAllEvilCharacters(char *pch); // Functions for converting hexidecimal character strings back into binary data // etc. // // e.g., // int output; // V_hextobinary( "ffffffff", 8, &output, sizeof( output ) ); // would make output == 0xfffffff or -1 // Similarly, // char buffer[ 9 ]; // V_binarytohex( &output, sizeof( output ), buffer, sizeof( buffer ) ); // would put "ffffffff" into buffer (note null terminator!!!) unsigned char V_nibble(char c); void V_hextobinary(char const *in, int numchars, byte *out, int maxoutputbytes); void V_binarytohex(const byte *in, int inputbytes, char *out, int outsize); // Tools for working with filenames // Extracts the base name of a file (no path, no extension, assumes '/' or '\' // as path separator) void V_FileBase(const char *in, char *out, int maxlen); // Remove the final characters of ppath if it's '\' or '/'. void V_StripTrailingSlash(char *ppath); // Remove any extension from in and return resulting string in out void V_StripExtension(const char *in, char *out, int outLen); // Make path end with extension if it doesn't already have an extension void V_DefaultExtension(char *path, const char *extension, int pathStringLength); // Strips any current extension from path and ensures that extension is the new // extension void V_SetExtension(char *path, const char *extension, int pathStringLength); // Removes any filename from path ( strips back to previous / or \ character ) void V_StripFilename(char *path); // Remove the final directory from the path bool V_StripLastDir(char *dirName, int maxlen); // Returns a pointer to the unqualified file name (no path) of a file name const char *V_UnqualifiedFileName(const char *in); // Given a path and a filename, composes "path\filename", inserting the (OS // correct) separator if necessary void V_ComposeFileName(const char *path, const char *filename, char *dest, int destSize); // Copy out the path except for the stuff after the final pathseparator bool V_ExtractFilePath(const char *path, char *dest, int destSize); // Copy out the file extension into dest void V_ExtractFileExtension(const char *path, char *dest, int destSize); const char *V_GetFileExtension(const char *path); // returns a pointer to just the filename part of the path // (everything after the last path seperator) const char *V_GetFileName(const char *path); // This removes "./" and "../" from the pathname. pFilename should be a full // pathname. Also incorporates the behavior of V_FixSlashes and optionally // V_FixDoubleSlashes. Returns false if it tries to ".." past the root directory // in the drive (in which case it is an invalid path). bool V_RemoveDotSlashes(char *pFilename, char separator = CORRECT_PATH_SEPARATOR, bool bRemoveDoubleSlashes = true); // If pPath is a relative path, this function makes it into an absolute path // using the current working directory as the base, or pStartingDir if it's // non-NULL. Returns false if it runs out of room in the string, or if pPath // tries to ".." past the root directory. void V_MakeAbsolutePath(char *pOut, int outLen, const char *pPath, const char *pStartingDir = NULL); // Creates a relative path given two full paths // The first is the full path of the file to make a relative path for. // The second is the full path of the directory to make the first file relative // to Returns false if they can't be made relative (on separate drives, for // example) bool V_MakeRelativePath(const char *pFullPath, const char *pDirectory, char *pRelativePath, int nBufLen); // Fixes up a file name, removing dot slashes, fixing slashes, converting to // lowercase, etc. void V_FixupPathName(OUT_Z_CAP(nOutLen) char *pOut, size_t nOutLen, const char *pPath); // Adds a path separator to the end of the string if there isn't one already. // Returns false if it would run out of space. void V_AppendSlash(INOUT_Z_CAP(strSize) char *pStr, int strSize); // Returns true if the path is an absolute path. bool V_IsAbsolutePath(IN_Z const char *pPath); // Scans pIn and replaces all occurences of pMatch with pReplaceWith. // Writes the result to pOut. // Returns true if it completed successfully. // If it would overflow pOut, it fills as much as it can and returns false. bool V_StrSubst(IN_Z const char *pIn, IN_Z const char *pMatch, const char *pReplaceWith, OUT_Z_CAP(outLen) char *pOut, int outLen, bool bCaseSensitive = false); // Split the specified string on the specified separator. // Returns a list of strings separated by pSeparator. // You are responsible for freeing the contents of outStrings (call // outStrings.PurgeAndDeleteElements). void V_SplitString(IN_Z const char *pString, IN_Z const char *pSeparator, CUtlVector > &outStrings); // Just like V_SplitString, but it can use multiple possible separators. void V_SplitString2(IN_Z const char *pString, const char **pSeparators, int nSeparators, CUtlVector > &outStrings); // Returns false if the buffer is not large enough to hold the working directory // name. bool V_GetCurrentDirectory(OUT_Z_CAP(maxLen) char *pOut, int maxLen); // Set the working directory thus. bool V_SetCurrentDirectory(const char *pDirName); // This function takes a slice out of pStr and stores it in pOut. // It follows the Python slice convention: // Negative numbers wrap around the string (-1 references the last character). // Large numbers are clamped to the end of the string. void V_StrSlice(const char *pStr, int firstChar, int lastCharNonInclusive, OUT_Z_CAP(outSize) char *pOut, int outSize); // Chop off the left nChars of a string. void V_StrLeft(const char *pStr, int nChars, OUT_Z_CAP(outSize) char *pOut, int outSize); // Chop off the right nChars of a string. void V_StrRight(const char *pStr, int nChars, OUT_Z_CAP(outSize) char *pOut, int outSize); // change "special" characters to have their c-style backslash sequence. like // \n, \r, \t, ", etc. returns a pointer to a newly allocated string, which you // must delete[] when finished with. char *V_AddBackSlashesToSpecialChars(char const *pSrc); // Force slashes of either type to be = separator character void V_FixSlashes(char *pname, char separator = CORRECT_PATH_SEPARATOR); // This function fixes cases of filenames like materials\\blah.vmt or // somepath\otherpath\\ and removes the extra double slash. void V_FixDoubleSlashes(char *pStr); // Convert multibyte to wchar + back // Specify -1 for nInSize for null-terminated string void V_strtowcs(const char *pString, int nInSize, OUT_Z_BYTECAP(nOutSizeInBytes) wchar_t *pWString, int nOutSizeInBytes); void V_wcstostr(const wchar_t *pWString, int nInSize, OUT_Z_CAP(nOutSizeInBytes) char *pString, int nOutSizeInBytes); // buffer-safe strcat inline void V_strcat(INOUT_Z_CAP(cchDest) char *dest, const char *src, int cchDest) { V_strncat(dest, src, cchDest, COPY_ALL_CHARACTERS); } // Buffer safe wcscat inline void V_wcscat(INOUT_Z_CAP(cchDest) wchar_t *dest, const wchar_t *src, int cchDest) { V_wcsncat(dest, src, cchDest, COPY_ALL_CHARACTERS); } //----------------------------------------------------------------------------- // generic unique name helper functions //----------------------------------------------------------------------------- // returns startindex if none found, 2 if "prefix" found, and n+1 if "prefixn" // found template int V_GenerateUniqueNameIndex(const char *prefix, const NameArray &nameArray, int startindex = 0) { if (prefix == NULL) return 0; int freeindex = startindex; int nNames = nameArray.Count(); for (int i = 0; i < nNames; ++i) { const char *pName = nameArray[i]; if (!pName) continue; const char *pIndexStr = StringAfterPrefix(pName, prefix); if (pIndexStr) { int index = *pIndexStr ? atoi(pIndexStr) : 1; if (index >= freeindex) { // TODO - check that there isn't more junk after the index in // pElementName freeindex = index + 1; } } } return freeindex; } template bool V_GenerateUniqueName(OUT_Z_CAP(memsize) char *name, int memsize, const char *prefix, const NameArray &nameArray) { if (name == NULL || memsize == 0) return false; if (prefix == NULL) { name[0] = '\0'; return false; } int prefixLength = V_strlen(prefix); if (prefixLength + 1 > memsize) { name[0] = '\0'; return false; } int i = V_GenerateUniqueNameIndex(prefix, nameArray); if (i <= 0) { V_strncpy(name, prefix, memsize); return true; } int newlen = prefixLength + (int)log10((float)i) + 1; if (newlen + 1 > memsize) { V_strncpy(name, prefix, memsize); return false; } V_snprintf(name, memsize, "%s%d", prefix, i); return true; } // // This utility class is for performing UTF-8 <-> UTF-16 conversion. // It is intended for use with function/method parameters. // // For example, you can call // FunctionTakingUTF16( CStrAutoEncode( utf8_string ).ToWString() ) // or // FunctionTakingUTF8( CStrAutoEncode( utf16_string ).ToString() ) // // The converted string is allocated off the heap, and destroyed when // the object goes out of scope. // // if the string cannot be converted, NULL is returned. // // This class doesn't have any conversion operators; the intention is // to encourage the developer to get used to having to think about which // encoding is desired. // class CStrAutoEncode { public: // ctor explicit CStrAutoEncode(const char *pch) { m_pch = pch; m_pwch = NULL; #if !defined(WIN32) && !defined(_WIN32) m_pucs2 = NULL; m_bCreatedUCS2 = false; #endif m_bCreatedUTF16 = false; } // ctor explicit CStrAutoEncode(const wchar_t *pwch) { m_pch = NULL; m_pwch = pwch; #if !defined(WIN32) && !defined(_WIN32) m_pucs2 = NULL; m_bCreatedUCS2 = false; #endif m_bCreatedUTF16 = true; } #if !defined(WIN32) && !defined(_WINDOWS) && !defined(_WIN32) explicit CStrAutoEncode(const ucs2 *pwch) { m_pch = NULL; m_pwch = NULL; m_pucs2 = pwch; m_bCreatedUCS2 = true; m_bCreatedUTF16 = false; } #endif // returns the UTF-8 string, converting on the fly. const char *ToString() { PopulateUTF8(); return m_pch; } // returns the UTF-8 string - a writable pointer. // only use this if you don't want to call const_cast // yourself. We need this for cases like CreateProcess. char *ToStringWritable() { PopulateUTF8(); return const_cast(m_pch); } // returns the UTF-16 string, converting on the fly. const wchar_t *ToWString() { PopulateUTF16(); return m_pwch; } #if !defined(WIN32) && !defined(_WIN32) // returns the UTF-16 string, converting on the fly. const ucs2 *ToUCS2String() { PopulateUCS2(); return m_pucs2; } #endif // returns the UTF-16 string - a writable pointer. // only use this if you don't want to call const_cast // yourself. We need this for cases like CreateProcess. wchar_t *ToWStringWritable() { PopulateUTF16(); return const_cast(m_pwch); } // dtor ~CStrAutoEncode() { // if we're "native unicode" then the UTF-8 string is something we // allocated, and vice versa. if (m_bCreatedUTF16) { delete[] m_pch; } else { delete[] m_pwch; } #if !defined(WIN32) && !defined(_WIN32) if (!m_bCreatedUCS2 && m_pucs2) delete[] m_pucs2; #endif } private: // ensure we have done any conversion work required to farm out a // UTF-8 encoded string. // // We perform two heap allocs here; the first one is the worst-case // (four bytes per Unicode code point). This is usually quite pessimistic, // so we perform a second allocation that's just the size we need. void PopulateUTF8() { if (!m_bCreatedUTF16) return; // no work to do if (m_pwch == NULL) return; // don't have a UTF-16 string to convert if (m_pch != NULL) return; // already been converted to UTF-8; no work to do // each Unicode code point can expand to as many as four bytes in UTF-8; // we also need to leave room for the terminating NUL. uint32 cbMax = 4 * static_cast(V_wcslen(m_pwch)) + 1; char *pchTemp = new char[cbMax]; if (V_UnicodeToUTF8(m_pwch, pchTemp, cbMax)) { uint32 cchAlloc = static_cast(V_strlen(pchTemp)) + 1; char *pchHeap = new char[cchAlloc]; V_strncpy(pchHeap, pchTemp, cchAlloc); delete[] pchTemp; m_pch = pchHeap; } else { // do nothing, and leave the UTF-8 string NULL delete[] pchTemp; } } // ensure we have done any conversion work required to farm out a // UTF-16 encoded string. // // We perform two heap allocs here; the first one is the worst-case // (one code point per UTF-8 byte). This is sometimes pessimistic, // so we perform a second allocation that's just the size we need. void PopulateUTF16() { if (m_bCreatedUTF16) return; // no work to do if (m_pch == NULL) return; // no UTF-8 string to convert if (m_pwch != NULL) return; // already been converted to UTF-16; no work to do uint32 cchMax = static_cast(V_strlen(m_pch)) + 1; wchar_t *pwchTemp = new wchar_t[cchMax]; if (V_UTF8ToUnicode(m_pch, pwchTemp, cchMax * sizeof(wchar_t))) { uint32 cchAlloc = static_cast(V_wcslen(pwchTemp)) + 1; wchar_t *pwchHeap = new wchar_t[cchAlloc]; V_wcsncpy(pwchHeap, pwchTemp, cchAlloc * sizeof(wchar_t)); delete[] pwchTemp; m_pwch = pwchHeap; } else { // do nothing, and leave the UTF-16 string NULL delete[] pwchTemp; } } #if !defined(WIN32) && !defined(_WIN32) // ensure we have done any conversion work required to farm out a // UTF-16 encoded string. // // We perform two heap allocs here; the first one is the worst-case // (one code point per UTF-8 byte). This is sometimes pessimistic, // so we perform a second allocation that's just the size we need. void PopulateUCS2() { if (m_bCreatedUCS2) return; if (m_pch == NULL) return; // no UTF-8 string to convert if (m_pucs2 != NULL) return; // already been converted to UTF-16; no work to do uint32 cchMax = static_cast(V_strlen(m_pch)) + 1; ucs2 *pwchTemp = new ucs2[cchMax]; if (V_UTF8ToUCS2(m_pch, cchMax, pwchTemp, cchMax * sizeof(ucs2))) { uint32 cchAlloc = cchMax; ucs2 *pwchHeap = new ucs2[cchAlloc]; memcpy(pwchHeap, pwchTemp, cchAlloc * sizeof(ucs2)); delete[] pwchTemp; m_pucs2 = pwchHeap; } else { // do nothing, and leave the UTF-16 string NULL delete[] pwchTemp; } } #endif // one of these pointers is an owned pointer; whichever // one is the encoding OTHER than the one we were initialized // with is the pointer we've allocated and must free. const char *m_pch; const wchar_t *m_pwch; #if !defined(WIN32) && !defined(_WIN32) const ucs2 *m_pucs2; bool m_bCreatedUCS2; #endif // "created as UTF-16", means our owned string is the UTF-8 string not the // UTF-16 one. bool m_bCreatedUTF16; }; // Encodes a string (or binary data) in URL encoding format, see rfc1738 // section 2.2. Dest buffer should be 3 times the size of source buffer to // guarantee it has room to encode. void Q_URLEncodeRaw(OUT_Z_CAP(nDestLen) char *pchDest, int nDestLen, const char *pchSource, int nSourceLen); // Decodes a string (or binary data) from URL encoding format, see rfc1738 // section 2.2. Dest buffer should be at least as large as source buffer to // gurantee room for decode. Dest buffer being the same as the source buffer // (decode in-place) is explicitly allowed. // // Returns the amount of space actually used in the output buffer. size_t Q_URLDecodeRaw(OUT_CAP(nDecodeDestLen) char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen); // Encodes a string (or binary data) in URL encoding format, this isn't the // strict rfc1738 format, but instead uses + for spaces. This is for historical // reasons and HTML spec foolishness that lead to + becoming a de facto standard // for spaces when encoding form data. Dest buffer should be 3 times the size of // source buffer to guarantee it has room to encode. void Q_URLEncode(OUT_Z_CAP(nDestLen) char *pchDest, int nDestLen, const char *pchSource, int nSourceLen); // Decodes a string (or binary data) in URL encoding format, this isn't the // strict rfc1738 format, but instead uses + for spaces. This is for historical // reasons and HTML spec foolishness that lead to + becoming a de facto standard // for spaces when encoding form data. Dest buffer should be at least as large // as source buffer to gurantee room for decode. Dest buffer being the same as // the source buffer (decode in-place) is explicitly allowed. // // Returns the amount of space actually used in the output buffer. size_t Q_URLDecode(OUT_CAP(nDecodeDestLen) char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen); // NOTE: This is for backward compatability! // We need to DLL-export the Q methods in vstdlib but not link to them in other // projects #if !defined(VSTDLIB_BACKWARD_COMPAT) #define Q_memset V_memset #define Q_memcpy V_memcpy #define Q_memmove V_memmove #define Q_memcmp V_memcmp #define Q_strlen V_strlen #define Q_strcpy V_strcpy #define Q_strrchr V_strrchr #define Q_strcmp V_strcmp #define Q_wcscmp V_wcscmp #define Q_stricmp V_stricmp #define Q_strstr V_strstr #define Q_strupr V_strupr #define Q_strlower V_strlower #define Q_wcslen V_wcslen #define Q_strncmp V_strncmp #define Q_strcasecmp V_strcasecmp #define Q_strncasecmp V_strncasecmp #define Q_strnicmp V_strnicmp #define Q_atoi V_atoi #define Q_atoi64 V_atoi64 #define Q_atoui64 V_atoui64 #define Q_atof V_atof #define Q_stristr V_stristr #define Q_strnistr V_strnistr #define Q_strnchr V_strnchr #define Q_normalizeFloatString V_normalizeFloatString #define Q_strncpy V_strncpy #define Q_snprintf V_snprintf #define Q_wcsncpy V_wcsncpy #define Q_strncat V_strncat #define Q_strnlwr V_strnlwr #define Q_vsnprintf V_vsnprintf #define Q_vsnprintfRet V_vsnprintfRet #define Q_pretifymem V_pretifymem #define Q_pretifynum V_pretifynum #define Q_UTF8ToUnicode V_UTF8ToUnicode #define Q_UnicodeToUTF8 V_UnicodeToUTF8 #define Q_hextobinary V_hextobinary #define Q_binarytohex V_binarytohex #define Q_FileBase V_FileBase #define Q_StripTrailingSlash V_StripTrailingSlash #define Q_StripExtension V_StripExtension #define Q_DefaultExtension V_DefaultExtension #define Q_SetExtension V_SetExtension #define Q_StripFilename V_StripFilename #define Q_StripLastDir V_StripLastDir #define Q_UnqualifiedFileName V_UnqualifiedFileName #define Q_ComposeFileName V_ComposeFileName #define Q_ExtractFilePath V_ExtractFilePath #define Q_ExtractFileExtension V_ExtractFileExtension #define Q_GetFileExtension V_GetFileExtension #define Q_RemoveDotSlashes V_RemoveDotSlashes #define Q_MakeAbsolutePath V_MakeAbsolutePath #define Q_AppendSlash V_AppendSlash #define Q_IsAbsolutePath V_IsAbsolutePath #define Q_StrSubst V_StrSubst #define Q_SplitString V_SplitString #define Q_SplitString2 V_SplitString2 #define Q_StrSlice V_StrSlice #define Q_StrLeft V_StrLeft #define Q_StrRight V_StrRight #define Q_FixSlashes V_FixSlashes #define Q_strtowcs V_strtowcs #define Q_wcstostr V_wcstostr #define Q_strcat V_strcat #define Q_GenerateUniqueNameIndex V_GenerateUniqueNameIndex #define Q_GenerateUniqueName V_GenerateUniqueName #define Q_MakeRelativePath V_MakeRelativePath #define Q_qsort_s V_qsort_s #endif // !defined( VSTDLIB_DLL_EXPORT ) #ifdef POSIX #define FMT_WS L"%ls" #else #define FMT_WS L"%s" #endif #endif // TIER1_STRTOOLS_H