blob: 24eeec3b32857b9ce0798f5777f19a575ee3032a [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
Greg Clayton67cc0632012-08-22 17:17:09 +000010#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
Greg Clayton67cc0632012-08-22 17:17:09 +000017#include "lldb/Core/State.h"
Enrico Granata5548cb52013-01-28 23:47:25 +000018#include "lldb/DataFormatters/FormatManager.h"
Greg Clayton67cc0632012-08-22 17:17:09 +000019#include "lldb/Interpreter/Args.h"
20#include "lldb/Interpreter/OptionValueString.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
25void
26OptionValueDictionary::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:
Zachary Turner3e7442b2015-01-12 20:44:02 +000065 case eTypeChar:
Greg Clayton67cc0632012-08-22 17:17:09 +000066 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
84size_t
85OptionValueDictionary::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());
Ed Masted78c9572014-04-20 00:31:37 +000093 pos->second->DumpValue(nullptr, strm, eDumpOptionValue|eDumpOptionRaw);
Greg Clayton67cc0632012-08-22 17:17:09 +000094 args.AppendArgument(strm.GetString().c_str());
95 }
96 return args.GetArgumentCount();
97}
98
99Error
100OptionValueDictionary::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 {
Enrico Granataa44c0e32015-06-15 21:37:05 +0000120 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
Greg Clayton67cc0632012-08-22 17:17:09 +0000126 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 {
Bruce Mitchener58ef3912015-06-18 05:27:05 +0000133 // Key name starts with '[', so the key value must be in single or double quotes like:
Greg Clayton67cc0632012-08-22 17:17:09 +0000134 // ['<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:
Pavel Labathc95f7e22015-02-20 11:14:59 +0000218 error = OptionValue::SetValueFromString (llvm::StringRef(), op);
Greg Clayton67cc0632012-08-22 17:17:09 +0000219 break;
220 }
221 return error;
222}
223
224Error
Pavel Labathc95f7e22015-02-20 11:14:59 +0000225OptionValueDictionary::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
Greg Clayton67cc0632012-08-22 17:17:09 +0000226{
Pavel Labathc95f7e22015-02-20 11:14:59 +0000227 Args args(value.str().c_str());
Greg Clayton332e8b12015-01-13 21:13:08 +0000228 Error error = SetArgs (args, op);
229 if (error.Success())
230 NotifyValueChanged();
231 return error;
Greg Clayton67cc0632012-08-22 17:17:09 +0000232}
233
234lldb::OptionValueSP
235OptionValueDictionary::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 {
Ed Masted78c9572014-04-20 00:31:37 +0000241 const char *sub_name = nullptr;
Greg Clayton67cc0632012-08-22 17:17:09 +0000242 ConstString key;
243 const char *open_bracket = ::strchr (name, '[');
244
245 if (open_bracket)
246 {
247 const char *key_start = open_bracket + 1;
Ed Masted78c9572014-04-20 00:31:37 +0000248 const char *key_end = nullptr;
Greg Clayton67cc0632012-08-22 17:17:09 +0000249 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 }
Ed Masted78c9572014-04-20 00:31:37 +0000325 if (!value_sp && error.AsCString() == nullptr)
Greg Clayton67cc0632012-08-22 17:17:09 +0000326 {
Bruce Mitchener58ef3912015-06-18 05:27:05 +0000327 error.SetErrorStringWithFormat ("invalid value path '%s', %s values only support '[<key>]' subvalues where <key> a string value optionally delimited by single or double quotes",
Greg Clayton67cc0632012-08-22 17:17:09 +0000328 name,
329 GetTypeAsCString());
330 }
331 }
332 return value_sp;
333}
334
335Error
336OptionValueDictionary::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)
Pavel Labathc95f7e22015-02-20 11:14:59 +0000342 error = value_sp->SetValueFromString(value, op);
Greg Clayton67cc0632012-08-22 17:17:09 +0000343 else
344 {
Ed Masted78c9572014-04-20 00:31:37 +0000345 if (error.AsCString() == nullptr)
Greg Clayton67cc0632012-08-22 17:17:09 +0000346 error.SetErrorStringWithFormat("invalid value path '%s'", name);
347 }
348 return error;
349}
350
351
352lldb::OptionValueSP
353OptionValueDictionary::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
362const char *
363OptionValueDictionary::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 }
Ed Masted78c9572014-04-20 00:31:37 +0000372 return nullptr;
Greg Clayton67cc0632012-08-22 17:17:09 +0000373}
374
375
376bool
377OptionValueDictionary::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 {
Pavel Labathc95f7e22015-02-20 11:14:59 +0000388 pos->second->SetValueFromString(value);
Greg Clayton67cc0632012-08-22 17:17:09 +0000389 return true;
390 }
391 }
392 m_values[key] = OptionValueSP (new OptionValueString (value));
393 return true;
394
395}
396
397bool
398OptionValueDictionary::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
418bool
419OptionValueDictionary::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
430lldb::OptionValueSP
431OptionValueDictionary::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