LLDB  mainline
OptionValueDictionary.cpp
Go to the documentation of this file.
1 //===-- OptionValueDictionary.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 
10 
11 #include "llvm/ADT/StringRef.h"
14 #include "lldb/Utility/Args.h"
15 #include "lldb/Utility/State.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
21  Stream &strm, uint32_t dump_mask) {
22  const Type dict_type = ConvertTypeMaskToType(m_type_mask);
23  if (dump_mask & eDumpOptionType) {
24  if (m_type_mask != eTypeInvalid)
25  strm.Printf("(%s of %ss)", GetTypeAsCString(),
26  GetBuiltinTypeAsCString(dict_type));
27  else
28  strm.Printf("(%s)", GetTypeAsCString());
29  }
30  if (dump_mask & eDumpOptionValue) {
31  const bool one_line = dump_mask & eDumpOptionCommand;
32  if (dump_mask & eDumpOptionType)
33  strm.PutCString(" =");
34 
35  collection::iterator pos, end = m_values.end();
36 
37  if (!one_line)
38  strm.IndentMore();
39 
40  for (pos = m_values.begin(); pos != end; ++pos) {
41  OptionValue *option_value = pos->second.get();
42 
43  if (one_line)
44  strm << ' ';
45  else
46  strm.EOL();
47 
48  strm.Indent(pos->first.GetCString());
49 
50  const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
51  switch (dict_type) {
52  default:
53  case eTypeArray:
54  case eTypeDictionary:
55  case eTypeProperties:
56  case eTypeFileSpecList:
57  case eTypePathMap:
58  strm.PutChar(' ');
59  option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
60  break;
61 
62  case eTypeBoolean:
63  case eTypeChar:
64  case eTypeEnum:
65  case eTypeFileSpec:
66  case eTypeFormat:
67  case eTypeSInt64:
68  case eTypeString:
69  case eTypeUInt64:
70  case eTypeUUID:
71  // No need to show the type for dictionaries of simple items
72  strm.PutCString("=");
73  option_value->DumpValue(exe_ctx, strm,
74  (dump_mask & (~eDumpOptionType)) |
75  extra_dump_options);
76  break;
77  }
78  }
79  if (!one_line)
80  strm.IndentLess();
81  }
82 }
83 
84 size_t OptionValueDictionary::GetArgs(Args &args) const {
85  args.Clear();
86  collection::const_iterator pos, end = m_values.end();
87  for (pos = m_values.begin(); pos != end; ++pos) {
88  StreamString strm;
89  strm.Printf("%s=", pos->first.GetCString());
90  pos->second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);
91  args.AppendArgument(strm.GetString());
92  }
93  return args.GetArgumentCount();
94 }
95 
96 Status OptionValueDictionary::SetArgs(const Args &args,
98  Status error;
99  const size_t argc = args.GetArgumentCount();
100  switch (op) {
102  Clear();
103  break;
104 
108  if (argc == 0) {
109  error.SetErrorString(
110  "assign operation takes one or more key=value arguments");
111  return error;
112  }
113  for (const auto &entry : args) {
114  if (entry.ref.empty()) {
115  error.SetErrorString("empty argument");
116  return error;
117  }
118  if (!entry.ref.contains('=')) {
119  error.SetErrorString(
120  "assign operation takes one or more key=value arguments");
121  return error;
122  }
123 
124  llvm::StringRef key, value;
125  std::tie(key, value) = entry.ref.split('=');
126  bool key_valid = false;
127  if (key.empty()) {
128  error.SetErrorString("empty dictionary key");
129  return error;
130  }
131 
132  if (key.front() == '[') {
133  // Key name starts with '[', so the key value must be in single or
134  // double quotes like: ['<key>'] ["<key>"]
135  if ((key.size() > 2) && (key.back() == ']')) {
136  // Strip leading '[' and trailing ']'
137  key = key.substr(1, key.size() - 2);
138  const char quote_char = key.front();
139  if ((quote_char == '\'') || (quote_char == '"')) {
140  if ((key.size() > 2) && (key.back() == quote_char)) {
141  // Strip the quotes
142  key = key.substr(1, key.size() - 2);
143  key_valid = true;
144  }
145  } else {
146  // square brackets, no quotes
147  key_valid = true;
148  }
149  }
150  } else {
151  // No square brackets or quotes
152  key_valid = true;
153  }
154  if (!key_valid) {
156  "invalid key \"%s\", the key must be a bare string or "
157  "surrounded by brackets with optional quotes: [<key>] or "
158  "['<key>'] or [\"<key>\"]",
159  key.str().c_str());
160  return error;
161  }
162 
163  lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
164  value.str().c_str(), m_type_mask, error));
165  if (value_sp) {
166  if (error.Fail())
167  return error;
168  m_value_was_set = true;
169  SetValueForKey(ConstString(key), value_sp, true);
170  } else {
171  error.SetErrorString("dictionaries that can contain multiple types "
172  "must subclass OptionValueArray");
173  }
174  }
175  break;
176 
178  if (argc > 0) {
179  for (size_t i = 0; i < argc; ++i) {
180  ConstString key(args.GetArgumentAtIndex(i));
181  if (!DeleteValueForKey(key)) {
183  "no value found named '%s', aborting remove operation",
184  key.GetCString());
185  break;
186  }
187  }
188  } else {
189  error.SetErrorString("remove operation takes one or more key arguments");
190  }
191  break;
192 
196  error = OptionValue::SetValueFromString(llvm::StringRef(), op);
197  break;
198  }
199  return error;
200 }
201 
202 Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,
203  VarSetOperationType op) {
204  Args args(value.str());
205  Status error = SetArgs(args, op);
206  if (error.Success())
207  NotifyValueChanged();
208  return error;
209 }
210 
211 lldb::OptionValueSP
212 OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
213  llvm::StringRef name, bool will_modify,
214  Status &error) const {
215  lldb::OptionValueSP value_sp;
216  if (name.empty())
217  return nullptr;
218 
219  llvm::StringRef left, temp;
220  std::tie(left, temp) = name.split('[');
221  if (left.size() == name.size()) {
222  error.SetErrorStringWithFormat("invalid value path '%s', %s values only "
223  "support '[<key>]' subvalues where <key> "
224  "a string value optionally delimited by "
225  "single or double quotes",
226  name.str().c_str(), GetTypeAsCString());
227  return nullptr;
228  }
229  assert(!temp.empty());
230 
231  llvm::StringRef key, quote_char;
232 
233  if (temp[0] == '\"' || temp[0] == '\'') {
234  quote_char = temp.take_front();
235  temp = temp.drop_front();
236  }
237 
238  llvm::StringRef sub_name;
239  std::tie(key, sub_name) = temp.split(']');
240 
241  if (!key.consume_back(quote_char) || key.empty()) {
242  error.SetErrorStringWithFormat("invalid value path '%s', "
243  "key names must be formatted as ['<key>'] where <key> "
244  "is a string that doesn't contain quotes and the quote"
245  " char is optional", name.str().c_str());
246  return nullptr;
247  }
248 
249  value_sp = GetValueForKey(ConstString(key));
250  if (!value_sp) {
252  "dictionary does not contain a value for the key name '%s'",
253  key.str().c_str());
254  return nullptr;
255  }
256 
257  if (sub_name.empty())
258  return value_sp;
259  return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);
260 }
261 
262 Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
264  llvm::StringRef name,
265  llvm::StringRef value) {
266  Status error;
267  const bool will_modify = true;
268  lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
269  if (value_sp)
270  error = value_sp->SetValueFromString(value, op);
271  else {
272  if (error.AsCString() == nullptr)
273  error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
274  }
275  return error;
276 }
277 
278 lldb::OptionValueSP
279 OptionValueDictionary::GetValueForKey(ConstString key) const {
280  lldb::OptionValueSP value_sp;
281  collection::const_iterator pos = m_values.find(key);
282  if (pos != m_values.end())
283  value_sp = pos->second;
284  return value_sp;
285 }
286 
287 bool OptionValueDictionary::SetValueForKey(ConstString key,
288  const lldb::OptionValueSP &value_sp,
289  bool can_replace) {
290  // Make sure the value_sp object is allowed to contain values of the type
291  // passed in...
292  if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {
293  if (!can_replace) {
294  collection::const_iterator pos = m_values.find(key);
295  if (pos != m_values.end())
296  return false;
297  }
298  m_values[key] = value_sp;
299  return true;
300  }
301  return false;
302 }
303 
304 bool OptionValueDictionary::DeleteValueForKey(ConstString key) {
305  collection::iterator pos = m_values.find(key);
306  if (pos != m_values.end()) {
307  m_values.erase(pos);
308  return true;
309  }
310  return false;
311 }
312 
313 lldb::OptionValueSP OptionValueDictionary::DeepCopy() const {
314  OptionValueDictionary *copied_dict =
315  new OptionValueDictionary(m_type_mask, m_raw_value_dump);
316  lldb::OptionValueSP copied_value_sp(copied_dict);
317  collection::const_iterator pos, end = m_values.end();
318  for (pos = m_values.begin(); pos != end; ++pos) {
319  StreamString strm;
320  strm.Printf("%s=", pos->first.GetCString());
321  copied_dict->SetValueForKey(pos->first, pos->second->DeepCopy(), true);
322  }
323  return copied_value_sp;
324 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
A command line argument class.
Definition: Args.h:32
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.cpp:254
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
VarSetOperationType
Settable state variable types.
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:127
llvm::StringRef GetString() const
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:241
void IndentLess(int amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:221
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
size_t PutChar(char ch)
Definition: Stream.cpp:103
virtual void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)=0
A uniqued constant string class.
Definition: ConstString.h:38
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
Definition: SBAddress.h:15
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
Definition: Args.cpp:321
size_t Indent(const char *s=nullptr)
Indent the current line in the stream.
Definition: Stream.cpp:131
bool SetValueForKey(ConstString key, const lldb::OptionValueSP &value_sp, bool can_replace=true)
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:255
void IndentMore(int amount=2)
Increment the current indentation level.
Definition: Stream.cpp:218
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:130
static bool DumpValue(Stream &s, const SymbolContext *sc, const ExecutionContext *exe_ctx, const FormatEntity::Entry &entry, ValueObject *valobj)
An error handling class.
Definition: Status.h:44