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