1*67cc0636SGreg Clayton //===-- OptionValueArray.cpp ------------------------------------*- C++ -*-===//
2*67cc0636SGreg Clayton //
3*67cc0636SGreg Clayton //                     The LLVM Compiler Infrastructure
4*67cc0636SGreg Clayton //
5*67cc0636SGreg Clayton // This file is distributed under the University of Illinois Open Source
6*67cc0636SGreg Clayton // License. See LICENSE.TXT for details.
7*67cc0636SGreg Clayton //
8*67cc0636SGreg Clayton //===----------------------------------------------------------------------===//
9*67cc0636SGreg Clayton 
10*67cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueArray.h"
11*67cc0636SGreg Clayton 
12*67cc0636SGreg Clayton // C Includes
13*67cc0636SGreg Clayton // C++ Includes
14*67cc0636SGreg Clayton // Other libraries and framework includes
15*67cc0636SGreg Clayton // Project includes
16*67cc0636SGreg Clayton #include "lldb/Core/Stream.h"
17*67cc0636SGreg Clayton #include "lldb/Interpreter/Args.h"
18*67cc0636SGreg Clayton 
19*67cc0636SGreg Clayton using namespace lldb;
20*67cc0636SGreg Clayton using namespace lldb_private;
21*67cc0636SGreg Clayton 
22*67cc0636SGreg Clayton void
23*67cc0636SGreg Clayton OptionValueArray::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
24*67cc0636SGreg Clayton {
25*67cc0636SGreg Clayton     const Type array_element_type = ConvertTypeMaskToType (m_type_mask);
26*67cc0636SGreg Clayton     if (dump_mask & eDumpOptionType)
27*67cc0636SGreg Clayton     {
28*67cc0636SGreg Clayton         if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))
29*67cc0636SGreg Clayton             strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(array_element_type));
30*67cc0636SGreg Clayton         else
31*67cc0636SGreg Clayton             strm.Printf ("(%s)", GetTypeAsCString());
32*67cc0636SGreg Clayton     }
33*67cc0636SGreg Clayton     if (dump_mask & eDumpOptionValue)
34*67cc0636SGreg Clayton     {
35*67cc0636SGreg Clayton         if (dump_mask & eDumpOptionType)
36*67cc0636SGreg Clayton             strm.Printf (" =%s", (m_values.size() > 0) ? "\n" : "");
37*67cc0636SGreg Clayton         strm.IndentMore();
38*67cc0636SGreg Clayton         const uint32_t size = m_values.size();
39*67cc0636SGreg Clayton         for (uint32_t i = 0; i<size; ++i)
40*67cc0636SGreg Clayton         {
41*67cc0636SGreg Clayton             strm.Indent();
42*67cc0636SGreg Clayton             strm.Printf("[%u]: ", i);
43*67cc0636SGreg Clayton             const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
44*67cc0636SGreg Clayton             switch (array_element_type)
45*67cc0636SGreg Clayton             {
46*67cc0636SGreg Clayton                 default:
47*67cc0636SGreg Clayton                 case eTypeArray:
48*67cc0636SGreg Clayton                 case eTypeDictionary:
49*67cc0636SGreg Clayton                 case eTypeProperties:
50*67cc0636SGreg Clayton                 case eTypeFileSpecList:
51*67cc0636SGreg Clayton                 case eTypePathMap:
52*67cc0636SGreg Clayton                     m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
53*67cc0636SGreg Clayton                     break;
54*67cc0636SGreg Clayton 
55*67cc0636SGreg Clayton                 case eTypeBoolean:
56*67cc0636SGreg Clayton                 case eTypeEnum:
57*67cc0636SGreg Clayton                 case eTypeFileSpec:
58*67cc0636SGreg Clayton                 case eTypeFormat:
59*67cc0636SGreg Clayton                 case eTypeSInt64:
60*67cc0636SGreg Clayton                 case eTypeString:
61*67cc0636SGreg Clayton                 case eTypeUInt64:
62*67cc0636SGreg Clayton                 case eTypeUUID:
63*67cc0636SGreg Clayton                     // No need to show the type for dictionaries of simple items
64*67cc0636SGreg Clayton                     m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options);
65*67cc0636SGreg Clayton                     break;
66*67cc0636SGreg Clayton             }
67*67cc0636SGreg Clayton             if (i < (size - 1))
68*67cc0636SGreg Clayton                 strm.EOL();
69*67cc0636SGreg Clayton         }
70*67cc0636SGreg Clayton         strm.IndentLess();
71*67cc0636SGreg Clayton     }
72*67cc0636SGreg Clayton }
73*67cc0636SGreg Clayton 
74*67cc0636SGreg Clayton Error
75*67cc0636SGreg Clayton OptionValueArray::SetValueFromCString (const char *value, VarSetOperationType op)
76*67cc0636SGreg Clayton {
77*67cc0636SGreg Clayton     Args args(value);
78*67cc0636SGreg Clayton     return SetArgs (args, op);
79*67cc0636SGreg Clayton }
80*67cc0636SGreg Clayton 
81*67cc0636SGreg Clayton 
82*67cc0636SGreg Clayton lldb::OptionValueSP
83*67cc0636SGreg Clayton OptionValueArray::GetSubValue (const ExecutionContext *exe_ctx,
84*67cc0636SGreg Clayton                                const char *name,
85*67cc0636SGreg Clayton                                bool will_modify,
86*67cc0636SGreg Clayton                                Error &error) const
87*67cc0636SGreg Clayton {
88*67cc0636SGreg Clayton     if (name && name[0] == '[')
89*67cc0636SGreg Clayton     {
90*67cc0636SGreg Clayton         const char *end_bracket = strchr (name+1, ']');
91*67cc0636SGreg Clayton         if (end_bracket)
92*67cc0636SGreg Clayton         {
93*67cc0636SGreg Clayton             const char *sub_value = NULL;
94*67cc0636SGreg Clayton             if (end_bracket[1])
95*67cc0636SGreg Clayton                 sub_value = end_bracket + 1;
96*67cc0636SGreg Clayton             std::string index_str (name+1, end_bracket);
97*67cc0636SGreg Clayton             const size_t array_count = m_values.size();
98*67cc0636SGreg Clayton             int32_t idx = Args::StringToSInt32(index_str.c_str(), INT32_MAX, 0, NULL);
99*67cc0636SGreg Clayton             if (idx != INT32_MAX)
100*67cc0636SGreg Clayton             {
101*67cc0636SGreg Clayton                 ;
102*67cc0636SGreg Clayton                 uint32_t new_idx = UINT32_MAX;
103*67cc0636SGreg Clayton                 if (idx < 0)
104*67cc0636SGreg Clayton                 {
105*67cc0636SGreg Clayton                     // Access from the end of the array if the index is negative
106*67cc0636SGreg Clayton                     new_idx = array_count - idx;
107*67cc0636SGreg Clayton                 }
108*67cc0636SGreg Clayton                 else
109*67cc0636SGreg Clayton                 {
110*67cc0636SGreg Clayton                     // Just a standard index
111*67cc0636SGreg Clayton                     new_idx = idx;
112*67cc0636SGreg Clayton                 }
113*67cc0636SGreg Clayton 
114*67cc0636SGreg Clayton                 if (new_idx < array_count)
115*67cc0636SGreg Clayton                 {
116*67cc0636SGreg Clayton                     if (m_values[new_idx])
117*67cc0636SGreg Clayton                     {
118*67cc0636SGreg Clayton                         if (sub_value)
119*67cc0636SGreg Clayton                             return m_values[new_idx]->GetSubValue (exe_ctx, sub_value, will_modify, error);
120*67cc0636SGreg Clayton                         else
121*67cc0636SGreg Clayton                             return m_values[new_idx];
122*67cc0636SGreg Clayton                     }
123*67cc0636SGreg Clayton                 }
124*67cc0636SGreg Clayton                 else
125*67cc0636SGreg Clayton                 {
126*67cc0636SGreg Clayton                     if (array_count == 0)
127*67cc0636SGreg Clayton                         error.SetErrorStringWithFormat("index %i is not valid for an empty array", idx);
128*67cc0636SGreg Clayton                     else if (idx > 0)
129*67cc0636SGreg Clayton                         error.SetErrorStringWithFormat("index %i out of range, valid values are 0 through %zu", idx, array_count - 1);
130*67cc0636SGreg Clayton                     else
131*67cc0636SGreg Clayton                         error.SetErrorStringWithFormat("negative index %i out of range, valid values are -1 through -%zu", idx, array_count);
132*67cc0636SGreg Clayton                 }
133*67cc0636SGreg Clayton             }
134*67cc0636SGreg Clayton         }
135*67cc0636SGreg Clayton     }
136*67cc0636SGreg Clayton     else
137*67cc0636SGreg Clayton     {
138*67cc0636SGreg Clayton         error.SetErrorStringWithFormat("invalid value path '%s', %s values only support '[<index>]' subvalues where <index> is a positive or negative array index", name, GetTypeAsCString());
139*67cc0636SGreg Clayton     }
140*67cc0636SGreg Clayton     return OptionValueSP();
141*67cc0636SGreg Clayton }
142*67cc0636SGreg Clayton 
143*67cc0636SGreg Clayton 
144*67cc0636SGreg Clayton size_t
145*67cc0636SGreg Clayton OptionValueArray::GetArgs (Args &args) const
146*67cc0636SGreg Clayton {
147*67cc0636SGreg Clayton     const uint32_t size = m_values.size();
148*67cc0636SGreg Clayton     std::vector<const char *> argv;
149*67cc0636SGreg Clayton     for (uint32_t i = 0; i<size; ++i)
150*67cc0636SGreg Clayton     {
151*67cc0636SGreg Clayton         const char *string_value = m_values[i]->GetStringValue ();
152*67cc0636SGreg Clayton         if (string_value)
153*67cc0636SGreg Clayton             argv.push_back(string_value);
154*67cc0636SGreg Clayton     }
155*67cc0636SGreg Clayton 
156*67cc0636SGreg Clayton     if (argv.empty())
157*67cc0636SGreg Clayton         args.Clear();
158*67cc0636SGreg Clayton     else
159*67cc0636SGreg Clayton         args.SetArguments(argv.size(), &argv[0]);
160*67cc0636SGreg Clayton     return args.GetArgumentCount();
161*67cc0636SGreg Clayton }
162*67cc0636SGreg Clayton 
163*67cc0636SGreg Clayton Error
164*67cc0636SGreg Clayton OptionValueArray::SetArgs (const Args &args, VarSetOperationType op)
165*67cc0636SGreg Clayton {
166*67cc0636SGreg Clayton     Error error;
167*67cc0636SGreg Clayton     const size_t argc = args.GetArgumentCount();
168*67cc0636SGreg Clayton     switch (op)
169*67cc0636SGreg Clayton     {
170*67cc0636SGreg Clayton     case eVarSetOperationInvalid:
171*67cc0636SGreg Clayton         error.SetErrorString("unsupported operation");
172*67cc0636SGreg Clayton         break;
173*67cc0636SGreg Clayton 
174*67cc0636SGreg Clayton     case eVarSetOperationInsertBefore:
175*67cc0636SGreg Clayton     case eVarSetOperationInsertAfter:
176*67cc0636SGreg Clayton         if (argc > 1)
177*67cc0636SGreg Clayton         {
178*67cc0636SGreg Clayton             uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
179*67cc0636SGreg Clayton             const uint32_t count = GetSize();
180*67cc0636SGreg Clayton             if (idx > count)
181*67cc0636SGreg Clayton             {
182*67cc0636SGreg Clayton                 error.SetErrorStringWithFormat("invalid insert array index %u, index must be 0 through %u", idx, count);
183*67cc0636SGreg Clayton             }
184*67cc0636SGreg Clayton             else
185*67cc0636SGreg Clayton             {
186*67cc0636SGreg Clayton                 if (op == eVarSetOperationInsertAfter)
187*67cc0636SGreg Clayton                     ++idx;
188*67cc0636SGreg Clayton                 for (size_t i=1; i<argc; ++i, ++idx)
189*67cc0636SGreg Clayton                 {
190*67cc0636SGreg Clayton                     lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i),
191*67cc0636SGreg Clayton                                                                                      m_type_mask,
192*67cc0636SGreg Clayton                                                                                      error));
193*67cc0636SGreg Clayton                     if (value_sp)
194*67cc0636SGreg Clayton                     {
195*67cc0636SGreg Clayton                         if (error.Fail())
196*67cc0636SGreg Clayton                             return error;
197*67cc0636SGreg Clayton                         if (idx >= m_values.size())
198*67cc0636SGreg Clayton                             m_values.push_back(value_sp);
199*67cc0636SGreg Clayton                         else
200*67cc0636SGreg Clayton                             m_values.insert(m_values.begin() + idx, value_sp);
201*67cc0636SGreg Clayton                     }
202*67cc0636SGreg Clayton                     else
203*67cc0636SGreg Clayton                     {
204*67cc0636SGreg Clayton                         error.SetErrorString("array of complex types must subclass OptionValueArray");
205*67cc0636SGreg Clayton                         return error;
206*67cc0636SGreg Clayton                     }
207*67cc0636SGreg Clayton                 }
208*67cc0636SGreg Clayton             }
209*67cc0636SGreg Clayton         }
210*67cc0636SGreg Clayton         else
211*67cc0636SGreg Clayton         {
212*67cc0636SGreg Clayton             error.SetErrorString("insert operation takes an array index followed by one or more values");
213*67cc0636SGreg Clayton         }
214*67cc0636SGreg Clayton         break;
215*67cc0636SGreg Clayton 
216*67cc0636SGreg Clayton     case eVarSetOperationRemove:
217*67cc0636SGreg Clayton         if (argc > 0)
218*67cc0636SGreg Clayton         {
219*67cc0636SGreg Clayton             const uint32_t size = m_values.size();
220*67cc0636SGreg Clayton             std::vector<int> remove_indexes;
221*67cc0636SGreg Clayton             bool all_indexes_valid = true;
222*67cc0636SGreg Clayton             size_t i;
223*67cc0636SGreg Clayton             for (i=0; i<argc; ++i)
224*67cc0636SGreg Clayton             {
225*67cc0636SGreg Clayton                 const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
226*67cc0636SGreg Clayton                 if (idx >= size)
227*67cc0636SGreg Clayton                 {
228*67cc0636SGreg Clayton                     all_indexes_valid = false;
229*67cc0636SGreg Clayton                     break;
230*67cc0636SGreg Clayton                 }
231*67cc0636SGreg Clayton                 else
232*67cc0636SGreg Clayton                     remove_indexes.push_back(idx);
233*67cc0636SGreg Clayton             }
234*67cc0636SGreg Clayton 
235*67cc0636SGreg Clayton             if (all_indexes_valid)
236*67cc0636SGreg Clayton             {
237*67cc0636SGreg Clayton                 size_t num_remove_indexes = remove_indexes.size();
238*67cc0636SGreg Clayton                 if (num_remove_indexes)
239*67cc0636SGreg Clayton                 {
240*67cc0636SGreg Clayton                     // Sort and then erase in reverse so indexes are always valid
241*67cc0636SGreg Clayton                     if (num_remove_indexes > 1)
242*67cc0636SGreg Clayton                     {
243*67cc0636SGreg Clayton                         std::sort(remove_indexes.begin(), remove_indexes.end());
244*67cc0636SGreg Clayton                         for (std::vector<int>::const_reverse_iterator pos = remove_indexes.rbegin(), end = remove_indexes.rend(); pos != end; ++pos)
245*67cc0636SGreg Clayton                         {
246*67cc0636SGreg Clayton                             m_values.erase(m_values.begin() + *pos);
247*67cc0636SGreg Clayton                         }
248*67cc0636SGreg Clayton                     }
249*67cc0636SGreg Clayton                     else
250*67cc0636SGreg Clayton                     {
251*67cc0636SGreg Clayton                         // Only one index
252*67cc0636SGreg Clayton                         m_values.erase(m_values.begin() + remove_indexes.front());
253*67cc0636SGreg Clayton                     }
254*67cc0636SGreg Clayton                 }
255*67cc0636SGreg Clayton             }
256*67cc0636SGreg Clayton             else
257*67cc0636SGreg Clayton             {
258*67cc0636SGreg Clayton                 error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i));
259*67cc0636SGreg Clayton             }
260*67cc0636SGreg Clayton         }
261*67cc0636SGreg Clayton         else
262*67cc0636SGreg Clayton         {
263*67cc0636SGreg Clayton             error.SetErrorString("remove operation takes one or more array indices");
264*67cc0636SGreg Clayton         }
265*67cc0636SGreg Clayton         break;
266*67cc0636SGreg Clayton 
267*67cc0636SGreg Clayton     case eVarSetOperationClear:
268*67cc0636SGreg Clayton         Clear ();
269*67cc0636SGreg Clayton         break;
270*67cc0636SGreg Clayton 
271*67cc0636SGreg Clayton     case eVarSetOperationReplace:
272*67cc0636SGreg Clayton         if (argc > 1)
273*67cc0636SGreg Clayton         {
274*67cc0636SGreg Clayton             uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
275*67cc0636SGreg Clayton             const uint32_t count = GetSize();
276*67cc0636SGreg Clayton             if (idx > count)
277*67cc0636SGreg Clayton             {
278*67cc0636SGreg Clayton                 error.SetErrorStringWithFormat("invalid replace array index %u, index must be 0 through %u", idx, count);
279*67cc0636SGreg Clayton             }
280*67cc0636SGreg Clayton             else
281*67cc0636SGreg Clayton             {
282*67cc0636SGreg Clayton                 for (size_t i=1; i<argc; ++i, ++idx)
283*67cc0636SGreg Clayton                 {
284*67cc0636SGreg Clayton                     lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i),
285*67cc0636SGreg Clayton                                                                                      m_type_mask,
286*67cc0636SGreg Clayton                                                                                      error));
287*67cc0636SGreg Clayton                     if (value_sp)
288*67cc0636SGreg Clayton                     {
289*67cc0636SGreg Clayton                         if (error.Fail())
290*67cc0636SGreg Clayton                             return error;
291*67cc0636SGreg Clayton                         if (idx < count)
292*67cc0636SGreg Clayton                             m_values[idx] = value_sp;
293*67cc0636SGreg Clayton                         else
294*67cc0636SGreg Clayton                             m_values.push_back(value_sp);
295*67cc0636SGreg Clayton                     }
296*67cc0636SGreg Clayton                     else
297*67cc0636SGreg Clayton                     {
298*67cc0636SGreg Clayton                         error.SetErrorString("array of complex types must subclass OptionValueArray");
299*67cc0636SGreg Clayton                         return error;
300*67cc0636SGreg Clayton                     }
301*67cc0636SGreg Clayton                 }
302*67cc0636SGreg Clayton             }
303*67cc0636SGreg Clayton         }
304*67cc0636SGreg Clayton         else
305*67cc0636SGreg Clayton         {
306*67cc0636SGreg Clayton             error.SetErrorString("replace operation takes an array index followed by one or more values");
307*67cc0636SGreg Clayton         }
308*67cc0636SGreg Clayton         break;
309*67cc0636SGreg Clayton 
310*67cc0636SGreg Clayton     case eVarSetOperationAssign:
311*67cc0636SGreg Clayton         m_values.clear();
312*67cc0636SGreg Clayton         // Fall through to append case
313*67cc0636SGreg Clayton     case eVarSetOperationAppend:
314*67cc0636SGreg Clayton         for (size_t i=0; i<argc; ++i)
315*67cc0636SGreg Clayton         {
316*67cc0636SGreg Clayton             lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i),
317*67cc0636SGreg Clayton                                                                              m_type_mask,
318*67cc0636SGreg Clayton                                                                              error));
319*67cc0636SGreg Clayton             if (value_sp)
320*67cc0636SGreg Clayton             {
321*67cc0636SGreg Clayton                 if (error.Fail())
322*67cc0636SGreg Clayton                     return error;
323*67cc0636SGreg Clayton                 m_value_was_set = true;
324*67cc0636SGreg Clayton                 AppendValue(value_sp);
325*67cc0636SGreg Clayton             }
326*67cc0636SGreg Clayton             else
327*67cc0636SGreg Clayton             {
328*67cc0636SGreg Clayton                 error.SetErrorString("array of complex types must subclass OptionValueArray");
329*67cc0636SGreg Clayton             }
330*67cc0636SGreg Clayton         }
331*67cc0636SGreg Clayton         break;
332*67cc0636SGreg Clayton     }
333*67cc0636SGreg Clayton     return error;
334*67cc0636SGreg Clayton }
335*67cc0636SGreg Clayton 
336*67cc0636SGreg Clayton lldb::OptionValueSP
337*67cc0636SGreg Clayton OptionValueArray::DeepCopy () const
338*67cc0636SGreg Clayton {
339*67cc0636SGreg Clayton     OptionValueArray *copied_array = new OptionValueArray (m_type_mask, m_raw_value_dump);
340*67cc0636SGreg Clayton     lldb::OptionValueSP copied_value_sp(copied_array);
341*67cc0636SGreg Clayton     const uint32_t size = m_values.size();
342*67cc0636SGreg Clayton     for (uint32_t i = 0; i<size; ++i)
343*67cc0636SGreg Clayton     {
344*67cc0636SGreg Clayton         copied_array->AppendValue (m_values[i]->DeepCopy());
345*67cc0636SGreg Clayton     }
346*67cc0636SGreg Clayton     return copied_value_sp;
347*67cc0636SGreg Clayton }
348*67cc0636SGreg Clayton 
349*67cc0636SGreg Clayton 
350*67cc0636SGreg Clayton 
351