xenia/third_party/crunch/crnlib/crn_strutils.cpp

614 lines
12 KiB
C++

// File: crn_strutils.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_strutils.h"
namespace crnlib
{
char* crn_strdup(const char* pStr)
{
if (!pStr)
pStr = "";
size_t l = strlen(pStr) + 1;
char *p = (char *)crnlib_malloc(l);
if (p)
memcpy(p, pStr, l);
return p;
}
int crn_stricmp(const char *p, const char *q)
{
return _stricmp(p, q);
}
char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc)
{
CRNLIB_ASSERT(pDst && pSrc && dst_len);
if (!dst_len)
return pDst;
char* q = pDst;
char c;
do
{
if (dst_len == 1)
{
*q++ = '\0';
break;
}
c = *pSrc++;
*q++ = c;
dst_len--;
} while (c);
CRNLIB_ASSERT((q - pDst) <= (int)dst_len);
return pDst;
}
bool int_to_string(int value, char* pDst, uint len)
{
CRNLIB_ASSERT(pDst);
const uint cBufSize = 16;
char buf[cBufSize];
uint j = static_cast<uint>((value < 0) ? -value : value);
char* p = buf + cBufSize - 1;
*p-- = '\0';
do
{
*p-- = static_cast<uint8>('0' + (j % 10));
j /= 10;
} while (j);
if (value < 0)
*p-- = '-';
const size_t total_bytes = (buf + cBufSize - 1) - p;
if (total_bytes > len)
return false;
for (size_t i = 0; i < total_bytes; i++)
pDst[i] = p[1 + i];
return true;
}
bool uint_to_string(uint value, char* pDst, uint len)
{
CRNLIB_ASSERT(pDst);
const uint cBufSize = 16;
char buf[cBufSize];
char* p = buf + cBufSize - 1;
*p-- = '\0';
do
{
*p-- = static_cast<uint8>('0' + (value % 10));
value /= 10;
} while (value);
const size_t total_bytes = (buf + cBufSize - 1) - p;
if (total_bytes > len)
return false;
for (size_t i = 0; i < total_bytes; i++)
pDst[i] = p[1 + i];
return true;
}
bool string_to_int(const char*& pBuf, int& value)
{
value = 0;
CRNLIB_ASSERT(pBuf);
const char* p = pBuf;
while (*p && isspace(*p))
p++;
uint result = 0;
bool negative = false;
if (!isdigit(*p))
{
if (p[0] == '-')
{
negative = true;
p++;
}
else
return false;
}
while (*p && isdigit(*p))
{
if (result & 0xE0000000U)
return false;
const uint result8 = result << 3U;
const uint result2 = result << 1U;
if (result2 > (0xFFFFFFFFU - result8))
return false;
result = result8 + result2;
uint c = p[0] - '0';
if (c > (0xFFFFFFFFU - result))
return false;
result += c;
p++;
}
if (negative)
{
if (result > 0x80000000U)
{
value = 0;
return false;
}
value = -static_cast<int>(result);
}
else
{
if (result > 0x7FFFFFFFU)
{
value = 0;
return false;
}
value = static_cast<int>(result);
}
pBuf = p;
return true;
}
bool string_to_int64(const char*& pBuf, int64& value)
{
value = 0;
CRNLIB_ASSERT(pBuf);
const char* p = pBuf;
while (*p && isspace(*p))
p++;
uint64 result = 0;
bool negative = false;
if (!isdigit(*p))
{
if (p[0] == '-')
{
negative = true;
p++;
}
else
return false;
}
while (*p && isdigit(*p))
{
if (result & 0xE000000000000000ULL)
return false;
const uint64 result8 = result << 3U;
const uint64 result2 = result << 1U;
if (result2 > (0xFFFFFFFFFFFFFFFFULL - result8))
return false;
result = result8 + result2;
uint c = p[0] - '0';
if (c > (0xFFFFFFFFFFFFFFFFULL - result))
return false;
result += c;
p++;
}
if (negative)
{
if (result > 0x8000000000000000ULL)
{
value = 0;
return false;
}
value = -static_cast<int64>(result);
}
else
{
if (result > 0x7FFFFFFFFFFFFFFFULL)
{
value = 0;
return false;
}
value = static_cast<int64>(result);
}
pBuf = p;
return true;
}
bool string_to_uint(const char*& pBuf, uint& value)
{
value = 0;
CRNLIB_ASSERT(pBuf);
const char* p = pBuf;
while (*p && isspace(*p))
p++;
uint result = 0;
if (!isdigit(*p))
return false;
while (*p && isdigit(*p))
{
if (result & 0xE0000000U)
return false;
const uint result8 = result << 3U;
const uint result2 = result << 1U;
if (result2 > (0xFFFFFFFFU - result8))
return false;
result = result8 + result2;
uint c = p[0] - '0';
if (c > (0xFFFFFFFFU - result))
return false;
result += c;
p++;
}
value = result;
pBuf = p;
return true;
}
bool string_to_uint64(const char*& pBuf, uint64& value)
{
value = 0;
CRNLIB_ASSERT(pBuf);
const char* p = pBuf;
while (*p && isspace(*p))
p++;
uint64 result = 0;
if (!isdigit(*p))
return false;
while (*p && isdigit(*p))
{
if (result & 0xE000000000000000ULL)
return false;
const uint64 result8 = result << 3U;
const uint64 result2 = result << 1U;
if (result2 > (0xFFFFFFFFFFFFFFFFULL - result8))
return false;
result = result8 + result2;
uint c = p[0] - '0';
if (c > (0xFFFFFFFFFFFFFFFFULL - result))
return false;
result += c;
p++;
}
value = result;
pBuf = p;
return true;
}
bool string_to_bool(const char* p, bool& value)
{
CRNLIB_ASSERT(p);
value = false;
if (_stricmp(p, "false") == 0)
return true;
if (_stricmp(p, "true") == 0)
{
value = true;
return true;
}
const char* q = p;
uint v;
if (string_to_uint(q, v))
{
if (!v)
return true;
else if (v == 1)
{
value = true;
return true;
}
}
return false;
}
bool string_to_float(const char*& p, float& value, uint round_digit)
{
double d;
if (!string_to_double(p, d, round_digit))
{
value = 0;
return false;
}
value = static_cast<float>(d);
return true;
}
bool string_to_double(const char*& p, double& value, uint round_digit)
{
return string_to_double(p, p + 128, value, round_digit);
}
// I wrote this approx. 20 years ago in C/assembly using a limited FP emulator package, so it's a bit crude.
bool string_to_double(const char*& p, const char *pEnd, double& value, uint round_digit)
{
CRNLIB_ASSERT(p);
value = 0;
enum { AF_BLANK = 1, AF_SIGN = 2, AF_DPOINT = 3, AF_BADCHAR = 4, AF_OVRFLOW = 5, AF_EXPONENT = 6, AF_NODIGITS = 7 };
int status = 0;
const char* buf = p;
int got_sign_flag = 0, got_dp_flag = 0, got_num_flag = 0;
int got_e_flag = 0, got_e_sign_flag = 0, e_sign = 0;
uint whole_count = 0, frac_count = 0;
double whole = 0, frac = 0, scale = 1, exponent = 1;
if (p >= pEnd)
{
status = AF_NODIGITS;
goto af_exit;
}
while (*buf)
{
if (!isspace(*buf))
break;
if (++buf >= pEnd)
{
status = AF_NODIGITS;
goto af_exit;
}
}
p = buf;
while (*buf)
{
p = buf;
if (buf >= pEnd)
break;
int i = *buf++;
switch (i)
{
case 'e':
case 'E':
{
got_e_flag = 1;
goto exit_while;
}
case '+':
{
if ((got_num_flag) || (got_sign_flag))
{
status = AF_SIGN;
goto af_exit;
}
got_sign_flag = 1;
break;
}
case '-':
{
if ((got_num_flag) || (got_sign_flag))
{
status = AF_SIGN;
goto af_exit;
}
got_sign_flag = -1;
break;
}
case '.':
{
if (got_dp_flag)
{
status = AF_DPOINT;
goto af_exit;
}
got_dp_flag = 1;
break;
}
default:
{
if ((i < '0') || (i > '9'))
goto exit_while;
else
{
i -= '0';
got_num_flag = 1;
if (got_dp_flag)
{
if (frac_count < round_digit)
{
frac = frac * 10.0f + i;
scale = scale * 10.0f;
}
else if (frac_count == round_digit)
{
if (i >= 5) /* check for round */
frac = frac + 1.0f;
}
frac_count++;
}
else
{
whole = whole * 10.0f + i;
whole_count++;
if (whole > 1e+100)
{
status = AF_OVRFLOW;
goto af_exit;
}
}
}
break;
}
}
}
exit_while:
if (got_e_flag)
{
if ((got_num_flag == 0) && (got_dp_flag))
{
status = AF_EXPONENT;
goto af_exit;
}
int e = 0;
e_sign = 1;
got_num_flag = 0;
got_e_sign_flag = 0;
while (*buf)
{
p = buf;
if (buf >= pEnd)
break;
int i = *buf++;
if (i == '+')
{
if ((got_num_flag) || (got_e_sign_flag))
{
status = AF_EXPONENT;
goto af_exit;
}
e_sign = 1;
got_e_sign_flag = 1;
}
else if (i == '-')
{
if ((got_num_flag) || (got_e_sign_flag))
{
status = AF_EXPONENT;
goto af_exit;
}
e_sign = -1;
got_e_sign_flag = 1;
}
else if ((i >= '0') && (i <= '9'))
{
got_num_flag = 1;
if ((e = (e * 10) + (i - 48)) > 100)
{
status = AF_EXPONENT;
goto af_exit;
}
}
else
break;
}
for (int i = 1; i <= e; i++) /* compute 10^e */
exponent = exponent * 10.0f;
}
if (((whole_count + frac_count) == 0) && (got_e_flag == 0))
{
status = AF_NODIGITS;
goto af_exit;
}
if (frac)
whole = whole + (frac / scale);
if (got_e_flag)
{
if (e_sign > 0)
whole = whole * exponent;
else
whole = whole / exponent;
}
if (got_sign_flag < 0)
whole = -whole;
value = whole;
af_exit:
return (status == 0);
}
} // namespace crnlib