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