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/Host/StringConvert.h" 17 #include "lldb/Interpreter/Args.h" 18 #include "lldb/Utility/Stream.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 Status OptionValueArray::SetValueFromString(llvm::StringRef value, 74 VarSetOperationType op) { 75 Args args(value.str()); 76 Status 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, 84 llvm::StringRef name, bool will_modify, 85 Status &error) const { 86 if (name.empty() || name.front() != '[') { 87 error.SetErrorStringWithFormat( 88 "invalid value path '%s', %s values only support '[<index>]' subvalues " 89 "where <index> is a positive or negative array index", 90 name.str().c_str(), GetTypeAsCString()); 91 return nullptr; 92 } 93 94 name = name.drop_front(); 95 llvm::StringRef index, sub_value; 96 std::tie(index, sub_value) = name.split(']'); 97 if (index.size() == name.size()) { 98 // Couldn't find a closing bracket 99 return nullptr; 100 } 101 102 const size_t array_count = m_values.size(); 103 int32_t idx = 0; 104 if (index.getAsInteger(0, idx)) 105 return nullptr; 106 107 uint32_t new_idx = UINT32_MAX; 108 if (idx < 0) { 109 // Access from the end of the array if the index is negative 110 new_idx = array_count - idx; 111 } else { 112 // Just a standard index 113 new_idx = idx; 114 } 115 116 if (new_idx < array_count) { 117 if (m_values[new_idx]) { 118 if (!sub_value.empty()) 119 return m_values[new_idx]->GetSubValue(exe_ctx, sub_value, 120 will_modify, error); 121 else 122 return m_values[new_idx]; 123 } 124 } else { 125 if (array_count == 0) 126 error.SetErrorStringWithFormat( 127 "index %i is not valid for an empty array", idx); 128 else if (idx > 0) 129 error.SetErrorStringWithFormat( 130 "index %i out of range, valid values are 0 through %" PRIu64, 131 idx, (uint64_t)(array_count - 1)); 132 else 133 error.SetErrorStringWithFormat("negative index %i out of range, " 134 "valid values are -1 through " 135 "-%" PRIu64, 136 idx, (uint64_t)array_count); 137 } 138 return OptionValueSP(); 139 } 140 141 size_t OptionValueArray::GetArgs(Args &args) const { 142 args.Clear(); 143 const uint32_t size = m_values.size(); 144 for (uint32_t i = 0; i < size; ++i) { 145 llvm::StringRef string_value = m_values[i]->GetStringValue(); 146 if (!string_value.empty()) 147 args.AppendArgument(string_value); 148 } 149 150 return args.GetArgumentCount(); 151 } 152 153 Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) { 154 Status error; 155 const size_t argc = args.GetArgumentCount(); 156 switch (op) { 157 case eVarSetOperationInvalid: 158 error.SetErrorString("unsupported operation"); 159 break; 160 161 case eVarSetOperationInsertBefore: 162 case eVarSetOperationInsertAfter: 163 if (argc > 1) { 164 uint32_t idx = 165 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 166 const uint32_t count = GetSize(); 167 if (idx > count) { 168 error.SetErrorStringWithFormat( 169 "invalid insert array index %u, index must be 0 through %u", idx, 170 count); 171 } else { 172 if (op == eVarSetOperationInsertAfter) 173 ++idx; 174 for (size_t i = 1; i < argc; ++i, ++idx) { 175 lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 176 args.GetArgumentAtIndex(i), m_type_mask, error)); 177 if (value_sp) { 178 if (error.Fail()) 179 return error; 180 if (idx >= m_values.size()) 181 m_values.push_back(value_sp); 182 else 183 m_values.insert(m_values.begin() + idx, value_sp); 184 } else { 185 error.SetErrorString( 186 "array of complex types must subclass OptionValueArray"); 187 return error; 188 } 189 } 190 } 191 } else { 192 error.SetErrorString("insert operation takes an array index followed by " 193 "one or more values"); 194 } 195 break; 196 197 case eVarSetOperationRemove: 198 if (argc > 0) { 199 const uint32_t size = m_values.size(); 200 std::vector<int> remove_indexes; 201 bool all_indexes_valid = true; 202 size_t i; 203 for (i = 0; i < argc; ++i) { 204 const size_t idx = 205 StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); 206 if (idx >= size) { 207 all_indexes_valid = false; 208 break; 209 } else 210 remove_indexes.push_back(idx); 211 } 212 213 if (all_indexes_valid) { 214 size_t num_remove_indexes = remove_indexes.size(); 215 if (num_remove_indexes) { 216 // Sort and then erase in reverse so indexes are always valid 217 if (num_remove_indexes > 1) { 218 std::sort(remove_indexes.begin(), remove_indexes.end()); 219 for (std::vector<int>::const_reverse_iterator 220 pos = remove_indexes.rbegin(), 221 end = remove_indexes.rend(); 222 pos != end; ++pos) { 223 m_values.erase(m_values.begin() + *pos); 224 } 225 } else { 226 // Only one index 227 m_values.erase(m_values.begin() + remove_indexes.front()); 228 } 229 } 230 } else { 231 error.SetErrorStringWithFormat( 232 "invalid array index '%s', aborting remove operation", 233 args.GetArgumentAtIndex(i)); 234 } 235 } else { 236 error.SetErrorString("remove operation takes one or more array indices"); 237 } 238 break; 239 240 case eVarSetOperationClear: 241 Clear(); 242 break; 243 244 case eVarSetOperationReplace: 245 if (argc > 1) { 246 uint32_t idx = 247 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 248 const uint32_t count = GetSize(); 249 if (idx > count) { 250 error.SetErrorStringWithFormat( 251 "invalid replace array index %u, index must be 0 through %u", idx, 252 count); 253 } else { 254 for (size_t i = 1; i < argc; ++i, ++idx) { 255 lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 256 args.GetArgumentAtIndex(i), m_type_mask, error)); 257 if (value_sp) { 258 if (error.Fail()) 259 return error; 260 if (idx < count) 261 m_values[idx] = value_sp; 262 else 263 m_values.push_back(value_sp); 264 } else { 265 error.SetErrorString( 266 "array of complex types must subclass OptionValueArray"); 267 return error; 268 } 269 } 270 } 271 } else { 272 error.SetErrorString("replace operation takes an array index followed by " 273 "one or more values"); 274 } 275 break; 276 277 case eVarSetOperationAssign: 278 m_values.clear(); 279 // Fall through to append case 280 LLVM_FALLTHROUGH; 281 case eVarSetOperationAppend: 282 for (size_t i = 0; i < argc; ++i) { 283 lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( 284 args.GetArgumentAtIndex(i), m_type_mask, error)); 285 if (value_sp) { 286 if (error.Fail()) 287 return error; 288 m_value_was_set = true; 289 AppendValue(value_sp); 290 } else { 291 error.SetErrorString( 292 "array of complex types must subclass OptionValueArray"); 293 } 294 } 295 break; 296 } 297 return error; 298 } 299 300 lldb::OptionValueSP OptionValueArray::DeepCopy() const { 301 OptionValueArray *copied_array = 302 new OptionValueArray(m_type_mask, m_raw_value_dump); 303 lldb::OptionValueSP copied_value_sp(copied_array); 304 *static_cast<OptionValue *>(copied_array) = *this; 305 copied_array->m_callback = m_callback; 306 const uint32_t size = m_values.size(); 307 for (uint32_t i = 0; i < size; ++i) { 308 copied_array->AppendValue(m_values[i]->DeepCopy()); 309 } 310 return copied_value_sp; 311 } 312