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