* 'no_sscanf' of https://github.com/MaxKellermann/zeek:
  util: optimize expand_escape() by avoiding sscanf()
This commit is contained in:
Jon Siwek 2020-01-31 14:18:17 -08:00
commit fa5b3bb91e
3 changed files with 65 additions and 22 deletions

View file

@ -293,6 +293,26 @@ int streq(const char* s1, const char* s2)
return ! strcmp(s1, s2);
}
static constexpr int parse_octal_digit(char ch) noexcept
{
if ( ch >= '0' && ch <= '7' )
return ch - '0';
else
return -1;
}
static constexpr int parse_hex_digit(char ch) noexcept
{
if ( ch >= '0' && ch <= '9' )
return ch - '0';
else if ( ch >= 'a' && ch <= 'f' )
return 10 + ch - 'a';
else if ( ch >= 'A' && ch <= 'F' )
return 10 + ch - 'A';
else
return -1;
}
int expand_escape(const char*& s)
{
switch ( *(s++) ) {
@ -310,23 +330,32 @@ int expand_escape(const char*& s)
--s; // put back the first octal digit
const char* start = s;
// Don't increment inside loop control
// because if isdigit() is a macro it might
// expand into multiple increments ...
// require at least one octal digit and parse at most three
// Here we define a maximum length for escape sequence
// to allow easy handling of string like: "^H0" as
// "\0100".
int result = parse_octal_digit(*s++);
for ( int len = 0; len < 3 && isascii(*s) && isdigit(*s);
++s, ++len)
;
int result;
if ( sscanf(start, "%3o", &result) != 1 )
if ( result < 0 )
{
reporter->Warning("bad octal escape: %s ", start);
result = 0;
reporter->Error("bad octal escape: %s", start);
return 0;
}
// second digit?
int digit = parse_octal_digit(*s);
if ( digit >= 0 )
{
result = (result << 3) | digit;
++s;
// third digit?
digit = parse_octal_digit(*s);
if ( digit >= 0 )
{
result = (result << 3) | digit;
++s;
}
}
return result;
@ -337,15 +366,22 @@ int expand_escape(const char*& s)
const char* start = s;
// Look at most 2 characters, so that "\x0ddir" -> "^Mdir".
for ( int len = 0; len < 2 && isascii(*s) && isxdigit(*s);
++s, ++len)
;
int result;
if ( sscanf(start, "%2x", &result) != 1 )
int result = parse_hex_digit(*s++);
if ( result < 0 )
{
reporter->Warning("bad hexadecimal escape: %s", start);
result = 0;
reporter->Error("bad hexadecimal escape: %s", start);
return 0;
}
// second digit?
int digit = parse_hex_digit(*s);
if ( digit >= 0 )
{
result = (result << 4) | digit;
++s;
}
return result;