mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 16:18:12 +00:00
Shell: Make escaping more intelligent
Instead of the previous only-escape-with-backslashes, extend the escaping to one of: - No escape - Escape with backslash - Escape with "\xhh" if control character that isn't easily represented as \X - Escape with "\uhhhhhhhh" if unicode character that is too big to represent as "\xhh". Fixes #6986.
This commit is contained in:
parent
22b244df45
commit
417910fd28
2 changed files with 93 additions and 21 deletions
|
@ -1142,9 +1142,9 @@ String Shell::escape_token_for_double_quotes(const String& token)
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
bool Shell::is_special(char c)
|
||||
Shell::SpecialCharacterEscapeMode Shell::special_character_escape_mode(u32 code_point)
|
||||
{
|
||||
switch (c) {
|
||||
switch (code_point) {
|
||||
case '\'':
|
||||
case '"':
|
||||
case '$':
|
||||
|
@ -1156,25 +1156,72 @@ bool Shell::is_special(char c)
|
|||
case '{':
|
||||
case '}':
|
||||
case '&':
|
||||
case ';':
|
||||
case '\\':
|
||||
case ' ':
|
||||
return true;
|
||||
return SpecialCharacterEscapeMode::Escaped;
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\r':
|
||||
return SpecialCharacterEscapeMode::QuotedAsEscape;
|
||||
default:
|
||||
return false;
|
||||
// FIXME: Should instead use unicode's "graphic" property (categories L, M, N, P, S, Zs)
|
||||
if (code_point < NumericLimits<i32>::max()) {
|
||||
if (isascii(static_cast<i32>(code_point)))
|
||||
return isprint(static_cast<i32>(code_point)) ? SpecialCharacterEscapeMode::Untouched : SpecialCharacterEscapeMode::QuotedAsHex;
|
||||
}
|
||||
return SpecialCharacterEscapeMode::Untouched;
|
||||
}
|
||||
}
|
||||
|
||||
String Shell::escape_token(const String& token)
|
||||
{
|
||||
StringBuilder builder;
|
||||
auto do_escape = [](auto& token) {
|
||||
StringBuilder builder;
|
||||
for (auto c : token) {
|
||||
static_assert(sizeof(c) == sizeof(u32) || sizeof(c) == sizeof(u8));
|
||||
switch (special_character_escape_mode(c)) {
|
||||
case SpecialCharacterEscapeMode::Untouched:
|
||||
if constexpr (sizeof(c) == sizeof(u8))
|
||||
builder.append(c);
|
||||
else
|
||||
builder.append(Utf32View { &c, 1 });
|
||||
break;
|
||||
case SpecialCharacterEscapeMode::Escaped:
|
||||
builder.append('\\');
|
||||
builder.append(c);
|
||||
break;
|
||||
case SpecialCharacterEscapeMode::QuotedAsEscape:
|
||||
switch (c) {
|
||||
case '\n':
|
||||
builder.append(R"("\n")");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append(R"("\t")");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append(R"("\r")");
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
case SpecialCharacterEscapeMode::QuotedAsHex:
|
||||
if (c <= NumericLimits<u8>::max())
|
||||
builder.appendff(R"("\x{:0>2x}")", static_cast<u8>(c));
|
||||
else
|
||||
builder.appendff(R"("\u{:0>8x}")", static_cast<u32>(c));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto c : token) {
|
||||
if (is_special(c))
|
||||
builder.append('\\');
|
||||
builder.append(c);
|
||||
}
|
||||
return builder.build();
|
||||
};
|
||||
|
||||
return builder.build();
|
||||
Utf8View view { token };
|
||||
if (view.validate())
|
||||
return do_escape(view);
|
||||
return do_escape(token);
|
||||
}
|
||||
|
||||
String Shell::unescape_token(const String& token)
|
||||
|
@ -2057,5 +2104,4 @@ SavedFileDescriptors::~SavedFileDescriptors()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue