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