diff options
Diffstat (limited to 'source/Interpreter/Args.cpp')
| -rw-r--r-- | source/Interpreter/Args.cpp | 2911 | 
1 files changed, 1318 insertions, 1593 deletions
| diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp index d90ef1d256a4..698432885d9b 100644 --- a/source/Interpreter/Args.cpp +++ b/source/Interpreter/Args.cpp @@ -12,1764 +12,1489 @@  // C++ Includes  // Other libraries and framework includes  // Project includes -#include "lldb/Interpreter/Args.h"  #include "lldb/Core/Stream.h"  #include "lldb/Core/StreamFile.h"  #include "lldb/Core/StreamString.h"  #include "lldb/DataFormatters/FormatManager.h"  #include "lldb/Host/StringConvert.h" -#include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/Args.h"  #include "lldb/Interpreter/CommandInterpreter.h"  #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/Options.h"  #include "lldb/Target/Process.h"  #include "lldb/Target/StackFrame.h"  #include "lldb/Target/Target.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +  using namespace lldb;  using namespace lldb_private; -//---------------------------------------------------------------------- -// Args constructor -//---------------------------------------------------------------------- -Args::Args (llvm::StringRef command) : -    m_args(), -    m_argv(), -    m_args_quote_char() -{ -    SetCommandString (command); -} - -//---------------------------------------------------------------------- -// We have to be very careful on the copy constructor of this class -// to make sure we copy all of the string values, but we can't copy the -// rhs.m_argv into m_argv since it will point to the "const char *" c  -// strings in rhs.m_args. We need to copy the string list and update our -// own m_argv appropriately.  -//---------------------------------------------------------------------- -Args::Args (const Args &rhs) : -    m_args (rhs.m_args), -    m_argv (), -    m_args_quote_char(rhs.m_args_quote_char) -{ -    UpdateArgvFromArgs(); -} - -//---------------------------------------------------------------------- -// We have to be very careful on the copy constructor of this class -// to make sure we copy all of the string values, but we can't copy the -// rhs.m_argv into m_argv since it will point to the "const char *" c  -// strings in rhs.m_args. We need to copy the string list and update our -// own m_argv appropriately.  -//---------------------------------------------------------------------- -const Args & -Args::operator= (const Args &rhs) -{ -    // Make sure we aren't assigning to self -    if (this != &rhs) -    { -        m_args = rhs.m_args; -        m_args_quote_char = rhs.m_args_quote_char; -        UpdateArgvFromArgs(); +// A helper function for argument parsing. +// Parses the initial part of the first argument using normal double quote +// rules: +// backslash escapes the double quote and itself. The parsed string is appended +// to the second +// argument. The function returns the unparsed portion of the string, starting +// at the closing +// quote. +static llvm::StringRef ParseDoubleQuotes(llvm::StringRef quoted, +                                         std::string &result) { +  // Inside double quotes, '\' and '"' are special. +  static const char *k_escapable_characters = "\"\\"; +  while (true) { +    // Skip over over regular characters and append them. +    size_t regular = quoted.find_first_of(k_escapable_characters); +    result += quoted.substr(0, regular); +    quoted = quoted.substr(regular); + +    // If we have reached the end of string or the closing quote, we're done. +    if (quoted.empty() || quoted.front() == '"') +      break; + +    // We have found a backslash. +    quoted = quoted.drop_front(); + +    if (quoted.empty()) { +      // A lone backslash at the end of string, let's just append it. +      result += '\\'; +      break;      } -    return *this; -} -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -Args::~Args () -{ -} +    // If the character after the backslash is not a whitelisted escapable +    // character, we +    // leave the character sequence untouched. +    if (strchr(k_escapable_characters, quoted.front()) == nullptr) +      result += '\\'; -void -Args::Dump (Stream &s, const char *label_name) const -{ -    if (!label_name) -        return; - -    const size_t argc = m_argv.size(); -    for (size_t i=0; i<argc; ++i) -    { -        s.Indent(); -        const char *arg_cstr = m_argv[i]; -        if (arg_cstr) -            s.Printf("%s[%zi]=\"%s\"\n", label_name, i, arg_cstr); -        else -            s.Printf("%s[%zi]=NULL\n", label_name, i); -    } -    s.EOL(); -} +    result += quoted.front(); +    quoted = quoted.drop_front(); +  } -bool -Args::GetCommandString (std::string &command) const -{ -    command.clear(); -    const size_t argc = GetArgumentCount(); -    for (size_t i=0; i<argc; ++i) -    { -        if (i > 0) -            command += ' '; -        command += m_argv[i]; -    } -    return argc > 0; +  return quoted;  } -bool -Args::GetQuotedCommandString (std::string &command) const -{ -    command.clear (); -    const size_t argc = GetArgumentCount(); -    for (size_t i = 0; i < argc; ++i) -    { -        if (i > 0) -            command.append (1, ' '); -        char quote_char = GetArgumentQuoteCharAtIndex(i); -        if (quote_char) -        { -            command.append (1, quote_char); -            command.append (m_argv[i]); -            command.append (1, quote_char); -        } -        else -            command.append (m_argv[i]); -    } -    return argc > 0; +static size_t ArgvToArgc(const char **argv) { +  if (!argv) +    return 0; +  size_t count = 0; +  while (*argv++) +    ++count; +  return count;  } -// A helper function for argument parsing. -// Parses the initial part of the first argument using normal double quote rules: -// backslash escapes the double quote and itself. The parsed string is appended to the second -// argument. The function returns the unparsed portion of the string, starting at the closing -// quote. -static llvm::StringRef -ParseDoubleQuotes(llvm::StringRef quoted, std::string &result) -{ -    // Inside double quotes, '\' and '"' are special. -    static const char *k_escapable_characters = "\"\\"; -    while (true) -    { -        // Skip over over regular characters and append them. -        size_t regular = quoted.find_first_of(k_escapable_characters); -        result += quoted.substr(0, regular); -        quoted = quoted.substr(regular); - -        // If we have reached the end of string or the closing quote, we're done. -        if (quoted.empty() || quoted.front() == '"') -            break; - -        // We have found a backslash. -        quoted = quoted.drop_front(); - -        if (quoted.empty()) -        { -            // A lone backslash at the end of string, let's just append it. -            result += '\\'; -            break; -        } - -        // If the character after the backslash is not a whitelisted escapable character, we -        // leave the character sequence untouched. -        if (strchr(k_escapable_characters, quoted.front()) == nullptr) -            result += '\\'; +// A helper function for SetCommandString. Parses a single argument from the +// command string, processing quotes and backslashes in a shell-like manner. +// The function returns a tuple consisting of the parsed argument, the quote +// char used, and the unparsed portion of the string starting at the first +// unqouted, unescaped whitespace character. +static std::tuple<std::string, char, llvm::StringRef> +ParseSingleArgument(llvm::StringRef command) { +  // Argument can be split into multiple discontiguous pieces, for example: +  //  "Hello ""World" +  // this would result in a single argument "Hello World" (without the quotes) +  // since the quotes would be removed and there is not space between the +  // strings. +  std::string arg; + +  // Since we can have multiple quotes that form a single command +  // in a command like: "Hello "world'!' (which will make a single +  // argument "Hello world!") we remember the first quote character +  // we encounter and use that for the quote character. +  char first_quote_char = '\0'; + +  bool arg_complete = false; +  do { +    // Skip over over regular characters and append them. +    size_t regular = command.find_first_of(" \t\"'`\\"); +    arg += command.substr(0, regular); +    command = command.substr(regular); + +    if (command.empty()) +      break; + +    char special = command.front(); +    command = command.drop_front(); +    switch (special) { +    case '\\': +      if (command.empty()) { +        arg += '\\'; +        break; +      } + +      // If the character after the backslash is not a whitelisted escapable +      // character, we +      // leave the character sequence untouched. +      if (strchr(" \t\\'\"`", command.front()) == nullptr) +        arg += '\\'; + +      arg += command.front(); +      command = command.drop_front(); + +      break; + +    case ' ': +    case '\t': +      // We are not inside any quotes, we just found a space after an +      // argument. We are done. +      arg_complete = true; +      break; + +    case '"': +    case '\'': +    case '`': +      // We found the start of a quote scope. +      if (first_quote_char == '\0') +        first_quote_char = special; + +      if (special == '"') +        command = ParseDoubleQuotes(command, arg); +      else { +        // For single quotes, we simply skip ahead to the matching quote +        // character +        // (or the end of the string). +        size_t quoted = command.find(special); +        arg += command.substr(0, quoted); +        command = command.substr(quoted); +      } + +      // If we found a closing quote, skip it. +      if (!command.empty()) +        command = command.drop_front(); -        result += quoted.front(); -        quoted = quoted.drop_front(); +      break;      } +  } while (!arg_complete); -    return quoted; +  return std::make_tuple(arg, first_quote_char, command);  } -// A helper function for SetCommandString. -// Parses a single argument from the command string, processing quotes and backslashes in a -// shell-like manner. The parsed argument is appended to the m_args array. The function returns -// the unparsed portion of the string, starting at the first unqouted, unescaped whitespace -// character. -llvm::StringRef -Args::ParseSingleArgument(llvm::StringRef command) -{ -    // Argument can be split into multiple discontiguous pieces, -    // for example: -    //  "Hello ""World" -    // this would result in a single argument "Hello World" (without/ -    // the quotes) since the quotes would be removed and there is -    // not space between the strings. - -    std::string arg; - -    // Since we can have multiple quotes that form a single command -    // in a command like: "Hello "world'!' (which will make a single -    // argument "Hello world!") we remember the first quote character -    // we encounter and use that for the quote character. -    char first_quote_char = '\0'; - -    bool arg_complete = false; -    do -    { -        // Skip over over regular characters and append them. -        size_t regular = command.find_first_of(" \t\"'`\\"); -        arg += command.substr(0, regular); -        command = command.substr(regular); - -        if (command.empty()) -            break; - -        char special = command.front(); -        command = command.drop_front(); -        switch (special) -        { -        case '\\': -            if (command.empty()) -            { -                arg += '\\'; -                break; -            } +Args::ArgEntry::ArgEntry(llvm::StringRef str, char quote) : quote(quote) { +  size_t size = str.size(); +  ptr.reset(new char[size + 1]); -            // If the character after the backslash is not a whitelisted escapable character, we -            // leave the character sequence untouched. -            if (strchr(" \t\\'\"`", command.front()) == nullptr) -                arg += '\\'; +  ::memcpy(data(), str.data() ? str.data() : "", size); +  ptr[size] = 0; +  ref = llvm::StringRef(c_str(), size); +} -            arg += command.front(); -            command = command.drop_front(); +//---------------------------------------------------------------------- +// Args constructor +//---------------------------------------------------------------------- +Args::Args(llvm::StringRef command) { SetCommandString(command); } -            break; +Args::Args(const Args &rhs) { *this = rhs; } -        case ' ': -        case '\t': -            // We are not inside any quotes, we just found a space after an -            // argument. We are done. -            arg_complete = true; -            break; +Args &Args::operator=(const Args &rhs) { +  Clear(); -        case '"': -        case '\'': -        case '`': -            // We found the start of a quote scope. -            if (first_quote_char == '\0') -                first_quote_char = special; - -            if (special == '"') -                command = ParseDoubleQuotes(command, arg); -            else -            { -                // For single quotes, we simply skip ahead to the matching quote character -                // (or the end of the string). -                size_t quoted = command.find(special); -                arg += command.substr(0, quoted); -                command = command.substr(quoted); -            } - -            // If we found a closing quote, skip it. -            if (! command.empty()) -                command = command.drop_front(); - -            break; -        } -    } while (!arg_complete); +  m_argv.clear(); +  m_entries.clear(); +  for (auto &entry : rhs.m_entries) { +    m_entries.emplace_back(entry.ref, entry.quote); +    m_argv.push_back(m_entries.back().data()); +  } +  m_argv.push_back(nullptr); +  return *this; +} -    m_args.push_back(arg); -    m_args_quote_char.push_back (first_quote_char); -    return command; +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +Args::~Args() {} + +void Args::Dump(Stream &s, const char *label_name) const { +  if (!label_name) +    return; + +  int i = 0; +  for (auto &entry : m_entries) { +    s.Indent(); +    s.Format("{0}[{1}]=\"{2}\"\n", label_name, i++, entry.ref); +  } +  s.Format("{0}[{1}]=NULL\n", label_name, i); +  s.EOL();  } -void -Args::SetCommandString (llvm::StringRef command) -{ -    m_args.clear(); -    m_argv.clear(); -    m_args_quote_char.clear(); +bool Args::GetCommandString(std::string &command) const { +  command.clear(); -    static const char *k_space_separators = " \t"; -    command = command.ltrim(k_space_separators); -    while (!command.empty()) -    { -        command = ParseSingleArgument(command); -        command = command.ltrim(k_space_separators); -    } +  for (size_t i = 0; i < m_entries.size(); ++i) { +    if (i > 0) +      command += ' '; +    command += m_entries[i].ref; +  } -    UpdateArgvFromArgs(); +  return !m_entries.empty();  } -void -Args::UpdateArgsAfterOptionParsing() -{ -    // Now m_argv might be out of date with m_args, so we need to fix that -    arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end(); -    arg_sstr_collection::iterator args_pos; -    arg_quote_char_collection::iterator quotes_pos; - -    for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin(); -         argv_pos != argv_end && args_pos != m_args.end(); -         ++argv_pos) -    { -        const char *argv_cstr = *argv_pos; -        if (argv_cstr == nullptr) -            break; - -        while (args_pos != m_args.end()) -        { -            const char *args_cstr = args_pos->c_str(); -            if (args_cstr == argv_cstr) -            { -                // We found the argument that matches the C string in the -                // vector, so we can now look for the next one -                ++args_pos; -                ++quotes_pos; -                break; -            } -            else -            { -                quotes_pos = m_args_quote_char.erase (quotes_pos); -                args_pos = m_args.erase (args_pos); -            } -        } -    } +bool Args::GetQuotedCommandString(std::string &command) const { +  command.clear(); -    if (args_pos != m_args.end()) -        m_args.erase (args_pos, m_args.end()); +  for (size_t i = 0; i < m_entries.size(); ++i) { +    if (i > 0) +      command += ' '; -    if (quotes_pos != m_args_quote_char.end()) -        m_args_quote_char.erase (quotes_pos, m_args_quote_char.end()); -} +    if (m_entries[i].quote) { +      command += m_entries[i].quote; +      command += m_entries[i].ref; +      command += m_entries[i].quote; +    } else { +      command += m_entries[i].ref; +    } +  } -void -Args::UpdateArgvFromArgs() -{ -    m_argv.clear(); -    arg_sstr_collection::const_iterator pos, end = m_args.end(); -    for (pos = m_args.begin(); pos != end; ++pos) -        m_argv.push_back(pos->c_str()); -    m_argv.push_back(nullptr); -    // Make sure we have enough arg quote chars in the array -    if (m_args_quote_char.size() < m_args.size()) -        m_args_quote_char.resize (m_argv.size()); +  return !m_entries.empty();  } -size_t -Args::GetArgumentCount() const -{ -    if (m_argv.empty()) -        return 0; -    return m_argv.size() - 1; +void Args::SetCommandString(llvm::StringRef command) { +  Clear(); +  m_argv.clear(); + +  static const char *k_space_separators = " \t"; +  command = command.ltrim(k_space_separators); +  std::string arg; +  char quote; +  while (!command.empty()) { +    std::tie(arg, quote, command) = ParseSingleArgument(command); +    m_entries.emplace_back(arg, quote); +    m_argv.push_back(m_entries.back().data()); +    command = command.ltrim(k_space_separators); +  } +  m_argv.push_back(nullptr);  } -const char * -Args::GetArgumentAtIndex (size_t idx) const -{ -    if (idx < m_argv.size()) -        return m_argv[idx]; -    return nullptr; +void Args::UpdateArgsAfterOptionParsing() { +  assert(!m_argv.empty()); +  assert(m_argv.back() == nullptr); + +  // Now m_argv might be out of date with m_entries, so we need to fix that. +  // This happens because getopt_long_only may permute the order of the +  // arguments in argv, so we need to re-order the quotes and the refs array +  // to match. +  for (size_t i = 0; i < m_argv.size() - 1; ++i) { +    const char *argv = m_argv[i]; +    auto pos = +        std::find_if(m_entries.begin() + i, m_entries.end(), +                     [argv](const ArgEntry &D) { return D.c_str() == argv; }); +    assert(pos != m_entries.end()); +    size_t distance = std::distance(m_entries.begin(), pos); +    if (i == distance) +      continue; + +    assert(distance > i); + +    std::swap(m_entries[i], m_entries[distance]); +    assert(m_entries[i].ref.data() == m_argv[i]); +  } +  m_entries.resize(m_argv.size() - 1);  } -char -Args::GetArgumentQuoteCharAtIndex (size_t idx) const -{ -    if (idx < m_args_quote_char.size()) -        return m_args_quote_char[idx]; -    return '\0'; +size_t Args::GetArgumentCount() const { return m_entries.size(); } + +const char *Args::GetArgumentAtIndex(size_t idx) const { +  if (idx < m_argv.size()) +    return m_argv[idx]; +  return nullptr;  } -char ** -Args::GetArgumentVector() -{ -    if (!m_argv.empty()) -        return const_cast<char **>(&m_argv[0]); -    return nullptr; +char Args::GetArgumentQuoteCharAtIndex(size_t idx) const { +  if (idx < m_entries.size()) +    return m_entries[idx].quote; +  return '\0';  } -const char ** -Args::GetConstArgumentVector() const -{ -    if (!m_argv.empty()) -        return const_cast<const char **>(&m_argv[0]); -    return nullptr; +char **Args::GetArgumentVector() { +  assert(!m_argv.empty()); +  // TODO: functions like execve and posix_spawnp exhibit undefined behavior +  // when argv or envp is null.  So the code below is actually wrong.  However, +  // other code in LLDB depends on it being null.  The code has been acting this +  // way for some time, so it makes sense to leave it this way until someone +  // has the time to come along and fix it. +  return (m_argv.size() > 1) ? m_argv.data() : nullptr;  } -void -Args::Shift () -{ -    // Don't pop the last NULL terminator from the argv array -    if (m_argv.size() > 1) -    { -        m_argv.erase(m_argv.begin()); -        m_args.pop_front(); -        if (!m_args_quote_char.empty()) -            m_args_quote_char.erase(m_args_quote_char.begin()); -    } +const char **Args::GetConstArgumentVector() const { +  assert(!m_argv.empty()); +  return (m_argv.size() > 1) ? const_cast<const char **>(m_argv.data()) +                             : nullptr;  } -const char * -Args::Unshift (const char *arg_cstr, char quote_char) -{ -    m_args.push_front(arg_cstr); -    m_argv.insert(m_argv.begin(), m_args.front().c_str()); -    m_args_quote_char.insert(m_args_quote_char.begin(), quote_char); -    return GetArgumentAtIndex (0); +void Args::Shift() { +  // Don't pop the last NULL terminator from the argv array +  if (m_entries.empty()) +    return; +  m_argv.erase(m_argv.begin()); +  m_entries.erase(m_entries.begin());  } -void -Args::AppendArguments (const Args &rhs) -{ -    const size_t rhs_argc = rhs.GetArgumentCount(); -    for (size_t i=0; i<rhs_argc; ++i) -        AppendArgument(rhs.GetArgumentAtIndex(i), -                       rhs.GetArgumentQuoteCharAtIndex(i)); +void Args::Unshift(llvm::StringRef arg_str, char quote_char) { +  InsertArgumentAtIndex(0, arg_str, quote_char);  } -void -Args::AppendArguments (const char **argv) -{ -    if (argv) -    { -        for (uint32_t i=0; argv[i]; ++i) -            AppendArgument(argv[i]); -    } +void Args::AppendArguments(const Args &rhs) { +  assert(m_argv.size() == m_entries.size() + 1); +  assert(m_argv.back() == nullptr); +  m_argv.pop_back(); +  for (auto &entry : rhs.m_entries) { +    m_entries.emplace_back(entry.ref, entry.quote); +    m_argv.push_back(m_entries.back().data()); +  } +  m_argv.push_back(nullptr);  } -const char * -Args::AppendArgument (const char *arg_cstr, char quote_char) -{ -    return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char); +void Args::AppendArguments(const char **argv) { +  size_t argc = ArgvToArgc(argv); + +  assert(m_argv.size() == m_entries.size() + 1); +  assert(m_argv.back() == nullptr); +  m_argv.pop_back(); +  for (auto arg : llvm::makeArrayRef(argv, argc)) { +    m_entries.emplace_back(arg, '\0'); +    m_argv.push_back(m_entries.back().data()); +  } + +  m_argv.push_back(nullptr);  } -const char * -Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char) -{ -    // Since we are using a std::list to hold onto the copied C string and -    // we don't have direct access to the elements, we have to iterate to -    // find the value. -    arg_sstr_collection::iterator pos, end = m_args.end(); -    size_t i = idx; -    for (pos = m_args.begin(); i > 0 && pos != end; ++pos) -        --i; - -    pos = m_args.insert(pos, arg_cstr); -     -    if (idx >= m_args_quote_char.size()) -    { -        m_args_quote_char.resize(idx + 1); -        m_args_quote_char[idx] = quote_char; -    } -    else -        m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char); -     -    UpdateArgvFromArgs(); -    return GetArgumentAtIndex(idx); +void Args::AppendArgument(llvm::StringRef arg_str, char quote_char) { +  InsertArgumentAtIndex(GetArgumentCount(), arg_str, quote_char);  } -const char * -Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char) -{ -    // Since we are using a std::list to hold onto the copied C string and -    // we don't have direct access to the elements, we have to iterate to -    // find the value. -    arg_sstr_collection::iterator pos, end = m_args.end(); -    size_t i = idx; -    for (pos = m_args.begin(); i > 0 && pos != end; ++pos) -        --i; - -    if (pos != end) -    { -        pos->assign(arg_cstr); -        assert(idx < m_argv.size() - 1); -        m_argv[idx] = pos->c_str(); -        if (idx >= m_args_quote_char.size()) -            m_args_quote_char.resize(idx + 1); -        m_args_quote_char[idx] = quote_char; -        return GetArgumentAtIndex(idx); -    } -    return nullptr; +void Args::InsertArgumentAtIndex(size_t idx, llvm::StringRef arg_str, +                                 char quote_char) { +  assert(m_argv.size() == m_entries.size() + 1); +  assert(m_argv.back() == nullptr); + +  if (idx > m_entries.size()) +    return; +  m_entries.emplace(m_entries.begin() + idx, arg_str, quote_char); +  m_argv.insert(m_argv.begin() + idx, m_entries[idx].data());  } -void -Args::DeleteArgumentAtIndex (size_t idx) -{ -    // Since we are using a std::list to hold onto the copied C string and -    // we don't have direct access to the elements, we have to iterate to -    // find the value. -    arg_sstr_collection::iterator pos, end = m_args.end(); -    size_t i = idx; -    for (pos = m_args.begin(); i > 0 && pos != end; ++pos) -        --i; - -    if (pos != end) -    { -        m_args.erase (pos); -        assert(idx < m_argv.size() - 1); -        m_argv.erase(m_argv.begin() + idx); -        if (idx < m_args_quote_char.size()) -            m_args_quote_char.erase(m_args_quote_char.begin() + idx); -    } +void Args::ReplaceArgumentAtIndex(size_t idx, llvm::StringRef arg_str, +                                  char quote_char) { +  assert(m_argv.size() == m_entries.size() + 1); +  assert(m_argv.back() == nullptr); + +  if (idx >= m_entries.size()) +    return; + +  if (arg_str.size() > m_entries[idx].ref.size()) { +    m_entries[idx] = ArgEntry(arg_str, quote_char); +    m_argv[idx] = m_entries[idx].data(); +  } else { +    const char *src_data = arg_str.data() ? arg_str.data() : ""; +    ::memcpy(m_entries[idx].data(), src_data, arg_str.size()); +    m_entries[idx].ptr[arg_str.size()] = 0; +    m_entries[idx].ref = m_entries[idx].ref.take_front(arg_str.size()); +  }  } -void -Args::SetArguments (size_t argc, const char **argv) -{ -    // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is -    // no need to clear it here. -    m_args.clear(); -    m_args_quote_char.clear(); - -    // First copy each string -    for (size_t i=0; i<argc; ++i) -    { -        m_args.push_back (argv[i]); -        if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`')) -            m_args_quote_char.push_back (argv[i][0]); -        else -            m_args_quote_char.push_back ('\0'); -    } +void Args::DeleteArgumentAtIndex(size_t idx) { +  if (idx >= m_entries.size()) +    return; -    UpdateArgvFromArgs(); +  m_argv.erase(m_argv.begin() + idx); +  m_entries.erase(m_entries.begin() + idx);  } -void -Args::SetArguments (const char **argv) -{ -    // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is -    // no need to clear it here. -    m_args.clear(); -    m_args_quote_char.clear(); -     -    if (argv) -    { -        // First copy each string -        for (size_t i=0; argv[i]; ++i) -        { -            m_args.push_back (argv[i]); -            if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`')) -                m_args_quote_char.push_back (argv[i][0]); -            else -                m_args_quote_char.push_back ('\0'); -        } -    } -     -    UpdateArgvFromArgs(); +void Args::SetArguments(size_t argc, const char **argv) { +  Clear(); + +  auto args = llvm::makeArrayRef(argv, argc); +  m_entries.resize(argc); +  m_argv.resize(argc + 1); +  for (size_t i = 0; i < args.size(); ++i) { +    char quote = +        ((args[i][0] == '\'') || (args[i][0] == '"') || (args[i][0] == '`')) +            ? args[i][0] +            : '\0'; + +    m_entries[i] = ArgEntry(args[i], quote); +    m_argv[i] = m_entries[i].data(); +  }  } +void Args::SetArguments(const char **argv) { +  SetArguments(ArgvToArgc(argv), argv); +} -Error -Args::ParseOptions (Options &options) -{ -    StreamString sstr; -    Error error; -    Option *long_options = options.GetLongOptions(); -    if (long_options == nullptr) -    { -        error.SetErrorStringWithFormat("invalid long options"); -        return error; -    } +Error Args::ParseOptions(Options &options, ExecutionContext *execution_context, +                         PlatformSP platform_sp, bool require_validation) { +  StreamString sstr; +  Error error; +  Option *long_options = options.GetLongOptions(); +  if (long_options == nullptr) { +    error.SetErrorStringWithFormat("invalid long options"); +    return error; +  } -    for (int i=0; long_options[i].definition != nullptr; ++i) -    { -        if (long_options[i].flag == nullptr) -        { -            if (isprint8(long_options[i].val)) -            { -                sstr << (char)long_options[i].val; -                switch (long_options[i].definition->option_has_arg) -                { -                default: -                case OptionParser::eNoArgument:                       break; -                case OptionParser::eRequiredArgument: sstr << ':';    break; -                case OptionParser::eOptionalArgument: sstr << "::";   break; -                } -            } +  for (int i = 0; long_options[i].definition != nullptr; ++i) { +    if (long_options[i].flag == nullptr) { +      if (isprint8(long_options[i].val)) { +        sstr << (char)long_options[i].val; +        switch (long_options[i].definition->option_has_arg) { +        default: +        case OptionParser::eNoArgument: +          break; +        case OptionParser::eRequiredArgument: +          sstr << ':'; +          break; +        case OptionParser::eOptionalArgument: +          sstr << "::"; +          break;          } +      }      } -    std::unique_lock<std::mutex> lock; -    OptionParser::Prepare(lock); -    int val; -    while (1) -    { -        int long_options_index = -1; -        val = OptionParser::Parse(GetArgumentCount(), -                                 GetArgumentVector(), -                                 sstr.GetData(), -                                 long_options, -                                 &long_options_index); -        if (val == -1) -            break; - -        // Did we get an error? -        if (val == '?') -        { -            error.SetErrorStringWithFormat("unknown or ambiguous option"); -            break; -        } -        // The option auto-set itself -        if (val == 0) -            continue; - -        ((Options *) &options)->OptionSeen (val); - -        // Lookup the long option index -        if (long_options_index == -1) -        { -            for (int i=0; -                 long_options[i].definition || long_options[i].flag || long_options[i].val; -                 ++i) -            { -                if (long_options[i].val == val) -                { -                    long_options_index = i; -                    break; -                } -            } -        } -        // Call the callback with the option -        if (long_options_index >= 0 && long_options[long_options_index].definition) -        { -            const OptionDefinition *def = long_options[long_options_index].definition; -            CommandInterpreter &interpreter = options.GetInterpreter(); -            OptionValidator *validator = def->validator; -            if (validator && !validator->IsValid(*interpreter.GetPlatform(true), interpreter.GetExecutionContext())) -            { -                error.SetErrorStringWithFormat("Option \"%s\" invalid.  %s", def->long_option, def->validator->LongConditionString()); -            } -            else -            { -                error = options.SetOptionValue(long_options_index, -                                               (def->option_has_arg == OptionParser::eNoArgument) ? nullptr : OptionParser::GetOptionArgument()); -            } +  } +  std::unique_lock<std::mutex> lock; +  OptionParser::Prepare(lock); +  int val; +  while (1) { +    int long_options_index = -1; +    val = OptionParser::Parse(GetArgumentCount(), GetArgumentVector(), +                              sstr.GetString(), long_options, +                              &long_options_index); +    if (val == -1) +      break; + +    // Did we get an error? +    if (val == '?') { +      error.SetErrorStringWithFormat("unknown or ambiguous option"); +      break; +    } +    // The option auto-set itself +    if (val == 0) +      continue; + +    ((Options *)&options)->OptionSeen(val); + +    // Lookup the long option index +    if (long_options_index == -1) { +      for (int i = 0; long_options[i].definition || long_options[i].flag || +                      long_options[i].val; +           ++i) { +        if (long_options[i].val == val) { +          long_options_index = i; +          break;          } -        else -        { -            error.SetErrorStringWithFormat("invalid option with value '%i'", val); +      } +    } +    // Call the callback with the option +    if (long_options_index >= 0 && +        long_options[long_options_index].definition) { +      const OptionDefinition *def = long_options[long_options_index].definition; + +      if (!platform_sp) { +        // User did not pass in an explicit platform.  Try to grab +        // from the execution context. +        TargetSP target_sp = +            execution_context ? execution_context->GetTargetSP() : TargetSP(); +        platform_sp = target_sp ? target_sp->GetPlatform() : PlatformSP(); +      } +      OptionValidator *validator = def->validator; + +      if (!platform_sp && require_validation) { +        // Caller requires validation but we cannot validate as we +        // don't have the mandatory platform against which to +        // validate. +        error.SetErrorString("cannot validate options: " +                             "no platform available"); +        return error; +      } + +      bool validation_failed = false; +      if (platform_sp) { +        // Ensure we have an execution context, empty or not. +        ExecutionContext dummy_context; +        ExecutionContext *exe_ctx_p = +            execution_context ? execution_context : &dummy_context; +        if (validator && !validator->IsValid(*platform_sp, *exe_ctx_p)) { +          validation_failed = true; +          error.SetErrorStringWithFormat("Option \"%s\" invalid.  %s", +                                         def->long_option, +                                         def->validator->LongConditionString());          } -        if (error.Fail()) -            break; +      } + +      // As long as validation didn't fail, we set the option value. +      if (!validation_failed) +        error = options.SetOptionValue( +            long_options_index, +            (def->option_has_arg == OptionParser::eNoArgument) +                ? nullptr +                : OptionParser::GetOptionArgument(), +            execution_context); +    } else { +      error.SetErrorStringWithFormat("invalid option with value '%i'", val);      } - -    // Update our ARGV now that get options has consumed all the options -    m_argv.erase(m_argv.begin(), m_argv.begin() + OptionParser::GetOptionIndex()); -    UpdateArgsAfterOptionParsing (); -    return error; +    if (error.Fail()) +      break; +  } + +  // Update our ARGV now that get options has consumed all the options +  m_argv.erase(m_argv.begin(), m_argv.begin() + OptionParser::GetOptionIndex()); +  UpdateArgsAfterOptionParsing(); +  return error;  } -void -Args::Clear () -{ -    m_args.clear (); -    m_argv.clear (); -    m_args_quote_char.clear(); +void Args::Clear() { +  m_entries.clear(); +  m_argv.clear(); +  m_argv.push_back(nullptr);  } -lldb::addr_t -Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr) -{ -    bool error_set = false; -    if (s && s[0]) -    { -        char *end = nullptr; -        lldb::addr_t addr = ::strtoull (s, &end, 0); -        if (*end == '\0') -        { -            if (error_ptr) -                error_ptr->Clear(); -            return addr; // All characters were used, return the result -        } -        // Try base 16 with no prefix... -        addr = ::strtoull (s, &end, 16); -        if (*end == '\0') -        { -            if (error_ptr) -                error_ptr->Clear(); -            return addr; // All characters were used, return the result -        } -         -        if (exe_ctx) -        { -            Target *target = exe_ctx->GetTargetPtr(); -            if (target) -            { -                lldb::ValueObjectSP valobj_sp; -                EvaluateExpressionOptions options; -                options.SetCoerceToId(false); -                options.SetUnwindOnError(true); -                options.SetKeepInMemory(false); -                options.SetTryAllThreads(true); -                 -                ExpressionResults expr_result = target->EvaluateExpression(s, -                                                                           exe_ctx->GetFramePtr(), -                                                                           valobj_sp, -                                                                           options); - -                bool success = false; -                if (expr_result == eExpressionCompleted) -                { -                    if (valobj_sp) -                        valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(valobj_sp->GetDynamicValueType(), true); -                    // Get the address to watch. -                    if (valobj_sp) -                        addr = valobj_sp->GetValueAsUnsigned(fail_value, &success); -                    if (success) -                    { -                        if (error_ptr) -                            error_ptr->Clear(); -                        return addr; -                    } -                    else -                    { -                        if (error_ptr) -                        { -                            error_set = true; -                            error_ptr->SetErrorStringWithFormat("address expression \"%s\" resulted in a value whose type can't be converted to an address: %s", s, valobj_sp->GetTypeName().GetCString()); -                        } -                    } -                     -                } -                else -                { -                    // Since the compiler can't handle things like "main + 12" we should -                    // try to do this for now. The compiler doesn't like adding offsets -                    // to function pointer types. -                    static RegularExpression g_symbol_plus_offset_regex("^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); -                    RegularExpression::Match regex_match(3); -                    if (g_symbol_plus_offset_regex.Execute(s, ®ex_match)) -                    { -                        uint64_t offset = 0; -                        bool add = true; -                        std::string name; -                        std::string str; -                        if (regex_match.GetMatchAtIndex(s, 1, name)) -                        { -                            if (regex_match.GetMatchAtIndex(s, 2, str)) -                            { -                                add = str[0] == '+'; -                                 -                                if (regex_match.GetMatchAtIndex(s, 3, str)) -                                { -                                    offset = StringConvert::ToUInt64(str.c_str(), 0, 0, &success); -                                     -                                    if (success) -                                    { -                                        Error error; -                                        addr = StringToAddress (exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error); -                                        if (addr != LLDB_INVALID_ADDRESS) -                                        { -                                            if (add) -                                                return addr + offset; -                                            else -                                                return addr - offset; -                                        } -                                    } -                                } -                            } -                        } -                    } -                     -                    if (error_ptr) -                    { -                        error_set = true; -                        error_ptr->SetErrorStringWithFormat("address expression \"%s\" evaluation failed", s); -                    } -                } -            } -        } -    } +lldb::addr_t Args::StringToAddress(const ExecutionContext *exe_ctx, +                                   llvm::StringRef s, lldb::addr_t fail_value, +                                   Error *error_ptr) { +  bool error_set = false; +  if (s.empty()) {      if (error_ptr) -    { -        if (!error_set) -            error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", s); -    } +      error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", +                                          s.str().c_str());      return fail_value; -} +  } -const char * -Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null_if_empty) -{ -    static const char *k_white_space = " \t\v"; -    if (!s.empty()) -    { -        if (leading) -        { -            size_t pos = s.find_first_not_of (k_white_space); -            if (pos == std::string::npos) -                s.clear(); -            else if (pos > 0) -                s.erase(0, pos); -        } -         -        if (trailing) -        { -            size_t rpos = s.find_last_not_of(k_white_space); -            if (rpos != std::string::npos && rpos + 1 < s.size()) -                s.erase(rpos + 1); -        } -    } -    if (return_null_if_empty && s.empty()) -        return nullptr; -    return s.c_str(); -} +  llvm::StringRef sref = s; -bool -Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr) -{ -    llvm::StringRef ref = llvm::StringRef(s).trim(); -    if (ref.equals_lower("false") || -        ref.equals_lower("off") || -        ref.equals_lower("no") || -        ref.equals_lower("0")) -    { -        if (success_ptr) -            *success_ptr = true; -        return false; -    } -    else -    if (ref.equals_lower("true") || -        ref.equals_lower("on") || -        ref.equals_lower("yes") || -        ref.equals_lower("1")) -    { -        if (success_ptr) *success_ptr = true; -        return true; -    } -    if (success_ptr) *success_ptr = false; -    return fail_value; -} +  lldb::addr_t addr = LLDB_INVALID_ADDRESS; +  if (!s.getAsInteger(0, addr)) { +    if (error_ptr) +      error_ptr->Clear(); +    return addr; +  } -char -Args::StringToChar(const char *s, char fail_value, bool *success_ptr) -{ -    bool success = false; -    char result = fail_value; - -    if (s) -    { -        size_t length = strlen(s); -        if (length == 1) -        { -            success = true; -            result = s[0]; -        } +  // Try base 16 with no prefix... +  if (!s.getAsInteger(16, addr)) { +    if (error_ptr) +      error_ptr->Clear(); +    return addr; +  } + +  Target *target = nullptr; +  if (!exe_ctx || !(target = exe_ctx->GetTargetPtr())) { +    if (error_ptr) +      error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", +                                          s.str().c_str()); +    return fail_value; +  } + +  lldb::ValueObjectSP valobj_sp; +  EvaluateExpressionOptions options; +  options.SetCoerceToId(false); +  options.SetUnwindOnError(true); +  options.SetKeepInMemory(false); +  options.SetTryAllThreads(true); + +  ExpressionResults expr_result = +      target->EvaluateExpression(s, exe_ctx->GetFramePtr(), valobj_sp, options); + +  bool success = false; +  if (expr_result == eExpressionCompleted) { +    if (valobj_sp) +      valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable( +          valobj_sp->GetDynamicValueType(), true); +    // Get the address to watch. +    if (valobj_sp) +      addr = valobj_sp->GetValueAsUnsigned(fail_value, &success); +    if (success) { +      if (error_ptr) +        error_ptr->Clear(); +      return addr; +    } else { +      if (error_ptr) { +        error_set = true; +        error_ptr->SetErrorStringWithFormat( +            "address expression \"%s\" resulted in a value whose type " +            "can't be converted to an address: %s", +            s.str().c_str(), valobj_sp->GetTypeName().GetCString()); +      }      } -    if (success_ptr) -        *success_ptr = success; -    return result; -} -const char * -Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update) -{ -    major = UINT32_MAX; -    minor = UINT32_MAX; -    update = UINT32_MAX; - -    if (s && s[0]) -    { -        char *pos = nullptr; -        unsigned long uval32 = ::strtoul (s, &pos, 0); -        if (pos == s) -            return s; -        major = uval32; -        if (*pos == '\0') -        { -            return pos;   // Decoded major and got end of string -        } -        else if (*pos == '.') -        { -            const char *minor_cstr = pos + 1; -            uval32 = ::strtoul (minor_cstr, &pos, 0); -            if (pos == minor_cstr) -                return pos; // Didn't get any digits for the minor version... -            minor = uval32; -            if (*pos == '.') -            { -                const char *update_cstr = pos + 1; -                uval32 = ::strtoul (update_cstr, &pos, 0); -                if (pos == update_cstr) -                    return pos; -                update = uval32; +  } else { +    // Since the compiler can't handle things like "main + 12" we should +    // try to do this for now. The compiler doesn't like adding offsets +    // to function pointer types. +    static RegularExpression g_symbol_plus_offset_regex( +        "^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); +    RegularExpression::Match regex_match(3); +    if (g_symbol_plus_offset_regex.Execute(sref, ®ex_match)) { +      uint64_t offset = 0; +      bool add = true; +      std::string name; +      std::string str; +      if (regex_match.GetMatchAtIndex(s, 1, name)) { +        if (regex_match.GetMatchAtIndex(s, 2, str)) { +          add = str[0] == '+'; + +          if (regex_match.GetMatchAtIndex(s, 3, str)) { +            offset = StringConvert::ToUInt64(str.c_str(), 0, 0, &success); + +            if (success) { +              Error error; +              addr = StringToAddress(exe_ctx, name.c_str(), +                                     LLDB_INVALID_ADDRESS, &error); +              if (addr != LLDB_INVALID_ADDRESS) { +                if (add) +                  return addr + offset; +                else +                  return addr - offset; +              }              } -            return pos; +          }          } +      }      } -    return nullptr; + +    if (error_ptr) { +      error_set = true; +      error_ptr->SetErrorStringWithFormat( +          "address expression \"%s\" evaluation failed", s.str().c_str()); +    } +  } + +  if (error_ptr) { +    if (!error_set) +      error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", +                                          s.str().c_str()); +  } +  return fail_value;  } -const char * -Args::GetShellSafeArgument (const FileSpec& shell, -                            const char *unsafe_arg, -                            std::string &safe_arg) -{ -    struct ShellDescriptor -    { -        ConstString m_basename; -        const char* m_escapables; -    }; -     -    static ShellDescriptor g_Shells[] = { -        {ConstString("bash")," '\"<>()&"}, -        {ConstString("tcsh")," '\"<>()&$"}, -        {ConstString("sh")," '\"<>()&"} -    }; -     -    // safe minimal set -    const char* escapables = " '\""; -     -    if (auto basename = shell.GetFilename()) -    { -        for (const auto& Shell : g_Shells) -        { -            if (Shell.m_basename == basename) -            { -                escapables = Shell.m_escapables; -                break; -            } -        } +const char *Args::StripSpaces(std::string &s, bool leading, bool trailing, +                              bool return_null_if_empty) { +  static const char *k_white_space = " \t\v"; +  if (!s.empty()) { +    if (leading) { +      size_t pos = s.find_first_not_of(k_white_space); +      if (pos == std::string::npos) +        s.clear(); +      else if (pos > 0) +        s.erase(0, pos);      } -    safe_arg.assign (unsafe_arg); -    size_t prev_pos = 0; -    while (prev_pos < safe_arg.size()) -    { -        // Escape spaces and quotes -        size_t pos = safe_arg.find_first_of(escapables, prev_pos); -        if (pos != std::string::npos) -        { -            safe_arg.insert (pos, 1, '\\'); -            prev_pos = pos + 2; -        } -        else -            break; +    if (trailing) { +      size_t rpos = s.find_last_not_of(k_white_space); +      if (rpos != std::string::npos && rpos + 1 < s.size()) +        s.erase(rpos + 1);      } -    return safe_arg.c_str(); +  } +  if (return_null_if_empty && s.empty()) +    return nullptr; +  return s.c_str();  } -int64_t -Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error) -{     -    if (enum_values) -    { -        if (s && s[0]) -        { -            for (int i = 0; enum_values[i].string_value != nullptr ; i++) -            { -                if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value) -                { -                    error.Clear(); -                    return enum_values[i].value; -                } -            } -        } +bool Args::StringToBoolean(llvm::StringRef ref, bool fail_value, +                           bool *success_ptr) { +  if (success_ptr) +    *success_ptr = true; +  ref = ref.trim(); +  if (ref.equals_lower("false") || ref.equals_lower("off") || +      ref.equals_lower("no") || ref.equals_lower("0")) { +    return false; +  } else if (ref.equals_lower("true") || ref.equals_lower("on") || +             ref.equals_lower("yes") || ref.equals_lower("1")) { +    return true; +  } +  if (success_ptr) +    *success_ptr = false; +  return fail_value; +} -        StreamString strm; -        strm.PutCString ("invalid enumeration value, valid values are: "); -        for (int i = 0; enum_values[i].string_value != nullptr; i++) -        { -            strm.Printf ("%s\"%s\"",  -                         i > 0 ? ", " : "", -                         enum_values[i].string_value); -        } -        error.SetErrorString(strm.GetData()); -    } -    else -    { -        error.SetErrorString ("invalid enumeration argument"); -    } +char Args::StringToChar(llvm::StringRef s, char fail_value, bool *success_ptr) { +  if (success_ptr) +    *success_ptr = false; +  if (s.size() != 1)      return fail_value; + +  if (success_ptr) +    *success_ptr = true; +  return s[0];  } -ScriptLanguage -Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr) -{ -    if (s && s[0]) -    { -        if ((::strcasecmp (s, "python") == 0) || -            (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault)) -        { -            if (success_ptr) *success_ptr = true; -            return eScriptLanguagePython; -        } -        if (::strcasecmp (s, "none")) -        { -            if (success_ptr) *success_ptr = true; -            return eScriptLanguageNone; -        } +bool Args::StringToVersion(llvm::StringRef string, uint32_t &major, +                           uint32_t &minor, uint32_t &update) { +  major = UINT32_MAX; +  minor = UINT32_MAX; +  update = UINT32_MAX; + +  if (string.empty()) +    return false; + +  llvm::StringRef major_str, minor_str, update_str; + +  std::tie(major_str, minor_str) = string.split('.'); +  std::tie(minor_str, update_str) = minor_str.split('.'); +  if (major_str.getAsInteger(10, major)) +    return false; +  if (!minor_str.empty() && minor_str.getAsInteger(10, minor)) +    return false; +  if (!update_str.empty() && update_str.getAsInteger(10, update)) +    return false; + +  return true; +} + +const char *Args::GetShellSafeArgument(const FileSpec &shell, +                                       const char *unsafe_arg, +                                       std::string &safe_arg) { +  struct ShellDescriptor { +    ConstString m_basename; +    const char *m_escapables; +  }; + +  static ShellDescriptor g_Shells[] = {{ConstString("bash"), " '\"<>()&"}, +                                       {ConstString("tcsh"), " '\"<>()&$"}, +                                       {ConstString("sh"), " '\"<>()&"}}; + +  // safe minimal set +  const char *escapables = " '\""; + +  if (auto basename = shell.GetFilename()) { +    for (const auto &Shell : g_Shells) { +      if (Shell.m_basename == basename) { +        escapables = Shell.m_escapables; +        break; +      }      } -    if (success_ptr) *success_ptr = false; -    return fail_value; +  } + +  safe_arg.assign(unsafe_arg); +  size_t prev_pos = 0; +  while (prev_pos < safe_arg.size()) { +    // Escape spaces and quotes +    size_t pos = safe_arg.find_first_of(escapables, prev_pos); +    if (pos != std::string::npos) { +      safe_arg.insert(pos, 1, '\\'); +      prev_pos = pos + 2; +    } else +      break; +  } +  return safe_arg.c_str();  } -Error -Args::StringToFormat -( -    const char *s, -    lldb::Format &format, -    size_t *byte_size_ptr -) -{ -    format = eFormatInvalid; -    Error error; - -    if (s && s[0]) -    { -        if (byte_size_ptr) -        { -            if (isdigit (s[0])) -            { -                char *format_char = nullptr; -                unsigned long byte_size = ::strtoul (s, &format_char, 0); -                if (byte_size != ULONG_MAX) -                    *byte_size_ptr = byte_size; -                s = format_char; -            } -            else -                *byte_size_ptr = 0; -        } +int64_t Args::StringToOptionEnum(llvm::StringRef s, +                                 OptionEnumValueElement *enum_values, +                                 int32_t fail_value, Error &error) { +  error.Clear(); +  if (!enum_values) { +    error.SetErrorString("invalid enumeration argument"); +    return fail_value; +  } -        const bool partial_match_ok = true; -        if (!FormatManager::GetFormatFromCString (s, partial_match_ok, format)) -        { -            StreamString error_strm; -            error_strm.Printf ("Invalid format character or name '%s'. Valid values are:\n", s); -            for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1)) -            { -                char format_char = FormatManager::GetFormatAsFormatChar(f); -                if (format_char) -                    error_strm.Printf ("'%c' or ", format_char); -             -                error_strm.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f)); -                error_strm.EOL(); -            } -             -            if (byte_size_ptr) -                error_strm.PutCString ("An optional byte size can precede the format character.\n"); -            error.SetErrorString(error_strm.GetString().c_str()); -        } +  if (s.empty()) { +    error.SetErrorString("empty enumeration string"); +    return fail_value; +  } + +  for (int i = 0; enum_values[i].string_value != nullptr; i++) { +    llvm::StringRef this_enum(enum_values[i].string_value); +    if (this_enum.startswith(s)) +      return enum_values[i].value; +  } + +  StreamString strm; +  strm.PutCString("invalid enumeration value, valid values are: "); +  for (int i = 0; enum_values[i].string_value != nullptr; i++) { +    strm.Printf("%s\"%s\"", i > 0 ? ", " : "", enum_values[i].string_value); +  } +  error.SetErrorString(strm.GetString()); +  return fail_value; +} -        if (error.Fail()) -            return error; +lldb::ScriptLanguage +Args::StringToScriptLanguage(llvm::StringRef s, lldb::ScriptLanguage fail_value, +                             bool *success_ptr) { +  if (success_ptr) +    *success_ptr = true; + +  if (s.equals_lower("python")) +    return eScriptLanguagePython; +  if (s.equals_lower("default")) +    return eScriptLanguageDefault; +  if (s.equals_lower("none")) +    return eScriptLanguageNone; + +  if (success_ptr) +    *success_ptr = false; +  return fail_value; +} + +Error Args::StringToFormat(const char *s, lldb::Format &format, +                           size_t *byte_size_ptr) { +  format = eFormatInvalid; +  Error error; + +  if (s && s[0]) { +    if (byte_size_ptr) { +      if (isdigit(s[0])) { +        char *format_char = nullptr; +        unsigned long byte_size = ::strtoul(s, &format_char, 0); +        if (byte_size != ULONG_MAX) +          *byte_size_ptr = byte_size; +        s = format_char; +      } else +        *byte_size_ptr = 0;      } -    else -    { -        error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid"); + +    const bool partial_match_ok = true; +    if (!FormatManager::GetFormatFromCString(s, partial_match_ok, format)) { +      StreamString error_strm; +      error_strm.Printf( +          "Invalid format character or name '%s'. Valid values are:\n", s); +      for (Format f = eFormatDefault; f < kNumFormats; f = Format(f + 1)) { +        char format_char = FormatManager::GetFormatAsFormatChar(f); +        if (format_char) +          error_strm.Printf("'%c' or ", format_char); + +        error_strm.Printf("\"%s\"", FormatManager::GetFormatAsCString(f)); +        error_strm.EOL(); +      } + +      if (byte_size_ptr) +        error_strm.PutCString( +            "An optional byte size can precede the format character.\n"); +      error.SetErrorString(error_strm.GetString());      } -    return error; + +    if (error.Fail()) +      return error; +  } else { +    error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid"); +  } +  return error;  } -lldb::Encoding -Args::StringToEncoding (const char *s, lldb::Encoding fail_value) -{ -    if (s && s[0]) -    { -        if (strcmp(s, "uint") == 0) -            return eEncodingUint; -        else if (strcmp(s, "sint") == 0) -            return eEncodingSint; -        else if (strcmp(s, "ieee754") == 0) -            return eEncodingIEEE754; -        else if (strcmp(s, "vector") == 0) -            return eEncodingVector; -    } -    return fail_value; +lldb::Encoding Args::StringToEncoding(llvm::StringRef s, +                                      lldb::Encoding fail_value) { +  return llvm::StringSwitch<lldb::Encoding>(s) +      .Case("uint", eEncodingUint) +      .Case("sint", eEncodingSint) +      .Case("ieee754", eEncodingIEEE754) +      .Case("vector", eEncodingVector) +      .Default(fail_value);  } -uint32_t -Args::StringToGenericRegister (const char *s) -{ -    if (s && s[0]) -    { -        if (strcmp(s, "pc") == 0) -            return LLDB_REGNUM_GENERIC_PC; -        else if (strcmp(s, "sp") == 0) -            return LLDB_REGNUM_GENERIC_SP; -        else if (strcmp(s, "fp") == 0) -            return LLDB_REGNUM_GENERIC_FP; -        else if (strcmp(s, "ra") == 0 || strcmp(s, "lr") == 0) -            return LLDB_REGNUM_GENERIC_RA; -        else if (strcmp(s, "flags") == 0) -            return LLDB_REGNUM_GENERIC_FLAGS; -        else if (strncmp(s, "arg", 3) == 0) -        { -            if (s[3] && s[4] == '\0') -            { -                switch (s[3]) -                { -                    case '1': return LLDB_REGNUM_GENERIC_ARG1; -                    case '2': return LLDB_REGNUM_GENERIC_ARG2; -                    case '3': return LLDB_REGNUM_GENERIC_ARG3; -                    case '4': return LLDB_REGNUM_GENERIC_ARG4; -                    case '5': return LLDB_REGNUM_GENERIC_ARG5; -                    case '6': return LLDB_REGNUM_GENERIC_ARG6; -                    case '7': return LLDB_REGNUM_GENERIC_ARG7; -                    case '8': return LLDB_REGNUM_GENERIC_ARG8; -                } -            } -        } -    } +uint32_t Args::StringToGenericRegister(llvm::StringRef s) { +  if (s.empty())      return LLDB_INVALID_REGNUM; +  uint32_t result = llvm::StringSwitch<uint32_t>(s) +                        .Case("pc", LLDB_REGNUM_GENERIC_PC) +                        .Case("sp", LLDB_REGNUM_GENERIC_SP) +                        .Case("fp", LLDB_REGNUM_GENERIC_FP) +                        .Cases("ra", "lr", LLDB_REGNUM_GENERIC_RA) +                        .Case("flags", LLDB_REGNUM_GENERIC_FLAGS) +                        .Case("arg1", LLDB_REGNUM_GENERIC_ARG1) +                        .Case("arg2", LLDB_REGNUM_GENERIC_ARG2) +                        .Case("arg3", LLDB_REGNUM_GENERIC_ARG3) +                        .Case("arg4", LLDB_REGNUM_GENERIC_ARG4) +                        .Case("arg5", LLDB_REGNUM_GENERIC_ARG5) +                        .Case("arg6", LLDB_REGNUM_GENERIC_ARG6) +                        .Case("arg7", LLDB_REGNUM_GENERIC_ARG7) +                        .Case("arg8", LLDB_REGNUM_GENERIC_ARG8) +                        .Default(LLDB_INVALID_REGNUM); +  return result;  } +void Args::AddOrReplaceEnvironmentVariable(llvm::StringRef env_var_name, +                                           llvm::StringRef new_value) { +  if (env_var_name.empty()) +    return; + +  // Build the new entry. +  std::string var_string(env_var_name); +  if (!new_value.empty()) { +    var_string += "="; +    var_string += new_value; +  } + +  size_t index = 0; +  if (ContainsEnvironmentVariable(env_var_name, &index)) { +    ReplaceArgumentAtIndex(index, var_string); +    return; +  } + +  // We didn't find it.  Append it instead. +  AppendArgument(var_string); +} -void -Args::LongestCommonPrefix (std::string &common_prefix) -{ -    arg_sstr_collection::iterator pos, end = m_args.end(); -    pos = m_args.begin(); -    if (pos == end) -        common_prefix.clear(); -    else -        common_prefix = (*pos); - -    for (++pos; pos != end; ++pos) -    { -        size_t new_size = (*pos).size(); - -        // First trim common_prefix if it is longer than the current element: -        if (common_prefix.size() > new_size) -            common_prefix.erase (new_size); - -        // Then trim it at the first disparity: - -        for (size_t i = 0; i < common_prefix.size(); i++) -        { -            if ((*pos)[i]  != common_prefix[i]) -            { -                common_prefix.erase(i); -                break; -            } -        } +bool Args::ContainsEnvironmentVariable(llvm::StringRef env_var_name, +                                       size_t *argument_index) const { +  // Validate args. +  if (env_var_name.empty()) +    return false; -        // If we've emptied the common prefix, we're done. -        if (common_prefix.empty()) -            break; -    } -} +  // Check each arg to see if it matches the env var name. +  for (auto arg : llvm::enumerate(m_entries)) { +    llvm::StringRef name, value; +    std::tie(name, value) = arg.Value.ref.split('='); +    if (name != env_var_name) +      continue; -bool -Args::ContainsEnvironmentVariable(const char *env_var_name) const -{ -    // Validate args. -    if (!env_var_name) -        return false; - -    // Check each arg to see if it matches the env var name. -    for (size_t i = 0; i < GetArgumentCount(); ++i) -    { -        // Get the arg value. -        const char *argument_value = GetArgumentAtIndex(i); -        if (!argument_value) -            continue; - -        // Check if we are the "{env_var_name}={env_var_value}" style. -        const char *equal_p = strchr(argument_value, '='); -        if (equal_p) -        { -            if (strncmp(env_var_name, argument_value, -                        equal_p - argument_value) == 0) -            { -                // We matched. -                return true; -            } -        } -        else -        { -            // We're a simple {env_var_name}-style entry. -            if (strcmp(argument_value, env_var_name) == 0) -            { -                // We matched. -                return true; -            } -        } -    } +    if (argument_index) +      *argument_index = arg.Index; +    return true; +  } -    // We didn't find a match. -    return false; +  // We didn't find a match. +  return false;  } -size_t -Args::FindArgumentIndexForOption (Option *long_options, int long_options_index) -{ -    char short_buffer[3]; -    char long_buffer[255]; -    ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val); -    ::snprintf (long_buffer, sizeof (long_buffer),  "--%s", long_options[long_options_index].definition->long_option); -    size_t end = GetArgumentCount (); -    size_t idx = 0; -    while (idx < end) -    {    -        if ((::strncmp (GetArgumentAtIndex (idx), short_buffer, strlen (short_buffer)) == 0) -            || (::strncmp (GetArgumentAtIndex (idx), long_buffer, strlen (long_buffer)) == 0)) -            { -                return idx; -            } -        ++idx; -    } - -    return end; +size_t Args::FindArgumentIndexForOption(Option *long_options, +                                        int long_options_index) const { +  char short_buffer[3]; +  char long_buffer[255]; +  ::snprintf(short_buffer, sizeof(short_buffer), "-%c", +             long_options[long_options_index].val); +  ::snprintf(long_buffer, sizeof(long_buffer), "--%s", +             long_options[long_options_index].definition->long_option); + +  for (auto entry : llvm::enumerate(m_entries)) { +    if (entry.Value.ref.startswith(short_buffer) || +        entry.Value.ref.startswith(long_buffer)) +      return entry.Index; +  } + +  return size_t(-1);  } -bool -Args::IsPositionalArgument (const char *arg) -{ -    if (arg == nullptr) -        return false; -         -    bool is_positional = true; -    const char *cptr = arg; -     -    if (cptr[0] == '%') -    { -        ++cptr; -        while (isdigit (cptr[0])) -            ++cptr; -        if (cptr[0] != '\0') -            is_positional = false; -    } -    else -        is_positional = false; +bool Args::IsPositionalArgument(const char *arg) { +  if (arg == nullptr) +    return false; + +  bool is_positional = true; +  const char *cptr = arg; + +  if (cptr[0] == '%') { +    ++cptr; +    while (isdigit(cptr[0])) +      ++cptr; +    if (cptr[0] != '\0') +      is_positional = false; +  } else +    is_positional = false; -    return is_positional; +  return is_positional;  } -void -Args::ParseAliasOptions (Options &options, -                         CommandReturnObject &result, -                         OptionArgVector *option_arg_vector, -                         std::string &raw_input_string) -{ -    StreamString sstr; -    int i; -    Option *long_options = options.GetLongOptions(); - -    if (long_options == nullptr) -    { -        result.AppendError ("invalid long options"); -        result.SetStatus (eReturnStatusFailed); -        return; +std::string Args::ParseAliasOptions(Options &options, +                                    CommandReturnObject &result, +                                    OptionArgVector *option_arg_vector, +                                    llvm::StringRef raw_input_string) { +  std::string result_string(raw_input_string); +  StreamString sstr; +  int i; +  Option *long_options = options.GetLongOptions(); + +  if (long_options == nullptr) { +    result.AppendError("invalid long options"); +    result.SetStatus(eReturnStatusFailed); +    return result_string; +  } + +  for (i = 0; long_options[i].definition != nullptr; ++i) { +    if (long_options[i].flag == nullptr) { +      sstr << (char)long_options[i].val; +      switch (long_options[i].definition->option_has_arg) { +      default: +      case OptionParser::eNoArgument: +        break; +      case OptionParser::eRequiredArgument: +        sstr << ":"; +        break; +      case OptionParser::eOptionalArgument: +        sstr << "::"; +        break; +      }      } - -    for (i = 0; long_options[i].definition != nullptr; ++i) -    { -        if (long_options[i].flag == nullptr) -        { -            sstr << (char) long_options[i].val; -            switch (long_options[i].definition->option_has_arg) -            { -                default: -                case OptionParser::eNoArgument: -                    break; -                case OptionParser::eRequiredArgument: -                    sstr << ":"; -                    break; -                case OptionParser::eOptionalArgument: -                    sstr << "::"; -                    break; -            } -        } +  } + +  std::unique_lock<std::mutex> lock; +  OptionParser::Prepare(lock); +  result.SetStatus(eReturnStatusSuccessFinishNoResult); +  int val; +  while (1) { +    int long_options_index = -1; +    val = OptionParser::Parse(GetArgumentCount(), GetArgumentVector(), +                              sstr.GetString(), long_options, +                              &long_options_index); + +    if (val == -1) +      break; + +    if (val == '?') { +      result.AppendError("unknown or ambiguous option"); +      result.SetStatus(eReturnStatusFailed); +      break;      } -    std::unique_lock<std::mutex> lock; -    OptionParser::Prepare(lock); -    int val; -    while (1) -    { -        int long_options_index = -1; -        val = OptionParser::Parse (GetArgumentCount(), -                                  GetArgumentVector(), -                                  sstr.GetData(), -                                  long_options, -                                  &long_options_index); - -        if (val == -1) -            break; - -        if (val == '?') -        { -            result.AppendError ("unknown or ambiguous option"); -            result.SetStatus (eReturnStatusFailed); -            break; -        } +    if (val == 0) +      continue; -        if (val == 0) -            continue; - -        options.OptionSeen (val); - -        // Look up the long option index -        if (long_options_index == -1) -        { -            for (int j = 0; -                 long_options[j].definition || long_options[j].flag || long_options[j].val; -                 ++j) -            { -                if (long_options[j].val == val) -                { -                    long_options_index = j; -                    break; -                } -            } -        } +    options.OptionSeen(val); -        // See if the option takes an argument, and see if one was supplied. -        if (long_options_index >= 0) -        { -            StreamString option_str; -            option_str.Printf ("-%c", val); -            const OptionDefinition *def = long_options[long_options_index].definition; -            int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; - -            switch (has_arg) -            { -            case OptionParser::eNoArgument: -                option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),  -                                                             OptionArgValue (OptionParser::eNoArgument, "<no-argument>"))); -                result.SetStatus (eReturnStatusSuccessFinishNoResult); -                break; -            case OptionParser::eRequiredArgument: -                if (OptionParser::GetOptionArgument() != nullptr) -                { -                    option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), -                                                                 OptionArgValue (OptionParser::eRequiredArgument, -                                                                                 std::string (OptionParser::GetOptionArgument())))); -                    result.SetStatus (eReturnStatusSuccessFinishNoResult); -                } -                else -                { -                    result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n", -                                                 option_str.GetData()); -                    result.SetStatus (eReturnStatusFailed); -                } -                break; -            case OptionParser::eOptionalArgument: -                if (OptionParser::GetOptionArgument() != nullptr) -                { -                    option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), -                                                                 OptionArgValue (OptionParser::eOptionalArgument, -                                                                                 std::string (OptionParser::GetOptionArgument())))); -                    result.SetStatus (eReturnStatusSuccessFinishNoResult); -                } -                else -                { -                    option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), -                                                                 OptionArgValue (OptionParser::eOptionalArgument, "<no-argument>"))); -                    result.SetStatus (eReturnStatusSuccessFinishNoResult); -                } -                break; -            default: -                result.AppendErrorWithFormat ("error with options table; invalid value in has_arg field for option '%c'.\n", val); -                result.SetStatus (eReturnStatusFailed); -                break; -            } -        } -        else -        { -            result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", val); -            result.SetStatus (eReturnStatusFailed); +    // Look up the long option index +    if (long_options_index == -1) { +      for (int j = 0; long_options[j].definition || long_options[j].flag || +                      long_options[j].val; +           ++j) { +        if (long_options[j].val == val) { +          long_options_index = j; +          break;          } +      } +    } -        if (long_options_index >= 0) -        { -            // Find option in the argument list; also see if it was supposed to take an argument and if one was -            // supplied.  Remove option (and argument, if given) from the argument list.  Also remove them from -            // the raw_input_string, if one was passed in. -            size_t idx = FindArgumentIndexForOption (long_options, long_options_index); -            if (idx < GetArgumentCount()) -            { -                if (raw_input_string.size() > 0) -                { -                    const char *tmp_arg = GetArgumentAtIndex (idx); -                    size_t pos = raw_input_string.find (tmp_arg); -                    if (pos != std::string::npos) -                        raw_input_string.erase (pos, strlen (tmp_arg)); -                } -                ReplaceArgumentAtIndex (idx, ""); -                if ((long_options[long_options_index].definition->option_has_arg != OptionParser::eNoArgument) -                    && (OptionParser::GetOptionArgument() != nullptr) -                    && (idx+1 < GetArgumentCount()) -                    && (strcmp (OptionParser::GetOptionArgument(), GetArgumentAtIndex(idx+1)) == 0)) -                { -                    if (raw_input_string.size() > 0) -                    { -                        const char *tmp_arg = GetArgumentAtIndex (idx+1); -                        size_t pos = raw_input_string.find (tmp_arg); -                        if (pos != std::string::npos) -                            raw_input_string.erase (pos, strlen (tmp_arg)); -                    } -                    ReplaceArgumentAtIndex (idx+1, ""); -                } -            } -        } +    // See if the option takes an argument, and see if one was supplied. +    if (long_options_index == -1) { +      result.AppendErrorWithFormat("Invalid option with value '%c'.\n", val); +      result.SetStatus(eReturnStatusFailed); +      return result_string; +    } -        if (!result.Succeeded()) -            break; +    StreamString option_str; +    option_str.Printf("-%c", val); +    const OptionDefinition *def = long_options[long_options_index].definition; +    int has_arg = +        (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; + +    const char *option_arg = nullptr; +    switch (has_arg) { +    case OptionParser::eRequiredArgument: +      if (OptionParser::GetOptionArgument() == nullptr) { +        result.AppendErrorWithFormat( +            "Option '%s' is missing argument specifier.\n", +            option_str.GetData()); +        result.SetStatus(eReturnStatusFailed); +        return result_string; +      } +      LLVM_FALLTHROUGH; +    case OptionParser::eOptionalArgument: +      option_arg = OptionParser::GetOptionArgument(); +      LLVM_FALLTHROUGH; +    case OptionParser::eNoArgument: +      break; +    default: +      result.AppendErrorWithFormat("error with options table; invalid value " +                                   "in has_arg field for option '%c'.\n", +                                   val); +      result.SetStatus(eReturnStatusFailed); +      return result_string;      } +    if (!option_arg) +      option_arg = "<no-argument>"; +    option_arg_vector->emplace_back(option_str.GetString(), has_arg, +                                    option_arg); + +    // Find option in the argument list; also see if it was supposed to take +    // an argument and if one was supplied.  Remove option (and argument, if +    // given) from the argument list.  Also remove them from the +    // raw_input_string, if one was passed in. +    size_t idx = FindArgumentIndexForOption(long_options, long_options_index); +    if (idx == size_t(-1)) +      continue; + +    if (!result_string.empty()) { +      auto tmp_arg = m_entries[idx].ref; +      size_t pos = result_string.find(tmp_arg); +      if (pos != std::string::npos) +        result_string.erase(pos, tmp_arg.size()); +    } +    ReplaceArgumentAtIndex(idx, llvm::StringRef()); +    if ((long_options[long_options_index].definition->option_has_arg != +         OptionParser::eNoArgument) && +        (OptionParser::GetOptionArgument() != nullptr) && +        (idx + 1 < GetArgumentCount()) && +        (m_entries[idx + 1].ref == OptionParser::GetOptionArgument())) { +      if (result_string.size() > 0) { +        auto tmp_arg = m_entries[idx + 1].ref; +        size_t pos = result_string.find(tmp_arg); +        if (pos != std::string::npos) +          result_string.erase(pos, tmp_arg.size()); +      } +      ReplaceArgumentAtIndex(idx + 1, llvm::StringRef()); +    } +  } +  return result_string;  } -void -Args::ParseArgsForCompletion -( -    Options &options, -    OptionElementVector &option_element_vector, -    uint32_t cursor_index -) -{ -    StreamString sstr; -    Option *long_options = options.GetLongOptions(); -    option_element_vector.clear(); - -    if (long_options == nullptr) -    { -        return; +void Args::ParseArgsForCompletion(Options &options, +                                  OptionElementVector &option_element_vector, +                                  uint32_t cursor_index) { +  StreamString sstr; +  Option *long_options = options.GetLongOptions(); +  option_element_vector.clear(); + +  if (long_options == nullptr) { +    return; +  } + +  // Leading : tells getopt to return a : for a missing option argument AND +  // to suppress error messages. + +  sstr << ":"; +  for (int i = 0; long_options[i].definition != nullptr; ++i) { +    if (long_options[i].flag == nullptr) { +      sstr << (char)long_options[i].val; +      switch (long_options[i].definition->option_has_arg) { +      default: +      case OptionParser::eNoArgument: +        break; +      case OptionParser::eRequiredArgument: +        sstr << ":"; +        break; +      case OptionParser::eOptionalArgument: +        sstr << "::"; +        break; +      }      } - -    // Leading : tells getopt to return a : for a missing option argument AND -    // to suppress error messages. - -    sstr << ":"; -    for (int i = 0; long_options[i].definition != nullptr; ++i) -    { -        if (long_options[i].flag == nullptr) -        { -            sstr << (char) long_options[i].val; -            switch (long_options[i].definition->option_has_arg) -            { -                default: -                case OptionParser::eNoArgument: -                    break; -                case OptionParser::eRequiredArgument: -                    sstr << ":"; -                    break; -                case OptionParser::eOptionalArgument: -                    sstr << "::"; -                    break; -            } -        } +  } + +  std::unique_lock<std::mutex> lock; +  OptionParser::Prepare(lock); +  OptionParser::EnableError(false); + +  int val; +  auto opt_defs = options.GetDefinitions(); + +  // Fooey... OptionParser::Parse permutes the GetArgumentVector to move the +  // options to the front. So we have to build another Arg and pass that to +  // OptionParser::Parse so it doesn't change the one we have. + +  std::vector<char *> dummy_vec = m_argv; + +  bool failed_once = false; +  uint32_t dash_dash_pos = -1; + +  while (1) { +    bool missing_argument = false; +    int long_options_index = -1; + +    val = OptionParser::Parse(dummy_vec.size() - 1, &dummy_vec[0], +                              sstr.GetString(), long_options, +                              &long_options_index); + +    if (val == -1) { +      // When we're completing a "--" which is the last option on line, +      if (failed_once) +        break; + +      failed_once = true; + +      // If this is a bare  "--" we mark it as such so we can complete it +      // successfully later. +      // Handling the "--" is a little tricky, since that may mean end of +      // options or arguments, or the +      // user might want to complete options by long name.  I make this work by +      // checking whether the +      // cursor is in the "--" argument, and if so I assume we're completing the +      // long option, otherwise +      // I let it pass to OptionParser::Parse which will terminate the option +      // parsing. +      // Note, in either case we continue parsing the line so we can figure out +      // what other options +      // were passed.  This will be useful when we come to restricting +      // completions based on what other +      // options we've seen on the line. + +      if (static_cast<size_t>(OptionParser::GetOptionIndex()) < +              dummy_vec.size() - 1 && +          (strcmp(dummy_vec[OptionParser::GetOptionIndex() - 1], "--") == 0)) { +        dash_dash_pos = OptionParser::GetOptionIndex() - 1; +        if (static_cast<size_t>(OptionParser::GetOptionIndex() - 1) == +            cursor_index) { +          option_element_vector.push_back( +              OptionArgElement(OptionArgElement::eBareDoubleDash, +                               OptionParser::GetOptionIndex() - 1, +                               OptionArgElement::eBareDoubleDash)); +          continue; +        } else +          break; +      } else +        break; +    } else if (val == '?') { +      option_element_vector.push_back( +          OptionArgElement(OptionArgElement::eUnrecognizedArg, +                           OptionParser::GetOptionIndex() - 1, +                           OptionArgElement::eUnrecognizedArg)); +      continue; +    } else if (val == 0) { +      continue; +    } else if (val == ':') { +      // This is a missing argument. +      val = OptionParser::GetOptionErrorCause(); +      missing_argument = true;      } -    std::unique_lock<std::mutex> lock; -    OptionParser::Prepare(lock); -    OptionParser::EnableError(false); - -    int val; -    const OptionDefinition *opt_defs = options.GetDefinitions(); - -    // Fooey... OptionParser::Parse permutes the GetArgumentVector to move the options to the front. -    // So we have to build another Arg and pass that to OptionParser::Parse so it doesn't -    // change the one we have. - -    std::vector<const char *> dummy_vec (GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1); - -    bool failed_once = false; -    uint32_t dash_dash_pos = -1; -         -    while (1) -    { -        bool missing_argument = false; -        int long_options_index = -1; -         -        val = OptionParser::Parse (dummy_vec.size() - 1, -                                  const_cast<char *const *>(&dummy_vec.front()), -                                  sstr.GetData(), -                                  long_options, -                                  &long_options_index); - -        if (val == -1) -        { -            // When we're completing a "--" which is the last option on line,  -            if (failed_once) -                break; -                 -            failed_once = true; -             -            // If this is a bare  "--" we mark it as such so we can complete it successfully later. -            // Handling the "--" is a little tricky, since that may mean end of options or arguments, or the -            // user might want to complete options by long name.  I make this work by checking whether the -            // cursor is in the "--" argument, and if so I assume we're completing the long option, otherwise -            // I let it pass to OptionParser::Parse which will terminate the option parsing. -            // Note, in either case we continue parsing the line so we can figure out what other options -            // were passed.  This will be useful when we come to restricting completions based on what other -            // options we've seen on the line. - -            if (static_cast<size_t>(OptionParser::GetOptionIndex()) < dummy_vec.size() - 1 -                && (strcmp (dummy_vec[OptionParser::GetOptionIndex()-1], "--") == 0)) -            { -                dash_dash_pos = OptionParser::GetOptionIndex() - 1; -                if (static_cast<size_t>(OptionParser::GetOptionIndex() - 1) == cursor_index) -                { -                    option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, OptionParser::GetOptionIndex() - 1, -                                                                   OptionArgElement::eBareDoubleDash)); -                    continue; -                } -                else -                    break; -            } -            else -                break; -        } -        else if (val == '?') -        { -            option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1, -                                                               OptionArgElement::eUnrecognizedArg)); -            continue; -        } -        else if (val == 0) -        { -            continue; -        } -        else if (val == ':') -        { -            // This is a missing argument. -            val = OptionParser::GetOptionErrorCause(); -            missing_argument = true; -        } +    ((Options *)&options)->OptionSeen(val); -        ((Options *) &options)->OptionSeen (val); - -        // Look up the long option index -        if (long_options_index == -1) -        { -            for (int j = 0; -                 long_options[j].definition || long_options[j].flag || long_options[j].val; -                 ++j) -            { -                if (long_options[j].val == val) -                { -                    long_options_index = j; -                    break; -                } -            } +    // Look up the long option index +    if (long_options_index == -1) { +      for (int j = 0; long_options[j].definition || long_options[j].flag || +                      long_options[j].val; +           ++j) { +        if (long_options[j].val == val) { +          long_options_index = j; +          break;          } +      } +    } -        // See if the option takes an argument, and see if one was supplied. -        if (long_options_index >= 0) -        { -            int opt_defs_index = -1; -            for (int i = 0; ; i++) -            { -                if (opt_defs[i].short_option == 0) -                    break; -                else if (opt_defs[i].short_option == val) -                { -                    opt_defs_index = i; -                    break; -                } -            } - -            const OptionDefinition *def = long_options[long_options_index].definition; -            int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; -            switch (has_arg) -            { -            case OptionParser::eNoArgument: -                option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, 0)); -                break; -            case OptionParser::eRequiredArgument: -                if (OptionParser::GetOptionArgument() != nullptr) -                { -                    int arg_index; -                    if (missing_argument) -                        arg_index = -1; -                    else -                        arg_index = OptionParser::GetOptionIndex() - 1; - -                    option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, arg_index)); -                } -                else -                { -                    option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, -1)); -                } -                break; -            case OptionParser::eOptionalArgument: -                if (OptionParser::GetOptionArgument() != nullptr) -                { -                    option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1)); -                } -                else -                { -                    option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1)); -                } -                break; -            default: -                // The options table is messed up.  Here we'll just continue -                option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1, -                                                                   OptionArgElement::eUnrecognizedArg)); -                break; -            } +    // See if the option takes an argument, and see if one was supplied. +    if (long_options_index >= 0) { +      int opt_defs_index = -1; +      for (size_t i = 0; i < opt_defs.size(); i++) { +        if (opt_defs[i].short_option != val) +          continue; +        opt_defs_index = i; +        break; +      } + +      const OptionDefinition *def = long_options[long_options_index].definition; +      int has_arg = +          (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; +      switch (has_arg) { +      case OptionParser::eNoArgument: +        option_element_vector.push_back(OptionArgElement( +            opt_defs_index, OptionParser::GetOptionIndex() - 1, 0)); +        break; +      case OptionParser::eRequiredArgument: +        if (OptionParser::GetOptionArgument() != nullptr) { +          int arg_index; +          if (missing_argument) +            arg_index = -1; +          else +            arg_index = OptionParser::GetOptionIndex() - 1; + +          option_element_vector.push_back(OptionArgElement( +              opt_defs_index, OptionParser::GetOptionIndex() - 2, arg_index)); +        } else { +          option_element_vector.push_back(OptionArgElement( +              opt_defs_index, OptionParser::GetOptionIndex() - 1, -1));          } -        else -        { -            option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1, -                                                               OptionArgElement::eUnrecognizedArg)); +        break; +      case OptionParser::eOptionalArgument: +        if (OptionParser::GetOptionArgument() != nullptr) { +          option_element_vector.push_back(OptionArgElement( +              opt_defs_index, OptionParser::GetOptionIndex() - 2, +              OptionParser::GetOptionIndex() - 1)); +        } else { +          option_element_vector.push_back(OptionArgElement( +              opt_defs_index, OptionParser::GetOptionIndex() - 2, +              OptionParser::GetOptionIndex() - 1));          } +        break; +      default: +        // The options table is messed up.  Here we'll just continue +        option_element_vector.push_back( +            OptionArgElement(OptionArgElement::eUnrecognizedArg, +                             OptionParser::GetOptionIndex() - 1, +                             OptionArgElement::eUnrecognizedArg)); +        break; +      } +    } else { +      option_element_vector.push_back( +          OptionArgElement(OptionArgElement::eUnrecognizedArg, +                           OptionParser::GetOptionIndex() - 1, +                           OptionArgElement::eUnrecognizedArg));      } -     -    // Finally we have to handle the case where the cursor index points at a single "-".  We want to mark that in -    // the option_element_vector, but only if it is not after the "--".  But it turns out that OptionParser::Parse just ignores -    // an isolated "-".  So we have to look it up by hand here.  We only care if it is AT the cursor position. -    // Note, a single quoted dash is not the same as a single dash... -     -    if ((static_cast<int32_t>(dash_dash_pos) == -1 || cursor_index < dash_dash_pos) -         && m_args_quote_char[cursor_index] == '\0' -         && strcmp (GetArgumentAtIndex(cursor_index), "-") == 0) -    { -        option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index,  -                                                           OptionArgElement::eBareDash)); -         -    } +  } + +  // Finally we have to handle the case where the cursor index points at a +  // single "-".  We want to mark that in +  // the option_element_vector, but only if it is not after the "--".  But it +  // turns out that OptionParser::Parse just ignores +  // an isolated "-".  So we have to look it up by hand here.  We only care if +  // it is AT the cursor position. +  // Note, a single quoted dash is not the same as a single dash... + +  const ArgEntry &cursor = m_entries[cursor_index]; +  if ((static_cast<int32_t>(dash_dash_pos) == -1 || +       cursor_index < dash_dash_pos) && +      cursor.quote == '\0' && cursor.ref == "-") { +    option_element_vector.push_back( +        OptionArgElement(OptionArgElement::eBareDash, cursor_index, +                         OptionArgElement::eBareDash)); +  }  } -void -Args::EncodeEscapeSequences (const char *src, std::string &dst) -{ -    dst.clear(); -    if (src) -    { -        for (const char *p = src; *p != '\0'; ++p) -        { -            size_t non_special_chars = ::strcspn (p, "\\"); -            if (non_special_chars > 0) -            { -                dst.append(p, non_special_chars); -                p += non_special_chars; -                if (*p == '\0') -                    break; +void Args::EncodeEscapeSequences(const char *src, std::string &dst) { +  dst.clear(); +  if (src) { +    for (const char *p = src; *p != '\0'; ++p) { +      size_t non_special_chars = ::strcspn(p, "\\"); +      if (non_special_chars > 0) { +        dst.append(p, non_special_chars); +        p += non_special_chars; +        if (*p == '\0') +          break; +      } + +      if (*p == '\\') { +        ++p; // skip the slash +        switch (*p) { +        case 'a': +          dst.append(1, '\a'); +          break; +        case 'b': +          dst.append(1, '\b'); +          break; +        case 'f': +          dst.append(1, '\f'); +          break; +        case 'n': +          dst.append(1, '\n'); +          break; +        case 'r': +          dst.append(1, '\r'); +          break; +        case 't': +          dst.append(1, '\t'); +          break; +        case 'v': +          dst.append(1, '\v'); +          break; +        case '\\': +          dst.append(1, '\\'); +          break; +        case '\'': +          dst.append(1, '\''); +          break; +        case '"': +          dst.append(1, '"'); +          break; +        case '0': +          // 1 to 3 octal chars +          { +            // Make a string that can hold onto the initial zero char, +            // up to 3 octal digits, and a terminating NULL. +            char oct_str[5] = {'\0', '\0', '\0', '\0', '\0'}; + +            int i; +            for (i = 0; (p[i] >= '0' && p[i] <= '7') && i < 4; ++i) +              oct_str[i] = p[i]; + +            // We don't want to consume the last octal character since +            // the main for loop will do this for us, so we advance p by +            // one less than i (even if i is zero) +            p += i - 1; +            unsigned long octal_value = ::strtoul(oct_str, nullptr, 8); +            if (octal_value <= UINT8_MAX) { +              dst.append(1, (char)octal_value);              } -             -            if (*p == '\\') -            { -                ++p; // skip the slash -                switch (*p) -                { -                    case 'a' : dst.append(1, '\a'); break; -                    case 'b' : dst.append(1, '\b'); break; -                    case 'f' : dst.append(1, '\f'); break; -                    case 'n' : dst.append(1, '\n'); break; -                    case 'r' : dst.append(1, '\r'); break; -                    case 't' : dst.append(1, '\t'); break; -                    case 'v' : dst.append(1, '\v'); break; -                    case '\\': dst.append(1, '\\'); break; -                    case '\'': dst.append(1, '\''); break; -                    case '"' : dst.append(1, '"'); break; -                    case '0' : -                        // 1 to 3 octal chars -                    { -                        // Make a string that can hold onto the initial zero char, -                        // up to 3 octal digits, and a terminating NULL. -                        char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' }; -                         -                        int i; -                        for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i) -                            oct_str[i] = p[i]; -                         -                        // We don't want to consume the last octal character since -                        // the main for loop will do this for us, so we advance p by -                        // one less than i (even if i is zero) -                        p += i - 1; -                        unsigned long octal_value = ::strtoul (oct_str, nullptr, 8); -                        if (octal_value <= UINT8_MAX) -                        { -                            dst.append(1, (char)octal_value); -                        } -                    } -                        break; -                         -                    case 'x': -                        // hex number in the format -                        if (isxdigit(p[1])) -                        { -                            ++p;    // Skip the 'x' -                             -                            // Make a string that can hold onto two hex chars plus a -                            // NULL terminator -                            char hex_str[3] = { *p, '\0', '\0' }; -                            if (isxdigit(p[1])) -                            { -                                ++p; // Skip the first of the two hex chars -                                hex_str[1] = *p; -                            } -                             -                            unsigned long hex_value = strtoul (hex_str, nullptr, 16); -                            if (hex_value <= UINT8_MAX) -                                dst.append (1, (char)hex_value); -                        } -                        else -                        { -                            dst.append(1, 'x'); -                        } -                        break; -                         -                    default: -                        // Just desensitize any other character by just printing what -                        // came after the '\' -                        dst.append(1, *p); -                        break; -                         -                } +          } +          break; + +        case 'x': +          // hex number in the format +          if (isxdigit(p[1])) { +            ++p; // Skip the 'x' + +            // Make a string that can hold onto two hex chars plus a +            // NULL terminator +            char hex_str[3] = {*p, '\0', '\0'}; +            if (isxdigit(p[1])) { +              ++p; // Skip the first of the two hex chars +              hex_str[1] = *p;              } -        } -    } -} +            unsigned long hex_value = strtoul(hex_str, nullptr, 16); +            if (hex_value <= UINT8_MAX) +              dst.append(1, (char)hex_value); +          } else { +            dst.append(1, 'x'); +          } +          break; -void -Args::ExpandEscapedCharacters (const char *src, std::string &dst) -{ -    dst.clear(); -    if (src) -    { -        for (const char *p = src; *p != '\0'; ++p) -        { -            if (isprint8(*p)) -                dst.append(1, *p); -            else -            { -                switch (*p) -                { -                    case '\a': dst.append("\\a"); break; -                    case '\b': dst.append("\\b"); break; -                    case '\f': dst.append("\\f"); break; -                    case '\n': dst.append("\\n"); break; -                    case '\r': dst.append("\\r"); break; -                    case '\t': dst.append("\\t"); break; -                    case '\v': dst.append("\\v"); break; -                    case '\'': dst.append("\\'"); break; -                    case '"': dst.append("\\\""); break; -                    case '\\': dst.append("\\\\"); break; -                    default: -                        { -                            // Just encode as octal -                            dst.append("\\0"); -                            char octal_str[32]; -                            snprintf(octal_str, sizeof(octal_str), "%o", *p); -                            dst.append(octal_str); -                        } -                        break; -                } -            } +        default: +          // Just desensitize any other character by just printing what +          // came after the '\' +          dst.append(1, *p); +          break;          } +      }      } +  }  } -std::string -Args::EscapeLLDBCommandArgument (const std::string& arg, char quote_char) -{ -    const char* chars_to_escape = nullptr; -    switch (quote_char) -    { -        case '\0': -            chars_to_escape = " \t\\'\"`"; -            break; +void Args::ExpandEscapedCharacters(const char *src, std::string &dst) { +  dst.clear(); +  if (src) { +    for (const char *p = src; *p != '\0'; ++p) { +      if (isprint8(*p)) +        dst.append(1, *p); +      else { +        switch (*p) { +        case '\a': +          dst.append("\\a"); +          break; +        case '\b': +          dst.append("\\b"); +          break; +        case '\f': +          dst.append("\\f"); +          break; +        case '\n': +          dst.append("\\n"); +          break; +        case '\r': +          dst.append("\\r"); +          break; +        case '\t': +          dst.append("\\t"); +          break; +        case '\v': +          dst.append("\\v"); +          break;          case '\'': -            chars_to_escape = ""; -            break; +          dst.append("\\'"); +          break;          case '"': -            chars_to_escape = "$\"`\\"; -            break; -        default: -            assert(false && "Unhandled quote character"); -    } - -    std::string res; -    res.reserve(arg.size()); -    for (char c : arg) -    { -        if (::strchr(chars_to_escape, c)) -            res.push_back('\\'); -        res.push_back(c); +          dst.append("\\\""); +          break; +        case '\\': +          dst.append("\\\\"); +          break; +        default: { +          // Just encode as octal +          dst.append("\\0"); +          char octal_str[32]; +          snprintf(octal_str, sizeof(octal_str), "%o", *p); +          dst.append(octal_str); +        } break; +        } +      }      } -    return res; +  }  } +std::string Args::EscapeLLDBCommandArgument(const std::string &arg, +                                            char quote_char) { +  const char *chars_to_escape = nullptr; +  switch (quote_char) { +  case '\0': +    chars_to_escape = " \t\\'\"`"; +    break; +  case '\'': +    chars_to_escape = ""; +    break; +  case '"': +    chars_to_escape = "$\"`\\"; +    break; +  default: +    assert(false && "Unhandled quote character"); +  } + +  std::string res; +  res.reserve(arg.size()); +  for (char c : arg) { +    if (::strchr(chars_to_escape, c)) +      res.push_back('\\'); +    res.push_back(c); +  } +  return res; +} | 
