167cc0636SGreg Clayton //===-- OptionValueArray.cpp ------------------------------------*- C++ -*-===// 267cc0636SGreg Clayton // 367cc0636SGreg Clayton // The LLVM Compiler Infrastructure 467cc0636SGreg Clayton // 567cc0636SGreg Clayton // This file is distributed under the University of Illinois Open Source 667cc0636SGreg Clayton // License. See LICENSE.TXT for details. 767cc0636SGreg Clayton // 867cc0636SGreg Clayton //===----------------------------------------------------------------------===// 967cc0636SGreg Clayton 1067cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueArray.h" 1167cc0636SGreg Clayton 1267cc0636SGreg Clayton // C Includes 1367cc0636SGreg Clayton // C++ Includes 1467cc0636SGreg Clayton // Other libraries and framework includes 1567cc0636SGreg Clayton // Project includes 1667cc0636SGreg Clayton #include "lldb/Core/Stream.h" 175275aaa0SVince Harron #include "lldb/Host/StringConvert.h" 1867cc0636SGreg Clayton #include "lldb/Interpreter/Args.h" 1967cc0636SGreg Clayton 2067cc0636SGreg Clayton using namespace lldb; 2167cc0636SGreg Clayton using namespace lldb_private; 2267cc0636SGreg Clayton 23b9c1b51eSKate Stone void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm, 24b9c1b51eSKate Stone uint32_t dump_mask) { 2567cc0636SGreg Clayton const Type array_element_type = ConvertTypeMaskToType(m_type_mask); 26b9c1b51eSKate Stone if (dump_mask & eDumpOptionType) { 2767cc0636SGreg Clayton if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid)) 28b9c1b51eSKate Stone strm.Printf("(%s of %ss)", GetTypeAsCString(), 29b9c1b51eSKate Stone GetBuiltinTypeAsCString(array_element_type)); 3067cc0636SGreg Clayton else 3167cc0636SGreg Clayton strm.Printf("(%s)", GetTypeAsCString()); 3267cc0636SGreg Clayton } 33b9c1b51eSKate Stone if (dump_mask & eDumpOptionValue) { 3467cc0636SGreg Clayton if (dump_mask & eDumpOptionType) 3567cc0636SGreg Clayton strm.Printf(" =%s", (m_values.size() > 0) ? "\n" : ""); 3667cc0636SGreg Clayton strm.IndentMore(); 3767cc0636SGreg Clayton const uint32_t size = m_values.size(); 38b9c1b51eSKate Stone for (uint32_t i = 0; i < size; ++i) { 3967cc0636SGreg Clayton strm.Indent(); 4067cc0636SGreg Clayton strm.Printf("[%u]: ", i); 4167cc0636SGreg Clayton const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; 42b9c1b51eSKate Stone switch (array_element_type) { 4367cc0636SGreg Clayton default: 4467cc0636SGreg Clayton case eTypeArray: 4567cc0636SGreg Clayton case eTypeDictionary: 4667cc0636SGreg Clayton case eTypeProperties: 4767cc0636SGreg Clayton case eTypeFileSpecList: 4867cc0636SGreg Clayton case eTypePathMap: 4967cc0636SGreg Clayton m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); 5067cc0636SGreg Clayton break; 5167cc0636SGreg Clayton 5267cc0636SGreg Clayton case eTypeBoolean: 533e7442b6SZachary Turner case eTypeChar: 5467cc0636SGreg Clayton case eTypeEnum: 5567cc0636SGreg Clayton case eTypeFileSpec: 5667cc0636SGreg Clayton case eTypeFormat: 5767cc0636SGreg Clayton case eTypeSInt64: 5867cc0636SGreg Clayton case eTypeString: 5967cc0636SGreg Clayton case eTypeUInt64: 6067cc0636SGreg Clayton case eTypeUUID: 6167cc0636SGreg Clayton // No need to show the type for dictionaries of simple items 62b9c1b51eSKate Stone m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | 63b9c1b51eSKate Stone extra_dump_options); 6467cc0636SGreg Clayton break; 6567cc0636SGreg Clayton } 6667cc0636SGreg Clayton if (i < (size - 1)) 6767cc0636SGreg Clayton strm.EOL(); 6867cc0636SGreg Clayton } 6967cc0636SGreg Clayton strm.IndentLess(); 7067cc0636SGreg Clayton } 7167cc0636SGreg Clayton } 7267cc0636SGreg Clayton 73b9c1b51eSKate Stone Error OptionValueArray::SetValueFromString(llvm::StringRef value, 74b9c1b51eSKate Stone VarSetOperationType op) { 75*771ef6d4SMalcolm Parsons Args args(value.str()); 768f37ca56SIlia K Error error = SetArgs(args, op); 778f37ca56SIlia K if (error.Success()) 78332e8b1cSGreg Clayton NotifyValueChanged(); 798f37ca56SIlia K return error; 8067cc0636SGreg Clayton } 8167cc0636SGreg Clayton 8267cc0636SGreg Clayton lldb::OptionValueSP 83b9c1b51eSKate Stone OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx, const char *name, 84b9c1b51eSKate Stone bool will_modify, Error &error) const { 85b9c1b51eSKate Stone if (name && name[0] == '[') { 8667cc0636SGreg Clayton const char *end_bracket = strchr(name + 1, ']'); 87b9c1b51eSKate Stone if (end_bracket) { 88d78c9576SEd Maste const char *sub_value = nullptr; 8967cc0636SGreg Clayton if (end_bracket[1]) 9067cc0636SGreg Clayton sub_value = end_bracket + 1; 9167cc0636SGreg Clayton std::string index_str(name + 1, end_bracket); 9267cc0636SGreg Clayton const size_t array_count = m_values.size(); 93b9c1b51eSKate Stone int32_t idx = 94b9c1b51eSKate Stone StringConvert::ToSInt32(index_str.c_str(), INT32_MAX, 0, nullptr); 95b9c1b51eSKate Stone if (idx != INT32_MAX) { 9667cc0636SGreg Clayton ; 9767cc0636SGreg Clayton uint32_t new_idx = UINT32_MAX; 98b9c1b51eSKate Stone if (idx < 0) { 9967cc0636SGreg Clayton // Access from the end of the array if the index is negative 10067cc0636SGreg Clayton new_idx = array_count - idx; 101b9c1b51eSKate Stone } else { 10267cc0636SGreg Clayton // Just a standard index 10367cc0636SGreg Clayton new_idx = idx; 10467cc0636SGreg Clayton } 10567cc0636SGreg Clayton 106b9c1b51eSKate Stone if (new_idx < array_count) { 107b9c1b51eSKate Stone if (m_values[new_idx]) { 10867cc0636SGreg Clayton if (sub_value) 109b9c1b51eSKate Stone return m_values[new_idx]->GetSubValue(exe_ctx, sub_value, 110b9c1b51eSKate Stone will_modify, error); 11167cc0636SGreg Clayton else 11267cc0636SGreg Clayton return m_values[new_idx]; 11367cc0636SGreg Clayton } 114b9c1b51eSKate Stone } else { 11567cc0636SGreg Clayton if (array_count == 0) 116b9c1b51eSKate Stone error.SetErrorStringWithFormat( 117b9c1b51eSKate Stone "index %i is not valid for an empty array", idx); 11867cc0636SGreg Clayton else if (idx > 0) 119b9c1b51eSKate Stone error.SetErrorStringWithFormat( 120b9c1b51eSKate Stone "index %i out of range, valid values are 0 through %" PRIu64, 121b9c1b51eSKate Stone idx, (uint64_t)(array_count - 1)); 12267cc0636SGreg Clayton else 123b9c1b51eSKate Stone error.SetErrorStringWithFormat("negative index %i out of range, " 124b9c1b51eSKate Stone "valid values are -1 through " 125b9c1b51eSKate Stone "-%" PRIu64, 126b9c1b51eSKate Stone idx, (uint64_t)array_count); 12767cc0636SGreg Clayton } 12867cc0636SGreg Clayton } 12967cc0636SGreg Clayton } 130b9c1b51eSKate Stone } else { 131b9c1b51eSKate Stone error.SetErrorStringWithFormat( 132b9c1b51eSKate Stone "invalid value path '%s', %s values only support '[<index>]' subvalues " 133b9c1b51eSKate Stone "where <index> is a positive or negative array index", 134b9c1b51eSKate Stone name, GetTypeAsCString()); 13567cc0636SGreg Clayton } 13667cc0636SGreg Clayton return OptionValueSP(); 13767cc0636SGreg Clayton } 13867cc0636SGreg Clayton 139b9c1b51eSKate Stone size_t OptionValueArray::GetArgs(Args &args) const { 14067cc0636SGreg Clayton const uint32_t size = m_values.size(); 14167cc0636SGreg Clayton std::vector<const char *> argv; 142b9c1b51eSKate Stone for (uint32_t i = 0; i < size; ++i) { 14367cc0636SGreg Clayton const char *string_value = m_values[i]->GetStringValue(); 14467cc0636SGreg Clayton if (string_value) 14567cc0636SGreg Clayton argv.push_back(string_value); 14667cc0636SGreg Clayton } 14767cc0636SGreg Clayton 14867cc0636SGreg Clayton if (argv.empty()) 14967cc0636SGreg Clayton args.Clear(); 15067cc0636SGreg Clayton else 15167cc0636SGreg Clayton args.SetArguments(argv.size(), &argv[0]); 15267cc0636SGreg Clayton return args.GetArgumentCount(); 15367cc0636SGreg Clayton } 15467cc0636SGreg Clayton 155b9c1b51eSKate Stone Error OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) { 15667cc0636SGreg Clayton Error error; 15767cc0636SGreg Clayton const size_t argc = args.GetArgumentCount(); 158b9c1b51eSKate Stone switch (op) { 15967cc0636SGreg Clayton case eVarSetOperationInvalid: 16067cc0636SGreg Clayton error.SetErrorString("unsupported operation"); 16167cc0636SGreg Clayton break; 16267cc0636SGreg Clayton 16367cc0636SGreg Clayton case eVarSetOperationInsertBefore: 16467cc0636SGreg Clayton case eVarSetOperationInsertAfter: 165b9c1b51eSKate Stone if (argc > 1) { 166b9c1b51eSKate Stone uint32_t idx = 167b9c1b51eSKate Stone StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 16867cc0636SGreg Clayton const uint32_t count = GetSize(); 169b9c1b51eSKate Stone if (idx > count) { 170b9c1b51eSKate Stone error.SetErrorStringWithFormat( 171b9c1b51eSKate Stone "invalid insert array index %u, index must be 0 through %u", idx, 172b9c1b51eSKate Stone count); 173b9c1b51eSKate Stone } else { 17467cc0636SGreg Clayton if (op == eVarSetOperationInsertAfter) 17567cc0636SGreg Clayton ++idx; 176b9c1b51eSKate Stone for (size_t i = 1; i < argc; ++i, ++idx) { 177b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 178b9c1b51eSKate Stone args.GetArgumentAtIndex(i), m_type_mask, error)); 179b9c1b51eSKate Stone if (value_sp) { 18067cc0636SGreg Clayton if (error.Fail()) 18167cc0636SGreg Clayton return error; 18267cc0636SGreg Clayton if (idx >= m_values.size()) 18367cc0636SGreg Clayton m_values.push_back(value_sp); 18467cc0636SGreg Clayton else 18567cc0636SGreg Clayton m_values.insert(m_values.begin() + idx, value_sp); 186b9c1b51eSKate Stone } else { 187b9c1b51eSKate Stone error.SetErrorString( 188b9c1b51eSKate Stone "array of complex types must subclass OptionValueArray"); 18967cc0636SGreg Clayton return error; 19067cc0636SGreg Clayton } 19167cc0636SGreg Clayton } 19267cc0636SGreg Clayton } 193b9c1b51eSKate Stone } else { 194b9c1b51eSKate Stone error.SetErrorString("insert operation takes an array index followed by " 195b9c1b51eSKate Stone "one or more values"); 19667cc0636SGreg Clayton } 19767cc0636SGreg Clayton break; 19867cc0636SGreg Clayton 19967cc0636SGreg Clayton case eVarSetOperationRemove: 200b9c1b51eSKate Stone if (argc > 0) { 20167cc0636SGreg Clayton const uint32_t size = m_values.size(); 20267cc0636SGreg Clayton std::vector<int> remove_indexes; 20367cc0636SGreg Clayton bool all_indexes_valid = true; 20467cc0636SGreg Clayton size_t i; 205b9c1b51eSKate Stone for (i = 0; i < argc; ++i) { 2063985c8c6SSaleem Abdulrasool const size_t idx = 2075275aaa0SVince Harron StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); 208b9c1b51eSKate Stone if (idx >= size) { 20967cc0636SGreg Clayton all_indexes_valid = false; 21067cc0636SGreg Clayton break; 211b9c1b51eSKate Stone } else 21267cc0636SGreg Clayton remove_indexes.push_back(idx); 21367cc0636SGreg Clayton } 21467cc0636SGreg Clayton 215b9c1b51eSKate Stone if (all_indexes_valid) { 21667cc0636SGreg Clayton size_t num_remove_indexes = remove_indexes.size(); 217b9c1b51eSKate Stone if (num_remove_indexes) { 21867cc0636SGreg Clayton // Sort and then erase in reverse so indexes are always valid 219b9c1b51eSKate Stone if (num_remove_indexes > 1) { 22067cc0636SGreg Clayton std::sort(remove_indexes.begin(), remove_indexes.end()); 221b9c1b51eSKate Stone for (std::vector<int>::const_reverse_iterator 222b9c1b51eSKate Stone pos = remove_indexes.rbegin(), 223b9c1b51eSKate Stone end = remove_indexes.rend(); 224b9c1b51eSKate Stone pos != end; ++pos) { 22567cc0636SGreg Clayton m_values.erase(m_values.begin() + *pos); 22667cc0636SGreg Clayton } 227b9c1b51eSKate Stone } else { 22867cc0636SGreg Clayton // Only one index 22967cc0636SGreg Clayton m_values.erase(m_values.begin() + remove_indexes.front()); 23067cc0636SGreg Clayton } 23167cc0636SGreg Clayton } 232b9c1b51eSKate Stone } else { 233b9c1b51eSKate Stone error.SetErrorStringWithFormat( 234b9c1b51eSKate Stone "invalid array index '%s', aborting remove operation", 235b9c1b51eSKate Stone args.GetArgumentAtIndex(i)); 23667cc0636SGreg Clayton } 237b9c1b51eSKate Stone } else { 23867cc0636SGreg Clayton error.SetErrorString("remove operation takes one or more array indices"); 23967cc0636SGreg Clayton } 24067cc0636SGreg Clayton break; 24167cc0636SGreg Clayton 24267cc0636SGreg Clayton case eVarSetOperationClear: 24367cc0636SGreg Clayton Clear(); 24467cc0636SGreg Clayton break; 24567cc0636SGreg Clayton 24667cc0636SGreg Clayton case eVarSetOperationReplace: 247b9c1b51eSKate Stone if (argc > 1) { 248b9c1b51eSKate Stone uint32_t idx = 249b9c1b51eSKate Stone StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 25067cc0636SGreg Clayton const uint32_t count = GetSize(); 251b9c1b51eSKate Stone if (idx > count) { 252b9c1b51eSKate Stone error.SetErrorStringWithFormat( 253b9c1b51eSKate Stone "invalid replace array index %u, index must be 0 through %u", idx, 254b9c1b51eSKate Stone count); 255b9c1b51eSKate Stone } else { 256b9c1b51eSKate Stone for (size_t i = 1; i < argc; ++i, ++idx) { 257b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 258b9c1b51eSKate Stone args.GetArgumentAtIndex(i), m_type_mask, error)); 259b9c1b51eSKate Stone if (value_sp) { 26067cc0636SGreg Clayton if (error.Fail()) 26167cc0636SGreg Clayton return error; 26267cc0636SGreg Clayton if (idx < count) 26367cc0636SGreg Clayton m_values[idx] = value_sp; 26467cc0636SGreg Clayton else 26567cc0636SGreg Clayton m_values.push_back(value_sp); 266b9c1b51eSKate Stone } else { 267b9c1b51eSKate Stone error.SetErrorString( 268b9c1b51eSKate Stone "array of complex types must subclass OptionValueArray"); 26967cc0636SGreg Clayton return error; 27067cc0636SGreg Clayton } 27167cc0636SGreg Clayton } 27267cc0636SGreg Clayton } 273b9c1b51eSKate Stone } else { 274b9c1b51eSKate Stone error.SetErrorString("replace operation takes an array index followed by " 275b9c1b51eSKate Stone "one or more values"); 27667cc0636SGreg Clayton } 27767cc0636SGreg Clayton break; 27867cc0636SGreg Clayton 27967cc0636SGreg Clayton case eVarSetOperationAssign: 28067cc0636SGreg Clayton m_values.clear(); 28167cc0636SGreg Clayton // Fall through to append case 28262e0681aSJason Molenda LLVM_FALLTHROUGH; 28367cc0636SGreg Clayton case eVarSetOperationAppend: 284b9c1b51eSKate Stone for (size_t i = 0; i < argc; ++i) { 285b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 286b9c1b51eSKate Stone args.GetArgumentAtIndex(i), m_type_mask, error)); 287b9c1b51eSKate Stone if (value_sp) { 28867cc0636SGreg Clayton if (error.Fail()) 28967cc0636SGreg Clayton return error; 29067cc0636SGreg Clayton m_value_was_set = true; 29167cc0636SGreg Clayton AppendValue(value_sp); 292b9c1b51eSKate Stone } else { 293b9c1b51eSKate Stone error.SetErrorString( 294b9c1b51eSKate Stone "array of complex types must subclass OptionValueArray"); 29567cc0636SGreg Clayton } 29667cc0636SGreg Clayton } 29767cc0636SGreg Clayton break; 29867cc0636SGreg Clayton } 29967cc0636SGreg Clayton return error; 30067cc0636SGreg Clayton } 30167cc0636SGreg Clayton 302b9c1b51eSKate Stone lldb::OptionValueSP OptionValueArray::DeepCopy() const { 303b9c1b51eSKate Stone OptionValueArray *copied_array = 304b9c1b51eSKate Stone new OptionValueArray(m_type_mask, m_raw_value_dump); 30567cc0636SGreg Clayton lldb::OptionValueSP copied_value_sp(copied_array); 3068f37ca56SIlia K *static_cast<OptionValue *>(copied_array) = *this; 3078f37ca56SIlia K copied_array->m_callback = m_callback; 30867cc0636SGreg Clayton const uint32_t size = m_values.size(); 309b9c1b51eSKate Stone for (uint32_t i = 0; i < size; ++i) { 31067cc0636SGreg Clayton copied_array->AppendValue(m_values[i]->DeepCopy()); 31167cc0636SGreg Clayton } 31267cc0636SGreg Clayton return copied_value_sp; 31367cc0636SGreg Clayton } 314