blob: e5299f8cc390ad8a89de21e24aaf00072a3a6a11 [file] [log] [blame]
Greg Clayton67cc0632012-08-22 17:17:09 +00001//===-- 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
Daniel Malea93a64302012-12-05 00:20:57 +000010#include "lldb/lldb-python.h"
11
Greg Clayton67cc0632012-08-22 17:17:09 +000012#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
Greg Clayton67cc0632012-08-22 17:17:09 +000019#include "lldb/Core/State.h"
Enrico Granata5548cb52013-01-28 23:47:25 +000020#include "lldb/DataFormatters/FormatManager.h"
Greg Clayton67cc0632012-08-22 17:17:09 +000021#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:
Zachary Turner3e7442b2015-01-12 20:44:02 +000067 case eTypeChar:
Greg Clayton67cc0632012-08-22 17:17:09 +000068 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
86size_t
87OptionValueDictionary::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());
Ed Masted78c9572014-04-20 00:31:37 +000095 pos->second->DumpValue(nullptr, strm, eDumpOptionValue|eDumpOptionRaw);
Greg Clayton67cc0632012-08-22 17:17:09 +000096 args.AppendArgument(strm.GetString().c_str());
97 }
98 return args.GetArgumentCount();
99}
100
101Error
102OptionValueDictionary::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:
Ed Masted78c9572014-04-20 00:31:37 +0000214 error = OptionValue::SetValueFromCString (nullptr, op);
Greg Clayton67cc0632012-08-22 17:17:09 +0000215 break;
216 }
217 return error;
218}
219
220Error
221OptionValueDictionary::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
222{
223 Args args(value_cstr);
Greg Clayton332e8b12015-01-13 21:13:08 +0000224 Error error = SetArgs (args, op);
225 if (error.Success())
226 NotifyValueChanged();
227 return error;
Greg Clayton67cc0632012-08-22 17:17:09 +0000228}
229
230lldb::OptionValueSP
231OptionValueDictionary::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 {
Ed Masted78c9572014-04-20 00:31:37 +0000237 const char *sub_name = nullptr;
Greg Clayton67cc0632012-08-22 17:17:09 +0000238 ConstString key;
239 const char *open_bracket = ::strchr (name, '[');
240
241 if (open_bracket)
242 {
243 const char *key_start = open_bracket + 1;
Ed Masted78c9572014-04-20 00:31:37 +0000244 const char *key_end = nullptr;
Greg Clayton67cc0632012-08-22 17:17:09 +0000245 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 }
Ed Masted78c9572014-04-20 00:31:37 +0000321 if (!value_sp && error.AsCString() == nullptr)
Greg Clayton67cc0632012-08-22 17:17:09 +0000322 {
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
331Error
332OptionValueDictionary::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->SetValueFromCString(value, op);
339 else
340 {
Ed Masted78c9572014-04-20 00:31:37 +0000341 if (error.AsCString() == nullptr)
Greg Clayton67cc0632012-08-22 17:17:09 +0000342 error.SetErrorStringWithFormat("invalid value path '%s'", name);
343 }
344 return error;
345}
346
347
348lldb::OptionValueSP
349OptionValueDictionary::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
358const char *
359OptionValueDictionary::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 }
Ed Masted78c9572014-04-20 00:31:37 +0000368 return nullptr;
Greg Clayton67cc0632012-08-22 17:17:09 +0000369}
370
371
372bool
373OptionValueDictionary::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->SetValueFromCString(value);
385 return true;
386 }
387 }
388 m_values[key] = OptionValueSP (new OptionValueString (value));
389 return true;
390
391}
392
393bool
394OptionValueDictionary::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
414bool
415OptionValueDictionary::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
426lldb::OptionValueSP
427OptionValueDictionary::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