xref: /llvm-project/lldb/source/Commands/CommandObjectSettings.cpp (revision 57179860a0547afc482171ef304976c7761a3fd8)
1 //===-- CommandObjectSettings.cpp -------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CommandObjectSettings.h"
10 
11 #include "llvm/ADT/StringRef.h"
12 
13 #include "lldb/Host/OptionParser.h"
14 #include "lldb/Interpreter/CommandCompletions.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/OptionValueProperties.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 // CommandObjectSettingsSet
23 
24 static constexpr OptionDefinition g_settings_set_options[] = {
25     // clang-format off
26   { LLDB_OPT_SET_2, false, "global", 'g', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Apply the new value to the global default value." },
27   { LLDB_OPT_SET_2, false, "force",  'f', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Force an empty value to be accepted as the default." }
28     // clang-format on
29 };
30 
31 class CommandObjectSettingsSet : public CommandObjectRaw {
32 public:
33   CommandObjectSettingsSet(CommandInterpreter &interpreter)
34       : CommandObjectRaw(interpreter, "settings set",
35                          "Set the value of the specified debugger setting."),
36         m_options() {
37     CommandArgumentEntry arg1;
38     CommandArgumentEntry arg2;
39     CommandArgumentData var_name_arg;
40     CommandArgumentData value_arg;
41 
42     // Define the first (and only) variant of this arg.
43     var_name_arg.arg_type = eArgTypeSettingVariableName;
44     var_name_arg.arg_repetition = eArgRepeatPlain;
45 
46     // There is only one variant this argument could be; put it into the
47     // argument entry.
48     arg1.push_back(var_name_arg);
49 
50     // Define the first (and only) variant of this arg.
51     value_arg.arg_type = eArgTypeValue;
52     value_arg.arg_repetition = eArgRepeatPlain;
53 
54     // There is only one variant this argument could be; put it into the
55     // argument entry.
56     arg2.push_back(value_arg);
57 
58     // Push the data for the first argument into the m_arguments vector.
59     m_arguments.push_back(arg1);
60     m_arguments.push_back(arg2);
61 
62     SetHelpLong(
63         "\nWhen setting a dictionary or array variable, you can set multiple entries \
64 at once by giving the values to the set command.  For example:"
65         R"(
66 
67 (lldb) settings set target.run-args value1 value2 value3
68 (lldb) settings set target.env-vars MYPATH=~/.:/usr/bin  SOME_ENV_VAR=12345
69 
70 (lldb) settings show target.run-args
71   [0]: 'value1'
72   [1]: 'value2'
73   [3]: 'value3'
74 (lldb) settings show target.env-vars
75   'MYPATH=~/.:/usr/bin'
76   'SOME_ENV_VAR=12345'
77 
78 )"
79         "Warning:  The 'set' command re-sets the entire array or dictionary.  If you \
80 just want to add, remove or update individual values (or add something to \
81 the end), use one of the other settings sub-commands: append, replace, \
82 insert-before or insert-after.");
83   }
84 
85   ~CommandObjectSettingsSet() override = default;
86 
87   // Overrides base class's behavior where WantsCompletion =
88   // !WantsRawCommandString.
89   bool WantsCompletion() override { return true; }
90 
91   Options *GetOptions() override { return &m_options; }
92 
93   class CommandOptions : public Options {
94   public:
95     CommandOptions() : Options(), m_global(false) {}
96 
97     ~CommandOptions() override = default;
98 
99     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
100                           ExecutionContext *execution_context) override {
101       Status error;
102       const int short_option = m_getopt_table[option_idx].val;
103 
104       switch (short_option) {
105       case 'f':
106         m_force = true;
107         break;
108       case 'g':
109         m_global = true;
110         break;
111       default:
112         error.SetErrorStringWithFormat("unrecognized options '%c'",
113                                        short_option);
114         break;
115       }
116 
117       return error;
118     }
119 
120     void OptionParsingStarting(ExecutionContext *execution_context) override {
121       m_global = false;
122       m_force = false;
123     }
124 
125     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
126       return llvm::makeArrayRef(g_settings_set_options);
127     }
128 
129     // Instance variables to hold the values for command options.
130     bool m_global;
131     bool m_force;
132   };
133 
134   int HandleArgumentCompletion(
135       CompletionRequest &request,
136       OptionElementVector &opt_element_vector) override {
137 
138     const size_t argc = request.GetParsedLine().GetArgumentCount();
139     const char *arg = nullptr;
140     int setting_var_idx;
141     for (setting_var_idx = 0; setting_var_idx < static_cast<int>(argc);
142          ++setting_var_idx) {
143       arg = request.GetParsedLine().GetArgumentAtIndex(setting_var_idx);
144       if (arg && arg[0] != '-')
145         break; // We found our setting variable name index
146     }
147     if (request.GetCursorIndex() == setting_var_idx) {
148       // Attempting to complete setting variable name
149       CommandCompletions::InvokeCommonCompletionCallbacks(
150           GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
151           request, nullptr);
152     } else {
153       arg =
154           request.GetParsedLine().GetArgumentAtIndex(request.GetCursorIndex());
155 
156       if (arg) {
157         if (arg[0] == '-') {
158           // Complete option name
159         } else {
160           // Complete setting value
161           const char *setting_var_name =
162               request.GetParsedLine().GetArgumentAtIndex(setting_var_idx);
163           Status error;
164           lldb::OptionValueSP value_sp(GetDebugger().GetPropertyValue(
165               &m_exe_ctx, setting_var_name, false, error));
166           if (value_sp) {
167             value_sp->AutoComplete(m_interpreter, request);
168           }
169         }
170       }
171     }
172     return request.GetNumberOfMatches();
173   }
174 
175 protected:
176   bool DoExecute(llvm::StringRef command,
177                  CommandReturnObject &result) override {
178     Args cmd_args(command);
179 
180     // Process possible options.
181     if (!ParseOptions(cmd_args, result))
182       return false;
183 
184     const size_t min_argc = m_options.m_force ? 1 : 2;
185     const size_t argc = cmd_args.GetArgumentCount();
186 
187     if ((argc < min_argc) && (!m_options.m_global)) {
188       result.AppendError("'settings set' takes more arguments");
189       result.SetStatus(eReturnStatusFailed);
190       return false;
191     }
192 
193     const char *var_name = cmd_args.GetArgumentAtIndex(0);
194     if ((var_name == nullptr) || (var_name[0] == '\0')) {
195       result.AppendError(
196           "'settings set' command requires a valid variable name");
197       result.SetStatus(eReturnStatusFailed);
198       return false;
199     }
200 
201     // A missing value corresponds to clearing the setting when "force" is
202     // specified.
203     if (argc == 1 && m_options.m_force) {
204       Status error(GetDebugger().SetPropertyValue(
205           &m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef()));
206       if (error.Fail()) {
207         result.AppendError(error.AsCString());
208         result.SetStatus(eReturnStatusFailed);
209         return false;
210       }
211       return result.Succeeded();
212     }
213 
214     // Split the raw command into var_name and value pair.
215     llvm::StringRef raw_str(command);
216     std::string var_value_string = raw_str.split(var_name).second.str();
217     const char *var_value_cstr =
218         Args::StripSpaces(var_value_string, true, false, false);
219 
220     Status error;
221     if (m_options.m_global) {
222       error = GetDebugger().SetPropertyValue(nullptr, eVarSetOperationAssign,
223                                              var_name, var_value_cstr);
224     }
225 
226     if (error.Success()) {
227       // FIXME this is the same issue as the one in commands script import
228       // we could be setting target.load-script-from-symbol-file which would
229       // cause Python scripts to be loaded, which could run LLDB commands (e.g.
230       // settings set target.process.python-os-plugin-path) and cause a crash
231       // if we did not clear the command's exe_ctx first
232       ExecutionContext exe_ctx(m_exe_ctx);
233       m_exe_ctx.Clear();
234       error = GetDebugger().SetPropertyValue(&exe_ctx, eVarSetOperationAssign,
235                                              var_name, var_value_cstr);
236     }
237 
238     if (error.Fail()) {
239       result.AppendError(error.AsCString());
240       result.SetStatus(eReturnStatusFailed);
241       return false;
242     } else {
243       result.SetStatus(eReturnStatusSuccessFinishResult);
244     }
245 
246     return result.Succeeded();
247   }
248 
249 private:
250   CommandOptions m_options;
251 };
252 
253 // CommandObjectSettingsShow -- Show current values
254 
255 class CommandObjectSettingsShow : public CommandObjectParsed {
256 public:
257   CommandObjectSettingsShow(CommandInterpreter &interpreter)
258       : CommandObjectParsed(interpreter, "settings show",
259                             "Show matching debugger settings and their current "
260                             "values.  Defaults to showing all settings.",
261                             nullptr) {
262     CommandArgumentEntry arg1;
263     CommandArgumentData var_name_arg;
264 
265     // Define the first (and only) variant of this arg.
266     var_name_arg.arg_type = eArgTypeSettingVariableName;
267     var_name_arg.arg_repetition = eArgRepeatOptional;
268 
269     // There is only one variant this argument could be; put it into the
270     // argument entry.
271     arg1.push_back(var_name_arg);
272 
273     // Push the data for the first argument into the m_arguments vector.
274     m_arguments.push_back(arg1);
275   }
276 
277   ~CommandObjectSettingsShow() override = default;
278 
279   int HandleArgumentCompletion(
280       CompletionRequest &request,
281       OptionElementVector &opt_element_vector) override {
282     CommandCompletions::InvokeCommonCompletionCallbacks(
283         GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
284         request, nullptr);
285     return request.GetNumberOfMatches();
286   }
287 
288 protected:
289   bool DoExecute(Args &args, CommandReturnObject &result) override {
290     result.SetStatus(eReturnStatusSuccessFinishResult);
291 
292     if (!args.empty()) {
293       for (const auto &arg : args) {
294         Status error(GetDebugger().DumpPropertyValue(
295             &m_exe_ctx, result.GetOutputStream(), arg.ref,
296             OptionValue::eDumpGroupValue));
297         if (error.Success()) {
298           result.GetOutputStream().EOL();
299         } else {
300           result.AppendError(error.AsCString());
301           result.SetStatus(eReturnStatusFailed);
302         }
303       }
304     } else {
305       GetDebugger().DumpAllPropertyValues(&m_exe_ctx, result.GetOutputStream(),
306                                           OptionValue::eDumpGroupValue);
307     }
308 
309     return result.Succeeded();
310   }
311 };
312 
313 // CommandObjectSettingsWrite -- Write settings to file
314 
315 static constexpr OptionDefinition g_settings_write_options[] = {
316     // clang-format off
317   { LLDB_OPT_SET_ALL, true,  "file",  'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,    "The file into which to write the settings." },
318   { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument,       nullptr, {}, 0,                                       eArgTypeNone,        "Append to saved settings file if it exists."},
319     // clang-format on
320 };
321 
322 class CommandObjectSettingsWrite : public CommandObjectParsed {
323 public:
324   CommandObjectSettingsWrite(CommandInterpreter &interpreter)
325       : CommandObjectParsed(
326             interpreter, "settings export",
327             "Write matching debugger settings and their "
328             "current values to a file that can be read in with "
329             "\"settings read\". Defaults to writing all settings.",
330             nullptr),
331         m_options() {
332     CommandArgumentEntry arg1;
333     CommandArgumentData var_name_arg;
334 
335     // Define the first (and only) variant of this arg.
336     var_name_arg.arg_type = eArgTypeSettingVariableName;
337     var_name_arg.arg_repetition = eArgRepeatOptional;
338 
339     // There is only one variant this argument could be; put it into the
340     // argument entry.
341     arg1.push_back(var_name_arg);
342 
343     // Push the data for the first argument into the m_arguments vector.
344     m_arguments.push_back(arg1);
345   }
346 
347   ~CommandObjectSettingsWrite() override = default;
348 
349   Options *GetOptions() override { return &m_options; }
350 
351   class CommandOptions : public Options {
352   public:
353     CommandOptions() : Options() {}
354 
355     ~CommandOptions() override = default;
356 
357     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
358                           ExecutionContext *execution_context) override {
359       Status error;
360       const int short_option = m_getopt_table[option_idx].val;
361 
362       switch (short_option) {
363       case 'f':
364         m_filename.assign(option_arg);
365         break;
366       case 'a':
367         m_append = true;
368         break;
369       default:
370         error.SetErrorStringWithFormat("unrecognized option '%c'",
371                                        short_option);
372         break;
373       }
374 
375       return error;
376     }
377 
378     void OptionParsingStarting(ExecutionContext *execution_context) override {
379       m_filename.clear();
380       m_append = false;
381     }
382 
383     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
384       return llvm::makeArrayRef(g_settings_write_options);
385     }
386 
387     // Instance variables to hold the values for command options.
388     std::string m_filename;
389     bool m_append = false;
390   };
391 
392 protected:
393   bool DoExecute(Args &args, CommandReturnObject &result) override {
394     FileSpec file_spec(m_options.m_filename);
395     FileSystem::Instance().Resolve(file_spec);
396     std::string path(file_spec.GetPath());
397     uint32_t options = File::OpenOptions::eOpenOptionWrite |
398                        File::OpenOptions::eOpenOptionCanCreate;
399     if (m_options.m_append)
400       options |= File::OpenOptions::eOpenOptionAppend;
401     else
402       options |= File::OpenOptions::eOpenOptionTruncate;
403 
404     StreamFile out_file(path.c_str(), options,
405                         lldb::eFilePermissionsFileDefault);
406 
407     if (!out_file.GetFile().IsValid()) {
408       result.AppendErrorWithFormat("%s: unable to write to file", path.c_str());
409       result.SetStatus(eReturnStatusFailed);
410       return false;
411     }
412 
413     // Exporting should not be context sensitive.
414     ExecutionContext clean_ctx;
415 
416     if (args.empty()) {
417       GetDebugger().DumpAllPropertyValues(&clean_ctx, out_file,
418                                           OptionValue::eDumpGroupExport);
419       return result.Succeeded();
420     }
421 
422     for (const auto &arg : args) {
423       Status error(GetDebugger().DumpPropertyValue(
424           &clean_ctx, out_file, arg.ref, OptionValue::eDumpGroupExport));
425       if (!error.Success()) {
426         result.AppendError(error.AsCString());
427         result.SetStatus(eReturnStatusFailed);
428       }
429     }
430 
431     return result.Succeeded();
432   }
433 
434 private:
435   CommandOptions m_options;
436 };
437 
438 // CommandObjectSettingsRead -- Read settings from file
439 
440 static constexpr OptionDefinition g_settings_read_options[] = {
441     // clang-format off
442   {LLDB_OPT_SET_ALL, true, "file",'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,       "The file from which to read the breakpoints." },
443     // clang-format on
444 };
445 
446 class CommandObjectSettingsRead : public CommandObjectParsed {
447 public:
448   CommandObjectSettingsRead(CommandInterpreter &interpreter)
449       : CommandObjectParsed(
450             interpreter, "settings read",
451             "Read settings previously saved to a file with \"settings write\".",
452             nullptr),
453         m_options() {}
454 
455   ~CommandObjectSettingsRead() override = default;
456 
457   Options *GetOptions() override { return &m_options; }
458 
459   class CommandOptions : public Options {
460   public:
461     CommandOptions() : Options() {}
462 
463     ~CommandOptions() override = default;
464 
465     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
466                           ExecutionContext *execution_context) override {
467       Status error;
468       const int short_option = m_getopt_table[option_idx].val;
469 
470       switch (short_option) {
471       case 'f':
472         m_filename.assign(option_arg);
473         break;
474       default:
475         error.SetErrorStringWithFormat("unrecognized option '%c'",
476                                        short_option);
477         break;
478       }
479 
480       return error;
481     }
482 
483     void OptionParsingStarting(ExecutionContext *execution_context) override {
484       m_filename.clear();
485     }
486 
487     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
488       return llvm::makeArrayRef(g_settings_read_options);
489     }
490 
491     // Instance variables to hold the values for command options.
492     std::string m_filename;
493   };
494 
495 protected:
496   bool DoExecute(Args &command, CommandReturnObject &result) override {
497     FileSpec file(m_options.m_filename);
498     FileSystem::Instance().Resolve(file);
499     ExecutionContext clean_ctx;
500     CommandInterpreterRunOptions options;
501     options.SetAddToHistory(false);
502     options.SetEchoCommands(false);
503     options.SetPrintResults(true);
504     options.SetStopOnError(false);
505     m_interpreter.HandleCommandsFromFile(file, &clean_ctx, options, result);
506     return result.Succeeded();
507   }
508 
509 private:
510   CommandOptions m_options;
511 };
512 
513 // CommandObjectSettingsList -- List settable variables
514 
515 class CommandObjectSettingsList : public CommandObjectParsed {
516 public:
517   CommandObjectSettingsList(CommandInterpreter &interpreter)
518       : CommandObjectParsed(interpreter, "settings list",
519                             "List and describe matching debugger settings.  "
520                             "Defaults to all listing all settings.",
521                             nullptr) {
522     CommandArgumentEntry arg;
523     CommandArgumentData var_name_arg;
524     CommandArgumentData prefix_name_arg;
525 
526     // Define the first variant of this arg.
527     var_name_arg.arg_type = eArgTypeSettingVariableName;
528     var_name_arg.arg_repetition = eArgRepeatOptional;
529 
530     // Define the second variant of this arg.
531     prefix_name_arg.arg_type = eArgTypeSettingPrefix;
532     prefix_name_arg.arg_repetition = eArgRepeatOptional;
533 
534     arg.push_back(var_name_arg);
535     arg.push_back(prefix_name_arg);
536 
537     // Push the data for the first argument into the m_arguments vector.
538     m_arguments.push_back(arg);
539   }
540 
541   ~CommandObjectSettingsList() override = default;
542 
543   int HandleArgumentCompletion(
544       CompletionRequest &request,
545       OptionElementVector &opt_element_vector) override {
546     CommandCompletions::InvokeCommonCompletionCallbacks(
547         GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
548         request, nullptr);
549     return request.GetNumberOfMatches();
550   }
551 
552 protected:
553   bool DoExecute(Args &args, CommandReturnObject &result) override {
554     result.SetStatus(eReturnStatusSuccessFinishResult);
555 
556     const bool will_modify = false;
557     const size_t argc = args.GetArgumentCount();
558     if (argc > 0) {
559       const bool dump_qualified_name = true;
560 
561       // TODO: Convert to StringRef based enumeration.  Requires converting
562       // GetPropertyAtPath first.
563       for (size_t i = 0; i < argc; ++i) {
564         const char *property_path = args.GetArgumentAtIndex(i);
565 
566         const Property *property =
567             GetDebugger().GetValueProperties()->GetPropertyAtPath(
568                 &m_exe_ctx, will_modify, property_path);
569 
570         if (property) {
571           property->DumpDescription(m_interpreter, result.GetOutputStream(), 0,
572                                     dump_qualified_name);
573         } else {
574           result.AppendErrorWithFormat("invalid property path '%s'",
575                                        property_path);
576           result.SetStatus(eReturnStatusFailed);
577         }
578       }
579     } else {
580       GetDebugger().DumpAllDescriptions(m_interpreter,
581                                         result.GetOutputStream());
582     }
583 
584     return result.Succeeded();
585   }
586 };
587 
588 // CommandObjectSettingsRemove
589 
590 class CommandObjectSettingsRemove : public CommandObjectRaw {
591 public:
592   CommandObjectSettingsRemove(CommandInterpreter &interpreter)
593       : CommandObjectRaw(interpreter, "settings remove",
594                          "Remove a value from a setting, specified by array "
595                          "index or dictionary key.") {
596     CommandArgumentEntry arg1;
597     CommandArgumentEntry arg2;
598     CommandArgumentData var_name_arg;
599     CommandArgumentData index_arg;
600     CommandArgumentData key_arg;
601 
602     // Define the first (and only) variant of this arg.
603     var_name_arg.arg_type = eArgTypeSettingVariableName;
604     var_name_arg.arg_repetition = eArgRepeatPlain;
605 
606     // There is only one variant this argument could be; put it into the
607     // argument entry.
608     arg1.push_back(var_name_arg);
609 
610     // Define the first variant of this arg.
611     index_arg.arg_type = eArgTypeSettingIndex;
612     index_arg.arg_repetition = eArgRepeatPlain;
613 
614     // Define the second variant of this arg.
615     key_arg.arg_type = eArgTypeSettingKey;
616     key_arg.arg_repetition = eArgRepeatPlain;
617 
618     // Push both variants into this arg
619     arg2.push_back(index_arg);
620     arg2.push_back(key_arg);
621 
622     // Push the data for the first argument into the m_arguments vector.
623     m_arguments.push_back(arg1);
624     m_arguments.push_back(arg2);
625   }
626 
627   ~CommandObjectSettingsRemove() override = default;
628 
629   int HandleArgumentCompletion(
630       CompletionRequest &request,
631       OptionElementVector &opt_element_vector) override {
632     if (request.GetCursorIndex() < 2)
633       CommandCompletions::InvokeCommonCompletionCallbacks(
634           GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
635           request, nullptr);
636     return request.GetNumberOfMatches();
637   }
638 
639 protected:
640   bool DoExecute(llvm::StringRef command,
641                  CommandReturnObject &result) override {
642     result.SetStatus(eReturnStatusSuccessFinishNoResult);
643 
644     Args cmd_args(command);
645 
646     // Process possible options.
647     if (!ParseOptions(cmd_args, result))
648       return false;
649 
650     const size_t argc = cmd_args.GetArgumentCount();
651     if (argc == 0) {
652       result.AppendError("'settings set' takes an array or dictionary item, or "
653                          "an array followed by one or more indexes, or a "
654                          "dictionary followed by one or more key names to "
655                          "remove");
656       result.SetStatus(eReturnStatusFailed);
657       return false;
658     }
659 
660     const char *var_name = cmd_args.GetArgumentAtIndex(0);
661     if ((var_name == nullptr) || (var_name[0] == '\0')) {
662       result.AppendError(
663           "'settings set' command requires a valid variable name");
664       result.SetStatus(eReturnStatusFailed);
665       return false;
666     }
667 
668     // Split the raw command into var_name and value pair.
669     llvm::StringRef raw_str(command);
670     std::string var_value_string = raw_str.split(var_name).second.str();
671     const char *var_value_cstr =
672         Args::StripSpaces(var_value_string, true, true, false);
673 
674     Status error(GetDebugger().SetPropertyValue(
675         &m_exe_ctx, eVarSetOperationRemove, var_name, var_value_cstr));
676     if (error.Fail()) {
677       result.AppendError(error.AsCString());
678       result.SetStatus(eReturnStatusFailed);
679       return false;
680     }
681 
682     return result.Succeeded();
683   }
684 };
685 
686 // CommandObjectSettingsReplace
687 
688 class CommandObjectSettingsReplace : public CommandObjectRaw {
689 public:
690   CommandObjectSettingsReplace(CommandInterpreter &interpreter)
691       : CommandObjectRaw(interpreter, "settings replace",
692                          "Replace the debugger setting value specified by "
693                          "array index or dictionary key.") {
694     CommandArgumentEntry arg1;
695     CommandArgumentEntry arg2;
696     CommandArgumentEntry arg3;
697     CommandArgumentData var_name_arg;
698     CommandArgumentData index_arg;
699     CommandArgumentData key_arg;
700     CommandArgumentData value_arg;
701 
702     // Define the first (and only) variant of this arg.
703     var_name_arg.arg_type = eArgTypeSettingVariableName;
704     var_name_arg.arg_repetition = eArgRepeatPlain;
705 
706     // There is only one variant this argument could be; put it into the
707     // argument entry.
708     arg1.push_back(var_name_arg);
709 
710     // Define the first (variant of this arg.
711     index_arg.arg_type = eArgTypeSettingIndex;
712     index_arg.arg_repetition = eArgRepeatPlain;
713 
714     // Define the second (variant of this arg.
715     key_arg.arg_type = eArgTypeSettingKey;
716     key_arg.arg_repetition = eArgRepeatPlain;
717 
718     // Put both variants into this arg
719     arg2.push_back(index_arg);
720     arg2.push_back(key_arg);
721 
722     // Define the first (and only) variant of this arg.
723     value_arg.arg_type = eArgTypeValue;
724     value_arg.arg_repetition = eArgRepeatPlain;
725 
726     // There is only one variant this argument could be; put it into the
727     // argument entry.
728     arg3.push_back(value_arg);
729 
730     // Push the data for the first argument into the m_arguments vector.
731     m_arguments.push_back(arg1);
732     m_arguments.push_back(arg2);
733     m_arguments.push_back(arg3);
734   }
735 
736   ~CommandObjectSettingsReplace() override = default;
737 
738   // Overrides base class's behavior where WantsCompletion =
739   // !WantsRawCommandString.
740   bool WantsCompletion() override { return true; }
741 
742   int HandleArgumentCompletion(
743       CompletionRequest &request,
744       OptionElementVector &opt_element_vector) override {
745     // Attempting to complete variable name
746     if (request.GetCursorIndex() < 2)
747       CommandCompletions::InvokeCommonCompletionCallbacks(
748           GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
749           request, nullptr);
750 
751     return request.GetNumberOfMatches();
752   }
753 
754 protected:
755   bool DoExecute(llvm::StringRef command,
756                  CommandReturnObject &result) override {
757     result.SetStatus(eReturnStatusSuccessFinishNoResult);
758 
759     Args cmd_args(command);
760     const char *var_name = cmd_args.GetArgumentAtIndex(0);
761     if ((var_name == nullptr) || (var_name[0] == '\0')) {
762       result.AppendError("'settings replace' command requires a valid variable "
763                          "name; No value supplied");
764       result.SetStatus(eReturnStatusFailed);
765       return false;
766     }
767 
768     // Split the raw command into var_name, index_value, and value triple.
769     llvm::StringRef raw_str(command);
770     std::string var_value_string = raw_str.split(var_name).second.str();
771     const char *var_value_cstr =
772         Args::StripSpaces(var_value_string, true, true, false);
773 
774     Status error(GetDebugger().SetPropertyValue(
775         &m_exe_ctx, eVarSetOperationReplace, var_name, var_value_cstr));
776     if (error.Fail()) {
777       result.AppendError(error.AsCString());
778       result.SetStatus(eReturnStatusFailed);
779       return false;
780     } else {
781       result.SetStatus(eReturnStatusSuccessFinishNoResult);
782     }
783 
784     return result.Succeeded();
785   }
786 };
787 
788 // CommandObjectSettingsInsertBefore
789 
790 class CommandObjectSettingsInsertBefore : public CommandObjectRaw {
791 public:
792   CommandObjectSettingsInsertBefore(CommandInterpreter &interpreter)
793       : CommandObjectRaw(interpreter, "settings insert-before",
794                          "Insert one or more values into an debugger array "
795                          "setting immediately before the specified element "
796                          "index.") {
797     CommandArgumentEntry arg1;
798     CommandArgumentEntry arg2;
799     CommandArgumentEntry arg3;
800     CommandArgumentData var_name_arg;
801     CommandArgumentData index_arg;
802     CommandArgumentData value_arg;
803 
804     // Define the first (and only) variant of this arg.
805     var_name_arg.arg_type = eArgTypeSettingVariableName;
806     var_name_arg.arg_repetition = eArgRepeatPlain;
807 
808     // There is only one variant this argument could be; put it into the
809     // argument entry.
810     arg1.push_back(var_name_arg);
811 
812     // Define the first (variant of this arg.
813     index_arg.arg_type = eArgTypeSettingIndex;
814     index_arg.arg_repetition = eArgRepeatPlain;
815 
816     // There is only one variant this argument could be; put it into the
817     // argument entry.
818     arg2.push_back(index_arg);
819 
820     // Define the first (and only) variant of this arg.
821     value_arg.arg_type = eArgTypeValue;
822     value_arg.arg_repetition = eArgRepeatPlain;
823 
824     // There is only one variant this argument could be; put it into the
825     // argument entry.
826     arg3.push_back(value_arg);
827 
828     // Push the data for the first argument into the m_arguments vector.
829     m_arguments.push_back(arg1);
830     m_arguments.push_back(arg2);
831     m_arguments.push_back(arg3);
832   }
833 
834   ~CommandObjectSettingsInsertBefore() override = default;
835 
836   // Overrides base class's behavior where WantsCompletion =
837   // !WantsRawCommandString.
838   bool WantsCompletion() override { return true; }
839 
840   int HandleArgumentCompletion(
841       CompletionRequest &request,
842       OptionElementVector &opt_element_vector) override {
843     // Attempting to complete variable name
844     if (request.GetCursorIndex() < 2)
845       CommandCompletions::InvokeCommonCompletionCallbacks(
846           GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
847           request, nullptr);
848 
849     return request.GetNumberOfMatches();
850   }
851 
852 protected:
853   bool DoExecute(llvm::StringRef command,
854                  CommandReturnObject &result) override {
855     result.SetStatus(eReturnStatusSuccessFinishNoResult);
856 
857     Args cmd_args(command);
858     const size_t argc = cmd_args.GetArgumentCount();
859 
860     if (argc < 3) {
861       result.AppendError("'settings insert-before' takes more arguments");
862       result.SetStatus(eReturnStatusFailed);
863       return false;
864     }
865 
866     const char *var_name = cmd_args.GetArgumentAtIndex(0);
867     if ((var_name == nullptr) || (var_name[0] == '\0')) {
868       result.AppendError("'settings insert-before' command requires a valid "
869                          "variable name; No value supplied");
870       result.SetStatus(eReturnStatusFailed);
871       return false;
872     }
873 
874     // Split the raw command into var_name, index_value, and value triple.
875     llvm::StringRef raw_str(command);
876     std::string var_value_string = raw_str.split(var_name).second.str();
877     const char *var_value_cstr =
878         Args::StripSpaces(var_value_string, true, true, false);
879 
880     Status error(GetDebugger().SetPropertyValue(
881         &m_exe_ctx, eVarSetOperationInsertBefore, var_name, var_value_cstr));
882     if (error.Fail()) {
883       result.AppendError(error.AsCString());
884       result.SetStatus(eReturnStatusFailed);
885       return false;
886     }
887 
888     return result.Succeeded();
889   }
890 };
891 
892 // CommandObjectSettingInsertAfter
893 
894 class CommandObjectSettingsInsertAfter : public CommandObjectRaw {
895 public:
896   CommandObjectSettingsInsertAfter(CommandInterpreter &interpreter)
897       : CommandObjectRaw(interpreter, "settings insert-after",
898                          "Insert one or more values into a debugger array "
899                          "settings after the specified element index.") {
900     CommandArgumentEntry arg1;
901     CommandArgumentEntry arg2;
902     CommandArgumentEntry arg3;
903     CommandArgumentData var_name_arg;
904     CommandArgumentData index_arg;
905     CommandArgumentData value_arg;
906 
907     // Define the first (and only) variant of this arg.
908     var_name_arg.arg_type = eArgTypeSettingVariableName;
909     var_name_arg.arg_repetition = eArgRepeatPlain;
910 
911     // There is only one variant this argument could be; put it into the
912     // argument entry.
913     arg1.push_back(var_name_arg);
914 
915     // Define the first (variant of this arg.
916     index_arg.arg_type = eArgTypeSettingIndex;
917     index_arg.arg_repetition = eArgRepeatPlain;
918 
919     // There is only one variant this argument could be; put it into the
920     // argument entry.
921     arg2.push_back(index_arg);
922 
923     // Define the first (and only) variant of this arg.
924     value_arg.arg_type = eArgTypeValue;
925     value_arg.arg_repetition = eArgRepeatPlain;
926 
927     // There is only one variant this argument could be; put it into the
928     // argument entry.
929     arg3.push_back(value_arg);
930 
931     // Push the data for the first argument into the m_arguments vector.
932     m_arguments.push_back(arg1);
933     m_arguments.push_back(arg2);
934     m_arguments.push_back(arg3);
935   }
936 
937   ~CommandObjectSettingsInsertAfter() override = default;
938 
939   // Overrides base class's behavior where WantsCompletion =
940   // !WantsRawCommandString.
941   bool WantsCompletion() override { return true; }
942 
943   int HandleArgumentCompletion(
944       CompletionRequest &request,
945       OptionElementVector &opt_element_vector) override {
946     // Attempting to complete variable name
947     if (request.GetCursorIndex() < 2)
948       CommandCompletions::InvokeCommonCompletionCallbacks(
949           GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
950           request, nullptr);
951 
952     return request.GetNumberOfMatches();
953   }
954 
955 protected:
956   bool DoExecute(llvm::StringRef command,
957                  CommandReturnObject &result) override {
958     result.SetStatus(eReturnStatusSuccessFinishNoResult);
959 
960     Args cmd_args(command);
961     const size_t argc = cmd_args.GetArgumentCount();
962 
963     if (argc < 3) {
964       result.AppendError("'settings insert-after' takes more arguments");
965       result.SetStatus(eReturnStatusFailed);
966       return false;
967     }
968 
969     const char *var_name = cmd_args.GetArgumentAtIndex(0);
970     if ((var_name == nullptr) || (var_name[0] == '\0')) {
971       result.AppendError("'settings insert-after' command requires a valid "
972                          "variable name; No value supplied");
973       result.SetStatus(eReturnStatusFailed);
974       return false;
975     }
976 
977     // Split the raw command into var_name, index_value, and value triple.
978     llvm::StringRef raw_str(command);
979     std::string var_value_string = raw_str.split(var_name).second.str();
980     const char *var_value_cstr =
981         Args::StripSpaces(var_value_string, true, true, false);
982 
983     Status error(GetDebugger().SetPropertyValue(
984         &m_exe_ctx, eVarSetOperationInsertAfter, var_name, var_value_cstr));
985     if (error.Fail()) {
986       result.AppendError(error.AsCString());
987       result.SetStatus(eReturnStatusFailed);
988       return false;
989     }
990 
991     return result.Succeeded();
992   }
993 };
994 
995 // CommandObjectSettingsAppend
996 
997 class CommandObjectSettingsAppend : public CommandObjectRaw {
998 public:
999   CommandObjectSettingsAppend(CommandInterpreter &interpreter)
1000       : CommandObjectRaw(interpreter, "settings append",
1001                          "Append one or more values to a debugger array, "
1002                          "dictionary, or string setting.") {
1003     CommandArgumentEntry arg1;
1004     CommandArgumentEntry arg2;
1005     CommandArgumentData var_name_arg;
1006     CommandArgumentData value_arg;
1007 
1008     // Define the first (and only) variant of this arg.
1009     var_name_arg.arg_type = eArgTypeSettingVariableName;
1010     var_name_arg.arg_repetition = eArgRepeatPlain;
1011 
1012     // There is only one variant this argument could be; put it into the
1013     // argument entry.
1014     arg1.push_back(var_name_arg);
1015 
1016     // Define the first (and only) variant of this arg.
1017     value_arg.arg_type = eArgTypeValue;
1018     value_arg.arg_repetition = eArgRepeatPlain;
1019 
1020     // There is only one variant this argument could be; put it into the
1021     // argument entry.
1022     arg2.push_back(value_arg);
1023 
1024     // Push the data for the first argument into the m_arguments vector.
1025     m_arguments.push_back(arg1);
1026     m_arguments.push_back(arg2);
1027   }
1028 
1029   ~CommandObjectSettingsAppend() override = default;
1030 
1031   // Overrides base class's behavior where WantsCompletion =
1032   // !WantsRawCommandString.
1033   bool WantsCompletion() override { return true; }
1034 
1035   int HandleArgumentCompletion(
1036       CompletionRequest &request,
1037       OptionElementVector &opt_element_vector) override {
1038     // Attempting to complete variable name
1039     if (request.GetCursorIndex() < 2)
1040       CommandCompletions::InvokeCommonCompletionCallbacks(
1041           GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
1042           request, nullptr);
1043 
1044     return request.GetNumberOfMatches();
1045   }
1046 
1047 protected:
1048   bool DoExecute(llvm::StringRef command,
1049                  CommandReturnObject &result) override {
1050     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1051     Args cmd_args(command);
1052     const size_t argc = cmd_args.GetArgumentCount();
1053 
1054     if (argc < 2) {
1055       result.AppendError("'settings append' takes more arguments");
1056       result.SetStatus(eReturnStatusFailed);
1057       return false;
1058     }
1059 
1060     const char *var_name = cmd_args.GetArgumentAtIndex(0);
1061     if ((var_name == nullptr) || (var_name[0] == '\0')) {
1062       result.AppendError("'settings append' command requires a valid variable "
1063                          "name; No value supplied");
1064       result.SetStatus(eReturnStatusFailed);
1065       return false;
1066     }
1067 
1068     // Do not perform cmd_args.Shift() since StringRef is manipulating the raw
1069     // character string later on.
1070 
1071     // Split the raw command into var_name and value pair.
1072     llvm::StringRef raw_str(command);
1073     std::string var_value_string = raw_str.split(var_name).second.str();
1074     const char *var_value_cstr =
1075         Args::StripSpaces(var_value_string, true, true, false);
1076 
1077     Status error(GetDebugger().SetPropertyValue(
1078         &m_exe_ctx, eVarSetOperationAppend, var_name, var_value_cstr));
1079     if (error.Fail()) {
1080       result.AppendError(error.AsCString());
1081       result.SetStatus(eReturnStatusFailed);
1082       return false;
1083     }
1084 
1085     return result.Succeeded();
1086   }
1087 };
1088 
1089 // CommandObjectSettingsClear
1090 
1091 class CommandObjectSettingsClear : public CommandObjectParsed {
1092 public:
1093   CommandObjectSettingsClear(CommandInterpreter &interpreter)
1094       : CommandObjectParsed(
1095             interpreter, "settings clear",
1096             "Clear a debugger setting array, dictionary, or string.", nullptr) {
1097     CommandArgumentEntry arg;
1098     CommandArgumentData var_name_arg;
1099 
1100     // Define the first (and only) variant of this arg.
1101     var_name_arg.arg_type = eArgTypeSettingVariableName;
1102     var_name_arg.arg_repetition = eArgRepeatPlain;
1103 
1104     // There is only one variant this argument could be; put it into the
1105     // argument entry.
1106     arg.push_back(var_name_arg);
1107 
1108     // Push the data for the first argument into the m_arguments vector.
1109     m_arguments.push_back(arg);
1110   }
1111 
1112   ~CommandObjectSettingsClear() override = default;
1113 
1114   int HandleArgumentCompletion(
1115       CompletionRequest &request,
1116       OptionElementVector &opt_element_vector) override {
1117     // Attempting to complete variable name
1118     if (request.GetCursorIndex() < 2)
1119       CommandCompletions::InvokeCommonCompletionCallbacks(
1120           GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
1121           request, nullptr);
1122 
1123     return request.GetNumberOfMatches();
1124   }
1125 
1126 protected:
1127   bool DoExecute(Args &command, CommandReturnObject &result) override {
1128     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1129     const size_t argc = command.GetArgumentCount();
1130 
1131     if (argc != 1) {
1132       result.AppendError("'settings clear' takes exactly one argument");
1133       result.SetStatus(eReturnStatusFailed);
1134       return false;
1135     }
1136 
1137     const char *var_name = command.GetArgumentAtIndex(0);
1138     if ((var_name == nullptr) || (var_name[0] == '\0')) {
1139       result.AppendError("'settings clear' command requires a valid variable "
1140                          "name; No value supplied");
1141       result.SetStatus(eReturnStatusFailed);
1142       return false;
1143     }
1144 
1145     Status error(GetDebugger().SetPropertyValue(
1146         &m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef()));
1147     if (error.Fail()) {
1148       result.AppendError(error.AsCString());
1149       result.SetStatus(eReturnStatusFailed);
1150       return false;
1151     }
1152 
1153     return result.Succeeded();
1154   }
1155 };
1156 
1157 // CommandObjectMultiwordSettings
1158 
1159 CommandObjectMultiwordSettings::CommandObjectMultiwordSettings(
1160     CommandInterpreter &interpreter)
1161     : CommandObjectMultiword(interpreter, "settings",
1162                              "Commands for managing LLDB settings.",
1163                              "settings <subcommand> [<command-options>]") {
1164   LoadSubCommand("set",
1165                  CommandObjectSP(new CommandObjectSettingsSet(interpreter)));
1166   LoadSubCommand("show",
1167                  CommandObjectSP(new CommandObjectSettingsShow(interpreter)));
1168   LoadSubCommand("list",
1169                  CommandObjectSP(new CommandObjectSettingsList(interpreter)));
1170   LoadSubCommand("remove",
1171                  CommandObjectSP(new CommandObjectSettingsRemove(interpreter)));
1172   LoadSubCommand("replace", CommandObjectSP(
1173                                 new CommandObjectSettingsReplace(interpreter)));
1174   LoadSubCommand(
1175       "insert-before",
1176       CommandObjectSP(new CommandObjectSettingsInsertBefore(interpreter)));
1177   LoadSubCommand(
1178       "insert-after",
1179       CommandObjectSP(new CommandObjectSettingsInsertAfter(interpreter)));
1180   LoadSubCommand("append",
1181                  CommandObjectSP(new CommandObjectSettingsAppend(interpreter)));
1182   LoadSubCommand("clear",
1183                  CommandObjectSP(new CommandObjectSettingsClear(interpreter)));
1184   LoadSubCommand("write",
1185                  CommandObjectSP(new CommandObjectSettingsWrite(interpreter)));
1186   LoadSubCommand("read",
1187                  CommandObjectSP(new CommandObjectSettingsRead(interpreter)));
1188 }
1189 
1190 CommandObjectMultiwordSettings::~CommandObjectMultiwordSettings() = default;
1191