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