1ac7ddfbfSEd Maste //===-- OptionValueArray.cpp ------------------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste //                     The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste 
10ac7ddfbfSEd Maste #include "lldb/Interpreter/OptionValueArray.h"
11ac7ddfbfSEd Maste 
121c3bbb01SEd Maste #include "lldb/Host/StringConvert.h"
134ba319b5SDimitry Andric #include "lldb/Utility/Args.h"
14f678e45dSDimitry Andric #include "lldb/Utility/Stream.h"
15ac7ddfbfSEd Maste 
16ac7ddfbfSEd Maste using namespace lldb;
17ac7ddfbfSEd Maste using namespace lldb_private;
18ac7ddfbfSEd Maste 
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)19435933ddSDimitry Andric void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
20435933ddSDimitry Andric                                  uint32_t dump_mask) {
21ac7ddfbfSEd Maste   const Type array_element_type = ConvertTypeMaskToType(m_type_mask);
22435933ddSDimitry Andric   if (dump_mask & eDumpOptionType) {
23ac7ddfbfSEd Maste     if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))
24435933ddSDimitry Andric       strm.Printf("(%s of %ss)", GetTypeAsCString(),
25435933ddSDimitry Andric                   GetBuiltinTypeAsCString(array_element_type));
26ac7ddfbfSEd Maste     else
27ac7ddfbfSEd Maste       strm.Printf("(%s)", GetTypeAsCString());
28ac7ddfbfSEd Maste   }
29435933ddSDimitry Andric   if (dump_mask & eDumpOptionValue) {
30*b5893f02SDimitry Andric     const bool one_line = dump_mask & eDumpOptionCommand;
31ac7ddfbfSEd Maste     const uint32_t size = m_values.size();
32*b5893f02SDimitry Andric     if (dump_mask & eDumpOptionType)
33*b5893f02SDimitry Andric       strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : "");
34*b5893f02SDimitry Andric     if (!one_line)
35*b5893f02SDimitry Andric       strm.IndentMore();
36435933ddSDimitry Andric     for (uint32_t i = 0; i < size; ++i) {
37*b5893f02SDimitry Andric       if (!one_line) {
38ac7ddfbfSEd Maste         strm.Indent();
39ac7ddfbfSEd Maste         strm.Printf("[%u]: ", i);
40*b5893f02SDimitry Andric       }
41ac7ddfbfSEd Maste       const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
42435933ddSDimitry Andric       switch (array_element_type) {
43ac7ddfbfSEd Maste       default:
44ac7ddfbfSEd Maste       case eTypeArray:
45ac7ddfbfSEd Maste       case eTypeDictionary:
46ac7ddfbfSEd Maste       case eTypeProperties:
47ac7ddfbfSEd Maste       case eTypeFileSpecList:
48ac7ddfbfSEd Maste       case eTypePathMap:
49ac7ddfbfSEd Maste         m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
50ac7ddfbfSEd Maste         break;
51ac7ddfbfSEd Maste 
52ac7ddfbfSEd Maste       case eTypeBoolean:
537aa51b79SEd Maste       case eTypeChar:
54ac7ddfbfSEd Maste       case eTypeEnum:
55ac7ddfbfSEd Maste       case eTypeFileSpec:
56ac7ddfbfSEd Maste       case eTypeFormat:
57ac7ddfbfSEd Maste       case eTypeSInt64:
58ac7ddfbfSEd Maste       case eTypeString:
59ac7ddfbfSEd Maste       case eTypeUInt64:
60ac7ddfbfSEd Maste       case eTypeUUID:
61ac7ddfbfSEd Maste         // No need to show the type for dictionaries of simple items
62435933ddSDimitry Andric         m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) |
63435933ddSDimitry Andric                                                   extra_dump_options);
64ac7ddfbfSEd Maste         break;
65ac7ddfbfSEd Maste       }
66*b5893f02SDimitry Andric 
67*b5893f02SDimitry Andric       if (!one_line) {
68ac7ddfbfSEd Maste         if (i < (size - 1))
69ac7ddfbfSEd Maste           strm.EOL();
70*b5893f02SDimitry Andric       } else {
71*b5893f02SDimitry Andric         strm << ' ';
72ac7ddfbfSEd Maste       }
73*b5893f02SDimitry Andric     }
74*b5893f02SDimitry Andric     if (!one_line)
75ac7ddfbfSEd Maste       strm.IndentLess();
76ac7ddfbfSEd Maste   }
77ac7ddfbfSEd Maste }
78ac7ddfbfSEd Maste 
SetValueFromString(llvm::StringRef value,VarSetOperationType op)795517e702SDimitry Andric Status OptionValueArray::SetValueFromString(llvm::StringRef value,
80435933ddSDimitry Andric                                             VarSetOperationType op) {
81435933ddSDimitry Andric   Args args(value.str());
825517e702SDimitry Andric   Status error = SetArgs(args, op);
831c3bbb01SEd Maste   if (error.Success())
847aa51b79SEd Maste     NotifyValueChanged();
851c3bbb01SEd Maste   return error;
86ac7ddfbfSEd Maste }
87ac7ddfbfSEd Maste 
88ac7ddfbfSEd Maste lldb::OptionValueSP
GetSubValue(const ExecutionContext * exe_ctx,llvm::StringRef name,bool will_modify,Status & error) const895517e702SDimitry Andric OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx,
905517e702SDimitry Andric                               llvm::StringRef name, bool will_modify,
915517e702SDimitry Andric                               Status &error) const {
92435933ddSDimitry Andric   if (name.empty() || name.front() != '[') {
93435933ddSDimitry Andric     error.SetErrorStringWithFormat(
94435933ddSDimitry Andric       "invalid value path '%s', %s values only support '[<index>]' subvalues "
95435933ddSDimitry Andric       "where <index> is a positive or negative array index",
96435933ddSDimitry Andric       name.str().c_str(), GetTypeAsCString());
97435933ddSDimitry Andric     return nullptr;
98435933ddSDimitry Andric   }
99435933ddSDimitry Andric 
100435933ddSDimitry Andric   name = name.drop_front();
101435933ddSDimitry Andric   llvm::StringRef index, sub_value;
102435933ddSDimitry Andric   std::tie(index, sub_value) = name.split(']');
103435933ddSDimitry Andric   if (index.size() == name.size()) {
104435933ddSDimitry Andric     // Couldn't find a closing bracket
105435933ddSDimitry Andric     return nullptr;
106435933ddSDimitry Andric   }
107435933ddSDimitry Andric 
108ac7ddfbfSEd Maste   const size_t array_count = m_values.size();
109435933ddSDimitry Andric   int32_t idx = 0;
110435933ddSDimitry Andric   if (index.getAsInteger(0, idx))
111435933ddSDimitry Andric     return nullptr;
112435933ddSDimitry Andric 
113ac7ddfbfSEd Maste   uint32_t new_idx = UINT32_MAX;
114435933ddSDimitry Andric   if (idx < 0) {
115ac7ddfbfSEd Maste     // Access from the end of the array if the index is negative
116ac7ddfbfSEd Maste     new_idx = array_count - idx;
117435933ddSDimitry Andric   } else {
118ac7ddfbfSEd Maste     // Just a standard index
119ac7ddfbfSEd Maste     new_idx = idx;
120ac7ddfbfSEd Maste   }
121ac7ddfbfSEd Maste 
122435933ddSDimitry Andric   if (new_idx < array_count) {
123435933ddSDimitry Andric     if (m_values[new_idx]) {
124435933ddSDimitry Andric       if (!sub_value.empty())
125435933ddSDimitry Andric         return m_values[new_idx]->GetSubValue(exe_ctx, sub_value,
126435933ddSDimitry Andric                                               will_modify, error);
127ac7ddfbfSEd Maste       else
128ac7ddfbfSEd Maste         return m_values[new_idx];
129ac7ddfbfSEd Maste     }
130435933ddSDimitry Andric   } else {
131ac7ddfbfSEd Maste     if (array_count == 0)
132435933ddSDimitry Andric       error.SetErrorStringWithFormat(
133435933ddSDimitry Andric           "index %i is not valid for an empty array", idx);
134ac7ddfbfSEd Maste     else if (idx > 0)
135435933ddSDimitry Andric       error.SetErrorStringWithFormat(
136435933ddSDimitry Andric           "index %i out of range, valid values are 0 through %" PRIu64,
137435933ddSDimitry Andric           idx, (uint64_t)(array_count - 1));
138ac7ddfbfSEd Maste     else
139435933ddSDimitry Andric       error.SetErrorStringWithFormat("negative index %i out of range, "
140435933ddSDimitry Andric                                       "valid values are -1 through "
141435933ddSDimitry Andric                                       "-%" PRIu64,
142435933ddSDimitry Andric                                       idx, (uint64_t)array_count);
143ac7ddfbfSEd Maste   }
144ac7ddfbfSEd Maste   return OptionValueSP();
145ac7ddfbfSEd Maste }
146ac7ddfbfSEd Maste 
GetArgs(Args & args) const147435933ddSDimitry Andric size_t OptionValueArray::GetArgs(Args &args) const {
148435933ddSDimitry Andric   args.Clear();
149ac7ddfbfSEd Maste   const uint32_t size = m_values.size();
150435933ddSDimitry Andric   for (uint32_t i = 0; i < size; ++i) {
151435933ddSDimitry Andric     llvm::StringRef string_value = m_values[i]->GetStringValue();
152435933ddSDimitry Andric     if (!string_value.empty())
153435933ddSDimitry Andric       args.AppendArgument(string_value);
154ac7ddfbfSEd Maste   }
155ac7ddfbfSEd Maste 
156ac7ddfbfSEd Maste   return args.GetArgumentCount();
157ac7ddfbfSEd Maste }
158ac7ddfbfSEd Maste 
SetArgs(const Args & args,VarSetOperationType op)1595517e702SDimitry Andric Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {
1605517e702SDimitry Andric   Status error;
161ac7ddfbfSEd Maste   const size_t argc = args.GetArgumentCount();
162435933ddSDimitry Andric   switch (op) {
163ac7ddfbfSEd Maste   case eVarSetOperationInvalid:
164ac7ddfbfSEd Maste     error.SetErrorString("unsupported operation");
165ac7ddfbfSEd Maste     break;
166ac7ddfbfSEd Maste 
167ac7ddfbfSEd Maste   case eVarSetOperationInsertBefore:
168ac7ddfbfSEd Maste   case eVarSetOperationInsertAfter:
169435933ddSDimitry Andric     if (argc > 1) {
170435933ddSDimitry Andric       uint32_t idx =
171435933ddSDimitry Andric           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
172ac7ddfbfSEd Maste       const uint32_t count = GetSize();
173435933ddSDimitry Andric       if (idx > count) {
174435933ddSDimitry Andric         error.SetErrorStringWithFormat(
175435933ddSDimitry Andric             "invalid insert array index %u, index must be 0 through %u", idx,
176435933ddSDimitry Andric             count);
177435933ddSDimitry Andric       } else {
178ac7ddfbfSEd Maste         if (op == eVarSetOperationInsertAfter)
179ac7ddfbfSEd Maste           ++idx;
180435933ddSDimitry Andric         for (size_t i = 1; i < argc; ++i, ++idx) {
181435933ddSDimitry Andric           lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
182435933ddSDimitry Andric               args.GetArgumentAtIndex(i), m_type_mask, error));
183435933ddSDimitry Andric           if (value_sp) {
184ac7ddfbfSEd Maste             if (error.Fail())
185ac7ddfbfSEd Maste               return error;
186ac7ddfbfSEd Maste             if (idx >= m_values.size())
187ac7ddfbfSEd Maste               m_values.push_back(value_sp);
188ac7ddfbfSEd Maste             else
189ac7ddfbfSEd Maste               m_values.insert(m_values.begin() + idx, value_sp);
190435933ddSDimitry Andric           } else {
191435933ddSDimitry Andric             error.SetErrorString(
192435933ddSDimitry Andric                 "array of complex types must subclass OptionValueArray");
193ac7ddfbfSEd Maste             return error;
194ac7ddfbfSEd Maste           }
195ac7ddfbfSEd Maste         }
196ac7ddfbfSEd Maste       }
197435933ddSDimitry Andric     } else {
198435933ddSDimitry Andric       error.SetErrorString("insert operation takes an array index followed by "
199435933ddSDimitry Andric                            "one or more values");
200ac7ddfbfSEd Maste     }
201ac7ddfbfSEd Maste     break;
202ac7ddfbfSEd Maste 
203ac7ddfbfSEd Maste   case eVarSetOperationRemove:
204435933ddSDimitry Andric     if (argc > 0) {
205ac7ddfbfSEd Maste       const uint32_t size = m_values.size();
206ac7ddfbfSEd Maste       std::vector<int> remove_indexes;
207ac7ddfbfSEd Maste       bool all_indexes_valid = true;
208ac7ddfbfSEd Maste       size_t i;
209435933ddSDimitry Andric       for (i = 0; i < argc; ++i) {
2100127ef0fSEd Maste         const size_t idx =
2111c3bbb01SEd Maste             StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
212435933ddSDimitry Andric         if (idx >= size) {
213ac7ddfbfSEd Maste           all_indexes_valid = false;
214ac7ddfbfSEd Maste           break;
215435933ddSDimitry Andric         } else
216ac7ddfbfSEd Maste           remove_indexes.push_back(idx);
217ac7ddfbfSEd Maste       }
218ac7ddfbfSEd Maste 
219435933ddSDimitry Andric       if (all_indexes_valid) {
220ac7ddfbfSEd Maste         size_t num_remove_indexes = remove_indexes.size();
221435933ddSDimitry Andric         if (num_remove_indexes) {
222ac7ddfbfSEd Maste           // Sort and then erase in reverse so indexes are always valid
223435933ddSDimitry Andric           if (num_remove_indexes > 1) {
224*b5893f02SDimitry Andric             llvm::sort(remove_indexes.begin(), remove_indexes.end());
225435933ddSDimitry Andric             for (std::vector<int>::const_reverse_iterator
226435933ddSDimitry Andric                      pos = remove_indexes.rbegin(),
227435933ddSDimitry Andric                      end = remove_indexes.rend();
228435933ddSDimitry Andric                  pos != end; ++pos) {
229ac7ddfbfSEd Maste               m_values.erase(m_values.begin() + *pos);
230ac7ddfbfSEd Maste             }
231435933ddSDimitry Andric           } else {
232ac7ddfbfSEd Maste             // Only one index
233ac7ddfbfSEd Maste             m_values.erase(m_values.begin() + remove_indexes.front());
234ac7ddfbfSEd Maste           }
235ac7ddfbfSEd Maste         }
236435933ddSDimitry Andric       } else {
237435933ddSDimitry Andric         error.SetErrorStringWithFormat(
238435933ddSDimitry Andric             "invalid array index '%s', aborting remove operation",
239435933ddSDimitry Andric             args.GetArgumentAtIndex(i));
240ac7ddfbfSEd Maste       }
241435933ddSDimitry Andric     } else {
242ac7ddfbfSEd Maste       error.SetErrorString("remove operation takes one or more array indices");
243ac7ddfbfSEd Maste     }
244ac7ddfbfSEd Maste     break;
245ac7ddfbfSEd Maste 
246ac7ddfbfSEd Maste   case eVarSetOperationClear:
247ac7ddfbfSEd Maste     Clear();
248ac7ddfbfSEd Maste     break;
249ac7ddfbfSEd Maste 
250ac7ddfbfSEd Maste   case eVarSetOperationReplace:
251435933ddSDimitry Andric     if (argc > 1) {
252435933ddSDimitry Andric       uint32_t idx =
253435933ddSDimitry Andric           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
254ac7ddfbfSEd Maste       const uint32_t count = GetSize();
255435933ddSDimitry Andric       if (idx > count) {
256435933ddSDimitry Andric         error.SetErrorStringWithFormat(
257435933ddSDimitry Andric             "invalid replace array index %u, index must be 0 through %u", idx,
258435933ddSDimitry Andric             count);
259435933ddSDimitry Andric       } else {
260435933ddSDimitry Andric         for (size_t i = 1; i < argc; ++i, ++idx) {
261435933ddSDimitry Andric           lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
262435933ddSDimitry Andric               args.GetArgumentAtIndex(i), m_type_mask, error));
263435933ddSDimitry Andric           if (value_sp) {
264ac7ddfbfSEd Maste             if (error.Fail())
265ac7ddfbfSEd Maste               return error;
266ac7ddfbfSEd Maste             if (idx < count)
267ac7ddfbfSEd Maste               m_values[idx] = value_sp;
268ac7ddfbfSEd Maste             else
269ac7ddfbfSEd Maste               m_values.push_back(value_sp);
270435933ddSDimitry Andric           } else {
271435933ddSDimitry Andric             error.SetErrorString(
272435933ddSDimitry Andric                 "array of complex types must subclass OptionValueArray");
273ac7ddfbfSEd Maste             return error;
274ac7ddfbfSEd Maste           }
275ac7ddfbfSEd Maste         }
276ac7ddfbfSEd Maste       }
277435933ddSDimitry Andric     } else {
278435933ddSDimitry Andric       error.SetErrorString("replace operation takes an array index followed by "
279435933ddSDimitry Andric                            "one or more values");
280ac7ddfbfSEd Maste     }
281ac7ddfbfSEd Maste     break;
282ac7ddfbfSEd Maste 
283ac7ddfbfSEd Maste   case eVarSetOperationAssign:
284ac7ddfbfSEd Maste     m_values.clear();
285ac7ddfbfSEd Maste     // Fall through to append case
2864bb0738eSEd Maste     LLVM_FALLTHROUGH;
287ac7ddfbfSEd Maste   case eVarSetOperationAppend:
288435933ddSDimitry Andric     for (size_t i = 0; i < argc; ++i) {
289435933ddSDimitry Andric       lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
290435933ddSDimitry Andric           args.GetArgumentAtIndex(i), m_type_mask, error));
291435933ddSDimitry Andric       if (value_sp) {
292ac7ddfbfSEd Maste         if (error.Fail())
293ac7ddfbfSEd Maste           return error;
294ac7ddfbfSEd Maste         m_value_was_set = true;
295ac7ddfbfSEd Maste         AppendValue(value_sp);
296435933ddSDimitry Andric       } else {
297435933ddSDimitry Andric         error.SetErrorString(
298435933ddSDimitry Andric             "array of complex types must subclass OptionValueArray");
299ac7ddfbfSEd Maste       }
300ac7ddfbfSEd Maste     }
301ac7ddfbfSEd Maste     break;
302ac7ddfbfSEd Maste   }
303ac7ddfbfSEd Maste   return error;
304ac7ddfbfSEd Maste }
305ac7ddfbfSEd Maste 
DeepCopy() const306435933ddSDimitry Andric lldb::OptionValueSP OptionValueArray::DeepCopy() const {
307435933ddSDimitry Andric   OptionValueArray *copied_array =
308435933ddSDimitry Andric       new OptionValueArray(m_type_mask, m_raw_value_dump);
309ac7ddfbfSEd Maste   lldb::OptionValueSP copied_value_sp(copied_array);
3101c3bbb01SEd Maste   *static_cast<OptionValue *>(copied_array) = *this;
3111c3bbb01SEd Maste   copied_array->m_callback = m_callback;
312ac7ddfbfSEd Maste   const uint32_t size = m_values.size();
313435933ddSDimitry Andric   for (uint32_t i = 0; i < size; ++i) {
314ac7ddfbfSEd Maste     copied_array->AppendValue(m_values[i]->DeepCopy());
315ac7ddfbfSEd Maste   }
316ac7ddfbfSEd Maste   return copied_value_sp;
317ac7ddfbfSEd Maste }
318