CommandObjectSettings.cpp revision 360784
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
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(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(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      // TODO: Convert to StringRef based enumeration.  Requires converting
535      // GetPropertyAtPath first.
536      for (size_t i = 0; i < argc; ++i) {
537        const char *property_path = args.GetArgumentAtIndex(i);
538
539        const Property *property =
540            GetDebugger().GetValueProperties()->GetPropertyAtPath(
541                &m_exe_ctx, will_modify, property_path);
542
543        if (property) {
544          property->DumpDescription(m_interpreter, result.GetOutputStream(), 0,
545                                    dump_qualified_name);
546        } else {
547          result.AppendErrorWithFormat("invalid property path '%s'",
548                                       property_path);
549          result.SetStatus(eReturnStatusFailed);
550        }
551      }
552    } else {
553      GetDebugger().DumpAllDescriptions(m_interpreter,
554                                        result.GetOutputStream());
555    }
556
557    return result.Succeeded();
558  }
559};
560
561// CommandObjectSettingsRemove
562
563class CommandObjectSettingsRemove : public CommandObjectRaw {
564public:
565  CommandObjectSettingsRemove(CommandInterpreter &interpreter)
566      : CommandObjectRaw(interpreter, "settings remove",
567                         "Remove a value from a setting, specified by array "
568                         "index or dictionary key.") {
569    CommandArgumentEntry arg1;
570    CommandArgumentEntry arg2;
571    CommandArgumentData var_name_arg;
572    CommandArgumentData index_arg;
573    CommandArgumentData key_arg;
574
575    // Define the first (and only) variant of this arg.
576    var_name_arg.arg_type = eArgTypeSettingVariableName;
577    var_name_arg.arg_repetition = eArgRepeatPlain;
578
579    // There is only one variant this argument could be; put it into the
580    // argument entry.
581    arg1.push_back(var_name_arg);
582
583    // Define the first variant of this arg.
584    index_arg.arg_type = eArgTypeSettingIndex;
585    index_arg.arg_repetition = eArgRepeatPlain;
586
587    // Define the second variant of this arg.
588    key_arg.arg_type = eArgTypeSettingKey;
589    key_arg.arg_repetition = eArgRepeatPlain;
590
591    // Push both variants into this arg
592    arg2.push_back(index_arg);
593    arg2.push_back(key_arg);
594
595    // Push the data for the first argument into the m_arguments vector.
596    m_arguments.push_back(arg1);
597    m_arguments.push_back(arg2);
598  }
599
600  ~CommandObjectSettingsRemove() override = default;
601
602  bool WantsCompletion() override { return true; }
603
604  void
605  HandleArgumentCompletion(CompletionRequest &request,
606                           OptionElementVector &opt_element_vector) override {
607    if (request.GetCursorIndex() < 2)
608      CommandCompletions::InvokeCommonCompletionCallbacks(
609          GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
610          request, nullptr);
611  }
612
613protected:
614  bool DoExecute(llvm::StringRef command,
615                 CommandReturnObject &result) override {
616    result.SetStatus(eReturnStatusSuccessFinishNoResult);
617
618    Args cmd_args(command);
619
620    // Process possible options.
621    if (!ParseOptions(cmd_args, result))
622      return false;
623
624    const size_t argc = cmd_args.GetArgumentCount();
625    if (argc == 0) {
626      result.AppendError("'settings remove' takes an array or dictionary item, "
627                         "or an array followed by one or more indexes, or a "
628                         "dictionary followed by one or more key names to "
629                         "remove");
630      result.SetStatus(eReturnStatusFailed);
631      return false;
632    }
633
634    const char *var_name = cmd_args.GetArgumentAtIndex(0);
635    if ((var_name == nullptr) || (var_name[0] == '\0')) {
636      result.AppendError(
637          "'settings remove' command requires a valid variable name");
638      result.SetStatus(eReturnStatusFailed);
639      return false;
640    }
641
642    // Split the raw command into var_name and value pair.
643    llvm::StringRef var_value(command);
644    var_value = var_value.split(var_name).second.trim();
645
646    Status error(GetDebugger().SetPropertyValue(
647        &m_exe_ctx, eVarSetOperationRemove, var_name, var_value));
648    if (error.Fail()) {
649      result.AppendError(error.AsCString());
650      result.SetStatus(eReturnStatusFailed);
651      return false;
652    }
653
654    return result.Succeeded();
655  }
656};
657
658// CommandObjectSettingsReplace
659
660class CommandObjectSettingsReplace : public CommandObjectRaw {
661public:
662  CommandObjectSettingsReplace(CommandInterpreter &interpreter)
663      : CommandObjectRaw(interpreter, "settings replace",
664                         "Replace the debugger setting value specified by "
665                         "array index or dictionary key.") {
666    CommandArgumentEntry arg1;
667    CommandArgumentEntry arg2;
668    CommandArgumentEntry arg3;
669    CommandArgumentData var_name_arg;
670    CommandArgumentData index_arg;
671    CommandArgumentData key_arg;
672    CommandArgumentData value_arg;
673
674    // Define the first (and only) variant of this arg.
675    var_name_arg.arg_type = eArgTypeSettingVariableName;
676    var_name_arg.arg_repetition = eArgRepeatPlain;
677
678    // There is only one variant this argument could be; put it into the
679    // argument entry.
680    arg1.push_back(var_name_arg);
681
682    // Define the first (variant of this arg.
683    index_arg.arg_type = eArgTypeSettingIndex;
684    index_arg.arg_repetition = eArgRepeatPlain;
685
686    // Define the second (variant of this arg.
687    key_arg.arg_type = eArgTypeSettingKey;
688    key_arg.arg_repetition = eArgRepeatPlain;
689
690    // Put both variants into this arg
691    arg2.push_back(index_arg);
692    arg2.push_back(key_arg);
693
694    // Define the first (and only) variant of this arg.
695    value_arg.arg_type = eArgTypeValue;
696    value_arg.arg_repetition = eArgRepeatPlain;
697
698    // There is only one variant this argument could be; put it into the
699    // argument entry.
700    arg3.push_back(value_arg);
701
702    // Push the data for the first argument into the m_arguments vector.
703    m_arguments.push_back(arg1);
704    m_arguments.push_back(arg2);
705    m_arguments.push_back(arg3);
706  }
707
708  ~CommandObjectSettingsReplace() override = default;
709
710  // Overrides base class's behavior where WantsCompletion =
711  // !WantsRawCommandString.
712  bool WantsCompletion() override { return true; }
713
714  void
715  HandleArgumentCompletion(CompletionRequest &request,
716                           OptionElementVector &opt_element_vector) override {
717    // Attempting to complete variable name
718    if (request.GetCursorIndex() < 2)
719      CommandCompletions::InvokeCommonCompletionCallbacks(
720          GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
721          request, nullptr);
722  }
723
724protected:
725  bool DoExecute(llvm::StringRef command,
726                 CommandReturnObject &result) override {
727    result.SetStatus(eReturnStatusSuccessFinishNoResult);
728
729    Args cmd_args(command);
730    const char *var_name = cmd_args.GetArgumentAtIndex(0);
731    if ((var_name == nullptr) || (var_name[0] == '\0')) {
732      result.AppendError("'settings replace' command requires a valid variable "
733                         "name; No value supplied");
734      result.SetStatus(eReturnStatusFailed);
735      return false;
736    }
737
738    // Split the raw command into var_name, index_value, and value triple.
739    llvm::StringRef var_value(command);
740    var_value = var_value.split(var_name).second.trim();
741
742    Status error(GetDebugger().SetPropertyValue(
743        &m_exe_ctx, eVarSetOperationReplace, var_name, var_value));
744    if (error.Fail()) {
745      result.AppendError(error.AsCString());
746      result.SetStatus(eReturnStatusFailed);
747      return false;
748    } else {
749      result.SetStatus(eReturnStatusSuccessFinishNoResult);
750    }
751
752    return result.Succeeded();
753  }
754};
755
756// CommandObjectSettingsInsertBefore
757
758class CommandObjectSettingsInsertBefore : public CommandObjectRaw {
759public:
760  CommandObjectSettingsInsertBefore(CommandInterpreter &interpreter)
761      : CommandObjectRaw(interpreter, "settings insert-before",
762                         "Insert one or more values into an debugger array "
763                         "setting immediately before the specified element "
764                         "index.") {
765    CommandArgumentEntry arg1;
766    CommandArgumentEntry arg2;
767    CommandArgumentEntry arg3;
768    CommandArgumentData var_name_arg;
769    CommandArgumentData index_arg;
770    CommandArgumentData value_arg;
771
772    // Define the first (and only) variant of this arg.
773    var_name_arg.arg_type = eArgTypeSettingVariableName;
774    var_name_arg.arg_repetition = eArgRepeatPlain;
775
776    // There is only one variant this argument could be; put it into the
777    // argument entry.
778    arg1.push_back(var_name_arg);
779
780    // Define the first (variant of this arg.
781    index_arg.arg_type = eArgTypeSettingIndex;
782    index_arg.arg_repetition = eArgRepeatPlain;
783
784    // There is only one variant this argument could be; put it into the
785    // argument entry.
786    arg2.push_back(index_arg);
787
788    // Define the first (and only) variant of this arg.
789    value_arg.arg_type = eArgTypeValue;
790    value_arg.arg_repetition = eArgRepeatPlain;
791
792    // There is only one variant this argument could be; put it into the
793    // argument entry.
794    arg3.push_back(value_arg);
795
796    // Push the data for the first argument into the m_arguments vector.
797    m_arguments.push_back(arg1);
798    m_arguments.push_back(arg2);
799    m_arguments.push_back(arg3);
800  }
801
802  ~CommandObjectSettingsInsertBefore() override = default;
803
804  // Overrides base class's behavior where WantsCompletion =
805  // !WantsRawCommandString.
806  bool WantsCompletion() override { return true; }
807
808  void
809  HandleArgumentCompletion(CompletionRequest &request,
810                           OptionElementVector &opt_element_vector) override {
811    // Attempting to complete variable name
812    if (request.GetCursorIndex() < 2)
813      CommandCompletions::InvokeCommonCompletionCallbacks(
814          GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
815          request, nullptr);
816  }
817
818protected:
819  bool DoExecute(llvm::StringRef command,
820                 CommandReturnObject &result) override {
821    result.SetStatus(eReturnStatusSuccessFinishNoResult);
822
823    Args cmd_args(command);
824    const size_t argc = cmd_args.GetArgumentCount();
825
826    if (argc < 3) {
827      result.AppendError("'settings insert-before' takes more arguments");
828      result.SetStatus(eReturnStatusFailed);
829      return false;
830    }
831
832    const char *var_name = cmd_args.GetArgumentAtIndex(0);
833    if ((var_name == nullptr) || (var_name[0] == '\0')) {
834      result.AppendError("'settings insert-before' command requires a valid "
835                         "variable name; No value supplied");
836      result.SetStatus(eReturnStatusFailed);
837      return false;
838    }
839
840    // Split the raw command into var_name, index_value, and value triple.
841    llvm::StringRef var_value(command);
842    var_value = var_value.split(var_name).second.trim();
843
844    Status error(GetDebugger().SetPropertyValue(
845        &m_exe_ctx, eVarSetOperationInsertBefore, var_name, var_value));
846    if (error.Fail()) {
847      result.AppendError(error.AsCString());
848      result.SetStatus(eReturnStatusFailed);
849      return false;
850    }
851
852    return result.Succeeded();
853  }
854};
855
856// CommandObjectSettingInsertAfter
857
858class CommandObjectSettingsInsertAfter : public CommandObjectRaw {
859public:
860  CommandObjectSettingsInsertAfter(CommandInterpreter &interpreter)
861      : CommandObjectRaw(interpreter, "settings insert-after",
862                         "Insert one or more values into a debugger array "
863                         "settings after the specified element index.") {
864    CommandArgumentEntry arg1;
865    CommandArgumentEntry arg2;
866    CommandArgumentEntry arg3;
867    CommandArgumentData var_name_arg;
868    CommandArgumentData index_arg;
869    CommandArgumentData value_arg;
870
871    // Define the first (and only) variant of this arg.
872    var_name_arg.arg_type = eArgTypeSettingVariableName;
873    var_name_arg.arg_repetition = eArgRepeatPlain;
874
875    // There is only one variant this argument could be; put it into the
876    // argument entry.
877    arg1.push_back(var_name_arg);
878
879    // Define the first (variant of this arg.
880    index_arg.arg_type = eArgTypeSettingIndex;
881    index_arg.arg_repetition = eArgRepeatPlain;
882
883    // There is only one variant this argument could be; put it into the
884    // argument entry.
885    arg2.push_back(index_arg);
886
887    // Define the first (and only) variant of this arg.
888    value_arg.arg_type = eArgTypeValue;
889    value_arg.arg_repetition = eArgRepeatPlain;
890
891    // There is only one variant this argument could be; put it into the
892    // argument entry.
893    arg3.push_back(value_arg);
894
895    // Push the data for the first argument into the m_arguments vector.
896    m_arguments.push_back(arg1);
897    m_arguments.push_back(arg2);
898    m_arguments.push_back(arg3);
899  }
900
901  ~CommandObjectSettingsInsertAfter() override = default;
902
903  // Overrides base class's behavior where WantsCompletion =
904  // !WantsRawCommandString.
905  bool WantsCompletion() override { return true; }
906
907  void
908  HandleArgumentCompletion(CompletionRequest &request,
909                           OptionElementVector &opt_element_vector) override {
910    // Attempting to complete variable name
911    if (request.GetCursorIndex() < 2)
912      CommandCompletions::InvokeCommonCompletionCallbacks(
913          GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
914          request, nullptr);
915  }
916
917protected:
918  bool DoExecute(llvm::StringRef command,
919                 CommandReturnObject &result) override {
920    result.SetStatus(eReturnStatusSuccessFinishNoResult);
921
922    Args cmd_args(command);
923    const size_t argc = cmd_args.GetArgumentCount();
924
925    if (argc < 3) {
926      result.AppendError("'settings insert-after' takes more arguments");
927      result.SetStatus(eReturnStatusFailed);
928      return false;
929    }
930
931    const char *var_name = cmd_args.GetArgumentAtIndex(0);
932    if ((var_name == nullptr) || (var_name[0] == '\0')) {
933      result.AppendError("'settings insert-after' command requires a valid "
934                         "variable name; No value supplied");
935      result.SetStatus(eReturnStatusFailed);
936      return false;
937    }
938
939    // Split the raw command into var_name, index_value, and value triple.
940    llvm::StringRef var_value(command);
941    var_value = var_value.split(var_name).second.trim();
942
943    Status error(GetDebugger().SetPropertyValue(
944        &m_exe_ctx, eVarSetOperationInsertAfter, var_name, var_value));
945    if (error.Fail()) {
946      result.AppendError(error.AsCString());
947      result.SetStatus(eReturnStatusFailed);
948      return false;
949    }
950
951    return result.Succeeded();
952  }
953};
954
955// CommandObjectSettingsAppend
956
957class CommandObjectSettingsAppend : public CommandObjectRaw {
958public:
959  CommandObjectSettingsAppend(CommandInterpreter &interpreter)
960      : CommandObjectRaw(interpreter, "settings append",
961                         "Append one or more values to a debugger array, "
962                         "dictionary, or string setting.") {
963    CommandArgumentEntry arg1;
964    CommandArgumentEntry arg2;
965    CommandArgumentData var_name_arg;
966    CommandArgumentData value_arg;
967
968    // Define the first (and only) variant of this arg.
969    var_name_arg.arg_type = eArgTypeSettingVariableName;
970    var_name_arg.arg_repetition = eArgRepeatPlain;
971
972    // There is only one variant this argument could be; put it into the
973    // argument entry.
974    arg1.push_back(var_name_arg);
975
976    // Define the first (and only) variant of this arg.
977    value_arg.arg_type = eArgTypeValue;
978    value_arg.arg_repetition = eArgRepeatPlain;
979
980    // There is only one variant this argument could be; put it into the
981    // argument entry.
982    arg2.push_back(value_arg);
983
984    // Push the data for the first argument into the m_arguments vector.
985    m_arguments.push_back(arg1);
986    m_arguments.push_back(arg2);
987  }
988
989  ~CommandObjectSettingsAppend() override = default;
990
991  // Overrides base class's behavior where WantsCompletion =
992  // !WantsRawCommandString.
993  bool WantsCompletion() override { return true; }
994
995  void
996  HandleArgumentCompletion(CompletionRequest &request,
997                           OptionElementVector &opt_element_vector) override {
998    // Attempting to complete variable name
999    if (request.GetCursorIndex() < 2)
1000      CommandCompletions::InvokeCommonCompletionCallbacks(
1001          GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
1002          request, nullptr);
1003  }
1004
1005protected:
1006  bool DoExecute(llvm::StringRef command,
1007                 CommandReturnObject &result) override {
1008    result.SetStatus(eReturnStatusSuccessFinishNoResult);
1009    Args cmd_args(command);
1010    const size_t argc = cmd_args.GetArgumentCount();
1011
1012    if (argc < 2) {
1013      result.AppendError("'settings append' takes more arguments");
1014      result.SetStatus(eReturnStatusFailed);
1015      return false;
1016    }
1017
1018    const char *var_name = cmd_args.GetArgumentAtIndex(0);
1019    if ((var_name == nullptr) || (var_name[0] == '\0')) {
1020      result.AppendError("'settings append' command requires a valid variable "
1021                         "name; No value supplied");
1022      result.SetStatus(eReturnStatusFailed);
1023      return false;
1024    }
1025
1026    // Do not perform cmd_args.Shift() since StringRef is manipulating the raw
1027    // character string later on.
1028
1029    // Split the raw command into var_name and value pair.
1030    llvm::StringRef var_value(command);
1031    var_value = var_value.split(var_name).second.trim();
1032
1033    Status error(GetDebugger().SetPropertyValue(
1034        &m_exe_ctx, eVarSetOperationAppend, var_name, var_value));
1035    if (error.Fail()) {
1036      result.AppendError(error.AsCString());
1037      result.SetStatus(eReturnStatusFailed);
1038      return false;
1039    }
1040
1041    return result.Succeeded();
1042  }
1043};
1044
1045// CommandObjectSettingsClear
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.", nullptr) {
1053    CommandArgumentEntry arg;
1054    CommandArgumentData var_name_arg;
1055
1056    // Define the first (and only) variant of this arg.
1057    var_name_arg.arg_type = eArgTypeSettingVariableName;
1058    var_name_arg.arg_repetition = eArgRepeatPlain;
1059
1060    // There is only one variant this argument could be; put it into the
1061    // argument entry.
1062    arg.push_back(var_name_arg);
1063
1064    // Push the data for the first argument into the m_arguments vector.
1065    m_arguments.push_back(arg);
1066  }
1067
1068  ~CommandObjectSettingsClear() override = default;
1069
1070  void
1071  HandleArgumentCompletion(CompletionRequest &request,
1072                           OptionElementVector &opt_element_vector) override {
1073    // Attempting to complete variable name
1074    if (request.GetCursorIndex() < 2)
1075      CommandCompletions::InvokeCommonCompletionCallbacks(
1076          GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
1077          request, nullptr);
1078  }
1079
1080protected:
1081  bool DoExecute(Args &command, CommandReturnObject &result) override {
1082    result.SetStatus(eReturnStatusSuccessFinishNoResult);
1083    const size_t argc = command.GetArgumentCount();
1084
1085    if (argc != 1) {
1086      result.AppendError("'settings clear' takes exactly one argument");
1087      result.SetStatus(eReturnStatusFailed);
1088      return false;
1089    }
1090
1091    const char *var_name = command.GetArgumentAtIndex(0);
1092    if ((var_name == nullptr) || (var_name[0] == '\0')) {
1093      result.AppendError("'settings clear' command requires a valid variable "
1094                         "name; No value supplied");
1095      result.SetStatus(eReturnStatusFailed);
1096      return false;
1097    }
1098
1099    Status error(GetDebugger().SetPropertyValue(
1100        &m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef()));
1101    if (error.Fail()) {
1102      result.AppendError(error.AsCString());
1103      result.SetStatus(eReturnStatusFailed);
1104      return false;
1105    }
1106
1107    return result.Succeeded();
1108  }
1109};
1110
1111// CommandObjectMultiwordSettings
1112
1113CommandObjectMultiwordSettings::CommandObjectMultiwordSettings(
1114    CommandInterpreter &interpreter)
1115    : CommandObjectMultiword(interpreter, "settings",
1116                             "Commands for managing LLDB settings.",
1117                             "settings <subcommand> [<command-options>]") {
1118  LoadSubCommand("set",
1119                 CommandObjectSP(new CommandObjectSettingsSet(interpreter)));
1120  LoadSubCommand("show",
1121                 CommandObjectSP(new CommandObjectSettingsShow(interpreter)));
1122  LoadSubCommand("list",
1123                 CommandObjectSP(new CommandObjectSettingsList(interpreter)));
1124  LoadSubCommand("remove",
1125                 CommandObjectSP(new CommandObjectSettingsRemove(interpreter)));
1126  LoadSubCommand("replace", CommandObjectSP(
1127                                new CommandObjectSettingsReplace(interpreter)));
1128  LoadSubCommand(
1129      "insert-before",
1130      CommandObjectSP(new CommandObjectSettingsInsertBefore(interpreter)));
1131  LoadSubCommand(
1132      "insert-after",
1133      CommandObjectSP(new CommandObjectSettingsInsertAfter(interpreter)));
1134  LoadSubCommand("append",
1135                 CommandObjectSP(new CommandObjectSettingsAppend(interpreter)));
1136  LoadSubCommand("clear",
1137                 CommandObjectSP(new CommandObjectSettingsClear(interpreter)));
1138  LoadSubCommand("write",
1139                 CommandObjectSP(new CommandObjectSettingsWrite(interpreter)));
1140  LoadSubCommand("read",
1141                 CommandObjectSP(new CommandObjectSettingsRead(interpreter)));
1142}
1143
1144CommandObjectMultiwordSettings::~CommandObjectMultiwordSettings() = default;
1145