blob: e291f7faa54ce5e983b8da6b1d219a0b2b04bab6 [file] [log] [blame]
Greg Clayton73844aa2012-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
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
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:
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
83size_t
84OptionValueDictionary::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
98Error
99OptionValueDictionary::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
217Error
218OptionValueDictionary::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
219{
220 Args args(value_cstr);
221 return SetArgs (args, op);
222}
223
224lldb::OptionValueSP
225OptionValueDictionary::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
325Error
326OptionValueDictionary::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
342lldb::OptionValueSP
343OptionValueDictionary::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
352const char *
353OptionValueDictionary::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
366bool
367OptionValueDictionary::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
387bool
388OptionValueDictionary::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
408bool
409OptionValueDictionary::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
420lldb::OptionValueSP
421OptionValueDictionary::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