コード例 #1
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Parse a string field
        /// </summary>
        static bool ParseString(Action <object> add, TextVisiter input, FormatSpecifier spec)
        {
            // Skip any whitespace
            input.MovePastWhitespace();

            // Parse string characters
            var start = input.Position;

            while (!input.EndOfText && !char.IsWhiteSpace(input.Peek()))
            {
                input.MoveAhead();
            }

            // Don't exceed field width
            if (spec.Width > 0)
            {
                var count = input.Position - start;
                if (spec.Width < count)
                {
                    input.MoveAhead(spec.Width - count);
                }
            }

            // Extract token
            if (input.Position > start)
            {
                if (!spec.NoResult)
                {
                    add(input.Extract(start, input.Position));
                }
                return(true);
            }
            return(false);
        }
コード例 #2
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Parse an octal field
        /// </summary>
        static bool ParseOctal(Action <object> add, TextVisiter input, FormatSpecifier spec)
        {
            // Skip any whitespace
            input.MovePastWhitespace();

            // Parse digits
            var start = input.Position;

            while (IsValidDigit(input.Peek(), 8))
            {
                input.MoveAhead();
            }

            // Don't exceed field width
            if (spec.Width > 0)
            {
                var count = input.Position - start;
                if (spec.Width < count)
                {
                    input.MoveAhead(spec.Width - count);
                }
            }

            // Extract token
            if (input.Position > start)
            {
                if (!spec.NoResult)
                {
                    add(Unsigned(input.Extract(start, input.Position), spec.Modifier, 8));
                }
                return(true);
            }
            return(false);
        }
コード例 #3
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Parse integer field
        /// </summary>
        static bool ParseDecimal(Action <object> add, TextVisiter input, FormatSpecifier spec)
        {
            // Skip any whitespace
            input.MovePastWhitespace();

            // Parse leading sign
            var radix = 10;
            var start = input.Position;

            if (input.Peek() == '+' || input.Peek() == '-')
            {
                input.MoveAhead();
            }
            else if (input.Peek() == '0')
            {
                if (char.ToLower(input.Peek(1)) == 'x')
                {
                    radix = 16; input.MoveAhead(2);
                }
                else
                {
                    radix = 8; input.MoveAhead();
                }
            }

            // Parse digits
            while (IsValidDigit(input.Peek(), radix))
            {
                input.MoveAhead();
            }

            // Don't exceed field width
            if (spec.Width > 0)
            {
                var count = input.Position - start;
                if (spec.Width < count)
                {
                    input.MoveAhead(spec.Width - count);
                }
            }

            // Extract token
            if (input.Position > start)
            {
                if (!spec.NoResult)
                {
                    add(spec.Type == Types.Decimal
                        ? Signed(input.Extract(start, input.Position), spec.Modifier, radix)
                        : Unsigned(input.Extract(start, input.Position), spec.Modifier, radix));
                }
                return(true);
            }
            return(false);
        }
コード例 #4
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Parses the input string according to the rules in the
        /// format string. Similar to the standard C library's
        /// sscanf() function. Parsed fields are placed in the
        /// class' Results member.
        /// </summary>
        /// <param name="input">String to parse</param>
        /// <param name="format">Specifies rules for parsing input</param>
        public static int Parse(string input, string format, out IList <object> values)
        {
            var inp     = new TextVisiter(input);
            var fmt     = new TextVisiter(format);
            var results = new List <object>();
            var spec    = new FormatSpecifier();
            var count   = 0;

            // Process input string as indicated in format string
            while (!fmt.EndOfText && !inp.EndOfText)
            {
                if (ParseFormatSpecifier(fmt, spec))
                {
                    // Found a format specifier
                    var parser = _typeParsers.First(tp => tp.Type == spec.Type);
                    if (parser.Parser(results.Add, inp, spec))
                    {
                        count++;
                    }
                    else
                    {
                        break;
                    }
                }
                else if (char.IsWhiteSpace(fmt.Peek()))
                {
                    // Whitespace
                    inp.MovePastWhitespace();
                    fmt.MoveAhead();
                }
                else if (fmt.Peek() == inp.Peek())
                {
                    // Matching character
                    inp.MoveAhead();
                    fmt.MoveAhead();
                }
                else
                {
                    break;     // Break at mismatch
                }
            }
            // Return number of fields successfully parsed
            values = results;
            return(count);
        }
コード例 #5
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Parse a scan-set field
        /// </summary>
        static bool ParseScanSet(Action <object> add, TextVisiter input, FormatSpecifier spec)
        {
            // Parse characters
            var start = input.Position;

            if (!spec.ScanSetExclude)
            {
                while (spec.ScanSet.Contains(input.Peek()))
                {
                    input.MoveAhead();
                }
            }
            else
            {
                while (!input.EndOfText && !spec.ScanSet.Contains(input.Peek()))
                {
                    input.MoveAhead();
                }
            }

            // Don't exceed field width
            if (spec.Width > 0)
            {
                var count = input.Position - start;
                if (spec.Width < count)
                {
                    input.MoveAhead(spec.Width - count);
                }
            }

            // Extract token
            if (input.Position > start)
            {
                if (!spec.NoResult)
                {
                    add(input.Extract(start, input.Position));
                }
                return(true);
            }
            return(false);
        }
コード例 #6
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Parse a character field
        /// </summary>
        static bool ParseCharacter(Action <object> add, TextVisiter input, FormatSpecifier spec)
        {
            // Parse character(s)
            var start = input.Position;
            var count = (spec.Width > 1) ? spec.Width : 1;

            while (!input.EndOfText && count-- > 0)
            {
                input.MoveAhead();
            }

            // Extract token
            if (count <= 0 && input.Position > start)
            {
                if (!spec.NoResult)
                {
                    var token = input.Extract(start, input.Position);
                    add(token.Length > 1 ? token.ToCharArray() : token[0]);
                }
                return(true);
            }
            return(false);
        }
コード例 #7
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Parse a floating-point field
        /// </summary>
        static bool ParseFloat(Action <object> add, TextVisiter input, FormatSpecifier spec)
        {
            // Skip any whitespace
            input.MovePastWhitespace();

            // Parse leading sign
            var start = input.Position;

            if (input.Peek() == '+' || input.Peek() == '-')
            {
                input.MoveAhead();
            }

            // Parse digits
            var hasPoint = false;

            while (char.IsDigit(input.Peek()) || input.Peek() == '.')
            {
                if (input.Peek() == '.')
                {
                    if (hasPoint)
                    {
                        break;
                    }
                    hasPoint = true;
                }
                input.MoveAhead();
            }

            // Parse exponential notation
            if (char.ToLower(input.Peek()) == 'e')
            {
                input.MoveAhead();
                if (input.Peek() == '+' || input.Peek() == '-')
                {
                    input.MoveAhead();
                }
                while (char.IsDigit(input.Peek()))
                {
                    input.MoveAhead();
                }
            }

            // Don't exceed field width
            if (spec.Width > 0)
            {
                var count = input.Position - start;
                if (spec.Width < count)
                {
                    input.MoveAhead(spec.Width - count);
                }
            }

            // Because we parse the exponential notation before we apply any field-width constraint, it becomes awkward to verify
            // we have a valid floating point token. To prevent an exception, we use TryParse() here instead of Parse().

            // Extract token
            if (input.Position > start && double.TryParse(input.Extract(start, input.Position), out var result))
            {
                if (!spec.NoResult)
                {
                    add(spec.Modifier == Modifiers.Long || spec.Modifier == Modifiers.LongLong ? result : result);
                }
                return(true);
            }
            return(false);
        }
コード例 #8
0
ファイル: TextScanFormatted.cs プロジェクト: bclnet/DroidNet
        /// <summary>
        /// Attempts to parse a field format specifier from the format string.
        /// </summary>
        static bool ParseFormatSpecifier(TextVisiter format, FormatSpecifier spec)
        {
            // Return if not a field format specifier
            if (format.Peek() != '%')
            {
                return(false);
            }
            format.MoveAhead();

            // Return if "%%" (treat as '%' literal)
            if (format.Peek() == '%')
            {
                return(false);
            }

            // Test for asterisk, which indicates result is not stored
            if (format.Peek() == '*')
            {
                spec.NoResult = true; format.MoveAhead();
            }
            else
            {
                spec.NoResult = false;
            }

            // Parse width
            var start = format.Position;

            while (char.IsDigit(format.Peek()))
            {
                format.MoveAhead();
            }
            if (format.Position > start)
            {
                spec.Width = int.Parse(format.Extract(start, format.Position));
            }
            else
            {
                spec.Width = 0;
            }

            // Parse modifier
            if (format.Peek() == 'h')
            {
                format.MoveAhead();
                if (format.Peek() == 'h')
                {
                    format.MoveAhead(); spec.Modifier = Modifiers.ShortShort;
                }
                else
                {
                    spec.Modifier = Modifiers.Short;
                }
            }
            else if (char.ToLower(format.Peek()) == 'l')
            {
                format.MoveAhead();
                if (format.Peek() == 'l')
                {
                    format.MoveAhead(); spec.Modifier = Modifiers.LongLong;
                }
                else
                {
                    spec.Modifier = Modifiers.Long;
                }
            }
            else
            {
                spec.Modifier = Modifiers.None;
            }

            // Parse type
            switch (format.Peek())
            {
            case 'c': spec.Type = Types.Character; break;

            case 'd':
            case 'i': spec.Type = Types.Decimal; break;

            case 'a':
            case 'A':
            case 'e':
            case 'E':
            case 'f':
            case 'F':
            case 'g':
            case 'G': spec.Type = Types.Float; break;

            case 'o': spec.Type = Types.Octal; break;

            case 's': spec.Type = Types.String; break;

            case 'u': spec.Type = Types.Unsigned; break;

            case 'x':
            case 'X': spec.Type = Types.Hexadecimal; break;

            case '[':
                spec.Type = Types.ScanSet;
                format.MoveAhead();
                // Parse scan set characters
                if (format.Peek() == '^')
                {
                    spec.ScanSetExclude = true; format.MoveAhead();
                }
                else
                {
                    spec.ScanSetExclude = false;
                }
                start = format.Position;
                // Treat immediate ']' as literal
                if (format.Peek() == ']')
                {
                    format.MoveAhead();
                }
                format.MoveTo(']');
                if (format.EndOfText)
                {
                    throw new Exception("Type specifier expected character : ']'");
                }
                spec.ScanSet = format.Extract(start, format.Position);
                break;

            default: throw new Exception($"Unknown format type specified : '{format.Peek()}'");
            }
            format.MoveAhead();
            return(true);
        }