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