]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Interpreter/OptionValueDictionary.cpp
Merge llvm trunk r300422 and resolve conflicts.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Interpreter / OptionValueDictionary.cpp
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/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/State.h"
18 #include "lldb/DataFormatters/FormatManager.h"
19 #include "lldb/Interpreter/Args.h"
20 #include "lldb/Interpreter/OptionValueString.h"
21
22 using namespace lldb;
23 using namespace lldb_private;
24
25 void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
26                                       Stream &strm, uint32_t dump_mask) {
27   const Type dict_type = ConvertTypeMaskToType(m_type_mask);
28   if (dump_mask & eDumpOptionType) {
29     if (m_type_mask != eTypeInvalid)
30       strm.Printf("(%s of %ss)", GetTypeAsCString(),
31                   GetBuiltinTypeAsCString(dict_type));
32     else
33       strm.Printf("(%s)", GetTypeAsCString());
34   }
35   if (dump_mask & eDumpOptionValue) {
36     if (dump_mask & eDumpOptionType)
37       strm.PutCString(" =");
38
39     collection::iterator pos, end = m_values.end();
40
41     strm.IndentMore();
42
43     for (pos = m_values.begin(); pos != end; ++pos) {
44       OptionValue *option_value = pos->second.get();
45       strm.EOL();
46       strm.Indent(pos->first.GetCString());
47
48       const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
49       switch (dict_type) {
50       default:
51       case eTypeArray:
52       case eTypeDictionary:
53       case eTypeProperties:
54       case eTypeFileSpecList:
55       case eTypePathMap:
56         strm.PutChar(' ');
57         option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
58         break;
59
60       case eTypeBoolean:
61       case eTypeChar:
62       case eTypeEnum:
63       case eTypeFileSpec:
64       case eTypeFormat:
65       case eTypeSInt64:
66       case eTypeString:
67       case eTypeUInt64:
68       case eTypeUUID:
69         // No need to show the type for dictionaries of simple items
70         strm.PutCString("=");
71         option_value->DumpValue(exe_ctx, strm,
72                                 (dump_mask & (~eDumpOptionType)) |
73                                     extra_dump_options);
74         break;
75       }
76     }
77     strm.IndentLess();
78   }
79 }
80
81 size_t OptionValueDictionary::GetArgs(Args &args) const {
82   args.Clear();
83   collection::const_iterator pos, end = m_values.end();
84   for (pos = m_values.begin(); pos != end; ++pos) {
85     StreamString strm;
86     strm.Printf("%s=", pos->first.GetCString());
87     pos->second->DumpValue(nullptr, strm, eDumpOptionValue | eDumpOptionRaw);
88     args.AppendArgument(strm.GetString());
89   }
90   return args.GetArgumentCount();
91 }
92
93 Error OptionValueDictionary::SetArgs(const Args &args, VarSetOperationType op) {
94   Error error;
95   const size_t argc = args.GetArgumentCount();
96   switch (op) {
97   case eVarSetOperationClear:
98     Clear();
99     break;
100
101   case eVarSetOperationAppend:
102   case eVarSetOperationReplace:
103   case eVarSetOperationAssign:
104     if (argc == 0) {
105       error.SetErrorString(
106           "assign operation takes one or more key=value arguments");
107       return error;
108     }
109     for (const auto &entry : args) {
110       if (entry.ref.empty()) {
111         error.SetErrorString("empty argument");
112         return error;
113       }
114       if (!entry.ref.contains('=')) {
115         error.SetErrorString(
116             "assign operation takes one or more key=value arguments");
117         return error;
118       }
119
120       llvm::StringRef key, value;
121       std::tie(key, value) = entry.ref.split('=');
122       bool key_valid = false;
123       if (key.empty()) {
124         error.SetErrorString("empty dictionary key");
125         return error;
126       }
127
128       if (key.front() == '[') {
129         // Key name starts with '[', so the key value must be in single or
130         // double quotes like:
131         // ['<key>']
132         // ["<key>"]
133         if ((key.size() > 2) && (key.back() == ']')) {
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             if ((key.size() > 2) && (key.back() == quote_char)) {
139               // Strip the quotes
140               key = key.substr(1, key.size() - 2);
141               key_valid = true;
142             }
143           } else {
144             // square brackets, no quotes
145             key_valid = true;
146           }
147         }
148       } else {
149         // No square brackets or quotes
150         key_valid = true;
151       }
152       if (!key_valid) {
153         error.SetErrorStringWithFormat(
154             "invalid key \"%s\", the key must be a bare string or "
155             "surrounded by brackets with optional quotes: [<key>] or "
156             "['<key>'] or [\"<key>\"]",
157             key.str().c_str());
158         return error;
159       }
160
161       lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
162           value.str().c_str(), m_type_mask, error));
163       if (value_sp) {
164         if (error.Fail())
165           return error;
166         m_value_was_set = true;
167         SetValueForKey(ConstString(key), value_sp, true);
168       } else {
169         error.SetErrorString("dictionaries that can contain multiple types "
170                              "must subclass OptionValueArray");
171       }
172     }
173     break;
174
175   case eVarSetOperationRemove:
176     if (argc > 0) {
177       for (size_t i = 0; i < argc; ++i) {
178         ConstString key(args.GetArgumentAtIndex(i));
179         if (!DeleteValueForKey(key)) {
180           error.SetErrorStringWithFormat(
181               "no value found named '%s', aborting remove operation",
182               key.GetCString());
183           break;
184         }
185       }
186     } else {
187       error.SetErrorString("remove operation takes one or more key arguments");
188     }
189     break;
190
191   case eVarSetOperationInsertBefore:
192   case eVarSetOperationInsertAfter:
193   case eVarSetOperationInvalid:
194     error = OptionValue::SetValueFromString(llvm::StringRef(), op);
195     break;
196   }
197   return error;
198 }
199
200 Error OptionValueDictionary::SetValueFromString(llvm::StringRef value,
201                                                 VarSetOperationType op) {
202   Args args(value.str());
203   Error error = SetArgs(args, op);
204   if (error.Success())
205     NotifyValueChanged();
206   return error;
207 }
208
209 lldb::OptionValueSP
210 OptionValueDictionary::GetSubValue(const ExecutionContext *exe_ctx,
211   llvm::StringRef name, bool will_modify,
212                                    Error &error) const {
213   lldb::OptionValueSP value_sp;
214   if (name.empty())
215     return nullptr;
216
217   llvm::StringRef left, temp;
218   std::tie(left, temp) = name.split('[');
219   if (left.size() == name.size()) {
220     error.SetErrorStringWithFormat("invalid value path '%s', %s values only "
221       "support '[<key>]' subvalues where <key> "
222       "a string value optionally delimited by "
223       "single or double quotes",
224       name.str().c_str(), GetTypeAsCString());
225     return nullptr;
226   }
227   assert(!temp.empty());
228
229   llvm::StringRef key, value;
230   llvm::StringRef quote_char;
231
232   if (temp[0] == '\"' || temp[0] == '\'') {
233     quote_char = temp.take_front();
234     temp = temp.drop_front();
235   }
236
237   llvm::StringRef sub_name;
238   std::tie(key, sub_name) = temp.split(']');
239
240   if (!key.consume_back(quote_char) || key.empty()) {
241     error.SetErrorStringWithFormat("invalid value path '%s', "
242       "key names must be formatted as ['<key>'] where <key> "
243       "is a string that doesn't contain quotes and the quote"
244       " char is optional", name.str().c_str());
245     return nullptr;
246   }
247
248   value_sp = GetValueForKey(ConstString(key));
249   if (!value_sp) {
250     error.SetErrorStringWithFormat(
251       "dictionary does not contain a value for the key name '%s'",
252       key.str().c_str());
253     return nullptr;
254   }
255
256   if (sub_name.empty())
257     return value_sp;
258   return value_sp->GetSubValue(exe_ctx, sub_name, will_modify, error);
259 }
260
261 Error OptionValueDictionary::SetSubValue(const ExecutionContext *exe_ctx,
262                                          VarSetOperationType op,
263   llvm::StringRef name, llvm::StringRef value) {
264   Error error;
265   const bool will_modify = true;
266   lldb::OptionValueSP value_sp(GetSubValue(exe_ctx, name, will_modify, error));
267   if (value_sp)
268     error = value_sp->SetValueFromString(value, op);
269   else {
270     if (error.AsCString() == nullptr)
271       error.SetErrorStringWithFormat("invalid value path '%s'", name.str().c_str());
272   }
273   return error;
274 }
275
276 lldb::OptionValueSP
277 OptionValueDictionary::GetValueForKey(const ConstString &key) const {
278   lldb::OptionValueSP value_sp;
279   collection::const_iterator pos = m_values.find(key);
280   if (pos != m_values.end())
281     value_sp = pos->second;
282   return value_sp;
283 }
284
285 bool OptionValueDictionary::SetValueForKey(const ConstString &key,
286                                            const lldb::OptionValueSP &value_sp,
287                                            bool can_replace) {
288   // Make sure the value_sp object is allowed to contain
289   // values of the type passed in...
290   if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) {
291     if (!can_replace) {
292       collection::const_iterator pos = m_values.find(key);
293       if (pos != m_values.end())
294         return false;
295     }
296     m_values[key] = value_sp;
297     return true;
298   }
299   return false;
300 }
301
302 bool OptionValueDictionary::DeleteValueForKey(const ConstString &key) {
303   collection::iterator pos = m_values.find(key);
304   if (pos != m_values.end()) {
305     m_values.erase(pos);
306     return true;
307   }
308   return false;
309 }
310
311 lldb::OptionValueSP OptionValueDictionary::DeepCopy() const {
312   OptionValueDictionary *copied_dict =
313       new OptionValueDictionary(m_type_mask, m_raw_value_dump);
314   lldb::OptionValueSP copied_value_sp(copied_dict);
315   collection::const_iterator pos, end = m_values.end();
316   for (pos = m_values.begin(); pos != end; ++pos) {
317     StreamString strm;
318     strm.Printf("%s=", pos->first.GetCString());
319     copied_dict->SetValueForKey(pos->first, pos->second->DeepCopy(), true);
320   }
321   return copied_value_sp;
322 }