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