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