1 //===-- OptionValueDictionary.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/lldb-python.h" 11 12 #include "lldb/Interpreter/OptionValueDictionary.h" 13 14 // C Includes 15 // C++ Includes 16 // Other libraries and framework includes 17 #include "llvm/ADT/StringRef.h" 18 // Project includes 19 #include "lldb/Core/State.h" 20 #include "lldb/DataFormatters/FormatManager.h" 21 #include "lldb/Interpreter/Args.h" 22 #include "lldb/Interpreter/OptionValueString.h" 23 24 using namespace lldb; 25 using namespace lldb_private; 26 27 void 28 OptionValueDictionary::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) 29 { 30 const Type dict_type = ConvertTypeMaskToType (m_type_mask); 31 if (dump_mask & eDumpOptionType) 32 { 33 if (m_type_mask != eTypeInvalid) 34 strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(dict_type)); 35 else 36 strm.Printf ("(%s)", GetTypeAsCString()); 37 } 38 if (dump_mask & eDumpOptionValue) 39 { 40 if (dump_mask & eDumpOptionType) 41 strm.PutCString (" ="); 42 43 collection::iterator pos, end = m_values.end(); 44 45 strm.IndentMore(); 46 47 for (pos = m_values.begin(); pos != end; ++pos) 48 { 49 OptionValue *option_value = pos->second.get(); 50 strm.EOL(); 51 strm.Indent(pos->first.GetCString()); 52 53 const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; 54 switch (dict_type) 55 { 56 default: 57 case eTypeArray: 58 case eTypeDictionary: 59 case eTypeProperties: 60 case eTypeFileSpecList: 61 case eTypePathMap: 62 strm.PutChar (' '); 63 option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); 64 break; 65 66 case eTypeBoolean: 67 case eTypeChar: 68 case eTypeEnum: 69 case eTypeFileSpec: 70 case eTypeFormat: 71 case eTypeSInt64: 72 case eTypeString: 73 case eTypeUInt64: 74 case eTypeUUID: 75 // No need to show the type for dictionaries of simple items 76 strm.PutCString("="); 77 option_value->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options); 78 break; 79 } 80 } 81 strm.IndentLess(); 82 } 83 84 } 85 86 size_t 87 OptionValueDictionary::GetArgs (Args &args) const 88 { 89 args.Clear(); 90 collection::const_iterator pos, end = m_values.end(); 91 for (pos = m_values.begin(); pos != end; ++pos) 92 { 93 StreamString strm; 94 strm.Printf("%s=", pos->first.GetCString()); 95 pos->second->DumpValue(nullptr, strm, eDumpOptionValue|eDumpOptionRaw); 96 args.AppendArgument(strm.GetString().c_str()); 97 } 98 return args.GetArgumentCount(); 99 } 100 101 Error 102 OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op) 103 { 104 Error error; 105 const size_t argc = args.GetArgumentCount(); 106 switch (op) 107 { 108 case eVarSetOperationClear: 109 Clear(); 110 break; 111 112 case eVarSetOperationAppend: 113 case eVarSetOperationReplace: 114 case eVarSetOperationAssign: 115 if (argc > 0) 116 { 117 for (size_t i=0; i<argc; ++i) 118 { 119 llvm::StringRef key_and_value(args.GetArgumentAtIndex(i)); 120 if (!key_and_value.empty()) 121 { 122 std::pair<llvm::StringRef, llvm::StringRef> kvp(key_and_value.split('=')); 123 llvm::StringRef key = kvp.first; 124 bool key_valid = false; 125 if (!key.empty()) 126 { 127 if (key.front() == '[') 128 { 129 // Key name starts with '[', so the the key value must be in single or double quotes like: 130 // ['<key>'] 131 // ["<key>"] 132 if ((key.size() > 2) && (key.back() == ']')) 133 { 134 // Strip leading '[' and trailing ']' 135 key = key.substr(1, key.size()-2); 136 const char quote_char = key.front(); 137 if ((quote_char == '\'') || (quote_char == '"')) 138 { 139 if ((key.size() > 2) && (key.back() == quote_char)) 140 { 141 // Strip the quotes 142 key = key.substr(1, key.size()-2); 143 key_valid = true; 144 } 145 } 146 else 147 { 148 // square brackets, no quotes 149 key_valid = true; 150 } 151 } 152 } 153 else 154 { 155 // No square brackets or quotes 156 key_valid = true; 157 } 158 } 159 if (!key_valid) 160 { 161 error.SetErrorStringWithFormat("invalid key \"%s\", the key must be a bare string or surrounded by brackets with optional quotes: [<key>] or ['<key>'] or [\"<key>\"]", kvp.first.str().c_str()); 162 return error; 163 } 164 165 lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (kvp.second.data(), 166 m_type_mask, 167 error)); 168 if (value_sp) 169 { 170 if (error.Fail()) 171 return error; 172 m_value_was_set = true; 173 SetValueForKey (ConstString(key), value_sp, true); 174 } 175 else 176 { 177 error.SetErrorString("dictionaries that can contain multiple types must subclass OptionValueArray"); 178 } 179 } 180 else 181 { 182 error.SetErrorString("empty argument"); 183 } 184 } 185 } 186 else 187 { 188 error.SetErrorString("assign operation takes one or more key=value arguments"); 189 } 190 break; 191 192 case eVarSetOperationRemove: 193 if (argc > 0) 194 { 195 for (size_t i=0; i<argc; ++i) 196 { 197 ConstString key(args.GetArgumentAtIndex(i)); 198 if (!DeleteValueForKey(key)) 199 { 200 error.SetErrorStringWithFormat("no value found named '%s', aborting remove operation", key.GetCString()); 201 break; 202 } 203 } 204 } 205 else 206 { 207 error.SetErrorString("remove operation takes one or more key arguments"); 208 } 209 break; 210 211 case eVarSetOperationInsertBefore: 212 case eVarSetOperationInsertAfter: 213 case eVarSetOperationInvalid: 214 error = OptionValue::SetValueFromString (llvm::StringRef(), op); 215 break; 216 } 217 return error; 218 } 219 220 Error 221 OptionValueDictionary::SetValueFromString (llvm::StringRef value, VarSetOperationType op) 222 { 223 Args args(value.str().c_str()); 224 Error error = SetArgs (args, op); 225 if (error.Success()) 226 NotifyValueChanged(); 227 return error; 228 } 229 230 lldb::OptionValueSP 231 OptionValueDictionary::GetSubValue (const ExecutionContext *exe_ctx, const char *name, bool will_modify, Error &error) const 232 { 233 lldb::OptionValueSP value_sp; 234 235 if (name && name[0]) 236 { 237 const char *sub_name = nullptr; 238 ConstString key; 239 const char *open_bracket = ::strchr (name, '['); 240 241 if (open_bracket) 242 { 243 const char *key_start = open_bracket + 1; 244 const char *key_end = nullptr; 245 switch (open_bracket[1]) 246 { 247 case '\'': 248 ++key_start; 249 key_end = strchr(key_start, '\''); 250 if (key_end) 251 { 252 if (key_end[1] == ']') 253 { 254 if (key_end[2]) 255 sub_name = key_end + 2; 256 } 257 else 258 { 259 error.SetErrorStringWithFormat ("invalid value path '%s', single quoted key names must be formatted as ['<key>'] where <key> is a string that doesn't contain quotes", name); 260 return value_sp; 261 } 262 } 263 else 264 { 265 error.SetErrorString ("missing '] key name terminator, key name started with ['"); 266 return value_sp; 267 } 268 break; 269 case '"': 270 ++key_start; 271 key_end = strchr(key_start, '"'); 272 if (key_end) 273 { 274 if (key_end[1] == ']') 275 { 276 if (key_end[2]) 277 sub_name = key_end + 2; 278 break; 279 } 280 error.SetErrorStringWithFormat ("invalid value path '%s', double quoted key names must be formatted as [\"<key>\"] where <key> is a string that doesn't contain quotes", name); 281 return value_sp; 282 } 283 else 284 { 285 error.SetErrorString ("missing \"] key name terminator, key name started with [\""); 286 return value_sp; 287 } 288 break; 289 290 default: 291 key_end = strchr(key_start, ']'); 292 if (key_end) 293 { 294 if (key_end[1]) 295 sub_name = key_end + 1; 296 } 297 else 298 { 299 error.SetErrorString ("missing ] key name terminator, key name started with ["); 300 return value_sp; 301 } 302 break; 303 } 304 305 if (key_start && key_end) 306 { 307 key.SetCStringWithLength (key_start, key_end - key_start); 308 309 value_sp = GetValueForKey (key); 310 if (value_sp) 311 { 312 if (sub_name) 313 return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error); 314 } 315 else 316 { 317 error.SetErrorStringWithFormat("dictionary does not contain a value for the key name '%s'", key.GetCString()); 318 } 319 } 320 } 321 if (!value_sp && error.AsCString() == nullptr) 322 { 323 error.SetErrorStringWithFormat ("invalid value path '%s', %s values only support '[<key>]' subvalues where <key> a string value optionally delimitted by single or double quotes", 324 name, 325 GetTypeAsCString()); 326 } 327 } 328 return value_sp; 329 } 330 331 Error 332 OptionValueDictionary::SetSubValue (const ExecutionContext *exe_ctx, VarSetOperationType op, const char *name, const char *value) 333 { 334 Error error; 335 const bool will_modify = true; 336 lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error)); 337 if (value_sp) 338 error = value_sp->SetValueFromString(value, op); 339 else 340 { 341 if (error.AsCString() == nullptr) 342 error.SetErrorStringWithFormat("invalid value path '%s'", name); 343 } 344 return error; 345 } 346 347 348 lldb::OptionValueSP 349 OptionValueDictionary::GetValueForKey (const ConstString &key) const 350 { 351 lldb::OptionValueSP value_sp; 352 collection::const_iterator pos = m_values.find (key); 353 if (pos != m_values.end()) 354 value_sp = pos->second; 355 return value_sp; 356 } 357 358 const char * 359 OptionValueDictionary::GetStringValueForKey (const ConstString &key) 360 { 361 collection::const_iterator pos = m_values.find (key); 362 if (pos != m_values.end()) 363 { 364 OptionValueString *string_value = pos->second->GetAsString(); 365 if (string_value) 366 return string_value->GetCurrentValue(); 367 } 368 return nullptr; 369 } 370 371 372 bool 373 OptionValueDictionary::SetStringValueForKey (const ConstString &key, 374 const char *value, 375 bool can_replace) 376 { 377 collection::const_iterator pos = m_values.find (key); 378 if (pos != m_values.end()) 379 { 380 if (!can_replace) 381 return false; 382 if (pos->second->GetType() == OptionValue::eTypeString) 383 { 384 pos->second->SetValueFromString(value); 385 return true; 386 } 387 } 388 m_values[key] = OptionValueSP (new OptionValueString (value)); 389 return true; 390 391 } 392 393 bool 394 OptionValueDictionary::SetValueForKey (const ConstString &key, 395 const lldb::OptionValueSP &value_sp, 396 bool can_replace) 397 { 398 // Make sure the value_sp object is allowed to contain 399 // values of the type passed in... 400 if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) 401 { 402 if (!can_replace) 403 { 404 collection::const_iterator pos = m_values.find (key); 405 if (pos != m_values.end()) 406 return false; 407 } 408 m_values[key] = value_sp; 409 return true; 410 } 411 return false; 412 } 413 414 bool 415 OptionValueDictionary::DeleteValueForKey (const ConstString &key) 416 { 417 collection::iterator pos = m_values.find (key); 418 if (pos != m_values.end()) 419 { 420 m_values.erase(pos); 421 return true; 422 } 423 return false; 424 } 425 426 lldb::OptionValueSP 427 OptionValueDictionary::DeepCopy () const 428 { 429 OptionValueDictionary *copied_dict = new OptionValueDictionary (m_type_mask, m_raw_value_dump); 430 lldb::OptionValueSP copied_value_sp(copied_dict); 431 collection::const_iterator pos, end = m_values.end(); 432 for (pos = m_values.begin(); pos != end; ++pos) 433 { 434 StreamString strm; 435 strm.Printf("%s=", pos->first.GetCString()); 436 copied_dict->SetValueForKey (pos->first, pos->second->DeepCopy(), true); 437 } 438 return copied_value_sp; 439 } 440 441