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