180814287SRaphael Isemann //===-- OptionValueDictionary.cpp -----------------------------------------===//
267cc0636SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
667cc0636SGreg Clayton //
767cc0636SGreg Clayton //===----------------------------------------------------------------------===//
867cc0636SGreg Clayton
967cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueDictionary.h"
1067cc0636SGreg Clayton
115548cb50SEnrico Granata #include "lldb/DataFormatters/FormatManager.h"
12*3c867898SAlvin Wong #include "lldb/Interpreter/OptionValueEnumeration.h"
1367cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueString.h"
14145d95c9SPavel Labath #include "lldb/Utility/Args.h"
15d821c997SPavel Labath #include "lldb/Utility/State.h"
16*3c867898SAlvin Wong #include "llvm/ADT/StringRef.h"
1767cc0636SGreg Clayton
1867cc0636SGreg Clayton using namespace lldb;
1967cc0636SGreg Clayton using namespace lldb_private;
2067cc0636SGreg Clayton
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)21b9c1b51eSKate Stone void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
22b9c1b51eSKate Stone Stream &strm, uint32_t dump_mask) {
2367cc0636SGreg Clayton const Type dict_type = ConvertTypeMaskToType(m_type_mask);
24b9c1b51eSKate Stone if (dump_mask & eDumpOptionType) {
2567cc0636SGreg Clayton if (m_type_mask != eTypeInvalid)
26b9c1b51eSKate Stone strm.Printf("(%s of %ss)", GetTypeAsCString(),
27b9c1b51eSKate Stone GetBuiltinTypeAsCString(dict_type));
2867cc0636SGreg Clayton else
2967cc0636SGreg Clayton strm.Printf("(%s)", GetTypeAsCString());
3067cc0636SGreg Clayton }
31b9c1b51eSKate Stone if (dump_mask & eDumpOptionValue) {
32b76e25a2SJonas Devlieghere const bool one_line = dump_mask & eDumpOptionCommand;
3367cc0636SGreg Clayton if (dump_mask & eDumpOptionType)
3467cc0636SGreg Clayton strm.PutCString(" =");
3567cc0636SGreg Clayton
3667cc0636SGreg Clayton collection::iterator pos, end = m_values.end();
3767cc0636SGreg Clayton
38b76e25a2SJonas Devlieghere if (!one_line)
3967cc0636SGreg Clayton strm.IndentMore();
4067cc0636SGreg Clayton
41b9c1b51eSKate Stone for (pos = m_values.begin(); pos != end; ++pos) {
4267cc0636SGreg Clayton OptionValue *option_value = pos->second.get();
43b76e25a2SJonas Devlieghere
44b76e25a2SJonas Devlieghere if (one_line)
45b76e25a2SJonas Devlieghere strm << ' ';
46b76e25a2SJonas Devlieghere else
4767cc0636SGreg Clayton strm.EOL();
48b76e25a2SJonas Devlieghere
499dfd4e26SRaphael Isemann strm.Indent(pos->first.GetStringRef());
5067cc0636SGreg Clayton
5167cc0636SGreg Clayton const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
52b9c1b51eSKate Stone switch (dict_type) {
5367cc0636SGreg Clayton default:
5467cc0636SGreg Clayton case eTypeArray:
5567cc0636SGreg Clayton case eTypeDictionary:
5667cc0636SGreg Clayton case eTypeProperties:
5767cc0636SGreg Clayton case eTypeFileSpecList:
5867cc0636SGreg Clayton case eTypePathMap:
5967cc0636SGreg Clayton strm.PutChar(' ');
6067cc0636SGreg Clayton option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
6167cc0636SGreg Clayton break;
6267cc0636SGreg Clayton
6367cc0636SGreg Clayton case eTypeBoolean:
643e7442b6SZachary Turner case eTypeChar:
6567cc0636SGreg Clayton case eTypeEnum:
66bc0a9a17SJim Ingham case eTypeFileLineColumn:
6767cc0636SGreg Clayton case eTypeFileSpec:
6867cc0636SGreg Clayton case eTypeFormat:
6967cc0636SGreg Clayton case eTypeSInt64:
7067cc0636SGreg Clayton case eTypeString:
7167cc0636SGreg Clayton case eTypeUInt64:
7267cc0636SGreg Clayton case eTypeUUID:
7367cc0636SGreg Clayton // No need to show the type for dictionaries of simple items
7467cc0636SGreg Clayton strm.PutCString("=");
75b9c1b51eSKate Stone option_value->DumpValue(exe_ctx, strm,
76b9c1b51eSKate Stone (dump_mask & (~eDumpOptionType)) |
77b9c1b51eSKate Stone extra_dump_options);
7867cc0636SGreg Clayton break;
7967cc0636SGreg Clayton }
8067cc0636SGreg Clayton }
81b76e25a2SJonas Devlieghere if (!one_line)
8267cc0636SGreg Clayton strm.IndentLess();
8367cc0636SGreg Clayton }
8467cc0636SGreg Clayton }
8567cc0636SGreg Clayton
GetArgs(Args & args) const86b9c1b51eSKate Stone size_t OptionValueDictionary::GetArgs(Args &args) const {
8767cc0636SGreg Clayton args.Clear();
8867cc0636SGreg Clayton collection::const_iterator pos, end = m_values.end();
89b9c1b51eSKate Stone for (pos = m_values.begin(); pos != end; ++pos) {
9067cc0636SGreg Clayton StreamString strm;
9167cc0636SGreg Clayton strm.Printf("%s=", pos->first.GetCString());
92d78c9576SEd Maste pos->second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);
93ecbb0bb1SZachary Turner args.AppendArgument(strm.GetString());
9467cc0636SGreg Clayton }
9567cc0636SGreg Clayton return args.GetArgumentCount();
9667cc0636SGreg Clayton }
9767cc0636SGreg Clayton
SetArgs(const Args & args,VarSetOperationType op)9897206d57SZachary Turner Status OptionValueDictionary::SetArgs(const Args &args,
9997206d57SZachary Turner VarSetOperationType op) {
10097206d57SZachary Turner Status error;
10167cc0636SGreg Clayton const size_t argc = args.GetArgumentCount();
102b9c1b51eSKate Stone switch (op) {
10367cc0636SGreg Clayton case eVarSetOperationClear:
10467cc0636SGreg Clayton Clear();
10567cc0636SGreg Clayton break;
10667cc0636SGreg Clayton
10767cc0636SGreg Clayton case eVarSetOperationAppend:
10867cc0636SGreg Clayton case eVarSetOperationReplace:
10967cc0636SGreg Clayton case eVarSetOperationAssign:
110d6a24757SZachary Turner if (argc == 0) {
111d6a24757SZachary Turner error.SetErrorString(
112d6a24757SZachary Turner "assign operation takes one or more key=value arguments");
113d6a24757SZachary Turner return error;
114d6a24757SZachary Turner }
115d6a24757SZachary Turner for (const auto &entry : args) {
1160d9a201eSRaphael Isemann if (entry.ref().empty()) {
117d6a24757SZachary Turner error.SetErrorString("empty argument");
118d6a24757SZachary Turner return error;
119d6a24757SZachary Turner }
1200d9a201eSRaphael Isemann if (!entry.ref().contains('=')) {
121b9c1b51eSKate Stone error.SetErrorString(
122b9c1b51eSKate Stone "assign operation takes one or more key=value arguments");
123a44c0e31SEnrico Granata return error;
124a44c0e31SEnrico Granata }
125a44c0e31SEnrico Granata
126d6a24757SZachary Turner llvm::StringRef key, value;
1270d9a201eSRaphael Isemann std::tie(key, value) = entry.ref().split('=');
12867cc0636SGreg Clayton bool key_valid = false;
129d6a24757SZachary Turner if (key.empty()) {
130d6a24757SZachary Turner error.SetErrorString("empty dictionary key");
131d6a24757SZachary Turner return error;
132d6a24757SZachary Turner }
133d6a24757SZachary Turner
134b9c1b51eSKate Stone if (key.front() == '[') {
135b9c1b51eSKate Stone // Key name starts with '[', so the key value must be in single or
13605097246SAdrian Prantl // double quotes like: ['<key>'] ["<key>"]
137b9c1b51eSKate Stone if ((key.size() > 2) && (key.back() == ']')) {
13867cc0636SGreg Clayton // Strip leading '[' and trailing ']'
13967cc0636SGreg Clayton key = key.substr(1, key.size() - 2);
14067cc0636SGreg Clayton const char quote_char = key.front();
141b9c1b51eSKate Stone if ((quote_char == '\'') || (quote_char == '"')) {
142b9c1b51eSKate Stone if ((key.size() > 2) && (key.back() == quote_char)) {
14367cc0636SGreg Clayton // Strip the quotes
14467cc0636SGreg Clayton key = key.substr(1, key.size() - 2);
14567cc0636SGreg Clayton key_valid = true;
14667cc0636SGreg Clayton }
147b9c1b51eSKate Stone } else {
14867cc0636SGreg Clayton // square brackets, no quotes
14967cc0636SGreg Clayton key_valid = true;
15067cc0636SGreg Clayton }
15167cc0636SGreg Clayton }
152b9c1b51eSKate Stone } else {
15367cc0636SGreg Clayton // No square brackets or quotes
15467cc0636SGreg Clayton key_valid = true;
15567cc0636SGreg Clayton }
156b9c1b51eSKate Stone if (!key_valid) {
157b9c1b51eSKate Stone error.SetErrorStringWithFormat(
158b9c1b51eSKate Stone "invalid key \"%s\", the key must be a bare string or "
159b9c1b51eSKate Stone "surrounded by brackets with optional quotes: [<key>] or "
160b9c1b51eSKate Stone "['<key>'] or [\"<key>\"]",
161d6a24757SZachary Turner key.str().c_str());
16267cc0636SGreg Clayton return error;
16367cc0636SGreg Clayton }
16467cc0636SGreg Clayton
165*3c867898SAlvin Wong if (m_type_mask == 1u << eTypeEnum) {
166*3c867898SAlvin Wong auto enum_value =
167*3c867898SAlvin Wong std::make_shared<OptionValueEnumeration>(m_enum_values, 0);
168*3c867898SAlvin Wong error = enum_value->SetValueFromString(value);
169*3c867898SAlvin Wong if (error.Fail())
170*3c867898SAlvin Wong return error;
171*3c867898SAlvin Wong m_value_was_set = true;
172*3c867898SAlvin Wong SetValueForKey(ConstString(key), enum_value, true);
173*3c867898SAlvin Wong } else {
174b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
175d6a24757SZachary Turner value.str().c_str(), m_type_mask, error));
176b9c1b51eSKate Stone if (value_sp) {
17767cc0636SGreg Clayton if (error.Fail())
17867cc0636SGreg Clayton return error;
17967cc0636SGreg Clayton m_value_was_set = true;
18067cc0636SGreg Clayton SetValueForKey(ConstString(key), value_sp, true);
181b9c1b51eSKate Stone } else {
182b9c1b51eSKate Stone error.SetErrorString("dictionaries that can contain multiple types "
183b9c1b51eSKate Stone "must subclass OptionValueArray");
18467cc0636SGreg Clayton }
18567cc0636SGreg Clayton }
186*3c867898SAlvin Wong }
18767cc0636SGreg Clayton break;
18867cc0636SGreg Clayton
18967cc0636SGreg Clayton case eVarSetOperationRemove:
190b9c1b51eSKate Stone if (argc > 0) {
191b9c1b51eSKate Stone for (size_t i = 0; i < argc; ++i) {
19267cc0636SGreg Clayton ConstString key(args.GetArgumentAtIndex(i));
193b9c1b51eSKate Stone if (!DeleteValueForKey(key)) {
194b9c1b51eSKate Stone error.SetErrorStringWithFormat(
195b9c1b51eSKate Stone "no value found named '%s', aborting remove operation",
196b9c1b51eSKate Stone key.GetCString());
19767cc0636SGreg Clayton break;
19867cc0636SGreg Clayton }
19967cc0636SGreg Clayton }
200b9c1b51eSKate Stone } else {
20167cc0636SGreg Clayton error.SetErrorString("remove operation takes one or more key arguments");
20267cc0636SGreg Clayton }
20367cc0636SGreg Clayton break;
20467cc0636SGreg Clayton
20567cc0636SGreg Clayton case eVarSetOperationInsertBefore:
20667cc0636SGreg Clayton case eVarSetOperationInsertAfter:
20767cc0636SGreg Clayton case eVarSetOperationInvalid:
208c95f7e2aSPavel Labath error = OptionValue::SetValueFromString(llvm::StringRef(), op);
20967cc0636SGreg Clayton break;
21067cc0636SGreg Clayton }
21167cc0636SGreg Clayton return error;
21267cc0636SGreg Clayton }
21367cc0636SGreg Clayton
SetValueFromString(llvm::StringRef value,VarSetOperationType op)21497206d57SZachary Turner Status OptionValueDictionary::SetValueFromString(llvm::StringRef value,
215b9c1b51eSKate Stone VarSetOperationType op) {
216771ef6d4SMalcolm Parsons Args args(value.str());
21797206d57SZachary Turner Status error = SetArgs(args, op);
218332e8b1cSGreg Clayton if (error.Success())
219332e8b1cSGreg Clayton NotifyValueChanged();
220332e8b1cSGreg Clayton return error;
22167cc0636SGreg Clayton }
22267cc0636SGreg Clayton
22367cc0636SGreg Clayton lldb::OptionValueSP
GetSubValue(const ExecutionContext * exe_ctx,llvm::StringRef name,bool will_modify,Status & error) const224b9c1b51eSKate Stone OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
22531d97a5cSZachary Turner llvm::StringRef name, bool will_modify,
22697206d57SZachary Turner Status &error) const {
22767cc0636SGreg Clayton lldb::OptionValueSP value_sp;
22831d97a5cSZachary Turner if (name.empty())
22931d97a5cSZachary Turner return nullptr;
23067cc0636SGreg Clayton
23131d97a5cSZachary Turner llvm::StringRef left, temp;
23231d97a5cSZachary Turner std::tie(left, temp) = name.split('[');
23331d97a5cSZachary Turner if (left.size() == name.size()) {
234b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid value path '%s', %s values only "
235b9c1b51eSKate Stone "support '[<key>]' subvalues where <key> "
236b9c1b51eSKate Stone "a string value optionally delimited by "
237b9c1b51eSKate Stone "single or double quotes",
23831d97a5cSZachary Turner name.str().c_str(), GetTypeAsCString());
23931d97a5cSZachary Turner return nullptr;
24067cc0636SGreg Clayton }
24131d97a5cSZachary Turner assert(!temp.empty());
24231d97a5cSZachary Turner
2438e353b90SDavide Italiano llvm::StringRef key, quote_char;
24431d97a5cSZachary Turner
24531d97a5cSZachary Turner if (temp[0] == '\"' || temp[0] == '\'') {
24631d97a5cSZachary Turner quote_char = temp.take_front();
24731d97a5cSZachary Turner temp = temp.drop_front();
24867cc0636SGreg Clayton }
24931d97a5cSZachary Turner
25031d97a5cSZachary Turner llvm::StringRef sub_name;
25131d97a5cSZachary Turner std::tie(key, sub_name) = temp.split(']');
25231d97a5cSZachary Turner
25331d97a5cSZachary Turner if (!key.consume_back(quote_char) || key.empty()) {
25431d97a5cSZachary Turner error.SetErrorStringWithFormat("invalid value path '%s', "
25531d97a5cSZachary Turner "key names must be formatted as ['<key>'] where <key> "
25631d97a5cSZachary Turner "is a string that doesn't contain quotes and the quote"
25731d97a5cSZachary Turner " char is optional", name.str().c_str());
25831d97a5cSZachary Turner return nullptr;
25931d97a5cSZachary Turner }
26031d97a5cSZachary Turner
26131d97a5cSZachary Turner value_sp = GetValueForKey(ConstString(key));
26231d97a5cSZachary Turner if (!value_sp) {
26331d97a5cSZachary Turner error.SetErrorStringWithFormat(
26431d97a5cSZachary Turner "dictionary does not contain a value for the key name '%s'",
26531d97a5cSZachary Turner key.str().c_str());
26631d97a5cSZachary Turner return nullptr;
26731d97a5cSZachary Turner }
26831d97a5cSZachary Turner
26931d97a5cSZachary Turner if (sub_name.empty())
27067cc0636SGreg Clayton return value_sp;
27131d97a5cSZachary Turner return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);
27267cc0636SGreg Clayton }
27367cc0636SGreg Clayton
SetSubValue(const ExecutionContext * exe_ctx,VarSetOperationType op,llvm::StringRef name,llvm::StringRef value)27497206d57SZachary Turner Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
275b9c1b51eSKate Stone VarSetOperationType op,
27697206d57SZachary Turner llvm::StringRef name,
27797206d57SZachary Turner llvm::StringRef value) {
27897206d57SZachary Turner Status error;
27967cc0636SGreg Clayton const bool will_modify = true;
28067cc0636SGreg Clayton lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
28167cc0636SGreg Clayton if (value_sp)
28231d97a5cSZachary Turner error = value_sp->SetValueFromString(value, op);
283b9c1b51eSKate Stone else {
284d78c9576SEd Maste if (error.AsCString() == nullptr)
28531d97a5cSZachary Turner error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
28667cc0636SGreg Clayton }
28767cc0636SGreg Clayton return error;
28867cc0636SGreg Clayton }
28967cc0636SGreg Clayton
29067cc0636SGreg Clayton lldb::OptionValueSP
GetValueForKey(ConstString key) const2910e4c4821SAdrian Prantl OptionValueDictionary::GetValueForKey(ConstString key) const {
29267cc0636SGreg Clayton lldb::OptionValueSP value_sp;
29367cc0636SGreg Clayton collection::const_iterator pos = m_values.find(key);
29467cc0636SGreg Clayton if (pos != m_values.end())
29567cc0636SGreg Clayton value_sp = pos->second;
29667cc0636SGreg Clayton return value_sp;
29767cc0636SGreg Clayton }
29867cc0636SGreg Clayton
SetValueForKey(ConstString key,const lldb::OptionValueSP & value_sp,bool can_replace)2990e4c4821SAdrian Prantl bool OptionValueDictionary::SetValueForKey(ConstString key,
30067cc0636SGreg Clayton const lldb::OptionValueSP &value_sp,
301b9c1b51eSKate Stone bool can_replace) {
30205097246SAdrian Prantl // Make sure the value_sp object is allowed to contain values of the type
30305097246SAdrian Prantl // passed in...
304b9c1b51eSKate Stone if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {
305b9c1b51eSKate Stone if (!can_replace) {
30667cc0636SGreg Clayton collection::const_iterator pos = m_values.find(key);
30767cc0636SGreg Clayton if (pos != m_values.end())
30867cc0636SGreg Clayton return false;
30967cc0636SGreg Clayton }
31067cc0636SGreg Clayton m_values[key] = value_sp;
31167cc0636SGreg Clayton return true;
31267cc0636SGreg Clayton }
31367cc0636SGreg Clayton return false;
31467cc0636SGreg Clayton }
31567cc0636SGreg Clayton
DeleteValueForKey(ConstString key)3160e4c4821SAdrian Prantl bool OptionValueDictionary::DeleteValueForKey(ConstString key) {
31767cc0636SGreg Clayton collection::iterator pos = m_values.find(key);
318b9c1b51eSKate Stone if (pos != m_values.end()) {
31967cc0636SGreg Clayton m_values.erase(pos);
32067cc0636SGreg Clayton return true;
32167cc0636SGreg Clayton }
32267cc0636SGreg Clayton return false;
32367cc0636SGreg Clayton }
32467cc0636SGreg Clayton
325f0f183eeSTatyana Krasnukha OptionValueSP
DeepCopy(const OptionValueSP & new_parent) const326f0f183eeSTatyana Krasnukha OptionValueDictionary::DeepCopy(const OptionValueSP &new_parent) const {
327f0f183eeSTatyana Krasnukha auto copy_sp = OptionValue::DeepCopy(new_parent);
328f0f183eeSTatyana Krasnukha // copy_sp->GetAsDictionary cannot be used here as it doesn't work for derived
329f0f183eeSTatyana Krasnukha // types that override GetType returning a different value.
330f0f183eeSTatyana Krasnukha auto *dict_value_ptr = static_cast<OptionValueDictionary *>(copy_sp.get());
331f0f183eeSTatyana Krasnukha lldbassert(dict_value_ptr);
332f0f183eeSTatyana Krasnukha
333f0f183eeSTatyana Krasnukha for (auto &value : dict_value_ptr->m_values)
334f0f183eeSTatyana Krasnukha value.second = value.second->DeepCopy(copy_sp);
335f0f183eeSTatyana Krasnukha
336f0f183eeSTatyana Krasnukha return copy_sp;
33767cc0636SGreg Clayton }
338