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