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