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
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)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 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
85 size_t
GetArgs(Args & args) const86 OptionValueDictionary::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
100 Error
SetArgs(const Args & args,VarSetOperationType op)101 OptionValueDictionary::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
219 Error
SetValueFromCString(const char * value_cstr,VarSetOperationType op)220 OptionValueDictionary::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
221 {
222 Args args(value_cstr);
223 return SetArgs (args, op);
224 }
225
226 lldb::OptionValueSP
GetSubValue(const ExecutionContext * exe_ctx,const char * name,bool will_modify,Error & error) const227 OptionValueDictionary::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
327 Error
SetSubValue(const ExecutionContext * exe_ctx,VarSetOperationType op,const char * name,const char * value)328 OptionValueDictionary::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
344 lldb::OptionValueSP
GetValueForKey(const ConstString & key) const345 OptionValueDictionary::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
354 const char *
GetStringValueForKey(const ConstString & key)355 OptionValueDictionary::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
368 bool
SetStringValueForKey(const ConstString & key,const char * value,bool can_replace)369 OptionValueDictionary::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
389 bool
SetValueForKey(const ConstString & key,const lldb::OptionValueSP & value_sp,bool can_replace)390 OptionValueDictionary::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
410 bool
DeleteValueForKey(const ConstString & key)411 OptionValueDictionary::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
422 lldb::OptionValueSP
DeepCopy() const423 OptionValueDictionary::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