System.Globalization.FormatProvider.Number.ParseNumber C# (CSharp) Method

ParseNumber() private static method

private static ParseNumber ( char &str, NumberStyles options, NumberBuffer &number, System.StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal ) : bool
str char
options NumberStyles
number NumberBuffer
sb System.StringBuilder
numfmt NumberFormatInfo
parseDecimal bool
return bool
            private unsafe static bool ParseNumber(ref char* str, NumberStyles options, ref NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal)
            {
                const int StateSign = 0x0001;
                const int StateParens = 0x0002;
                const int StateDigits = 0x0004;
                const int StateNonZero = 0x0008;
                const int StateDecimal = 0x0010;
                const int StateCurrency = 0x0020;

                number.scale = 0;
                number.sign = false;
                string decSep;                  // Decimal separator from NumberFormatInfo.
                string groupSep;                // Group separator from NumberFormatInfo.
                string currSymbol = null;       // Currency symbol from NumberFormatInfo.

                bool parsingCurrency = false;
                if ((options & NumberStyles.AllowCurrencySymbol) != 0)
                {
                    currSymbol = numfmt.CurrencySymbol;
                    // The idea here is to match the currency separators and on failure match the number separators to keep the perf of VB's IsNumeric fast.
                    // The values of decSep are setup to use the correct relevant separator (currency in the if part and decimal in the else part).
                    decSep = numfmt.CurrencyDecimalSeparator;
                    groupSep = numfmt.CurrencyGroupSeparator;
                    parsingCurrency = true;
                }
                else
                {
                    decSep = numfmt.NumberDecimalSeparator;
                    groupSep = numfmt.NumberGroupSeparator;
                }

                int state = 0;
                bool bigNumber = (sb != null); // When a StringBuilder is provided then we use it in place of the number.digits char[50]
                int maxParseDigits = bigNumber ? int.MaxValue : NumberMaxDigits;

                char* p = str;
                char ch = *p;
                char* next;

                char* dig = number.digits;

                while (true)
                {
                    // Eat whitespace unless we've found a sign which isn't followed by a currency symbol.
                    // "-Kr 1231.47" is legal but "- 1231.47" is not.
                    if (!IsWhite(ch) || (options & NumberStyles.AllowLeadingWhite) == 0 || ((state & StateSign) != 0 && ((state & StateCurrency) == 0 && numfmt.NumberNegativePattern != 2)))
                    {
                        if ((((options & NumberStyles.AllowLeadingSign) != 0) && (state & StateSign) == 0) && ((next = MatchChars(p, numfmt.PositiveSign)) != null || ((next = MatchChars(p, numfmt.NegativeSign)) != null && (number.sign = true))))
                        {
                            state |= StateSign;
                            p = next - 1;
                        }
                        else if (ch == '(' && ((options & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0))
                        {
                            state |= StateSign | StateParens;
                            number.sign = true;
                        }
                        else if (currSymbol != null && (next = MatchChars(p, currSymbol)) != null)
                        {
                            state |= StateCurrency;
                            currSymbol = null;  

                            // We already found the currency symbol. There should not be more currency symbols. Set
                            // currSymbol to NULL so that we won't search it again in the later code path.
                            p = next - 1;
                        }
                        else
                        {
                            break;
                        }
                    }
                    ch = *++p;
                }

                int digCount = 0;
                int digEnd = 0;
                while (true)
                {
                    if ((ch >= '0' && ch <= '9') || (((options & NumberStyles.AllowHexSpecifier) != 0) && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))))
                    {
                        state |= StateDigits;

                        if (ch != '0' || (state & StateNonZero) != 0 || (bigNumber && ((options & NumberStyles.AllowHexSpecifier) != 0)))
                        {
                            if (digCount < maxParseDigits)
                            {
                                if (bigNumber)
                                    sb.Append(ch);
                                else
                                    dig[digCount++] = ch;
                                if (ch != '0' || parseDecimal)
                                {
                                    digEnd = digCount;
                                }
                            }
                            if ((state & StateDecimal) == 0)
                            {
                                number.scale++;
                            }
                            state |= StateNonZero;
                        }
                        else if ((state & StateDecimal) != 0)
                        {
                            number.scale--;
                        }
                    }
                    else if (((options & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, decSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, numfmt.NumberDecimalSeparator)) != null))
                    {
                        state |= StateDecimal;
                        p = next - 1;
                    }
                    else if (((options & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, groupSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, numfmt.NumberGroupSeparator)) != null))
                    {
                        p = next - 1;
                    }
                    else
                    {
                        break;
                    }
                    ch = *++p;
                }

                bool negExp = false;
                number.precision = digEnd;
                if (bigNumber)
                    sb.Append('\0');
                else
                    dig[digEnd] = '\0';
                if ((state & StateDigits) != 0)
                {
                    if ((ch == 'E' || ch == 'e') && ((options & NumberStyles.AllowExponent) != 0))
                    {
                        char* temp = p;
                        ch = *++p;
                        if ((next = MatchChars(p, numfmt.PositiveSign)) != null)
                        {
                            ch = *(p = next);
                        }
                        else if ((next = MatchChars(p, numfmt.NegativeSign)) != null)
                        {
                            ch = *(p = next);
                            negExp = true;
                        }
                        if (ch >= '0' && ch <= '9')
                        {
                            int exp = 0;
                            do
                            {
                                exp = exp * 10 + (ch - '0');
                                ch = *++p;
                                if (exp > 1000)
                                {
                                    exp = 9999;
                                    while (ch >= '0' && ch <= '9')
                                    {
                                        ch = *++p;
                                    }
                                }
                            } while (ch >= '0' && ch <= '9');
                            if (negExp)
                            {
                                exp = -exp;
                            }
                            number.scale += exp;
                        }
                        else
                        {
                            p = temp;
                            ch = *p;
                        }
                    }
                    while (true)
                    {
                        if (!IsWhite(ch) || (options & NumberStyles.AllowTrailingWhite) == 0)
                        {
                            if (((options & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0)) && ((next = MatchChars(p, numfmt.PositiveSign)) != null || (((next = MatchChars(p, numfmt.NegativeSign)) != null) && (number.sign = true))))
                            {
                                state |= StateSign;
                                p = next - 1;
                            }
                            else if (ch == ')' && ((state & StateParens) != 0))
                            {
                                state &= ~StateParens;
                            }
                            else if (currSymbol != null && (next = MatchChars(p, currSymbol)) != null)
                            {
                                currSymbol = null;
                                p = next - 1;
                            }
                            else
                            {
                                break;
                            }
                        }
                        ch = *++p;
                    }
                    if ((state & StateParens) == 0)
                    {
                        if ((state & StateNonZero) == 0)
                        {
                            if (!parseDecimal)
                            {
                                number.scale = 0;
                            }
                            if ((state & StateDecimal) == 0)
                            {
                                number.sign = false;
                            }
                        }
                        str = p;
                        return true;
                    }
                }
                str = p;
                return false;
            }