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