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