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