14 #include "llvm/ADT/StringSwitch.h"
27 static const char *k_escapable_characters =
"\"\\";
30 size_t regular = quoted.find_first_of(k_escapable_characters);
31 result += quoted.substr(0, regular);
32 quoted = quoted.substr(regular);
35 if (quoted.empty() || quoted.front() ==
'"')
39 quoted = quoted.drop_front();
49 if (strchr(k_escapable_characters, quoted.front()) ==
nullptr)
52 result += quoted.front();
53 quoted = quoted.drop_front();
71 static const char *k_space_separators =
" \t";
72 return str.ltrim(k_space_separators);
80 static std::tuple<std::string, char, llvm::StringRef>
93 char first_quote_char =
'\0';
95 bool arg_complete =
false;
98 size_t regular = command.find_first_of(
" \t\r\"'`\\");
99 arg += command.substr(0, regular);
100 command = command.substr(regular);
105 char special = command.front();
106 command = command.drop_front();
109 if (command.empty()) {
116 if (strchr(
" \t\\'\"`", command.front()) ==
nullptr)
119 arg += command.front();
120 command = command.drop_front();
136 if (first_quote_char ==
'\0')
137 first_quote_char = special;
144 size_t quoted = command.find(special);
145 arg += command.substr(0, quoted);
146 command = command.substr(quoted);
150 if (!command.empty())
151 command = command.drop_front();
155 }
while (!arg_complete);
157 return std::make_tuple(arg, first_quote_char, command);
160 Args::ArgEntry::ArgEntry(llvm::StringRef str,
char quote) : quote(quote) {
161 size_t size = str.size();
164 ::memcpy(
data(), str.data() ? str.data() :
"",
size);
179 for (llvm::StringRef arg : args)
189 m_entries.emplace_back(entry.ref(), entry.quote);
192 m_argv.push_back(
nullptr);
206 s.
Format(
"{0}[{1}]=\"{2}\"\n", label_name, i++, entry.ref());
208 s.
Format(
"{0}[{1}]=NULL\n", label_name, i);
215 for (
size_t i = 0; i <
m_entries.size(); ++i) {
232 for (
size_t i = 0; i <
m_entries.size(); ++i) {
255 while (!command.empty()) {
261 m_argv.push_back(
nullptr);
282 return (
m_argv.size() > 1) ?
const_cast<const char **
>(
m_argv.data())
300 assert(
m_argv.back() ==
nullptr);
303 m_entries.emplace_back(entry.ref(), entry.quote);
306 m_argv.push_back(
nullptr);
313 assert(
m_argv.back() ==
nullptr);
315 for (
auto arg : llvm::ArrayRef(argv, argc)) {
320 m_argv.push_back(
nullptr);
330 assert(
m_argv.back() ==
nullptr);
341 assert(
m_argv.back() ==
nullptr);
361 auto args = llvm::ArrayRef(argv, argc);
364 for (
size_t i = 0; i < args.size(); ++i) {
366 ((args[i][0] ==
'\'') || (args[i][0] ==
'"') || (args[i][0] ==
'`'))
382 m_argv.push_back(
nullptr);
386 llvm::StringRef unsafe_arg) {
387 struct ShellDescriptor {
389 llvm::StringRef m_escapables;
392 static ShellDescriptor g_Shells[] = {{
ConstString(
"bash"),
" '\"<>()&;"},
399 llvm::StringRef escapables =
" '\"";
402 for (
const auto &Shell : g_Shells) {
403 if (Shell.m_basename == basename) {
404 escapables = Shell.m_escapables;
411 safe_arg.reserve(unsafe_arg.size());
413 for (
char c : unsafe_arg) {
414 if (escapables.contains(c))
415 safe_arg.push_back(
'\\');
416 safe_arg.push_back(c);
423 return llvm::StringSwitch<lldb::Encoding>(s)
428 .Default(fail_value);
434 uint32_t result = llvm::StringSwitch<uint32_t>(s)
455 for (
const char *p = src; *p !=
'\0'; ++p) {
456 size_t non_special_chars = ::strcspn(p,
"\\");
457 if (non_special_chars > 0) {
458 dst.append(p, non_special_chars);
459 p += non_special_chars;
502 char oct_str[5] = {
'\0',
'\0',
'\0',
'\0',
'\0'};
505 for (i = 0; (p[i] >=
'0' && p[i] <=
'7') && i < 4; ++i)
512 unsigned long octal_value = ::strtoul(oct_str,
nullptr, 8);
513 if (octal_value <= UINT8_MAX) {
514 dst.append(1,
static_cast<char>(octal_value));
521 if (isxdigit(p[1])) {
526 char hex_str[3] = {*p,
'\0',
'\0'};
527 if (isxdigit(p[1])) {
532 unsigned long hex_value = strtoul(hex_str,
nullptr, 16);
533 if (hex_value <= UINT8_MAX)
534 dst.append(1,
static_cast<char>(hex_value));
554 for (
const char *p = src; *p !=
'\0'; ++p) {
555 if (llvm::isPrint(*p))
593 snprintf(octal_str,
sizeof(octal_str),
"%o", *p);
594 dst.append(octal_str);
604 const char *chars_to_escape =
nullptr;
605 switch (quote_char) {
607 chars_to_escape =
" \t\\'\"`";
610 chars_to_escape =
"$\"`\\";
616 assert(
false &&
"Unhandled quote character");
621 res.reserve(arg.size());
623 if (::strchr(chars_to_escape, c))
635 const llvm::StringRef original_args = arg_string;
643 if (!arg_string.startswith(
"-")) {
648 bool found_suffix =
false;
649 while (!arg_string.empty()) {
651 std::size_t prev_prefix_length = original_args.size() - arg_string.size();
659 if (!entry.
IsQuoted() && arg ==
"--") {
667 std::size_t prefix_length = original_args.size() - arg_string.size();
671 llvm::StringRef prefix = original_args.take_front(prev_prefix_length);