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