/crnlib/crn_strutils.cpp
https://gitlab.com/BoTranVan/crunch · C++ · 613 lines · 470 code · 140 blank · 3 comment · 117 complexity · 701c7e6757fbe724325b5aa7fc1a7ddd MD5 · raw file
- // 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