summaryrefslogtreecommitdiffstats
path: root/staptree.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'staptree.cxx')
-rw-r--r--staptree.cxx304
1 files changed, 128 insertions, 176 deletions
diff --git a/staptree.cxx b/staptree.cxx
index 6ea1fc70..6f75e09b 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -404,206 +404,158 @@ print_format::string_to_components(string const & str)
format_component curr;
vector<format_component> res;
- enum
- {
- parsing_plain_data,
- parsing_flags,
- parsing_width,
- parsing_precision,
- parsing_conversion_specifier
- }
- state = parsing_plain_data;
-
curr.clear();
string::const_iterator i = str.begin();
-
+
while (i != str.end())
{
- switch (state)
+ if (*i != '%')
{
- case parsing_plain_data:
-
- if (*i != '%')
- {
- assert (curr.type == conv_unspecified || curr.type == conv_literal);
- curr.type = conv_literal;
- curr.literal_string += *i;
- }
- else if (i+1 == str.end() || *(i+1) == '%')
- {
- assert(*i == '%');
- // *i == '%' and *(i+1) == '%'; append only one '%' to the literal string
- assert (curr.type == conv_unspecified || curr.type == conv_literal);
- curr.type = conv_literal;
- curr.literal_string += '%';
- }
- else
- {
- assert(*i == '%');
- state = parsing_flags;
- if (curr.type != conv_unspecified)
- {
- assert (curr.type == conv_literal);
- res.push_back(curr);
- curr.clear();
- }
- }
+ assert (curr.type == conv_unspecified || curr.type == conv_literal);
+ curr.type = conv_literal;
+ curr.literal_string += *i;
++i;
- break;
-
- case parsing_flags:
- switch (*i)
+ continue;
+ }
+ else if (i+1 == str.end() || *(i+1) == '%')
+ {
+ assert(*i == '%');
+ // *i == '%' and *(i+1) == '%'; append only one '%' to the literal string
+ assert (curr.type == conv_unspecified || curr.type == conv_literal);
+ curr.type = conv_literal;
+ curr.literal_string += '%';
+ ++i;
+ continue;
+ }
+ else
+ {
+ assert(*i == '%');
+ if (curr.type != conv_unspecified)
{
- case '0':
- curr.flags |= static_cast<unsigned long>(fmt_flag_zeropad);
- ++i;
- break;
-
- case '+':
- curr.flags |= static_cast<unsigned long>(fmt_flag_plus);
- ++i;
- break;
-
- case '-':
- curr.flags |= static_cast<unsigned long>(fmt_flag_left);
- ++i;
- break;
-
- case ' ':
- curr.flags |= static_cast<unsigned long>(fmt_flag_space);
- ++i;
- break;
+ // Flush any component we were previously accumulating
+ assert (curr.type == conv_literal);
+ res.push_back(curr);
+ curr.clear();
+ }
+ }
+ ++i;
+
+ if (i == str.end())
+ break;
- case '#':
- curr.flags |= static_cast<unsigned long>(fmt_flag_special);
- ++i;
- break;
+ // Now we are definitely parsing a conversion.
+ // Begin by parsing flags (whicih are optional).
- default:
- state = parsing_width;
- break;
- }
+ switch (*i)
+ {
+ case '0':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_zeropad);
+ ++i;
break;
-
- case parsing_width:
- while (isdigit(*i))
- {
- curr.width *= 10;
- curr.width += (*i - '0');
- ++i;
- }
- state = parsing_precision;
+
+ case '+':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_plus);
+ ++i;
break;
- case parsing_precision:
- if (*i == '.')
- {
- ++i;
- while (isdigit(*i))
- {
- curr.precision *= 10;
- curr.precision += (*i - '0');
- ++i;
- }
- }
- state = parsing_conversion_specifier;
+ case '-':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_left);
+ ++i;
break;
+
+ case ' ':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_space);
+ ++i;
+ break;
+
+ case '#':
+ curr.flags |= static_cast<unsigned long>(fmt_flag_special);
+ ++i;
+ break;
+
+ default:
+ break;
+ }
- case parsing_conversion_specifier:
- switch (*i)
- {
-
- default:
- if (curr.type == conv_unspecified)
- throw semantic_error("no conversion specifier provided");
-
- res.push_back(curr);
- curr.clear();
- state = parsing_plain_data;
- break;
-
- // Valid conversion types
- case 's':
- if (curr.type != conv_unspecified)
- throw semantic_error("multiple conversion types supplied");
- curr.type = conv_string;
- ++i;
- break;
-
- case 'd':
- case 'i':
- if (curr.type != conv_unspecified)
- throw semantic_error("multiple conversion types supplied");
- curr.type = conv_signed_decimal;
- ++i;
- break;
-
- case 'o':
- if (curr.type != conv_unspecified)
- throw semantic_error("multiple conversion types supplied");
- curr.type = conv_unsigned_octal;
- ++i;
- break;
+ // Parse optional width
+
+ while (i != str.end() && isdigit(*i))
+ {
+ curr.width *= 10;
+ curr.width += (*i - '0');
+ ++i;
+ }
- case 'u':
- if (curr.type != conv_unspecified)
- throw semantic_error("multiple conversion types supplied");
- curr.type = conv_unsigned_decimal;
- ++i;
- break;
+ if (i == str.end())
+ break;
- case 'X':
- if (curr.type != conv_unspecified)
- throw semantic_error("multiple conversion types supplied");
- curr.type = conv_unsigned_uppercase_hex;
+ // Parse optional precision
+ if (*i == '.')
+ {
+ ++i;
+ if (i == str.end())
+ break;
+ while (i != str.end() && isdigit(*i))
+ {
+ curr.precision *= 10;
+ curr.precision += (*i - '0');
++i;
+ }
+ }
- case 'x':
- if (curr.type != conv_unspecified)
- throw semantic_error("multiple conversion types supplied");
- curr.type = conv_unsigned_lowercase_hex;
- ++i;
- break;
+ if (i == str.end())
+ break;
- // We prohibit users passing any funny stuff through which might
- // make linux's printf function do naughty things.
- case 'p':
- case 'n':
- case 'c':
- case 'q':
- case 'j':
- case 't':
-
- case ',':
- case '.':
- case '*':
-
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- case 'I':
- case 'l':
- case 'L':
- case 'z':
- case 'Z':
- string err("prohibited conversion character '");
- err += *i;
- err += '"';
- throw parse_error(err);
- }
+ // Parse the actual conversion specifier (sdiouxX)
+ switch (*i)
+ {
+ // Valid conversion types
+ case 's':
+ curr.type = conv_string;
+ break;
+
+ case 'd':
+ case 'i':
+ curr.type = conv_signed_decimal;
+ break;
+
+ case 'o':
+ curr.type = conv_unsigned_octal;
+ break;
+
+ case 'u':
+ curr.type = conv_unsigned_decimal;
+ break;
+
+ case 'X':
+ curr.type = conv_unsigned_uppercase_hex;
+ break;
+
+ case 'x':
+ curr.type = conv_unsigned_lowercase_hex;
+ break;
+
+ default:
break;
}
+
+ if (curr.type == conv_unspecified)
+ throw semantic_error("invalid or missing conversion specifier");
+
+ ++i;
+ res.push_back(curr);
+ curr.clear();
}
- // Flush final component
- if (curr.type != conv_unspecified)
- res.push_back(curr);
+ // If there's a remaining partly-composed conversion, fail.
+ if (!curr.is_empty())
+ {
+ if (curr.type == conv_literal)
+ res.push_back(curr);
+ else
+ throw semantic_error("trailing incomplete print format conversion");
+ }
return res;
}