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