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 165275aaa0SVince Harron #include "lldb/Host/StringConvert.h" 17145d95c9SPavel Labath #include "lldb/Utility/Args.h" 18bf9a7730SZachary Turner #include "lldb/Utility/Stream.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) { 34*b76e25a2SJonas Devlieghere const bool one_line = dump_mask & eDumpOptionCommand; 3567cc0636SGreg Clayton const uint32_t size = m_values.size(); 36*b76e25a2SJonas Devlieghere if (dump_mask & eDumpOptionType) 37*b76e25a2SJonas Devlieghere strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : ""); 38*b76e25a2SJonas Devlieghere if (!one_line) 39*b76e25a2SJonas Devlieghere strm.IndentMore(); 40b9c1b51eSKate Stone for (uint32_t i = 0; i < size; ++i) { 41*b76e25a2SJonas Devlieghere if (!one_line) { 4267cc0636SGreg Clayton strm.Indent(); 4367cc0636SGreg Clayton strm.Printf("[%u]: ", i); 44*b76e25a2SJonas Devlieghere } 4567cc0636SGreg Clayton const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; 46b9c1b51eSKate Stone switch (array_element_type) { 4767cc0636SGreg Clayton default: 4867cc0636SGreg Clayton case eTypeArray: 4967cc0636SGreg Clayton case eTypeDictionary: 5067cc0636SGreg Clayton case eTypeProperties: 5167cc0636SGreg Clayton case eTypeFileSpecList: 5267cc0636SGreg Clayton case eTypePathMap: 5367cc0636SGreg Clayton m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); 5467cc0636SGreg Clayton break; 5567cc0636SGreg Clayton 5667cc0636SGreg Clayton case eTypeBoolean: 573e7442b6SZachary Turner case eTypeChar: 5867cc0636SGreg Clayton case eTypeEnum: 5967cc0636SGreg Clayton case eTypeFileSpec: 6067cc0636SGreg Clayton case eTypeFormat: 6167cc0636SGreg Clayton case eTypeSInt64: 6267cc0636SGreg Clayton case eTypeString: 6367cc0636SGreg Clayton case eTypeUInt64: 6467cc0636SGreg Clayton case eTypeUUID: 6567cc0636SGreg Clayton // No need to show the type for dictionaries of simple items 66b9c1b51eSKate Stone m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | 67b9c1b51eSKate Stone extra_dump_options); 6867cc0636SGreg Clayton break; 6967cc0636SGreg Clayton } 70*b76e25a2SJonas Devlieghere 71*b76e25a2SJonas Devlieghere if (!one_line) { 7267cc0636SGreg Clayton if (i < (size - 1)) 7367cc0636SGreg Clayton strm.EOL(); 74*b76e25a2SJonas Devlieghere } else { 75*b76e25a2SJonas Devlieghere strm << ' '; 7667cc0636SGreg Clayton } 77*b76e25a2SJonas Devlieghere } 78*b76e25a2SJonas Devlieghere if (!one_line) 7967cc0636SGreg Clayton strm.IndentLess(); 8067cc0636SGreg Clayton } 8167cc0636SGreg Clayton } 8267cc0636SGreg Clayton 8397206d57SZachary Turner Status OptionValueArray::SetValueFromString(llvm::StringRef value, 84b9c1b51eSKate Stone VarSetOperationType op) { 85771ef6d4SMalcolm Parsons Args args(value.str()); 8697206d57SZachary Turner Status error = SetArgs(args, op); 878f37ca56SIlia K if (error.Success()) 88332e8b1cSGreg Clayton NotifyValueChanged(); 898f37ca56SIlia K return error; 9067cc0636SGreg Clayton } 9167cc0636SGreg Clayton 9267cc0636SGreg Clayton lldb::OptionValueSP 9397206d57SZachary Turner OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx, 9497206d57SZachary Turner llvm::StringRef name, bool will_modify, 9597206d57SZachary Turner Status &error) const { 9631d97a5cSZachary Turner if (name.empty() || name.front() != '[') { 9731d97a5cSZachary Turner error.SetErrorStringWithFormat( 9831d97a5cSZachary Turner "invalid value path '%s', %s values only support '[<index>]' subvalues " 9931d97a5cSZachary Turner "where <index> is a positive or negative array index", 10031d97a5cSZachary Turner name.str().c_str(), GetTypeAsCString()); 10131d97a5cSZachary Turner return nullptr; 10231d97a5cSZachary Turner } 10331d97a5cSZachary Turner 10431d97a5cSZachary Turner name = name.drop_front(); 10531d97a5cSZachary Turner llvm::StringRef index, sub_value; 10631d97a5cSZachary Turner std::tie(index, sub_value) = name.split(']'); 10731d97a5cSZachary Turner if (index.size() == name.size()) { 10831d97a5cSZachary Turner // Couldn't find a closing bracket 10931d97a5cSZachary Turner return nullptr; 11031d97a5cSZachary Turner } 11131d97a5cSZachary Turner 11267cc0636SGreg Clayton const size_t array_count = m_values.size(); 11331d97a5cSZachary Turner int32_t idx = 0; 11431d97a5cSZachary Turner if (index.getAsInteger(0, idx)) 11531d97a5cSZachary Turner return nullptr; 11631d97a5cSZachary Turner 11767cc0636SGreg Clayton uint32_t new_idx = UINT32_MAX; 118b9c1b51eSKate Stone if (idx < 0) { 11967cc0636SGreg Clayton // Access from the end of the array if the index is negative 12067cc0636SGreg Clayton new_idx = array_count - idx; 121b9c1b51eSKate Stone } else { 12267cc0636SGreg Clayton // Just a standard index 12367cc0636SGreg Clayton new_idx = idx; 12467cc0636SGreg Clayton } 12567cc0636SGreg Clayton 126b9c1b51eSKate Stone if (new_idx < array_count) { 127b9c1b51eSKate Stone if (m_values[new_idx]) { 12831d97a5cSZachary Turner if (!sub_value.empty()) 129b9c1b51eSKate Stone return m_values[new_idx]->GetSubValue(exe_ctx, sub_value, 130b9c1b51eSKate Stone will_modify, error); 13167cc0636SGreg Clayton else 13267cc0636SGreg Clayton return m_values[new_idx]; 13367cc0636SGreg Clayton } 134b9c1b51eSKate Stone } else { 13567cc0636SGreg Clayton if (array_count == 0) 136b9c1b51eSKate Stone error.SetErrorStringWithFormat( 137b9c1b51eSKate Stone "index %i is not valid for an empty array", idx); 13867cc0636SGreg Clayton else if (idx > 0) 139b9c1b51eSKate Stone error.SetErrorStringWithFormat( 140b9c1b51eSKate Stone "index %i out of range, valid values are 0 through %" PRIu64, 141b9c1b51eSKate Stone idx, (uint64_t)(array_count - 1)); 14267cc0636SGreg Clayton else 143b9c1b51eSKate Stone error.SetErrorStringWithFormat("negative index %i out of range, " 144b9c1b51eSKate Stone "valid values are -1 through " 145b9c1b51eSKate Stone "-%" PRIu64, 146b9c1b51eSKate Stone idx, (uint64_t)array_count); 14767cc0636SGreg Clayton } 14867cc0636SGreg Clayton return OptionValueSP(); 14967cc0636SGreg Clayton } 15067cc0636SGreg Clayton 151b9c1b51eSKate Stone size_t OptionValueArray::GetArgs(Args &args) const { 15231d97a5cSZachary Turner args.Clear(); 15367cc0636SGreg Clayton const uint32_t size = m_values.size(); 154b9c1b51eSKate Stone for (uint32_t i = 0; i < size; ++i) { 15531d97a5cSZachary Turner llvm::StringRef string_value = m_values[i]->GetStringValue(); 15631d97a5cSZachary Turner if (!string_value.empty()) 15731d97a5cSZachary Turner args.AppendArgument(string_value); 15867cc0636SGreg Clayton } 15967cc0636SGreg Clayton 16067cc0636SGreg Clayton return args.GetArgumentCount(); 16167cc0636SGreg Clayton } 16267cc0636SGreg Clayton 16397206d57SZachary Turner Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) { 16497206d57SZachary Turner Status error; 16567cc0636SGreg Clayton const size_t argc = args.GetArgumentCount(); 166b9c1b51eSKate Stone switch (op) { 16767cc0636SGreg Clayton case eVarSetOperationInvalid: 16867cc0636SGreg Clayton error.SetErrorString("unsupported operation"); 16967cc0636SGreg Clayton break; 17067cc0636SGreg Clayton 17167cc0636SGreg Clayton case eVarSetOperationInsertBefore: 17267cc0636SGreg Clayton case eVarSetOperationInsertAfter: 173b9c1b51eSKate Stone if (argc > 1) { 174b9c1b51eSKate Stone uint32_t idx = 175b9c1b51eSKate Stone StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 17667cc0636SGreg Clayton const uint32_t count = GetSize(); 177b9c1b51eSKate Stone if (idx > count) { 178b9c1b51eSKate Stone error.SetErrorStringWithFormat( 179b9c1b51eSKate Stone "invalid insert array index %u, index must be 0 through %u", idx, 180b9c1b51eSKate Stone count); 181b9c1b51eSKate Stone } else { 18267cc0636SGreg Clayton if (op == eVarSetOperationInsertAfter) 18367cc0636SGreg Clayton ++idx; 184b9c1b51eSKate Stone for (size_t i = 1; i < argc; ++i, ++idx) { 185b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 186b9c1b51eSKate Stone args.GetArgumentAtIndex(i), m_type_mask, error)); 187b9c1b51eSKate Stone if (value_sp) { 18867cc0636SGreg Clayton if (error.Fail()) 18967cc0636SGreg Clayton return error; 19067cc0636SGreg Clayton if (idx >= m_values.size()) 19167cc0636SGreg Clayton m_values.push_back(value_sp); 19267cc0636SGreg Clayton else 19367cc0636SGreg Clayton m_values.insert(m_values.begin() + idx, value_sp); 194b9c1b51eSKate Stone } else { 195b9c1b51eSKate Stone error.SetErrorString( 196b9c1b51eSKate Stone "array of complex types must subclass OptionValueArray"); 19767cc0636SGreg Clayton return error; 19867cc0636SGreg Clayton } 19967cc0636SGreg Clayton } 20067cc0636SGreg Clayton } 201b9c1b51eSKate Stone } else { 202b9c1b51eSKate Stone error.SetErrorString("insert operation takes an array index followed by " 203b9c1b51eSKate Stone "one or more values"); 20467cc0636SGreg Clayton } 20567cc0636SGreg Clayton break; 20667cc0636SGreg Clayton 20767cc0636SGreg Clayton case eVarSetOperationRemove: 208b9c1b51eSKate Stone if (argc > 0) { 20967cc0636SGreg Clayton const uint32_t size = m_values.size(); 21067cc0636SGreg Clayton std::vector<int> remove_indexes; 21167cc0636SGreg Clayton bool all_indexes_valid = true; 21267cc0636SGreg Clayton size_t i; 213b9c1b51eSKate Stone for (i = 0; i < argc; ++i) { 2143985c8c6SSaleem Abdulrasool const size_t idx = 2155275aaa0SVince Harron StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); 216b9c1b51eSKate Stone if (idx >= size) { 21767cc0636SGreg Clayton all_indexes_valid = false; 21867cc0636SGreg Clayton break; 219b9c1b51eSKate Stone } else 22067cc0636SGreg Clayton remove_indexes.push_back(idx); 22167cc0636SGreg Clayton } 22267cc0636SGreg Clayton 223b9c1b51eSKate Stone if (all_indexes_valid) { 22467cc0636SGreg Clayton size_t num_remove_indexes = remove_indexes.size(); 225b9c1b51eSKate Stone if (num_remove_indexes) { 22667cc0636SGreg Clayton // Sort and then erase in reverse so indexes are always valid 227b9c1b51eSKate Stone if (num_remove_indexes > 1) { 22867cc0636SGreg Clayton std::sort(remove_indexes.begin(), remove_indexes.end()); 229b9c1b51eSKate Stone for (std::vector<int>::const_reverse_iterator 230b9c1b51eSKate Stone pos = remove_indexes.rbegin(), 231b9c1b51eSKate Stone end = remove_indexes.rend(); 232b9c1b51eSKate Stone pos != end; ++pos) { 23367cc0636SGreg Clayton m_values.erase(m_values.begin() + *pos); 23467cc0636SGreg Clayton } 235b9c1b51eSKate Stone } else { 23667cc0636SGreg Clayton // Only one index 23767cc0636SGreg Clayton m_values.erase(m_values.begin() + remove_indexes.front()); 23867cc0636SGreg Clayton } 23967cc0636SGreg Clayton } 240b9c1b51eSKate Stone } else { 241b9c1b51eSKate Stone error.SetErrorStringWithFormat( 242b9c1b51eSKate Stone "invalid array index '%s', aborting remove operation", 243b9c1b51eSKate Stone args.GetArgumentAtIndex(i)); 24467cc0636SGreg Clayton } 245b9c1b51eSKate Stone } else { 24667cc0636SGreg Clayton error.SetErrorString("remove operation takes one or more array indices"); 24767cc0636SGreg Clayton } 24867cc0636SGreg Clayton break; 24967cc0636SGreg Clayton 25067cc0636SGreg Clayton case eVarSetOperationClear: 25167cc0636SGreg Clayton Clear(); 25267cc0636SGreg Clayton break; 25367cc0636SGreg Clayton 25467cc0636SGreg Clayton case eVarSetOperationReplace: 255b9c1b51eSKate Stone if (argc > 1) { 256b9c1b51eSKate Stone uint32_t idx = 257b9c1b51eSKate Stone StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 25867cc0636SGreg Clayton const uint32_t count = GetSize(); 259b9c1b51eSKate Stone if (idx > count) { 260b9c1b51eSKate Stone error.SetErrorStringWithFormat( 261b9c1b51eSKate Stone "invalid replace array index %u, index must be 0 through %u", idx, 262b9c1b51eSKate Stone count); 263b9c1b51eSKate Stone } else { 264b9c1b51eSKate Stone for (size_t i = 1; i < argc; ++i, ++idx) { 265b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 266b9c1b51eSKate Stone args.GetArgumentAtIndex(i), m_type_mask, error)); 267b9c1b51eSKate Stone if (value_sp) { 26867cc0636SGreg Clayton if (error.Fail()) 26967cc0636SGreg Clayton return error; 27067cc0636SGreg Clayton if (idx < count) 27167cc0636SGreg Clayton m_values[idx] = value_sp; 27267cc0636SGreg Clayton else 27367cc0636SGreg Clayton m_values.push_back(value_sp); 274b9c1b51eSKate Stone } else { 275b9c1b51eSKate Stone error.SetErrorString( 276b9c1b51eSKate Stone "array of complex types must subclass OptionValueArray"); 27767cc0636SGreg Clayton return error; 27867cc0636SGreg Clayton } 27967cc0636SGreg Clayton } 28067cc0636SGreg Clayton } 281b9c1b51eSKate Stone } else { 282b9c1b51eSKate Stone error.SetErrorString("replace operation takes an array index followed by " 283b9c1b51eSKate Stone "one or more values"); 28467cc0636SGreg Clayton } 28567cc0636SGreg Clayton break; 28667cc0636SGreg Clayton 28767cc0636SGreg Clayton case eVarSetOperationAssign: 28867cc0636SGreg Clayton m_values.clear(); 28967cc0636SGreg Clayton // Fall through to append case 29062e0681aSJason Molenda LLVM_FALLTHROUGH; 29167cc0636SGreg Clayton case eVarSetOperationAppend: 292b9c1b51eSKate Stone for (size_t i = 0; i < argc; ++i) { 293b9c1b51eSKate Stone lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 294b9c1b51eSKate Stone args.GetArgumentAtIndex(i), m_type_mask, error)); 295b9c1b51eSKate Stone if (value_sp) { 29667cc0636SGreg Clayton if (error.Fail()) 29767cc0636SGreg Clayton return error; 29867cc0636SGreg Clayton m_value_was_set = true; 29967cc0636SGreg Clayton AppendValue(value_sp); 300b9c1b51eSKate Stone } else { 301b9c1b51eSKate Stone error.SetErrorString( 302b9c1b51eSKate Stone "array of complex types must subclass OptionValueArray"); 30367cc0636SGreg Clayton } 30467cc0636SGreg Clayton } 30567cc0636SGreg Clayton break; 30667cc0636SGreg Clayton } 30767cc0636SGreg Clayton return error; 30867cc0636SGreg Clayton } 30967cc0636SGreg Clayton 310b9c1b51eSKate Stone lldb::OptionValueSP OptionValueArray::DeepCopy() const { 311b9c1b51eSKate Stone OptionValueArray *copied_array = 312b9c1b51eSKate Stone new OptionValueArray(m_type_mask, m_raw_value_dump); 31367cc0636SGreg Clayton lldb::OptionValueSP copied_value_sp(copied_array); 3148f37ca56SIlia K *static_cast<OptionValue *>(copied_array) = *this; 3158f37ca56SIlia K copied_array->m_callback = m_callback; 31667cc0636SGreg Clayton const uint32_t size = m_values.size(); 317b9c1b51eSKate Stone for (uint32_t i = 0; i < size; ++i) { 31867cc0636SGreg Clayton copied_array->AppendValue(m_values[i]->DeepCopy()); 31967cc0636SGreg Clayton } 32067cc0636SGreg Clayton return copied_value_sp; 32167cc0636SGreg Clayton } 322