Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Interpreter/OptionValueDictionary.cpp
39587 views
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
9
#include "lldb/Interpreter/OptionValueDictionary.h"
10
11
#include "lldb/DataFormatters/FormatManager.h"
12
#include "lldb/Interpreter/OptionValueEnumeration.h"
13
#include "lldb/Interpreter/OptionValueString.h"
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
21
void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
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
if (!one_line)
37
strm.IndentMore();
38
39
// m_values is not guaranteed to be sorted alphabetically, so for
40
// consistentcy we will sort them here before dumping
41
std::map<llvm::StringRef, OptionValue *> sorted_values;
42
for (const auto &value : m_values) {
43
sorted_values[value.first()] = value.second.get();
44
}
45
for (const auto &value : sorted_values) {
46
OptionValue *option_value = value.second;
47
48
if (one_line)
49
strm << ' ';
50
else
51
strm.EOL();
52
53
strm.Indent(value.first);
54
55
const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
56
switch (dict_type) {
57
default:
58
case eTypeArray:
59
case eTypeDictionary:
60
case eTypeProperties:
61
case eTypeFileSpecList:
62
case eTypePathMap:
63
strm.PutChar(' ');
64
option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
65
break;
66
67
case eTypeBoolean:
68
case eTypeChar:
69
case eTypeEnum:
70
case eTypeFileLineColumn:
71
case eTypeFileSpec:
72
case eTypeFormat:
73
case eTypeSInt64:
74
case eTypeString:
75
case eTypeUInt64:
76
case eTypeUUID:
77
// No need to show the type for dictionaries of simple items
78
strm.PutCString("=");
79
option_value->DumpValue(exe_ctx, strm,
80
(dump_mask & (~eDumpOptionType)) |
81
extra_dump_options);
82
break;
83
}
84
}
85
if (!one_line)
86
strm.IndentLess();
87
}
88
}
89
90
llvm::json::Value
91
OptionValueDictionary::ToJSON(const ExecutionContext *exe_ctx) {
92
llvm::json::Object dict;
93
for (const auto &value : m_values) {
94
dict.try_emplace(value.first(), value.second->ToJSON(exe_ctx));
95
}
96
return dict;
97
}
98
99
size_t OptionValueDictionary::GetArgs(Args &args) const {
100
args.Clear();
101
for (const auto &value : m_values) {
102
StreamString strm;
103
strm.Printf("%s=", value.first().data());
104
value.second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);
105
args.AppendArgument(strm.GetString());
106
}
107
return args.GetArgumentCount();
108
}
109
110
Status OptionValueDictionary::SetArgs(const Args &args,
111
VarSetOperationType op) {
112
Status error;
113
const size_t argc = args.GetArgumentCount();
114
switch (op) {
115
case eVarSetOperationClear:
116
Clear();
117
break;
118
119
case eVarSetOperationAppend:
120
case eVarSetOperationReplace:
121
case eVarSetOperationAssign:
122
if (argc == 0) {
123
error.SetErrorString(
124
"assign operation takes one or more key=value arguments");
125
return error;
126
}
127
for (const auto &entry : args) {
128
if (entry.ref().empty()) {
129
error.SetErrorString("empty argument");
130
return error;
131
}
132
if (!entry.ref().contains('=')) {
133
error.SetErrorString(
134
"assign operation takes one or more key=value arguments");
135
return error;
136
}
137
138
llvm::StringRef key, value;
139
std::tie(key, value) = entry.ref().split('=');
140
bool key_valid = false;
141
if (key.empty()) {
142
error.SetErrorString("empty dictionary key");
143
return error;
144
}
145
146
if (key.front() == '[') {
147
// Key name starts with '[', so the key value must be in single or
148
// double quotes like: ['<key>'] ["<key>"]
149
if ((key.size() > 2) && (key.back() == ']')) {
150
// Strip leading '[' and trailing ']'
151
key = key.substr(1, key.size() - 2);
152
const char quote_char = key.front();
153
if ((quote_char == '\'') || (quote_char == '"')) {
154
if ((key.size() > 2) && (key.back() == quote_char)) {
155
// Strip the quotes
156
key = key.substr(1, key.size() - 2);
157
key_valid = true;
158
}
159
} else {
160
// square brackets, no quotes
161
key_valid = true;
162
}
163
}
164
} else {
165
// No square brackets or quotes
166
key_valid = true;
167
}
168
if (!key_valid) {
169
error.SetErrorStringWithFormat(
170
"invalid key \"%s\", the key must be a bare string or "
171
"surrounded by brackets with optional quotes: [<key>] or "
172
"['<key>'] or [\"<key>\"]",
173
key.str().c_str());
174
return error;
175
}
176
177
if (m_type_mask == 1u << eTypeEnum) {
178
auto enum_value =
179
std::make_shared<OptionValueEnumeration>(m_enum_values, 0);
180
error = enum_value->SetValueFromString(value);
181
if (error.Fail())
182
return error;
183
m_value_was_set = true;
184
SetValueForKey(key, enum_value, true);
185
} else {
186
lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
187
value.str().c_str(), m_type_mask, error));
188
if (value_sp) {
189
if (error.Fail())
190
return error;
191
m_value_was_set = true;
192
SetValueForKey(key, value_sp, true);
193
} else {
194
error.SetErrorString("dictionaries that can contain multiple types "
195
"must subclass OptionValueArray");
196
}
197
}
198
}
199
break;
200
201
case eVarSetOperationRemove:
202
if (argc > 0) {
203
for (size_t i = 0; i < argc; ++i) {
204
llvm::StringRef key(args.GetArgumentAtIndex(i));
205
if (!DeleteValueForKey(key)) {
206
error.SetErrorStringWithFormat(
207
"no value found named '%s', aborting remove operation",
208
key.data());
209
break;
210
}
211
}
212
} else {
213
error.SetErrorString("remove operation takes one or more key arguments");
214
}
215
break;
216
217
case eVarSetOperationInsertBefore:
218
case eVarSetOperationInsertAfter:
219
case eVarSetOperationInvalid:
220
error = OptionValue::SetValueFromString(llvm::StringRef(), op);
221
break;
222
}
223
return error;
224
}
225
226
Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,
227
VarSetOperationType op) {
228
Args args(value.str());
229
Status error = SetArgs(args, op);
230
if (error.Success())
231
NotifyValueChanged();
232
return error;
233
}
234
235
lldb::OptionValueSP
236
OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
237
llvm::StringRef name, Status &error) const {
238
lldb::OptionValueSP value_sp;
239
if (name.empty())
240
return nullptr;
241
242
llvm::StringRef left, temp;
243
std::tie(left, temp) = name.split('[');
244
if (left.size() == name.size()) {
245
error.SetErrorStringWithFormat("invalid value path '%s', %s values only "
246
"support '[<key>]' subvalues where <key> "
247
"a string value optionally delimited by "
248
"single or double quotes",
249
name.str().c_str(), GetTypeAsCString());
250
return nullptr;
251
}
252
assert(!temp.empty());
253
254
llvm::StringRef key, quote_char;
255
256
if (temp[0] == '\"' || temp[0] == '\'') {
257
quote_char = temp.take_front();
258
temp = temp.drop_front();
259
}
260
261
llvm::StringRef sub_name;
262
std::tie(key, sub_name) = temp.split(']');
263
264
if (!key.consume_back(quote_char) || key.empty()) {
265
error.SetErrorStringWithFormat("invalid value path '%s', "
266
"key names must be formatted as ['<key>'] where <key> "
267
"is a string that doesn't contain quotes and the quote"
268
" char is optional", name.str().c_str());
269
return nullptr;
270
}
271
272
value_sp = GetValueForKey(key);
273
if (!value_sp) {
274
error.SetErrorStringWithFormat(
275
"dictionary does not contain a value for the key name '%s'",
276
key.str().c_str());
277
return nullptr;
278
}
279
280
if (sub_name.empty())
281
return value_sp;
282
return value_sp->GetSubValue(exe_ctx, sub_name, error);
283
}
284
285
Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
286
VarSetOperationType op,
287
llvm::StringRef name,
288
llvm::StringRef value) {
289
Status error;
290
lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, error));
291
if (value_sp)
292
error = value_sp->SetValueFromString(value, op);
293
else {
294
if (error.AsCString() == nullptr)
295
error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
296
}
297
return error;
298
}
299
300
lldb::OptionValueSP
301
OptionValueDictionary::GetValueForKey(llvm::StringRef key) const {
302
lldb::OptionValueSP value_sp;
303
auto pos = m_values.find(key);
304
if (pos != m_values.end())
305
value_sp = pos->second;
306
return value_sp;
307
}
308
309
bool OptionValueDictionary::SetValueForKey(llvm::StringRef key,
310
const lldb::OptionValueSP &value_sp,
311
bool can_replace) {
312
// Make sure the value_sp object is allowed to contain values of the type
313
// passed in...
314
if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {
315
if (!can_replace) {
316
auto pos = m_values.find(key);
317
if (pos != m_values.end())
318
return false;
319
}
320
m_values[key] = value_sp;
321
return true;
322
}
323
return false;
324
}
325
326
bool OptionValueDictionary::DeleteValueForKey(llvm::StringRef key) {
327
auto pos = m_values.find(key);
328
if (pos != m_values.end()) {
329
m_values.erase(pos);
330
return true;
331
}
332
return false;
333
}
334
335
OptionValueSP
336
OptionValueDictionary::DeepCopy(const OptionValueSP &new_parent) const {
337
auto copy_sp = OptionValue::DeepCopy(new_parent);
338
// copy_sp->GetAsDictionary cannot be used here as it doesn't work for derived
339
// types that override GetType returning a different value.
340
auto *dict_value_ptr = static_cast<OptionValueDictionary *>(copy_sp.get());
341
lldbassert(dict_value_ptr);
342
343
for (auto &value : dict_value_ptr->m_values)
344
value.second = value.second->DeepCopy(copy_sp);
345
346
return copy_sp;
347
}
348
349