mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
177 lines
4.8 KiB
C++
Executable File
177 lines
4.8 KiB
C++
Executable File
#include "KString.h"
|
|
#include <stdarg.h>
|
|
|
|
#include "MiniCppUnit.hxx"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// String Helper
|
|
|
|
static std::string vasprintf(const char *fmt, va_list argv) {
|
|
std::string result;
|
|
va_list argv_copy; // vsnprintf modifies argv, need copy
|
|
#ifndef va_copy
|
|
argv_copy = argv;
|
|
#else
|
|
va_copy(argv_copy, argv);
|
|
#endif
|
|
|
|
int len = vsnprintf(NULL, 0, fmt, argv_copy);
|
|
if (len > 0 && len < 255) {
|
|
// cover 90% of all calls
|
|
char str[256] = {0};
|
|
int len2 = vsnprintf(str, 255, fmt, argv);
|
|
result = str;
|
|
} else if (len > 0) {
|
|
char *str = static_cast<char *>(alloca(len + 1)); // alloca on stack, space for null-termination
|
|
int len2 = vsnprintf(str, len + 1, fmt, argv);
|
|
result = str;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
static void reportWarning(const std::string &warnStr) {
|
|
if (JetBrains::underTeamcity())
|
|
gTeamCityListener.messages.messageWarning(warnStr);
|
|
else
|
|
fprintf(stderr, "%s", warnStr.c_str());
|
|
}
|
|
|
|
static void reportError(const std::string &errorStr) {
|
|
if (JetBrains::underTeamcity())
|
|
gTeamCityListener.messages.messageError(errorStr);
|
|
else
|
|
fprintf(stderr, "%s", errorStr.c_str());
|
|
}
|
|
|
|
static void reportInfo(const std::string &infoStr) {
|
|
if (JetBrains::underTeamcity())
|
|
gTeamCityListener.messages.messageNormal(infoStr);
|
|
else
|
|
fprintf(stderr, "%s", infoStr.c_str());
|
|
}
|
|
|
|
static void reportDebug(const std::string &debugStr) {
|
|
fprintf(stderr, "%s", debugStr.c_str());
|
|
}
|
|
|
|
static void report(ErrorLevel level, const std::string &Str) {
|
|
switch (level) {
|
|
case WARNLVL:
|
|
reportWarning(Str);
|
|
break;
|
|
case ERRORLVL:
|
|
reportError(Str);
|
|
break;
|
|
case INFOLVL:
|
|
reportInfo(Str);
|
|
break;
|
|
case DEBUGLVL:
|
|
reportDebug(Str);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void KOutputDebug(ErrorLevel lvl, const char *fmt ...) {
|
|
va_list argList;
|
|
va_start(argList, fmt);
|
|
std::string str = vasprintf(fmt, argList);
|
|
va_end(argList);
|
|
|
|
report(lvl, str);
|
|
}
|
|
|
|
#define K_MAX(a, b) ((a>b) ? a : b)
|
|
|
|
std::string GetFileName(const std::string &thePath, bool noExtension) {
|
|
int aLastSlash = K_MAX((int) thePath.rfind('\\'), (int) thePath.rfind('/'));
|
|
|
|
if (noExtension) {
|
|
int aLastDot = (int) thePath.rfind('.');
|
|
if (aLastDot > aLastSlash)
|
|
return thePath.substr(aLastSlash + 1, aLastDot - aLastSlash - 1);
|
|
}
|
|
|
|
if (aLastSlash == -1)
|
|
return thePath;
|
|
else
|
|
return thePath.substr(aLastSlash + 1);
|
|
}
|
|
|
|
std::string GetFileDir(const std::string &thePath, bool withSlash) {
|
|
int aLastSlash = K_MAX((int) thePath.rfind(('\\')), (int) thePath.rfind(('/')));
|
|
|
|
if (aLastSlash == -1)
|
|
return ("");
|
|
else {
|
|
if (withSlash)
|
|
return thePath.substr(0, aLastSlash + 1);
|
|
else
|
|
return thePath.substr(0, aLastSlash);
|
|
}
|
|
}
|
|
|
|
std::string GetFileExt(const std::string &thePath) {
|
|
std::string::size_type idx = thePath.find_last_of('.');
|
|
|
|
if (idx != std::string::npos)
|
|
return thePath.substr(idx + 1);
|
|
|
|
return ("");
|
|
}
|
|
|
|
/**
|
|
* g_ascii_strcasecmp:
|
|
* @s1: string to compare with @s2.
|
|
* @s2: string to compare with @s1.
|
|
*
|
|
* Compare two strings, ignoring the case of ASCII characters.
|
|
*
|
|
* Unlike the BSD strcasecmp() function, this only recognizes standard
|
|
* ASCII letters and ignores the locale, treating all non-ASCII
|
|
* bytes as if they are not letters.
|
|
*
|
|
* This function should be used only on strings that are known to be
|
|
* in encodings where the bytes corresponding to ASCII letters always
|
|
* represent themselves. This includes UTF-8 and the ISO-8859-*
|
|
* charsets, but not for instance double-byte encodings like the
|
|
* Windows Codepage 932, where the trailing bytes of double-byte
|
|
* characters include all ASCII letters. If you compare two CP932
|
|
* strings using this function, you will get false matches.
|
|
*
|
|
* Return value: an integer less than, equal to, or greater than
|
|
* zero if @s1 is found, respectively, to be less than,
|
|
* to match, or to be greater than @s2.
|
|
**/
|
|
static int g_ascii_compare_caseless(const char *s1, const char *s2) {
|
|
#define TOUPPER(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 'a' + 'A' : (c))
|
|
#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
|
|
#define g_return_val_if_fail(expr, val) { if (!(expr)) return (val); }
|
|
|
|
int c1, c2;
|
|
|
|
g_return_val_if_fail(s1 != NULL, 0);
|
|
g_return_val_if_fail(s2 != NULL, 0);
|
|
|
|
while (*s1 && *s2) {
|
|
c1 = (int) (unsigned char) TOLOWER(*s1);
|
|
c2 = (int) (unsigned char) TOLOWER(*s2);
|
|
if (c1 != c2)
|
|
return (c1 - c2);
|
|
s1++;
|
|
s2++;
|
|
}
|
|
|
|
return (((int) (unsigned char) *s1) - ((int) (unsigned char) *s2));
|
|
|
|
#undef g_return_val_if_fail
|
|
#undef TOUPPER
|
|
#undef TOLOWER
|
|
}
|
|
|
|
|
|
int CompareNoCase(const std::string &str1, const std::string &str2) {
|
|
return g_ascii_compare_caseless(str1.c_str(), str2.c_str());
|
|
}
|