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