1 //===-- OptionValueArray.cpp ------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Interpreter/OptionValueArray.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/Stream.h" 17 #include "lldb/Host/StringConvert.h" 18 #include "lldb/Interpreter/Args.h" 19 20 using namespace lldb; 21 using namespace lldb_private; 22 23 void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm, 24 uint32_t dump_mask) { 25 const Type array_element_type = ConvertTypeMaskToType(m_type_mask); 26 if (dump_mask & eDumpOptionType) { 27 if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid)) 28 strm.Printf("(%s of %ss)", GetTypeAsCString(), 29 GetBuiltinTypeAsCString(array_element_type)); 30 else 31 strm.Printf("(%s)", GetTypeAsCString()); 32 } 33 if (dump_mask & eDumpOptionValue) { 34 if (dump_mask & eDumpOptionType) 35 strm.Printf(" =%s", (m_values.size() > 0) ? "\n" : ""); 36 strm.IndentMore(); 37 const uint32_t size = m_values.size(); 38 for (uint32_t i = 0; i < size; ++i) { 39 strm.Indent(); 40 strm.Printf("[%u]: ", i); 41 const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; 42 switch (array_element_type) { 43 default: 44 case eTypeArray: 45 case eTypeDictionary: 46 case eTypeProperties: 47 case eTypeFileSpecList: 48 case eTypePathMap: 49 m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); 50 break; 51 52 case eTypeBoolean: 53 case eTypeChar: 54 case eTypeEnum: 55 case eTypeFileSpec: 56 case eTypeFormat: 57 case eTypeSInt64: 58 case eTypeString: 59 case eTypeUInt64: 60 case eTypeUUID: 61 // No need to show the type for dictionaries of simple items 62 m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | 63 extra_dump_options); 64 break; 65 } 66 if (i < (size - 1)) 67 strm.EOL(); 68 } 69 strm.IndentLess(); 70 } 71 } 72 73 Error OptionValueArray::SetValueFromString(llvm::StringRef value, 74 VarSetOperationType op) { 75 Args args(value.str().c_str()); 76 Error error = SetArgs(args, op); 77 if (error.Success()) 78 NotifyValueChanged(); 79 return error; 80 } 81 82 lldb::OptionValueSP 83 OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx, const char *name, 84 bool will_modify, Error &error) const { 85 if (name && name[0] == '[') { 86 const char *end_bracket = strchr(name + 1, ']'); 87 if (end_bracket) { 88 const char *sub_value = nullptr; 89 if (end_bracket[1]) 90 sub_value = end_bracket + 1; 91 std::string index_str(name + 1, end_bracket); 92 const size_t array_count = m_values.size(); 93 int32_t idx = 94 StringConvert::ToSInt32(index_str.c_str(), INT32_MAX, 0, nullptr); 95 if (idx != INT32_MAX) { 96 ; 97 uint32_t new_idx = UINT32_MAX; 98 if (idx < 0) { 99 // Access from the end of the array if the index is negative 100 new_idx = array_count - idx; 101 } else { 102 // Just a standard index 103 new_idx = idx; 104 } 105 106 if (new_idx < array_count) { 107 if (m_values[new_idx]) { 108 if (sub_value) 109 return m_values[new_idx]->GetSubValue(exe_ctx, sub_value, 110 will_modify, error); 111 else 112 return m_values[new_idx]; 113 } 114 } else { 115 if (array_count == 0) 116 error.SetErrorStringWithFormat( 117 "index %i is not valid for an empty array", idx); 118 else if (idx > 0) 119 error.SetErrorStringWithFormat( 120 "index %i out of range, valid values are 0 through %" PRIu64, 121 idx, (uint64_t)(array_count - 1)); 122 else 123 error.SetErrorStringWithFormat("negative index %i out of range, " 124 "valid values are -1 through " 125 "-%" PRIu64, 126 idx, (uint64_t)array_count); 127 } 128 } 129 } 130 } else { 131 error.SetErrorStringWithFormat( 132 "invalid value path '%s', %s values only support '[<index>]' subvalues " 133 "where <index> is a positive or negative array index", 134 name, GetTypeAsCString()); 135 } 136 return OptionValueSP(); 137 } 138 139 size_t OptionValueArray::GetArgs(Args &args) const { 140 const uint32_t size = m_values.size(); 141 std::vector<const char *> argv; 142 for (uint32_t i = 0; i < size; ++i) { 143 const char *string_value = m_values[i]->GetStringValue(); 144 if (string_value) 145 argv.push_back(string_value); 146 } 147 148 if (argv.empty()) 149 args.Clear(); 150 else 151 args.SetArguments(argv.size(), &argv[0]); 152 return args.GetArgumentCount(); 153 } 154 155 Error OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) { 156 Error error; 157 const size_t argc = args.GetArgumentCount(); 158 switch (op) { 159 case eVarSetOperationInvalid: 160 error.SetErrorString("unsupported operation"); 161 break; 162 163 case eVarSetOperationInsertBefore: 164 case eVarSetOperationInsertAfter: 165 if (argc > 1) { 166 uint32_t idx = 167 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 168 const uint32_t count = GetSize(); 169 if (idx > count) { 170 error.SetErrorStringWithFormat( 171 "invalid insert array index %u, index must be 0 through %u", idx, 172 count); 173 } else { 174 if (op == eVarSetOperationInsertAfter) 175 ++idx; 176 for (size_t i = 1; i < argc; ++i, ++idx) { 177 lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 178 args.GetArgumentAtIndex(i), m_type_mask, error)); 179 if (value_sp) { 180 if (error.Fail()) 181 return error; 182 if (idx >= m_values.size()) 183 m_values.push_back(value_sp); 184 else 185 m_values.insert(m_values.begin() + idx, value_sp); 186 } else { 187 error.SetErrorString( 188 "array of complex types must subclass OptionValueArray"); 189 return error; 190 } 191 } 192 } 193 } else { 194 error.SetErrorString("insert operation takes an array index followed by " 195 "one or more values"); 196 } 197 break; 198 199 case eVarSetOperationRemove: 200 if (argc > 0) { 201 const uint32_t size = m_values.size(); 202 std::vector<int> remove_indexes; 203 bool all_indexes_valid = true; 204 size_t i; 205 for (i = 0; i < argc; ++i) { 206 const size_t idx = 207 StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); 208 if (idx >= size) { 209 all_indexes_valid = false; 210 break; 211 } else 212 remove_indexes.push_back(idx); 213 } 214 215 if (all_indexes_valid) { 216 size_t num_remove_indexes = remove_indexes.size(); 217 if (num_remove_indexes) { 218 // Sort and then erase in reverse so indexes are always valid 219 if (num_remove_indexes > 1) { 220 std::sort(remove_indexes.begin(), remove_indexes.end()); 221 for (std::vector<int>::const_reverse_iterator 222 pos = remove_indexes.rbegin(), 223 end = remove_indexes.rend(); 224 pos != end; ++pos) { 225 m_values.erase(m_values.begin() + *pos); 226 } 227 } else { 228 // Only one index 229 m_values.erase(m_values.begin() + remove_indexes.front()); 230 } 231 } 232 } else { 233 error.SetErrorStringWithFormat( 234 "invalid array index '%s', aborting remove operation", 235 args.GetArgumentAtIndex(i)); 236 } 237 } else { 238 error.SetErrorString("remove operation takes one or more array indices"); 239 } 240 break; 241 242 case eVarSetOperationClear: 243 Clear(); 244 break; 245 246 case eVarSetOperationReplace: 247 if (argc > 1) { 248 uint32_t idx = 249 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 250 const uint32_t count = GetSize(); 251 if (idx > count) { 252 error.SetErrorStringWithFormat( 253 "invalid replace array index %u, index must be 0 through %u", idx, 254 count); 255 } else { 256 for (size_t i = 1; i < argc; ++i, ++idx) { 257 lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 258 args.GetArgumentAtIndex(i), m_type_mask, error)); 259 if (value_sp) { 260 if (error.Fail()) 261 return error; 262 if (idx < count) 263 m_values[idx] = value_sp; 264 else 265 m_values.push_back(value_sp); 266 } else { 267 error.SetErrorString( 268 "array of complex types must subclass OptionValueArray"); 269 return error; 270 } 271 } 272 } 273 } else { 274 error.SetErrorString("replace operation takes an array index followed by " 275 "one or more values"); 276 } 277 break; 278 279 case eVarSetOperationAssign: 280 m_values.clear(); 281 // Fall through to append case 282 LLVM_FALLTHROUGH; 283 case eVarSetOperationAppend: 284 for (size_t i = 0; i < argc; ++i) { 285 lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 286 args.GetArgumentAtIndex(i), m_type_mask, error)); 287 if (value_sp) { 288 if (error.Fail()) 289 return error; 290 m_value_was_set = true; 291 AppendValue(value_sp); 292 } else { 293 error.SetErrorString( 294 "array of complex types must subclass OptionValueArray"); 295 } 296 } 297 break; 298 } 299 return error; 300 } 301 302 lldb::OptionValueSP OptionValueArray::DeepCopy() const { 303 OptionValueArray *copied_array = 304 new OptionValueArray(m_type_mask, m_raw_value_dump); 305 lldb::OptionValueSP copied_value_sp(copied_array); 306 *static_cast<OptionValue *>(copied_array) = *this; 307 copied_array->m_callback = m_callback; 308 const uint32_t size = m_values.size(); 309 for (uint32_t i = 0; i < size; ++i) { 310 copied_array->AppendValue(m_values[i]->DeepCopy()); 311 } 312 return copied_value_sp; 313 } 314