zturner updated this revision to Diff 72657.
zturner added a comment.

Updated


https://reviews.llvm.org/D24952

Files:
  examples/plugins/commands/fooplugin.cpp
  include/lldb/API/SBCommandInterpreter.h
  include/lldb/Host/OptionParser.h
  include/lldb/Interpreter/Args.h
  source/API/SBCommandInterpreter.cpp
  source/API/SBLaunchInfo.cpp
  source/API/SBProcess.cpp
  source/API/SBTarget.cpp
  source/Commands/CommandObjectBreakpoint.cpp
  source/Commands/CommandObjectLog.cpp
  source/Host/common/OptionParser.cpp
  source/Interpreter/Args.cpp
  source/Interpreter/CommandInterpreter.cpp
  source/Interpreter/CommandObject.cpp
  source/Interpreter/OptionValueArgs.cpp
  source/Interpreter/OptionValueArray.cpp
  source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
  source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
  source/Target/ProcessInfo.cpp
  source/Target/ProcessLaunchInfo.cpp

Index: source/Target/ProcessLaunchInfo.cpp
===================================================================
--- source/Target/ProcessLaunchInfo.cpp
+++ source/Target/ProcessLaunchInfo.cpp
@@ -339,8 +339,8 @@
     if (m_shell) {
       std::string shell_executable = m_shell.GetPath();
 
-      const char **argv = GetArguments().GetConstArgumentVector();
-      if (argv == nullptr || argv[0] == nullptr)
+      const auto argv = GetArguments().GetArgumentVector();
+      if (!argv[0])
         return false;
       Args shell_arguments;
       std::string safe_arg;
Index: source/Target/ProcessInfo.cpp
===================================================================
--- source/Target/ProcessInfo.cpp
+++ source/Target/ProcessInfo.cpp
@@ -91,7 +91,7 @@
 
 void ProcessInfo::SetArguments(char const **argv,
                                bool first_arg_is_executable) {
-  m_arguments.SetArguments(argv);
+  m_arguments.SetArguments(Args::ArgvToArrayRef(argv));
 
   // Is the first argument the executable?
   if (first_arg_is_executable) {
Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
===================================================================
--- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -421,15 +421,11 @@
   }
 
   // Send the environment and the program + arguments after we connect
-  const char **envp =
-      launch_info.GetEnvironmentEntries().GetConstArgumentVector();
-
-  if (envp) {
-    const char *env_entry;
-    for (int i = 0; (env_entry = envp[i]); ++i) {
-      if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
-        break;
-    }
+  const auto argv = launch_info.GetEnvironmentEntries().GetArgumentVector();
+
+  for (auto env_entry : argv) {
+    if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
+      break;
   }
 
   ArchSpec arch_spec = launch_info.GetArchitecture();
Index: source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
===================================================================
--- source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -1391,6 +1391,7 @@
   if (!shell)
     return 1;
 
+  // CLEANUP: This function could be made nicer / safer with StringRef.
   std::string shell_string = shell.GetPath();
   const char *shell_name = strrchr(shell_string.c_str(), '/');
   if (shell_name == NULL)
@@ -1402,13 +1403,10 @@
     // /bin/sh re-exec's itself as /bin/bash requiring another resume.
     // But it only does this if the COMMAND_MODE environment variable
     // is set to "legacy".
-    const char **envp =
-        launch_info.GetEnvironmentEntries().GetConstArgumentVector();
-    if (envp != NULL) {
-      for (int i = 0; envp[i] != NULL; i++) {
-        if (strcmp(envp[i], "COMMAND_MODE=legacy") == 0)
-          return 2;
-      }
+    const auto argv = launch_info.GetEnvironmentEntries().GetArgumentVector();
+    for (auto env_entry : argv) {
+      if (strcmp(env_entry, "COMMAND_MODE=legacy") == 0)
+        return 2;
     }
     return 1;
   } else if (strcmp(shell_name, "csh") == 0 ||
Index: source/Interpreter/OptionValueArray.cpp
===================================================================
--- source/Interpreter/OptionValueArray.cpp
+++ source/Interpreter/OptionValueArray.cpp
@@ -148,7 +148,7 @@
   if (argv.empty())
     args.Clear();
   else
-    args.SetArguments(argv.size(), &argv[0]);
+    args.SetArguments(argv);
   return args.GetArgumentCount();
 }
 
Index: source/Interpreter/OptionValueArgs.cpp
===================================================================
--- source/Interpreter/OptionValueArgs.cpp
+++ source/Interpreter/OptionValueArgs.cpp
@@ -30,6 +30,6 @@
   if (argv.empty())
     args.Clear();
   else
-    args.SetArguments(argv.size(), &argv[0]);
+    args.SetArguments(argv);
   return args.GetArgumentCount();
 }
Index: source/Interpreter/CommandObject.cpp
===================================================================
--- source/Interpreter/CommandObject.cpp
+++ source/Interpreter/CommandObject.cpp
@@ -116,7 +116,6 @@
     // ParseOptions calls getopt_long_only, which always skips the zero'th item
     // in the array and starts at position 1,
     // so we need to push a dummy value into position zero.
-    args.Unshift(llvm::StringRef("dummy_string"));
     const bool require_validation = true;
     error = args.ParseOptions(*options, &exe_ctx,
                               GetCommandInterpreter().GetPlatform(true),
@@ -992,8 +991,9 @@
   if (HasOverrideCallback()) {
     Args full_args(GetCommandName());
     full_args.AppendArguments(cmd_args);
-    handled =
-        InvokeOverrideCallback(full_args.GetConstArgumentVector(), result);
+
+    auto argv = full_args.GetArgumentVector();
+    handled = InvokeOverrideCallback(&argv[0], result);
   }
   if (!handled) {
     for (size_t i = 0; i < cmd_args.GetArgumentCount(); ++i) {
Index: source/Interpreter/CommandInterpreter.cpp
===================================================================
--- source/Interpreter/CommandInterpreter.cpp
+++ source/Interpreter/CommandInterpreter.cpp
@@ -2047,8 +2047,7 @@
     }
 
     cmd_args.Clear();
-    cmd_args.SetArguments(new_args.GetArgumentCount(),
-                          new_args.GetConstArgumentVector());
+    cmd_args.SetArguments(new_args);
   } else {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
     // This alias was not created with any options; nothing further needs to be
@@ -2058,8 +2057,7 @@
     // input string.
     if (wants_raw_input) {
       cmd_args.Clear();
-      cmd_args.SetArguments(new_args.GetArgumentCount(),
-                            new_args.GetConstArgumentVector());
+      cmd_args.SetArguments(new_args);
     }
     return;
   }
Index: source/Interpreter/Args.cpp
===================================================================
--- source/Interpreter/Args.cpp
+++ source/Interpreter/Args.cpp
@@ -25,43 +25,27 @@
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/Target.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() {
+Args::Args(llvm::StringRef command) : m_args(), 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();
-}
+    : m_args(rhs.m_args), m_args_quote_char(rhs.m_args_quote_char) {}
 
-//----------------------------------------------------------------------
-// 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();
   }
   return *this;
 }
@@ -75,42 +59,32 @@
   if (!label_name)
     return;
 
-  const size_t argc = m_argv.size();
-  for (size_t i = 0; i < argc; ++i) {
+  for (int i = 0; i < m_args.size(); ++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.Printf("%s[%zi]=\"%s\"\n", label_name, i, m_args[i].c_str());
   }
   s.EOL();
 }
 
 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;
+  command = llvm::join(m_args.begin(), m_args.end(), " ");
+
+  return !m_args.empty();
 }
 
 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, ' ');
+      command += ' ';
     char quote_char = GetArgumentQuoteCharAtIndex(i);
     if (quote_char) {
-      command.append(1, quote_char);
-      command.append(m_argv[i]);
-      command.append(1, quote_char);
+      command += quote_char;
+      command += m_args[i];
+      command += quote_char;
     } else
-      command.append(m_argv[i]);
+      command += m_args[i];
   }
   return argc > 0;
 }
@@ -253,74 +227,48 @@
 
 void Args::SetCommandString(llvm::StringRef command) {
   m_args.clear();
-  m_argv.clear();
   m_args_quote_char.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);
   }
-
-  UpdateArgvFromArgs();
 }
 
-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);
-      }
-    }
+void Args::UpdateArgsAfterOptionParsing(llvm::ArrayRef<const char *> new_argv) {
+  // By now many of the arguments will have been removed since they were
+  // consumed. Some options will remain and be potentially in a different order
+  // than they started in due to the behavior of getopt_long_only.  For the
+  // options that remain, map them back to their original location so we can
+  // determine their quote char.  Then move their quote char to the correct new
+  // location.
+  for (int i = 0; i < new_argv.size(); ++i) {
+    auto iter = std::find(m_args.begin(), m_args.end(), new_argv[i]);
+    lldbassert(iter != m_args.end());
+    size_t pos = std::distance(m_args.begin(), iter);
+    std::swap(m_args_quote_char[pos], m_args_quote_char[i]);
   }
-
-  if (args_pos != m_args.end())
-    m_args.erase(args_pos, m_args.end());
-
-  if (quotes_pos != m_args_quote_char.end())
-    m_args_quote_char.erase(quotes_pos, m_args_quote_char.end());
-}
-
-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());
+  m_args_quote_char.resize(new_argv.size());
+
+  // Since new_argv is a collection of *references* to strings from m_args, we
+  // can't simply assign it directly, as saying m_args[x] = new_argv[y] would
+  // invalidate the existing value of m_args[x], which is itself another pointer
+  // somewhere in new_argv.  So make a copy and then swap it in.
+  std::vector<std::string> new_args(new_argv.begin(), new_argv.end());
+  std::swap(m_args, new_args);
 }
 
 size_t Args::GetArgumentCount() const {
-  if (m_argv.empty())
+  if (m_args.empty())
     return 0;
-  return m_argv.size() - 1;
+  return m_args.size();
 }
 
 const char *Args::GetArgumentAtIndex(size_t idx) const {
-  if (idx < m_argv.size())
-    return m_argv[idx];
+  if (idx < m_args.size())
+    return m_args[idx].c_str();
   return nullptr;
 }
 
@@ -330,152 +278,101 @@
   return '\0';
 }
 
-char **Args::GetArgumentVector() {
-  if (!m_argv.empty())
-    return const_cast<char **>(&m_argv[0]);
-  return nullptr;
-}
+std::vector<const char *> Args::GetArgumentVector() const {
+  std::vector<const char *> result;
+  for (auto &arg : m_args)
+    result.push_back(arg.c_str());
 
-const char **Args::GetConstArgumentVector() const {
-  if (!m_argv.empty())
-    return const_cast<const char **>(&m_argv[0]);
-  return nullptr;
+  // This is kind of gross, but it ensures that if someone passes args.data() to
+  // a function which expects an array terminated with a null entry, it will
+  // work.
+  result.push_back(nullptr);
+  result.pop_back();
+  return result;
 }
 
 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());
-  }
+  if (m_args.empty())
+    return;
+
+  m_args.erase(m_args.begin());
+  if (!m_args_quote_char.empty())
+    m_args_quote_char.erase(m_args_quote_char.begin());
 }
 
 llvm::StringRef Args::Unshift(llvm::StringRef arg_str, char quote_char) {
-  m_args.push_front(arg_str);
-  m_argv.insert(m_argv.begin(), m_args.front().c_str());
+  m_args.insert(m_args.begin(), arg_str);
   m_args_quote_char.insert(m_args_quote_char.begin(), quote_char);
-  return llvm::StringRef::withNullAsEmpty(GetArgumentAtIndex(0));
+  return m_args[0];
 }
 
 void Args::AppendArguments(const Args &rhs) {
   const size_t rhs_argc = rhs.GetArgumentCount();
   for (size_t i = 0; i < rhs_argc; ++i)
-    AppendArgument(llvm::StringRef(rhs.GetArgumentAtIndex(i)),
+    AppendArgument(rhs.GetArgumentAtIndex(i),
                    rhs.GetArgumentQuoteCharAtIndex(i));
 }
 
-void Args::AppendArguments(const char **argv) {
-  if (argv) {
-    for (uint32_t i = 0; argv[i]; ++i)
-      AppendArgument(llvm::StringRef::withNullAsEmpty(argv[i]));
-  }
+void Args::AppendArguments(llvm::ArrayRef<const char *> args) {
+  for (uint32_t i = 0; args[i]; ++i)
+    AppendArgument(args[i]);
 }
 
 llvm::StringRef Args::AppendArgument(llvm::StringRef arg_str, char quote_char) {
   return InsertArgumentAtIndex(GetArgumentCount(), arg_str, quote_char);
 }
 
 llvm::StringRef Args::InsertArgumentAtIndex(size_t idx, llvm::StringRef arg_str,
                                             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_str);
+  m_args.insert(m_args.begin() + idx, arg_str);
 
   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);
 }
 
 llvm::StringRef Args::ReplaceArgumentAtIndex(size_t idx,
                                              llvm::StringRef arg_str,
                                              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_str);
-    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 llvm::StringRef();
+  if (idx >= m_args.size())
+    return llvm::StringRef();
+
+  m_args[idx] = arg_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);
 }
 
 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);
-  }
+  if (idx >= m_args.size())
+    return;
+
+  m_args.erase(m_args.begin() + idx);
+  if (idx < m_args_quote_char.size())
+    m_args_quote_char.erase(m_args_quote_char.begin() + idx);
 }
 
-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.
+void Args::SetArguments(llvm::ArrayRef<const char *> args) {
   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]);
+  for (const char *arg : args) {
+    m_args.push_back(arg);
+    if ((arg[0] == '\'') || (arg[0] == '"') || (arg[0] == '`'))
+      m_args_quote_char.push_back(arg[0]);
     else
       m_args_quote_char.push_back('\0');
   }
-
-  UpdateArgvFromArgs();
 }
 
-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(const Args &other) {
+  m_args = other.m_args;
+  m_args_quote_char = other.m_args_quote_char;
 }
 
 Error Args::ParseOptions(Options &options, ExecutionContext *execution_context,
@@ -509,11 +406,12 @@
   std::unique_lock<std::mutex> lock;
   OptionParser::Prepare(lock);
   int val;
+  auto args = GetArgumentVector();
+  args.insert(args.begin(), "dummy");
   while (1) {
     int long_options_index = -1;
-    val =
-        OptionParser::Parse(GetArgumentCount(), GetArgumentVector(),
-                            sstr.GetData(), long_options, &long_options_index);
+    val = OptionParser::Parse(args.size(), &args[0], sstr.GetData(),
+                              long_options, &long_options_index);
     if (val == -1)
       break;
 
@@ -591,15 +489,14 @@
       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();
+  args.erase(args.begin(), args.begin() + OptionParser::GetOptionIndex());
+  UpdateArgsAfterOptionParsing(llvm::makeArrayRef(args));
+
   return error;
 }
 
 void Args::Clear() {
   m_args.clear();
-  m_argv.clear();
   m_args_quote_char.clear();
 }
 
@@ -853,6 +750,14 @@
   return fail_value;
 }
 
+llvm::ArrayRef<const char *> Args::ArgvToArrayRef(const char **args) {
+  int argc = 0;
+  const char **argv2 = args;
+  while (*argv2)
+    ++argc;
+  return llvm::ArrayRef<const char *>(args, argc);
+}
+
 lldb::ScriptLanguage
 Args::StringToScriptLanguage(llvm::StringRef s, lldb::ScriptLanguage fail_value,
                              bool *success_ptr) {
@@ -1097,11 +1002,11 @@
   std::unique_lock<std::mutex> lock;
   OptionParser::Prepare(lock);
   int val;
+  const auto args = GetArgumentVector();
   while (1) {
     int long_options_index = -1;
-    val =
-        OptionParser::Parse(GetArgumentCount(), GetArgumentVector(),
-                            sstr.GetData(), long_options, &long_options_index);
+    val = OptionParser::Parse(args.size(), &args[0], sstr.GetData(),
+                              long_options, &long_options_index);
 
     if (val == -1)
       break;
@@ -1261,25 +1166,16 @@
   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<const char *> dummy_vec(
-      GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1);
-
+  const auto dummy_vec = GetArgumentVector();
   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);
+    val = OptionParser::Parse(dummy_vec.size(), &dummy_vec[0], sstr.GetData(),
+                              long_options, &long_options_index);
 
     if (val == -1) {
       // When we're completing a "--" which is the last option on line,
Index: source/Host/common/OptionParser.cpp
===================================================================
--- source/Host/common/OptionParser.cpp
+++ source/Host/common/OptionParser.cpp
@@ -28,8 +28,9 @@
 
 void OptionParser::EnableError(bool error) { opterr = error ? 1 : 0; }
 
-int OptionParser::Parse(int argc, char *const argv[], const char *optstring,
-                        const Option *longopts, int *longindex) {
+int OptionParser::Parse(int argc, char const *const argv[],
+                        const char *optstring, const Option *longopts,
+                        int *longindex) {
   std::vector<option> opts;
   while (longopts->definition != nullptr) {
     option opt;
@@ -41,7 +42,8 @@
     ++longopts;
   }
   opts.push_back(option());
-  return getopt_long_only(argc, argv, optstring, &opts[0], longindex);
+  return getopt_long_only(argc, const_cast<char *const *>(argv), optstring,
+                          &opts[0], longindex);
 }
 
 char *OptionParser::GetOptionArgument() { return optarg; }
Index: source/Commands/CommandObjectLog.cpp
===================================================================
--- source/Commands/CommandObjectLog.cpp
+++ source/Commands/CommandObjectLog.cpp
@@ -190,9 +190,10 @@
         m_options.log_file.GetPath(log_file, sizeof(log_file));
       else
         log_file[0] = '\0';
+      auto argv = args.GetArgumentVector();
       bool success = m_interpreter.GetDebugger().EnableLog(
-          channel.c_str(), args.GetConstArgumentVector(), log_file,
-          m_options.log_options, result.GetErrorStream());
+          channel.c_str(), &argv[0], log_file, m_options.log_options,
+          result.GetErrorStream());
       if (success)
         result.SetStatus(eReturnStatusSuccessFinishNoResult);
       else
@@ -250,18 +251,18 @@
 
       std::string channel(args.GetArgumentAtIndex(0));
       args.Shift(); // Shift off the channel
+      auto argv = args.GetArgumentVector();
+
       if (Log::GetLogChannelCallbacks(ConstString(channel.c_str()),
                                       log_callbacks)) {
-        log_callbacks.disable(args.GetConstArgumentVector(),
-                              &result.GetErrorStream());
+        log_callbacks.disable(&argv[0], &result.GetErrorStream());
         result.SetStatus(eReturnStatusSuccessFinishNoResult);
       } else if (channel == "all") {
         Log::DisableAllLogChannels(&result.GetErrorStream());
       } else {
         LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel.c_str()));
         if (log_channel_sp) {
-          log_channel_sp->Disable(args.GetConstArgumentVector(),
-                                  &result.GetErrorStream());
+          log_channel_sp->Disable(&argv[0], &result.GetErrorStream());
           result.SetStatus(eReturnStatusSuccessFinishNoResult);
         } else
           result.AppendErrorWithFormat("Invalid log channel '%s'.\n",
Index: source/Commands/CommandObjectBreakpoint.cpp
===================================================================
--- source/Commands/CommandObjectBreakpoint.cpp
+++ source/Commands/CommandObjectBreakpoint.cpp
@@ -2423,8 +2423,8 @@
   // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
   // BreakpointIDList:
 
-  valid_ids->InsertStringArray(temp_args.GetConstArgumentVector(),
-                               temp_args.GetArgumentCount(), result);
+  auto argv = temp_args.GetArgumentVector();
+  valid_ids->InsertStringArray(&argv[0], temp_args.GetArgumentCount(), result);
 
   // At this point,  all of the breakpoint ids that the user passed in have been
   // converted to breakpoint IDs
Index: source/API/SBTarget.cpp
===================================================================
--- source/API/SBTarget.cpp
+++ source/API/SBTarget.cpp
@@ -287,9 +287,10 @@
     if (exe_module)
       launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
     if (argv)
-      launch_info.GetArguments().AppendArguments(argv);
+      launch_info.GetArguments().AppendArguments(Args::ArgvToArrayRef(argv));
     if (envp)
-      launch_info.GetEnvironmentEntries().SetArguments(envp);
+      launch_info.GetEnvironmentEntries().SetArguments(
+          Args::ArgvToArrayRef(envp));
 
     if (listener.IsValid())
       launch_info.SetListener(listener.GetSP());
Index: source/API/SBProcess.cpp
===================================================================
--- source/API/SBProcess.cpp
+++ source/API/SBProcess.cpp
@@ -136,9 +136,10 @@
       if (exe_module)
         launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
       if (argv)
-        launch_info.GetArguments().AppendArguments(argv);
+        launch_info.GetArguments().AppendArguments(Args::ArgvToArrayRef(argv));
       if (envp)
-        launch_info.GetEnvironmentEntries().SetArguments(envp);
+        launch_info.GetEnvironmentEntries().SetArguments(
+            Args::ArgvToArrayRef(envp));
       error.SetError(process_sp->Launch(launch_info));
     } else {
       error.SetErrorString("must be in eStateConnected to call RemoteLaunch");
Index: source/API/SBLaunchInfo.cpp
===================================================================
--- source/API/SBLaunchInfo.cpp
+++ source/API/SBLaunchInfo.cpp
@@ -19,8 +19,9 @@
 SBLaunchInfo::SBLaunchInfo(const char **argv)
     : m_opaque_sp(new ProcessLaunchInfo()) {
   m_opaque_sp->GetFlags().Reset(eLaunchFlagDebug | eLaunchFlagDisableASLR);
-  if (argv && argv[0])
-    m_opaque_sp->GetArguments().SetArguments(argv);
+  if (argv) {
+    m_opaque_sp->GetArguments().SetArguments(Args::ArgvToArrayRef(argv));
+  }
 }
 
 SBLaunchInfo::~SBLaunchInfo() {}
@@ -71,15 +72,11 @@
 }
 
 void SBLaunchInfo::SetArguments(const char **argv, bool append) {
-  if (append) {
-    if (argv)
-      m_opaque_sp->GetArguments().AppendArguments(argv);
-  } else {
-    if (argv)
-      m_opaque_sp->GetArguments().SetArguments(argv);
-    else
-      m_opaque_sp->GetArguments().Clear();
-  }
+  if (!append)
+    m_opaque_sp->GetArguments().Clear();
+
+  if (argv)
+    m_opaque_sp->GetArguments().AppendArguments(Args::ArgvToArrayRef(argv));
 }
 
 uint32_t SBLaunchInfo::GetNumEnvironmentEntries() {
@@ -91,15 +88,12 @@
 }
 
 void SBLaunchInfo::SetEnvironmentEntries(const char **envp, bool append) {
-  if (append) {
-    if (envp)
-      m_opaque_sp->GetEnvironmentEntries().AppendArguments(envp);
-  } else {
-    if (envp)
-      m_opaque_sp->GetEnvironmentEntries().SetArguments(envp);
-    else
-      m_opaque_sp->GetEnvironmentEntries().Clear();
-  }
+  if (!append)
+    m_opaque_sp->GetEnvironmentEntries().Clear();
+
+  if (envp)
+    m_opaque_sp->GetEnvironmentEntries().AppendArguments(
+        Args::ArgvToArrayRef(envp));
 }
 
 void SBLaunchInfo::Clear() { m_opaque_sp->Clear(); }
Index: source/API/SBCommandInterpreter.cpp
===================================================================
--- source/API/SBCommandInterpreter.cpp
+++ source/API/SBCommandInterpreter.cpp
@@ -115,8 +115,8 @@
     SBCommandReturnObject sb_return(&result);
     SBCommandInterpreter sb_interpreter(&m_interpreter);
     SBDebugger debugger_sb(m_interpreter.GetDebugger().shared_from_this());
-    bool ret = m_backend->DoExecute(
-        debugger_sb, (char **)command.GetArgumentVector(), sb_return);
+    auto argv = command.GetArgumentVector();
+    bool ret = m_backend->DoExecute(debugger_sb, &argv[0], sb_return);
     sb_return.Release();
     return ret;
   }
Index: include/lldb/Interpreter/Args.h
===================================================================
--- include/lldb/Interpreter/Args.h
+++ include/lldb/Interpreter/Args.h
@@ -18,7 +18,9 @@
 #include <vector>
 
 // Other libraries and framework includes
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
+
 // Project includes
 #include "lldb/Core/Error.h"
 #include "lldb/Host/OptionParser.h"
@@ -146,26 +148,15 @@
   ///     \endcode
   ///
   /// @return
-  ///     An array of NULL terminated C string argument pointers that
-  ///     also has a terminating NULL C string pointer
+  ///     A vector of NULL terminated C string argument pointers with
+  ///     an equivalent in-memory layout to that of a C-style argv
+  ///     array.  Calling .size() on the return value produces the same
+  ///     value as one would pass for argc, and calling .data() on the
+  ///     return value is guaranteed to be null terminated (even though
+  ///     the terminating null is not part of the vector, and as such
+  ///     is not taken into consideration when calling .size()).
   //------------------------------------------------------------------
-  char **GetArgumentVector();
-
-  //------------------------------------------------------------------
-  /// Gets the argument vector.
-  ///
-  /// The value returned by this function can be used by any function
-  /// that takes and vector. The return value is just like \a argv
-  /// in the standard C entry point function:
-  ///     \code
-  ///         int main (int argc, const char **argv);
-  ///     \endcode
-  ///
-  /// @return
-  ///     An array of NULL terminate C string argument pointers that
-  ///     also has a terminating NULL C string pointer
-  //------------------------------------------------------------------
-  const char **GetConstArgumentVector() const;
+  std::vector<const char *> GetArgumentVector() const;
 
   //------------------------------------------------------------------
   /// Appends a new argument to the end of the list argument list.
@@ -183,52 +174,7 @@
                                  char quote_char = '\0');
 
   void AppendArguments(const Args &rhs);
-
-  void AppendArguments(const char **argv);
-
-  // Delete const char* versions of StringRef functions.  Normally this would
-  // not be necessary, as const char * is implicitly convertible to StringRef.
-  // However, since the use of const char* is so pervasive, and since StringRef
-  // will assert if you try to construct one from nullptr, this allows the
-  // compiler to catch instances of the function being invoked with a
-  // const char *, allowing us to replace them with explicit conversions at each
-  // call-site.  This ensures that no callsites slip through the cracks where
-  // we would be trying to implicitly convert from nullptr, since it will force
-  // us to evaluate and explicitly convert each one.
-  //
-  // Once StringRef use becomes more pervasive, there will be fewer
-  // implicit conversions because we will be using StringRefs across the whole
-  // pipeline, so we won't have to have this "glue" that converts between the
-  // two, and at that point it becomes easy to just make sure you don't pass
-  // nullptr into the function on the odd occasion that you do pass a
-  // const char *.
-  // Call-site fixing methodology:
-  //   1. If you know the string cannot be null (e.g. it's a const char[], or
-  //      it's been checked for null), use llvm::StringRef(ptr).
-  //   2. If you don't know if it can be null (e.g. it's returned from a
-  //      function whose semantics are unclear), use
-  //      llvm::StringRef::withNullAsEmpty(ptr).
-  //   3. If it's .c_str() of a std::string, just pass the std::string directly.
-  //   4. If it's .str().c_str() of a StringRef, just pass the StringRef
-  //      directly.
-  void ReplaceArgumentAtIndex(size_t, const char *, char = '\0') = delete;
-  void AppendArgument(const char *arg_str, char quote_char = '\0') = delete;
-  void InsertArgumentAtIndex(size_t, const char *, char = '\0') = delete;
-  static bool StringToBoolean(const char *, bool, bool *) = delete;
-  static lldb::ScriptLanguage
-  StringToScriptLanguage(const char *, lldb::ScriptLanguage, bool *) = delete;
-  static lldb::Encoding
-  StringToEncoding(const char *,
-                   lldb::Encoding = lldb::eEncodingInvalid) = delete;
-  static uint32_t StringToGenericRegister(const char *) = delete;
-  static bool StringToVersion(const char *, uint32_t &, uint32_t &,
-                              uint32_t &) = delete;
-  const char *Unshift(const char *, char = '\0') = delete;
-  void AddOrReplaceEnvironmentVariable(const char *, const char *) = delete;
-  bool ContainsEnvironmentVariable(const char *,
-                                   size_t * = nullptr) const = delete;
-  static int64_t StringToOptionEnum(const char *, OptionEnumValueElement *,
-                                    int32_t, Error &) = delete;
+  void AppendArguments(llvm::ArrayRef<const char *> args);
 
   //------------------------------------------------------------------
   /// Insert the argument value at index \a idx to \a arg_cstr.
@@ -287,9 +233,8 @@
   //
   //  FIXME: Handle the quote character somehow.
   //------------------------------------------------------------------
-  void SetArguments(size_t argc, const char **argv);
-
-  void SetArguments(const char **argv);
+  void SetArguments(llvm::ArrayRef<const char *> args);
+  void SetArguments(const Args &other);
 
   //------------------------------------------------------------------
   /// Shifts the first argument C string value of the array off the
@@ -413,6 +358,8 @@
                                     OptionEnumValueElement *enum_values,
                                     int32_t fail_value, Error &error);
 
+  static llvm::ArrayRef<const char *> ArgvToArrayRef(const char **args);
+
   static lldb::ScriptLanguage
   StringToScriptLanguage(llvm::StringRef s, lldb::ScriptLanguage fail_value,
                          bool *success_ptr);
@@ -497,16 +444,12 @@
   //------------------------------------------------------------------
   // Classes that inherit from Args can see and modify these
   //------------------------------------------------------------------
-  typedef std::list<std::string> arg_sstr_collection;
-  typedef std::vector<const char *> arg_cstr_collection;
+  typedef std::vector<std::string> arg_sstr_collection;
   typedef std::vector<char> arg_quote_char_collection;
   arg_sstr_collection m_args;
-  arg_cstr_collection m_argv; ///< The current argument vector.
   arg_quote_char_collection m_args_quote_char;
 
-  void UpdateArgsAfterOptionParsing();
-
-  void UpdateArgvFromArgs();
+  void UpdateArgsAfterOptionParsing(llvm::ArrayRef<const char *> new_argv);
 
   llvm::StringRef ParseSingleArgument(llvm::StringRef command);
 };
Index: include/lldb/Host/OptionParser.h
===================================================================
--- include/lldb/Host/OptionParser.h
+++ include/lldb/Host/OptionParser.h
@@ -36,7 +36,7 @@
 
   static void EnableError(bool error);
 
-  static int Parse(int argc, char *const argv[], const char *optstring,
+  static int Parse(int argc, char const *const argv[], const char *optstring,
                    const Option *longopts, int *longindex);
 
   static char *GetOptionArgument();
Index: include/lldb/API/SBCommandInterpreter.h
===================================================================
--- include/lldb/API/SBCommandInterpreter.h
+++ include/lldb/API/SBCommandInterpreter.h
@@ -233,7 +233,8 @@
 public:
   virtual ~SBCommandPluginInterface() = default;
 
-  virtual bool DoExecute(lldb::SBDebugger /*debugger*/, char ** /*command*/,
+  virtual bool DoExecute(lldb::SBDebugger /*debugger*/,
+                         const char ** /*command*/,
                          lldb::SBCommandReturnObject & /*result*/) {
     return false;
   }
Index: examples/plugins/commands/fooplugin.cpp
===================================================================
--- examples/plugins/commands/fooplugin.cpp
+++ examples/plugins/commands/fooplugin.cpp
@@ -25,8 +25,8 @@
 
 class ChildCommand : public lldb::SBCommandPluginInterface {
 public:
-  virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
-                         lldb::SBCommandReturnObject &result) {
+  bool DoExecute(lldb::SBDebugger debugger, const char **command,
+                 lldb::SBCommandReturnObject &result) override {
     if (command) {
       const char *arg = *command;
       while (arg) {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to