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