Chromium Code Reviews| Index: tools/gn/string_utils.cc |
| diff --git a/tools/gn/string_utils.cc b/tools/gn/string_utils.cc |
| index 5ee12d9dcea34402ae7a912f9dda470b2646af5a..7246f75933e72a58e702c5831e07b0f8922a1aac 100644 |
| --- a/tools/gn/string_utils.cc |
| +++ b/tools/gn/string_utils.cc |
| @@ -5,7 +5,9 @@ |
| #include "tools/gn/string_utils.h" |
| #include <stddef.h> |
| +#include <cctype> |
| +#include "base/strings/string_number_conversions.h" |
| #include "tools/gn/err.h" |
| #include "tools/gn/input_file.h" |
| #include "tools/gn/parser.h" |
| @@ -131,7 +133,7 @@ bool AppendInterpolatedIdentifier(Scope* scope, |
| // Handles string interpolations: $identifier and ${expression} |
| // |
| -// |*i| is the index into |input| of the $. This will be updated to point to |
| +// |*i| is the index into |input| after the $. This will be updated to point to |
| // the last character consumed on success. The token is the original string |
| // to blame on failure. |
| // |
| @@ -143,13 +145,7 @@ bool AppendStringInterpolation(Scope* scope, |
| size_t* i, |
| std::string* output, |
| Err* err) { |
| - size_t dollars_index = *i; |
| - (*i)++; |
| - if (*i == size) { |
| - *err = ErrInsideStringToken(token, dollars_index, 1, "$ at end of string.", |
| - "I was expecting an identifier or {...} after the $."); |
| - return false; |
| - } |
| + size_t dollars_index = *i - 1; |
| if (input[*i] == '{') { |
| // Bracketed expression. |
| @@ -203,6 +199,40 @@ bool AppendStringInterpolation(Scope* scope, |
| end_offset, output, err); |
| } |
| +// Handles a hex literal: $0xFF |
| +// |
| +// |*i| is the index into |input| after the $. This will be updated to point to |
| +// the last character consumed on success. The token is the original string |
| +// to blame on failure. |
| +// |
| +// On failure, returns false and sets the error. On success, appends the |
| +// char with the given hex value to |*output|. |
| +bool AppendHexByte(Scope* scope, |
| + const Token& token, |
| + const char* input, size_t size, |
| + size_t* i, |
| + std::string* output, |
| + Err* err) { |
| + size_t dollars_index = *i - 1; |
| + // "$0" is already known to exist. |
| + if (*i + 3 >= size || input[*i + 1] != 'x' || !std::isxdigit(input[*i + 2]) || |
| + !std::isxdigit(input[*i + 3])) { |
| + *err = ErrInsideStringToken( |
| + token, dollars_index, *i - dollars_index + 1, |
| + "Invalid hex character. Hex values must look like 0xFF."); |
| + return false; |
| + } |
| + int value = 0; |
| + if (!base::HexStringToInt(base::StringPiece(&input[*i + 2], 2), &value)) { |
| + *err = ErrInsideStringToken(token, dollars_index, *i - dollars_index + 1, |
| + "Could not convert hex value."); |
| + return false; |
| + } |
| + *i += 3; |
| + output->push_back(value); |
|
brettw
2016/01/05 18:11:04
I'm surprised you can push_back an into on a strin
agrieve
2016/01/05 19:43:19
Yeah, just tried both GCC and clang again but no w
|
| + return true; |
| +} |
| + |
| } // namespace |
| bool ExpandStringLiteral(Scope* scope, |
| @@ -235,7 +265,16 @@ bool ExpandStringLiteral(Scope* scope, |
| } |
| output.push_back(input[i]); |
| } else if (input[i] == '$') { |
| - if (!AppendStringInterpolation(scope, literal, input, size, &i, |
| + i++; |
| + if (i == size) { |
| + *err = ErrInsideStringToken(literal, i - 1, 1, "$ at end of string.", |
| + "I was expecting an identifier, 0xFF, or {...} after the $."); |
| + return false; |
| + } |
| + if (input[i] == '0') { |
| + if (!AppendHexByte(scope, literal, input, size, &i, &output, err)) |
| + return false; |
| + } else if (!AppendStringInterpolation(scope, literal, input, size, &i, |
| &output, err)) |
| return false; |
| } else { |