1 //===-- OptionValueDictionary.cpp -------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Interpreter/OptionValueDictionary.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "lldb/DataFormatters/FormatManager.h"
13 #include "lldb/Interpreter/OptionValueString.h"
14 #include "lldb/Utility/Args.h"
15 #include "lldb/Utility/State.h"
18 using namespace lldb_private;
20 void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
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));
28 strm.Printf("(%s)", GetTypeAsCString());
30 if (dump_mask & eDumpOptionValue) {
31 const bool one_line = dump_mask & eDumpOptionCommand;
32 if (dump_mask & eDumpOptionType)
33 strm.PutCString(" =");
35 collection::iterator pos, end = m_values.end();
40 for (pos = m_values.begin(); pos != end; ++pos) {
41 OptionValue *option_value = pos->second.get();
48 strm.Indent(pos->first.GetCString());
50 const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
56 case eTypeFileSpecList:
59 option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
71 // No need to show the type for dictionaries of simple items
73 option_value->DumpValue(exe_ctx, strm,
74 (dump_mask & (~eDumpOptionType)) |
84 size_t OptionValueDictionary::GetArgs(Args &args) const {
86 collection::const_iterator pos, end = m_values.end();
87 for (pos = m_values.begin(); pos != end; ++pos) {
89 strm.Printf("%s=", pos->first.GetCString());
90 pos->second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);
91 args.AppendArgument(strm.GetString());
93 return args.GetArgumentCount();
96 Status OptionValueDictionary::SetArgs(const Args &args,
97 VarSetOperationType op) {
99 const size_t argc = args.GetArgumentCount();
101 case eVarSetOperationClear:
105 case eVarSetOperationAppend:
106 case eVarSetOperationReplace:
107 case eVarSetOperationAssign:
109 error.SetErrorString(
110 "assign operation takes one or more key=value arguments");
113 for (const auto &entry : args) {
114 if (entry.ref.empty()) {
115 error.SetErrorString("empty argument");
118 if (!entry.ref.contains('=')) {
119 error.SetErrorString(
120 "assign operation takes one or more key=value arguments");
124 llvm::StringRef key, value;
125 std::tie(key, value) = entry.ref.split('=');
126 bool key_valid = false;
128 error.SetErrorString("empty dictionary key");
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)) {
142 key = key.substr(1, key.size() - 2);
146 // square brackets, no quotes
151 // No square brackets or quotes
155 error.SetErrorStringWithFormat(
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>\"]",
163 lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
164 value.str().c_str(), m_type_mask, error));
168 m_value_was_set = true;
169 SetValueForKey(ConstString(key), value_sp, true);
171 error.SetErrorString("dictionaries that can contain multiple types "
172 "must subclass OptionValueArray");
177 case eVarSetOperationRemove:
179 for (size_t i = 0; i < argc; ++i) {
180 ConstString key(args.GetArgumentAtIndex(i));
181 if (!DeleteValueForKey(key)) {
182 error.SetErrorStringWithFormat(
183 "no value found named '%s', aborting remove operation",
189 error.SetErrorString("remove operation takes one or more key arguments");
193 case eVarSetOperationInsertBefore:
194 case eVarSetOperationInsertAfter:
195 case eVarSetOperationInvalid:
196 error = OptionValue::SetValueFromString(llvm::StringRef(), op);
202 Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,
203 VarSetOperationType op) {
204 Args args(value.str());
205 Status error = SetArgs(args, op);
207 NotifyValueChanged();
212 OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
213 llvm::StringRef name, bool will_modify,
214 Status &error) const {
215 lldb::OptionValueSP value_sp;
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());
229 assert(!temp.empty());
231 llvm::StringRef key, quote_char;
233 if (temp[0] == '\"' || temp[0] == '\'') {
234 quote_char = temp.take_front();
235 temp = temp.drop_front();
238 llvm::StringRef sub_name;
239 std::tie(key, sub_name) = temp.split(']');
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());
249 value_sp = GetValueForKey(ConstString(key));
251 error.SetErrorStringWithFormat(
252 "dictionary does not contain a value for the key name '%s'",
257 if (sub_name.empty())
259 return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);
262 Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
263 VarSetOperationType op,
264 llvm::StringRef name,
265 llvm::StringRef value) {
267 const bool will_modify = true;
268 lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
270 error = value_sp->SetValueFromString(value, op);
272 if (error.AsCString() == nullptr)
273 error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
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;
287 bool OptionValueDictionary::SetValueForKey(ConstString key,
288 const lldb::OptionValueSP &value_sp,
290 // Make sure the value_sp object is allowed to contain values of the type
292 if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {
294 collection::const_iterator pos = m_values.find(key);
295 if (pos != m_values.end())
298 m_values[key] = value_sp;
304 bool OptionValueDictionary::DeleteValueForKey(ConstString key) {
305 collection::iterator pos = m_values.find(key);
306 if (pos != m_values.end()) {
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) {
320 strm.Printf("%s=", pos->first.GetCString());
321 copied_dict->SetValueForKey(pos->first, pos->second->DeepCopy(), true);
323 return copied_value_sp;