xref: /openbsd-src/gnu/llvm/lldb/source/Interpreter/OptionValueArray.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1dda28197Spatrick //===-- OptionValueArray.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Interpreter/OptionValueArray.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Host/StringConvert.h"
12061da546Spatrick #include "lldb/Utility/Args.h"
13061da546Spatrick #include "lldb/Utility/Stream.h"
14061da546Spatrick 
15061da546Spatrick using namespace lldb;
16061da546Spatrick using namespace lldb_private;
17061da546Spatrick 
18061da546Spatrick void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
19061da546Spatrick                                  uint32_t dump_mask) {
20061da546Spatrick   const Type array_element_type = ConvertTypeMaskToType(m_type_mask);
21061da546Spatrick   if (dump_mask & eDumpOptionType) {
22061da546Spatrick     if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))
23061da546Spatrick       strm.Printf("(%s of %ss)", GetTypeAsCString(),
24061da546Spatrick                   GetBuiltinTypeAsCString(array_element_type));
25061da546Spatrick     else
26061da546Spatrick       strm.Printf("(%s)", GetTypeAsCString());
27061da546Spatrick   }
28061da546Spatrick   if (dump_mask & eDumpOptionValue) {
29061da546Spatrick     const bool one_line = dump_mask & eDumpOptionCommand;
30061da546Spatrick     const uint32_t size = m_values.size();
31061da546Spatrick     if (dump_mask & eDumpOptionType)
32061da546Spatrick       strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : "");
33061da546Spatrick     if (!one_line)
34061da546Spatrick       strm.IndentMore();
35061da546Spatrick     for (uint32_t i = 0; i < size; ++i) {
36061da546Spatrick       if (!one_line) {
37061da546Spatrick         strm.Indent();
38061da546Spatrick         strm.Printf("[%u]: ", i);
39061da546Spatrick       }
40061da546Spatrick       const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
41061da546Spatrick       switch (array_element_type) {
42061da546Spatrick       default:
43061da546Spatrick       case eTypeArray:
44061da546Spatrick       case eTypeDictionary:
45061da546Spatrick       case eTypeProperties:
46061da546Spatrick       case eTypeFileSpecList:
47061da546Spatrick       case eTypePathMap:
48061da546Spatrick         m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
49061da546Spatrick         break;
50061da546Spatrick 
51061da546Spatrick       case eTypeBoolean:
52061da546Spatrick       case eTypeChar:
53061da546Spatrick       case eTypeEnum:
54061da546Spatrick       case eTypeFileSpec:
55*be691f3bSpatrick       case eTypeFileLineColumn:
56061da546Spatrick       case eTypeFormat:
57061da546Spatrick       case eTypeSInt64:
58061da546Spatrick       case eTypeString:
59061da546Spatrick       case eTypeUInt64:
60061da546Spatrick       case eTypeUUID:
61061da546Spatrick         // No need to show the type for dictionaries of simple items
62061da546Spatrick         m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) |
63061da546Spatrick                                                   extra_dump_options);
64061da546Spatrick         break;
65061da546Spatrick       }
66061da546Spatrick 
67061da546Spatrick       if (!one_line) {
68061da546Spatrick         if (i < (size - 1))
69061da546Spatrick           strm.EOL();
70061da546Spatrick       } else {
71061da546Spatrick         strm << ' ';
72061da546Spatrick       }
73061da546Spatrick     }
74061da546Spatrick     if (!one_line)
75061da546Spatrick       strm.IndentLess();
76061da546Spatrick   }
77061da546Spatrick }
78061da546Spatrick 
79061da546Spatrick Status OptionValueArray::SetValueFromString(llvm::StringRef value,
80061da546Spatrick                                             VarSetOperationType op) {
81061da546Spatrick   Args args(value.str());
82061da546Spatrick   Status error = SetArgs(args, op);
83061da546Spatrick   if (error.Success())
84061da546Spatrick     NotifyValueChanged();
85061da546Spatrick   return error;
86061da546Spatrick }
87061da546Spatrick 
88061da546Spatrick lldb::OptionValueSP
89061da546Spatrick OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx,
90061da546Spatrick                               llvm::StringRef name, bool will_modify,
91061da546Spatrick                               Status &error) const {
92061da546Spatrick   if (name.empty() || name.front() != '[') {
93061da546Spatrick     error.SetErrorStringWithFormat(
94061da546Spatrick       "invalid value path '%s', %s values only support '[<index>]' subvalues "
95061da546Spatrick       "where <index> is a positive or negative array index",
96061da546Spatrick       name.str().c_str(), GetTypeAsCString());
97061da546Spatrick     return nullptr;
98061da546Spatrick   }
99061da546Spatrick 
100061da546Spatrick   name = name.drop_front();
101061da546Spatrick   llvm::StringRef index, sub_value;
102061da546Spatrick   std::tie(index, sub_value) = name.split(']');
103061da546Spatrick   if (index.size() == name.size()) {
104061da546Spatrick     // Couldn't find a closing bracket
105061da546Spatrick     return nullptr;
106061da546Spatrick   }
107061da546Spatrick 
108061da546Spatrick   const size_t array_count = m_values.size();
109061da546Spatrick   int32_t idx = 0;
110061da546Spatrick   if (index.getAsInteger(0, idx))
111061da546Spatrick     return nullptr;
112061da546Spatrick 
113061da546Spatrick   uint32_t new_idx = UINT32_MAX;
114061da546Spatrick   if (idx < 0) {
115061da546Spatrick     // Access from the end of the array if the index is negative
116061da546Spatrick     new_idx = array_count - idx;
117061da546Spatrick   } else {
118061da546Spatrick     // Just a standard index
119061da546Spatrick     new_idx = idx;
120061da546Spatrick   }
121061da546Spatrick 
122061da546Spatrick   if (new_idx < array_count) {
123061da546Spatrick     if (m_values[new_idx]) {
124061da546Spatrick       if (!sub_value.empty())
125061da546Spatrick         return m_values[new_idx]->GetSubValue(exe_ctx, sub_value,
126061da546Spatrick                                               will_modify, error);
127061da546Spatrick       else
128061da546Spatrick         return m_values[new_idx];
129061da546Spatrick     }
130061da546Spatrick   } else {
131061da546Spatrick     if (array_count == 0)
132061da546Spatrick       error.SetErrorStringWithFormat(
133061da546Spatrick           "index %i is not valid for an empty array", idx);
134061da546Spatrick     else if (idx > 0)
135061da546Spatrick       error.SetErrorStringWithFormat(
136061da546Spatrick           "index %i out of range, valid values are 0 through %" PRIu64,
137061da546Spatrick           idx, (uint64_t)(array_count - 1));
138061da546Spatrick     else
139061da546Spatrick       error.SetErrorStringWithFormat("negative index %i out of range, "
140061da546Spatrick                                       "valid values are -1 through "
141061da546Spatrick                                       "-%" PRIu64,
142061da546Spatrick                                       idx, (uint64_t)array_count);
143061da546Spatrick   }
144061da546Spatrick   return OptionValueSP();
145061da546Spatrick }
146061da546Spatrick 
147061da546Spatrick size_t OptionValueArray::GetArgs(Args &args) const {
148061da546Spatrick   args.Clear();
149061da546Spatrick   const uint32_t size = m_values.size();
150061da546Spatrick   for (uint32_t i = 0; i < size; ++i) {
151061da546Spatrick     llvm::StringRef string_value = m_values[i]->GetStringValue();
152061da546Spatrick     if (!string_value.empty())
153061da546Spatrick       args.AppendArgument(string_value);
154061da546Spatrick   }
155061da546Spatrick 
156061da546Spatrick   return args.GetArgumentCount();
157061da546Spatrick }
158061da546Spatrick 
159061da546Spatrick Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {
160061da546Spatrick   Status error;
161061da546Spatrick   const size_t argc = args.GetArgumentCount();
162061da546Spatrick   switch (op) {
163061da546Spatrick   case eVarSetOperationInvalid:
164061da546Spatrick     error.SetErrorString("unsupported operation");
165061da546Spatrick     break;
166061da546Spatrick 
167061da546Spatrick   case eVarSetOperationInsertBefore:
168061da546Spatrick   case eVarSetOperationInsertAfter:
169061da546Spatrick     if (argc > 1) {
170061da546Spatrick       uint32_t idx =
171061da546Spatrick           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
172061da546Spatrick       const uint32_t count = GetSize();
173061da546Spatrick       if (idx > count) {
174061da546Spatrick         error.SetErrorStringWithFormat(
175061da546Spatrick             "invalid insert array index %u, index must be 0 through %u", idx,
176061da546Spatrick             count);
177061da546Spatrick       } else {
178061da546Spatrick         if (op == eVarSetOperationInsertAfter)
179061da546Spatrick           ++idx;
180061da546Spatrick         for (size_t i = 1; i < argc; ++i, ++idx) {
181061da546Spatrick           lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
182061da546Spatrick               args.GetArgumentAtIndex(i), m_type_mask, error));
183061da546Spatrick           if (value_sp) {
184061da546Spatrick             if (error.Fail())
185061da546Spatrick               return error;
186061da546Spatrick             if (idx >= m_values.size())
187061da546Spatrick               m_values.push_back(value_sp);
188061da546Spatrick             else
189061da546Spatrick               m_values.insert(m_values.begin() + idx, value_sp);
190061da546Spatrick           } else {
191061da546Spatrick             error.SetErrorString(
192061da546Spatrick                 "array of complex types must subclass OptionValueArray");
193061da546Spatrick             return error;
194061da546Spatrick           }
195061da546Spatrick         }
196061da546Spatrick       }
197061da546Spatrick     } else {
198061da546Spatrick       error.SetErrorString("insert operation takes an array index followed by "
199061da546Spatrick                            "one or more values");
200061da546Spatrick     }
201061da546Spatrick     break;
202061da546Spatrick 
203061da546Spatrick   case eVarSetOperationRemove:
204061da546Spatrick     if (argc > 0) {
205061da546Spatrick       const uint32_t size = m_values.size();
206061da546Spatrick       std::vector<int> remove_indexes;
207061da546Spatrick       bool all_indexes_valid = true;
208061da546Spatrick       size_t i;
209061da546Spatrick       for (i = 0; i < argc; ++i) {
210061da546Spatrick         const size_t idx =
211061da546Spatrick             StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
212061da546Spatrick         if (idx >= size) {
213061da546Spatrick           all_indexes_valid = false;
214061da546Spatrick           break;
215061da546Spatrick         } else
216061da546Spatrick           remove_indexes.push_back(idx);
217061da546Spatrick       }
218061da546Spatrick 
219061da546Spatrick       if (all_indexes_valid) {
220061da546Spatrick         size_t num_remove_indexes = remove_indexes.size();
221061da546Spatrick         if (num_remove_indexes) {
222061da546Spatrick           // Sort and then erase in reverse so indexes are always valid
223061da546Spatrick           if (num_remove_indexes > 1) {
224061da546Spatrick             llvm::sort(remove_indexes.begin(), remove_indexes.end());
225061da546Spatrick             for (std::vector<int>::const_reverse_iterator
226061da546Spatrick                      pos = remove_indexes.rbegin(),
227061da546Spatrick                      end = remove_indexes.rend();
228061da546Spatrick                  pos != end; ++pos) {
229061da546Spatrick               m_values.erase(m_values.begin() + *pos);
230061da546Spatrick             }
231061da546Spatrick           } else {
232061da546Spatrick             // Only one index
233061da546Spatrick             m_values.erase(m_values.begin() + remove_indexes.front());
234061da546Spatrick           }
235061da546Spatrick         }
236061da546Spatrick       } else {
237061da546Spatrick         error.SetErrorStringWithFormat(
238061da546Spatrick             "invalid array index '%s', aborting remove operation",
239061da546Spatrick             args.GetArgumentAtIndex(i));
240061da546Spatrick       }
241061da546Spatrick     } else {
242061da546Spatrick       error.SetErrorString("remove operation takes one or more array indices");
243061da546Spatrick     }
244061da546Spatrick     break;
245061da546Spatrick 
246061da546Spatrick   case eVarSetOperationClear:
247061da546Spatrick     Clear();
248061da546Spatrick     break;
249061da546Spatrick 
250061da546Spatrick   case eVarSetOperationReplace:
251061da546Spatrick     if (argc > 1) {
252061da546Spatrick       uint32_t idx =
253061da546Spatrick           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
254061da546Spatrick       const uint32_t count = GetSize();
255061da546Spatrick       if (idx > count) {
256061da546Spatrick         error.SetErrorStringWithFormat(
257061da546Spatrick             "invalid replace array index %u, index must be 0 through %u", idx,
258061da546Spatrick             count);
259061da546Spatrick       } else {
260061da546Spatrick         for (size_t i = 1; i < argc; ++i, ++idx) {
261061da546Spatrick           lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
262061da546Spatrick               args.GetArgumentAtIndex(i), m_type_mask, error));
263061da546Spatrick           if (value_sp) {
264061da546Spatrick             if (error.Fail())
265061da546Spatrick               return error;
266061da546Spatrick             if (idx < count)
267061da546Spatrick               m_values[idx] = value_sp;
268061da546Spatrick             else
269061da546Spatrick               m_values.push_back(value_sp);
270061da546Spatrick           } else {
271061da546Spatrick             error.SetErrorString(
272061da546Spatrick                 "array of complex types must subclass OptionValueArray");
273061da546Spatrick             return error;
274061da546Spatrick           }
275061da546Spatrick         }
276061da546Spatrick       }
277061da546Spatrick     } else {
278061da546Spatrick       error.SetErrorString("replace operation takes an array index followed by "
279061da546Spatrick                            "one or more values");
280061da546Spatrick     }
281061da546Spatrick     break;
282061da546Spatrick 
283061da546Spatrick   case eVarSetOperationAssign:
284061da546Spatrick     m_values.clear();
285061da546Spatrick     // Fall through to append case
286061da546Spatrick     LLVM_FALLTHROUGH;
287061da546Spatrick   case eVarSetOperationAppend:
288061da546Spatrick     for (size_t i = 0; i < argc; ++i) {
289061da546Spatrick       lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
290061da546Spatrick           args.GetArgumentAtIndex(i), m_type_mask, error));
291061da546Spatrick       if (value_sp) {
292061da546Spatrick         if (error.Fail())
293061da546Spatrick           return error;
294061da546Spatrick         m_value_was_set = true;
295061da546Spatrick         AppendValue(value_sp);
296061da546Spatrick       } else {
297061da546Spatrick         error.SetErrorString(
298061da546Spatrick             "array of complex types must subclass OptionValueArray");
299061da546Spatrick       }
300061da546Spatrick     }
301061da546Spatrick     break;
302061da546Spatrick   }
303061da546Spatrick   return error;
304061da546Spatrick }
305061da546Spatrick 
306*be691f3bSpatrick OptionValueSP
307*be691f3bSpatrick OptionValueArray::DeepCopy(const OptionValueSP &new_parent) const {
308*be691f3bSpatrick   auto copy_sp = OptionValue::DeepCopy(new_parent);
309*be691f3bSpatrick   // copy_sp->GetAsArray cannot be used here as it doesn't work for derived
310*be691f3bSpatrick   // types that override GetType returning a different value.
311*be691f3bSpatrick   auto *array_value_ptr = static_cast<OptionValueArray *>(copy_sp.get());
312*be691f3bSpatrick   lldbassert(array_value_ptr);
313*be691f3bSpatrick 
314*be691f3bSpatrick   for (auto &value : array_value_ptr->m_values)
315*be691f3bSpatrick     value = value->DeepCopy(copy_sp);
316*be691f3bSpatrick 
317*be691f3bSpatrick   return copy_sp;
318061da546Spatrick }
319