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