in src/CalcManager/Ratpack/conv.cpp [612:743]
PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precision)
{
int32_t expSign = 1L; // expSign is exponent sign ( +/- 1 )
int32_t expValue = 0L; // expValue is exponent mantissa, should be unsigned
PNUMBER pnumret = nullptr;
createnum(pnumret, static_cast<uint32_t>(numberString.length()));
pnumret->sign = 1L;
pnumret->cdigit = 0;
pnumret->exp = 0;
MANTTYPE* pmant = pnumret->mant + numberString.length() - 1;
uint8_t state = START; // state is the state of the input state machine.
for (const auto& c : numberString)
{
// If the character is the decimal separator, use L'.' for the purposes of the state machine.
wchar_t curChar = (c == g_decimalSeparator ? L'.' : c);
// Switch states based on the character we encountered
switch (curChar)
{
case L'-':
case L'+':
state = machine[state][SG];
break;
case L'.':
state = machine[state][DP];
break;
case L'0':
state = machine[state][ZR];
break;
case L'^':
case L'e':
if (curChar == L'^' || radix == 10)
{
state = machine[state][EX];
break;
}
// Drop through in the 'e'-as-a-digit case
[[fallthrough]];
default:
state = machine[state][NZ];
break;
}
// Now update our result value based on the state we are in
switch (state)
{
case MANTS:
pnumret->sign = (curChar == L'-') ? -1 : 1;
break;
case EXPSZ:
case EXPS:
expSign = (curChar == L'-') ? -1 : 1;
break;
case EXPDZ:
case EXPD:
{
curChar = NormalizeCharDigit(curChar, radix);
size_t pos = DIGITS.find(curChar);
if (pos != wstring_view::npos)
{
expValue *= radix;
expValue += static_cast<int32_t>(pos);
}
else
{
state = ERR;
}
}
break;
case LD:
pnumret->exp++;
[[fallthrough]];
case DD:
{
curChar = NormalizeCharDigit(curChar, radix);
size_t pos = DIGITS.find(curChar);
if (pos != wstring_view::npos && pos < static_cast<size_t>(radix))
{
*pmant-- = static_cast<MANTTYPE>(pos);
pnumret->exp--;
pnumret->cdigit++;
}
else
{
state = ERR;
}
}
break;
case DZ:
pnumret->exp--;
break;
case LZ:
case LZDP:
case DDP:
break;
}
}
if (state == DZ || state == EXPDZ)
{
pnumret->cdigit = 1;
pnumret->exp = 0;
pnumret->sign = 1;
}
else
{
while (pnumret->cdigit < static_cast<int32_t>(numberString.length()))
{
pnumret->cdigit++;
pnumret->exp--;
}
pnumret->exp += expSign * expValue;
}
// If we don't have a number, clear our result.
if (pnumret->cdigit == 0)
{
destroynum(pnumret);
pnumret = nullptr;
}
else
{
stripzeroesnum(pnumret, precision);
}
return pnumret;
}