//===-- OptionValueArray.cpp ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Interpreter/OptionValueArray.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/Stream.h" #include "lldb/Interpreter/Args.h" using namespace lldb; using namespace lldb_private; void OptionValueArray::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) { const Type array_element_type = ConvertTypeMaskToType (m_type_mask); if (dump_mask & eDumpOptionType) { if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid)) strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(array_element_type)); else strm.Printf ("(%s)", GetTypeAsCString()); } if (dump_mask & eDumpOptionValue) { if (dump_mask & eDumpOptionType) strm.Printf (" =%s", (m_values.size() > 0) ? "\n" : ""); strm.IndentMore(); const uint32_t size = m_values.size(); for (uint32_t i = 0; i<size; ++i) { strm.Indent(); strm.Printf("[%u]: ", i); const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; switch (array_element_type) { default: case eTypeArray: case eTypeDictionary: case eTypeProperties: case eTypeFileSpecList: case eTypePathMap: m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); break; case eTypeBoolean: case eTypeEnum: case eTypeFileSpec: case eTypeFormat: case eTypeSInt64: case eTypeString: case eTypeUInt64: case eTypeUUID: // No need to show the type for dictionaries of simple items m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options); break; } if (i < (size - 1)) strm.EOL(); } strm.IndentLess(); } } Error OptionValueArray::SetValueFromCString (const char *value, VarSetOperationType op) { Args args(value); return SetArgs (args, op); } lldb::OptionValueSP OptionValueArray::GetSubValue (const ExecutionContext *exe_ctx, const char *name, bool will_modify, Error &error) const { if (name && name[0] == '[') { const char *end_bracket = strchr (name+1, ']'); if (end_bracket) { const char *sub_value = NULL; if (end_bracket[1]) sub_value = end_bracket + 1; std::string index_str (name+1, end_bracket); const size_t array_count = m_values.size(); int32_t idx = Args::StringToSInt32(index_str.c_str(), INT32_MAX, 0, NULL); if (idx != INT32_MAX) { ; uint32_t new_idx = UINT32_MAX; if (idx < 0) { // Access from the end of the array if the index is negative new_idx = array_count - idx; } else { // Just a standard index new_idx = idx; } if (new_idx < array_count) { if (m_values[new_idx]) { if (sub_value) return m_values[new_idx]->GetSubValue (exe_ctx, sub_value, will_modify, error); else return m_values[new_idx]; } } else { if (array_count == 0) error.SetErrorStringWithFormat("index %i is not valid for an empty array", idx); else if (idx > 0) error.SetErrorStringWithFormat("index %i out of range, valid values are 0 through %" PRIu64, idx, (uint64_t)(array_count - 1)); else error.SetErrorStringWithFormat("negative index %i out of range, valid values are -1 through -%" PRIu64, idx, (uint64_t)array_count); } } } } else { error.SetErrorStringWithFormat("invalid value path '%s', %s values only support '[<index>]' subvalues where <index> is a positive or negative array index", name, GetTypeAsCString()); } return OptionValueSP(); } size_t OptionValueArray::GetArgs (Args &args) const { const uint32_t size = m_values.size(); std::vector<const char *> argv; for (uint32_t i = 0; i<size; ++i) { const char *string_value = m_values[i]->GetStringValue (); if (string_value) argv.push_back(string_value); } if (argv.empty()) args.Clear(); else args.SetArguments(argv.size(), &argv[0]); return args.GetArgumentCount(); } Error OptionValueArray::SetArgs (const Args &args, VarSetOperationType op) { Error error; const size_t argc = args.GetArgumentCount(); switch (op) { case eVarSetOperationInvalid: error.SetErrorString("unsupported operation"); break; case eVarSetOperationInsertBefore: case eVarSetOperationInsertAfter: if (argc > 1) { uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); const uint32_t count = GetSize(); if (idx > count) { error.SetErrorStringWithFormat("invalid insert array index %u, index must be 0 through %u", idx, count); } else { if (op == eVarSetOperationInsertAfter) ++idx; for (size_t i=1; i<argc; ++i, ++idx) { lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), m_type_mask, error)); if (value_sp) { if (error.Fail()) return error; if (idx >= m_values.size()) m_values.push_back(value_sp); else m_values.insert(m_values.begin() + idx, value_sp); } else { error.SetErrorString("array of complex types must subclass OptionValueArray"); return error; } } } } else { error.SetErrorString("insert operation takes an array index followed by one or more values"); } break; case eVarSetOperationRemove: if (argc > 0) { const uint32_t size = m_values.size(); std::vector<int> remove_indexes; bool all_indexes_valid = true; size_t i; for (i=0; i<argc; ++i) { const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); if (idx >= size) { all_indexes_valid = false; break; } else remove_indexes.push_back(idx); } if (all_indexes_valid) { size_t num_remove_indexes = remove_indexes.size(); if (num_remove_indexes) { // Sort and then erase in reverse so indexes are always valid if (num_remove_indexes > 1) { std::sort(remove_indexes.begin(), remove_indexes.end()); for (std::vector<int>::const_reverse_iterator pos = remove_indexes.rbegin(), end = remove_indexes.rend(); pos != end; ++pos) { m_values.erase(m_values.begin() + *pos); } } else { // Only one index m_values.erase(m_values.begin() + remove_indexes.front()); } } } else { error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i)); } } else { error.SetErrorString("remove operation takes one or more array indices"); } break; case eVarSetOperationClear: Clear (); break; case eVarSetOperationReplace: if (argc > 1) { uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); const uint32_t count = GetSize(); if (idx > count) { error.SetErrorStringWithFormat("invalid replace array index %u, index must be 0 through %u", idx, count); } else { for (size_t i=1; i<argc; ++i, ++idx) { lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), m_type_mask, error)); if (value_sp) { if (error.Fail()) return error; if (idx < count) m_values[idx] = value_sp; else m_values.push_back(value_sp); } else { error.SetErrorString("array of complex types must subclass OptionValueArray"); return error; } } } } else { error.SetErrorString("replace operation takes an array index followed by one or more values"); } break; case eVarSetOperationAssign: m_values.clear(); // Fall through to append case case eVarSetOperationAppend: for (size_t i=0; i<argc; ++i) { lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i), m_type_mask, error)); if (value_sp) { if (error.Fail()) return error; m_value_was_set = true; AppendValue(value_sp); } else { error.SetErrorString("array of complex types must subclass OptionValueArray"); } } break; } return error; } lldb::OptionValueSP OptionValueArray::DeepCopy () const { OptionValueArray *copied_array = new OptionValueArray (m_type_mask, m_raw_value_dump); lldb::OptionValueSP copied_value_sp(copied_array); const uint32_t size = m_values.size(); for (uint32_t i = 0; i<size; ++i) { copied_array->AppendValue (m_values[i]->DeepCopy()); } return copied_value_sp; }