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 1167cc0636SGreg Clayton #include "llvm/ADT/StringRef.h" 125548cb50SEnrico Granata #include "lldb/DataFormatters/FormatManager.h" 1367cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueString.h" 14145d95c9SPavel Labath #include "lldb/Utility/Args.h" 15d821c997SPavel Labath #include "lldb/Utility/State.h" 1667cc0636SGreg Clayton 1767cc0636SGreg Clayton using namespace lldb; 1867cc0636SGreg Clayton using namespace lldb_private; 1967cc0636SGreg Clayton 20b9c1b51eSKate Stone void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx, 21b9c1b51eSKate Stone Stream &strm, uint32_t dump_mask) { 2267cc0636SGreg Clayton const Type dict_type = ConvertTypeMaskToType(m_type_mask); 23b9c1b51eSKate Stone if (dump_mask & eDumpOptionType) { 2467cc0636SGreg Clayton if (m_type_mask != eTypeInvalid) 25b9c1b51eSKate Stone strm.Printf("(%s of %ss)", GetTypeAsCString(), 26b9c1b51eSKate Stone GetBuiltinTypeAsCString(dict_type)); 2767cc0636SGreg Clayton else 2867cc0636SGreg Clayton strm.Printf("(%s)", GetTypeAsCString()); 2967cc0636SGreg Clayton } 30b9c1b51eSKate Stone if (dump_mask & eDumpOptionValue) { 31b76e25a2SJonas Devlieghere const bool one_line = dump_mask & eDumpOptionCommand; 3267cc0636SGreg Clayton if (dump_mask & eDumpOptionType) 3367cc0636SGreg Clayton strm.PutCString(" ="); 3467cc0636SGreg Clayton 3567cc0636SGreg Clayton collection::iterator pos, end = m_values.end(); 3667cc0636SGreg Clayton 37b76e25a2SJonas Devlieghere if (!one_line) 3867cc0636SGreg Clayton strm.IndentMore(); 3967cc0636SGreg Clayton 40b9c1b51eSKate Stone for (pos = m_values.begin(); pos != end; ++pos) { 4167cc0636SGreg Clayton OptionValue *option_value = pos->second.get(); 42b76e25a2SJonas Devlieghere 43b76e25a2SJonas Devlieghere if (one_line) 44b76e25a2SJonas Devlieghere strm << ' '; 45b76e25a2SJonas Devlieghere else 4667cc0636SGreg Clayton strm.EOL(); 47b76e25a2SJonas Devlieghere 48*9dfd4e26SRaphael Isemann strm.Indent(pos->first.GetStringRef()); 4967cc0636SGreg Clayton 5067cc0636SGreg Clayton const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; 51b9c1b51eSKate Stone switch (dict_type) { 5267cc0636SGreg Clayton default: 5367cc0636SGreg Clayton case eTypeArray: 5467cc0636SGreg Clayton case eTypeDictionary: 5567cc0636SGreg Clayton case eTypeProperties: 5667cc0636SGreg Clayton case eTypeFileSpecList: 5767cc0636SGreg Clayton case eTypePathMap: 5867cc0636SGreg Clayton strm.PutChar(' '); 5967cc0636SGreg Clayton option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); 6067cc0636SGreg Clayton break; 6167cc0636SGreg Clayton 6267cc0636SGreg Clayton case eTypeBoolean: 633e7442b6SZachary Turner case eTypeChar: 6467cc0636SGreg Clayton case eTypeEnum: 6567cc0636SGreg Clayton case eTypeFileSpec: 6667cc0636SGreg Clayton case eTypeFormat: 6767cc0636SGreg Clayton case eTypeSInt64: 6867cc0636SGreg Clayton case eTypeString: 6967cc0636SGreg Clayton case eTypeUInt64: 7067cc0636SGreg Clayton case eTypeUUID: 7167cc0636SGreg Clayton // No need to show the type for dictionaries of simple items 7267cc0636SGreg Clayton strm.PutCString("="); 73b9c1b51eSKate Stone option_value->DumpValue(exe_ctx, strm, 74b9c1b51eSKate Stone (dump_mask & (~eDumpOptionType)) | 75b9c1b51eSKate Stone extra_dump_options); 7667cc0636SGreg Clayton break; 7767cc0636SGreg Clayton } 7867cc0636SGreg Clayton } 79b76e25a2SJonas Devlieghere if (!one_line) 8067cc0636SGreg Clayton strm.IndentLess(); 8167cc0636SGreg Clayton } 8267cc0636SGreg Clayton } 8367cc0636SGreg Clayton 84b9c1b51eSKate Stone size_t OptionValueDictionary::GetArgs(Args &args) const { 8567cc0636SGreg Clayton args.Clear(); 8667cc0636SGreg Clayton collection::const_iterator pos, end = m_values.end(); 87b9c1b51eSKate Stone for (pos = m_values.begin(); pos != end; ++pos) { 8867cc0636SGreg Clayton StreamString strm; 8967cc0636SGreg Clayton strm.Printf("%s=", pos->first.GetCString()); 90d78c9576SEd Maste pos->second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw); 91ecbb0bb1SZachary Turner args.AppendArgument(strm.GetString()); 9267cc0636SGreg Clayton } 9367cc0636SGreg Clayton return args.GetArgumentCount(); 9467cc0636SGreg Clayton } 9567cc0636SGreg Clayton 9697206d57SZachary Turner Status OptionValueDictionary::SetArgs(const Args &args, 9797206d57SZachary Turner VarSetOperationType op) { 9897206d57SZachary Turner Status error; 9967cc0636SGreg Clayton const size_t argc = args.GetArgumentCount(); 100b9c1b51eSKate Stone switch (op) { 10167cc0636SGreg Clayton case eVarSetOperationClear: 10267cc0636SGreg Clayton Clear(); 10367cc0636SGreg Clayton break; 10467cc0636SGreg Clayton 10567cc0636SGreg Clayton case eVarSetOperationAppend: 10667cc0636SGreg Clayton case eVarSetOperationReplace: 10767cc0636SGreg Clayton case eVarSetOperationAssign: 108d6a24757SZachary Turner if (argc == 0) { 109d6a24757SZachary Turner error.SetErrorString( 110d6a24757SZachary Turner "assign operation takes one or more key=value arguments"); 111d6a24757SZachary Turner return error; 112d6a24757SZachary Turner } 113d6a24757SZachary Turner for (const auto &entry : args) { 1140d9a201eSRaphael Isemann if (entry.ref().empty()) { 115d6a24757SZachary Turner error.SetErrorString("empty argument"); 116d6a24757SZachary Turner return error; 117d6a24757SZachary Turner } 1180d9a201eSRaphael Isemann if (!entry.ref().contains('=')) { 119b9c1b51eSKate Stone error.SetErrorString( 120b9c1b51eSKate Stone "assign operation takes one or more key=value arguments"); 121a44c0e31SEnrico Granata return error; 122a44c0e31SEnrico Granata } 123a44c0e31SEnrico Granata 124d6a24757SZachary Turner llvm::StringRef key, value; 1250d9a201eSRaphael Isemann std::tie(key, value) = entry.ref().split('='); 12667cc0636SGreg Clayton bool key_valid = false; 127d6a24757SZachary Turner if (key.empty()) { 128d6a24757SZachary Turner error.SetErrorString("empty dictionary key"); 129d6a24757SZachary Turner return error; 130d6a24757SZachary Turner } 131d6a24757SZachary Turner 132b9c1b51eSKate Stone if (key.front() == '[') { 133b9c1b51eSKate Stone // Key name starts with '[', so the key value must be in single or 13405097246SAdrian Prantl // double quotes like: ['<key>'] ["<key>"] 135b9c1b51eSKate Stone if ((key.size() > 2) && (key.back() == ']')) { 13667cc0636SGreg Clayton // Strip leading '[' and trailing ']' 13767cc0636SGreg Clayton key = key.substr(1, key.size() - 2); 13867cc0636SGreg Clayton const char quote_char = key.front(); 139b9c1b51eSKate Stone if ((quote_char == '\'') || (quote_char == '"')) { 140b9c1b51eSKate Stone if ((key.size() > 2) && (key.back() == quote_char)) { 14167cc0636SGreg Clayton // Strip the quotes 14267cc0636SGreg Clayton key = key.substr(1, key.size() - 2); 14367cc0636SGreg Clayton key_valid = true; 14467cc0636SGreg Clayton } 145b9c1b51eSKate Stone } else { 14667cc0636SGreg Clayton // square brackets, no quotes 14767cc0636SGreg Clayton key_valid = true; 14867cc0636SGreg Clayton } 14967cc0636SGreg Clayton } 150b9c1b51eSKate Stone } else { 15167cc0636SGreg Clayton // No square brackets or quotes 15267cc0636SGreg Clayton key_valid = true; 15367cc0636SGreg Clayton } 154b9c1b51eSKate Stone if (!key_valid) { 155b9c1b51eSKate Stone error.SetErrorStringWithFormat( 156b9c1b51eSKate Stone "invalid key \"%s\", the key must be a bare string or " 157b9c1b51eSKate Stone "surrounded by brackets with optional quotes: [<key>] or " 158b9c1b51eSKate Stone "['<key>'] or [\"<key>\"]", 159d6a24757SZachary Turner key.str().c_str()); 16067cc0636SGreg Clayton return error; 16167cc0636SGreg Clayton } 16267cc0636SGreg Clayton 163b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 164d6a24757SZachary Turner value.str().c_str(), m_type_mask, error)); 165b9c1b51eSKate Stone if (value_sp) { 16667cc0636SGreg Clayton if (error.Fail()) 16767cc0636SGreg Clayton return error; 16867cc0636SGreg Clayton m_value_was_set = true; 16967cc0636SGreg Clayton SetValueForKey(ConstString(key), value_sp, true); 170b9c1b51eSKate Stone } else { 171b9c1b51eSKate Stone error.SetErrorString("dictionaries that can contain multiple types " 172b9c1b51eSKate Stone "must subclass OptionValueArray"); 17367cc0636SGreg Clayton } 17467cc0636SGreg Clayton } 17567cc0636SGreg Clayton break; 17667cc0636SGreg Clayton 17767cc0636SGreg Clayton case eVarSetOperationRemove: 178b9c1b51eSKate Stone if (argc > 0) { 179b9c1b51eSKate Stone for (size_t i = 0; i < argc; ++i) { 18067cc0636SGreg Clayton ConstString key(args.GetArgumentAtIndex(i)); 181b9c1b51eSKate Stone if (!DeleteValueForKey(key)) { 182b9c1b51eSKate Stone error.SetErrorStringWithFormat( 183b9c1b51eSKate Stone "no value found named '%s', aborting remove operation", 184b9c1b51eSKate Stone key.GetCString()); 18567cc0636SGreg Clayton break; 18667cc0636SGreg Clayton } 18767cc0636SGreg Clayton } 188b9c1b51eSKate Stone } else { 18967cc0636SGreg Clayton error.SetErrorString("remove operation takes one or more key arguments"); 19067cc0636SGreg Clayton } 19167cc0636SGreg Clayton break; 19267cc0636SGreg Clayton 19367cc0636SGreg Clayton case eVarSetOperationInsertBefore: 19467cc0636SGreg Clayton case eVarSetOperationInsertAfter: 19567cc0636SGreg Clayton case eVarSetOperationInvalid: 196c95f7e2aSPavel Labath error = OptionValue::SetValueFromString(llvm::StringRef(), op); 19767cc0636SGreg Clayton break; 19867cc0636SGreg Clayton } 19967cc0636SGreg Clayton return error; 20067cc0636SGreg Clayton } 20167cc0636SGreg Clayton 20297206d57SZachary Turner Status OptionValueDictionary::SetValueFromString(llvm::StringRef value, 203b9c1b51eSKate Stone VarSetOperationType op) { 204771ef6d4SMalcolm Parsons Args args(value.str()); 20597206d57SZachary Turner Status error = SetArgs(args, op); 206332e8b1cSGreg Clayton if (error.Success()) 207332e8b1cSGreg Clayton NotifyValueChanged(); 208332e8b1cSGreg Clayton return error; 20967cc0636SGreg Clayton } 21067cc0636SGreg Clayton 21167cc0636SGreg Clayton lldb::OptionValueSP 212b9c1b51eSKate Stone OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx, 21331d97a5cSZachary Turner llvm::StringRef name, bool will_modify, 21497206d57SZachary Turner Status &error) const { 21567cc0636SGreg Clayton lldb::OptionValueSP value_sp; 21631d97a5cSZachary Turner if (name.empty()) 21731d97a5cSZachary Turner return nullptr; 21867cc0636SGreg Clayton 21931d97a5cSZachary Turner llvm::StringRef left, temp; 22031d97a5cSZachary Turner std::tie(left, temp) = name.split('['); 22131d97a5cSZachary Turner if (left.size() == name.size()) { 222b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid value path '%s', %s values only " 223b9c1b51eSKate Stone "support '[<key>]' subvalues where <key> " 224b9c1b51eSKate Stone "a string value optionally delimited by " 225b9c1b51eSKate Stone "single or double quotes", 22631d97a5cSZachary Turner name.str().c_str(), GetTypeAsCString()); 22731d97a5cSZachary Turner return nullptr; 22867cc0636SGreg Clayton } 22931d97a5cSZachary Turner assert(!temp.empty()); 23031d97a5cSZachary Turner 2318e353b90SDavide Italiano llvm::StringRef key, quote_char; 23231d97a5cSZachary Turner 23331d97a5cSZachary Turner if (temp[0] == '\"' || temp[0] == '\'') { 23431d97a5cSZachary Turner quote_char = temp.take_front(); 23531d97a5cSZachary Turner temp = temp.drop_front(); 23667cc0636SGreg Clayton } 23731d97a5cSZachary Turner 23831d97a5cSZachary Turner llvm::StringRef sub_name; 23931d97a5cSZachary Turner std::tie(key, sub_name) = temp.split(']'); 24031d97a5cSZachary Turner 24131d97a5cSZachary Turner if (!key.consume_back(quote_char) || key.empty()) { 24231d97a5cSZachary Turner error.SetErrorStringWithFormat("invalid value path '%s', " 24331d97a5cSZachary Turner "key names must be formatted as ['<key>'] where <key> " 24431d97a5cSZachary Turner "is a string that doesn't contain quotes and the quote" 24531d97a5cSZachary Turner " char is optional", name.str().c_str()); 24631d97a5cSZachary Turner return nullptr; 24731d97a5cSZachary Turner } 24831d97a5cSZachary Turner 24931d97a5cSZachary Turner value_sp = GetValueForKey(ConstString(key)); 25031d97a5cSZachary Turner if (!value_sp) { 25131d97a5cSZachary Turner error.SetErrorStringWithFormat( 25231d97a5cSZachary Turner "dictionary does not contain a value for the key name '%s'", 25331d97a5cSZachary Turner key.str().c_str()); 25431d97a5cSZachary Turner return nullptr; 25531d97a5cSZachary Turner } 25631d97a5cSZachary Turner 25731d97a5cSZachary Turner if (sub_name.empty()) 25867cc0636SGreg Clayton return value_sp; 25931d97a5cSZachary Turner return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error); 26067cc0636SGreg Clayton } 26167cc0636SGreg Clayton 26297206d57SZachary Turner Status OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx, 263b9c1b51eSKate Stone VarSetOperationType op, 26497206d57SZachary Turner llvm::StringRef name, 26597206d57SZachary Turner llvm::StringRef value) { 26697206d57SZachary Turner Status error; 26767cc0636SGreg Clayton const bool will_modify = true; 26867cc0636SGreg Clayton lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error)); 26967cc0636SGreg Clayton if (value_sp) 27031d97a5cSZachary Turner error = value_sp->SetValueFromString(value, op); 271b9c1b51eSKate Stone else { 272d78c9576SEd Maste if (error.AsCString() == nullptr) 27331d97a5cSZachary Turner error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str()); 27467cc0636SGreg Clayton } 27567cc0636SGreg Clayton return error; 27667cc0636SGreg Clayton } 27767cc0636SGreg Clayton 27867cc0636SGreg Clayton lldb::OptionValueSP 2790e4c4821SAdrian Prantl OptionValueDictionary::GetValueForKey(ConstString key) const { 28067cc0636SGreg Clayton lldb::OptionValueSP value_sp; 28167cc0636SGreg Clayton collection::const_iterator pos = m_values.find(key); 28267cc0636SGreg Clayton if (pos != m_values.end()) 28367cc0636SGreg Clayton value_sp = pos->second; 28467cc0636SGreg Clayton return value_sp; 28567cc0636SGreg Clayton } 28667cc0636SGreg Clayton 2870e4c4821SAdrian Prantl bool OptionValueDictionary::SetValueForKey(ConstString key, 28867cc0636SGreg Clayton const lldb::OptionValueSP &value_sp, 289b9c1b51eSKate Stone bool can_replace) { 29005097246SAdrian Prantl // Make sure the value_sp object is allowed to contain values of the type 29105097246SAdrian Prantl // passed in... 292b9c1b51eSKate Stone if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) { 293b9c1b51eSKate Stone if (!can_replace) { 29467cc0636SGreg Clayton collection::const_iterator pos = m_values.find(key); 29567cc0636SGreg Clayton if (pos != m_values.end()) 29667cc0636SGreg Clayton return false; 29767cc0636SGreg Clayton } 29867cc0636SGreg Clayton m_values[key] = value_sp; 29967cc0636SGreg Clayton return true; 30067cc0636SGreg Clayton } 30167cc0636SGreg Clayton return false; 30267cc0636SGreg Clayton } 30367cc0636SGreg Clayton 3040e4c4821SAdrian Prantl bool OptionValueDictionary::DeleteValueForKey(ConstString key) { 30567cc0636SGreg Clayton collection::iterator pos = m_values.find(key); 306b9c1b51eSKate Stone if (pos != m_values.end()) { 30767cc0636SGreg Clayton m_values.erase(pos); 30867cc0636SGreg Clayton return true; 30967cc0636SGreg Clayton } 31067cc0636SGreg Clayton return false; 31167cc0636SGreg Clayton } 31267cc0636SGreg Clayton 313b9c1b51eSKate Stone lldb::OptionValueSP OptionValueDictionary::DeepCopy() const { 314b9c1b51eSKate Stone OptionValueDictionary *copied_dict = 315b9c1b51eSKate Stone new OptionValueDictionary(m_type_mask, m_raw_value_dump); 31667cc0636SGreg Clayton lldb::OptionValueSP copied_value_sp(copied_dict); 31767cc0636SGreg Clayton collection::const_iterator pos, end = m_values.end(); 318b9c1b51eSKate Stone for (pos = m_values.begin(); pos != end; ++pos) { 31967cc0636SGreg Clayton StreamString strm; 32067cc0636SGreg Clayton strm.Printf("%s=", pos->first.GetCString()); 32167cc0636SGreg Clayton copied_dict->SetValueForKey(pos->first, pos->second->DeepCopy(), true); 32267cc0636SGreg Clayton } 32367cc0636SGreg Clayton return copied_value_sp; 32467cc0636SGreg Clayton } 325