167cc0636SGreg Clayton //===-- OptionValueArray.cpp ------------------------------------*- C++ -*-===//
267cc0636SGreg Clayton //
367cc0636SGreg Clayton //                     The LLVM Compiler Infrastructure
467cc0636SGreg Clayton //
567cc0636SGreg Clayton // This file is distributed under the University of Illinois Open Source
667cc0636SGreg Clayton // License. See LICENSE.TXT for details.
767cc0636SGreg Clayton //
867cc0636SGreg Clayton //===----------------------------------------------------------------------===//
967cc0636SGreg Clayton 
1067cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueArray.h"
1167cc0636SGreg Clayton 
1267cc0636SGreg Clayton // C Includes
1367cc0636SGreg Clayton // C++ Includes
1467cc0636SGreg Clayton // Other libraries and framework includes
1567cc0636SGreg Clayton // Project includes
1667cc0636SGreg Clayton #include "lldb/Core/Stream.h"
175275aaa0SVince Harron #include "lldb/Host/StringConvert.h"
1867cc0636SGreg Clayton #include "lldb/Interpreter/Args.h"
1967cc0636SGreg Clayton 
2067cc0636SGreg Clayton using namespace lldb;
2167cc0636SGreg Clayton using namespace lldb_private;
2267cc0636SGreg Clayton 
23b9c1b51eSKate Stone void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
24b9c1b51eSKate Stone                                  uint32_t dump_mask) {
2567cc0636SGreg Clayton   const Type array_element_type = ConvertTypeMaskToType(m_type_mask);
26b9c1b51eSKate Stone   if (dump_mask & eDumpOptionType) {
2767cc0636SGreg Clayton     if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))
28b9c1b51eSKate Stone       strm.Printf("(%s of %ss)", GetTypeAsCString(),
29b9c1b51eSKate Stone                   GetBuiltinTypeAsCString(array_element_type));
3067cc0636SGreg Clayton     else
3167cc0636SGreg Clayton       strm.Printf("(%s)", GetTypeAsCString());
3267cc0636SGreg Clayton   }
33b9c1b51eSKate Stone   if (dump_mask & eDumpOptionValue) {
3467cc0636SGreg Clayton     if (dump_mask & eDumpOptionType)
3567cc0636SGreg Clayton       strm.Printf(" =%s", (m_values.size() > 0) ? "\n" : "");
3667cc0636SGreg Clayton     strm.IndentMore();
3767cc0636SGreg Clayton     const uint32_t size = m_values.size();
38b9c1b51eSKate Stone     for (uint32_t i = 0; i < size; ++i) {
3967cc0636SGreg Clayton       strm.Indent();
4067cc0636SGreg Clayton       strm.Printf("[%u]: ", i);
4167cc0636SGreg Clayton       const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
42b9c1b51eSKate Stone       switch (array_element_type) {
4367cc0636SGreg Clayton       default:
4467cc0636SGreg Clayton       case eTypeArray:
4567cc0636SGreg Clayton       case eTypeDictionary:
4667cc0636SGreg Clayton       case eTypeProperties:
4767cc0636SGreg Clayton       case eTypeFileSpecList:
4867cc0636SGreg Clayton       case eTypePathMap:
4967cc0636SGreg Clayton         m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
5067cc0636SGreg Clayton         break;
5167cc0636SGreg Clayton 
5267cc0636SGreg Clayton       case eTypeBoolean:
533e7442b6SZachary Turner       case eTypeChar:
5467cc0636SGreg Clayton       case eTypeEnum:
5567cc0636SGreg Clayton       case eTypeFileSpec:
5667cc0636SGreg Clayton       case eTypeFormat:
5767cc0636SGreg Clayton       case eTypeSInt64:
5867cc0636SGreg Clayton       case eTypeString:
5967cc0636SGreg Clayton       case eTypeUInt64:
6067cc0636SGreg Clayton       case eTypeUUID:
6167cc0636SGreg Clayton         // No need to show the type for dictionaries of simple items
62b9c1b51eSKate Stone         m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) |
63b9c1b51eSKate Stone                                                   extra_dump_options);
6467cc0636SGreg Clayton         break;
6567cc0636SGreg Clayton       }
6667cc0636SGreg Clayton       if (i < (size - 1))
6767cc0636SGreg Clayton         strm.EOL();
6867cc0636SGreg Clayton     }
6967cc0636SGreg Clayton     strm.IndentLess();
7067cc0636SGreg Clayton   }
7167cc0636SGreg Clayton }
7267cc0636SGreg Clayton 
73b9c1b51eSKate Stone Error OptionValueArray::SetValueFromString(llvm::StringRef value,
74b9c1b51eSKate Stone                                            VarSetOperationType op) {
75*771ef6d4SMalcolm Parsons   Args args(value.str());
768f37ca56SIlia K   Error error = SetArgs(args, op);
778f37ca56SIlia K   if (error.Success())
78332e8b1cSGreg Clayton     NotifyValueChanged();
798f37ca56SIlia K   return error;
8067cc0636SGreg Clayton }
8167cc0636SGreg Clayton 
8267cc0636SGreg Clayton lldb::OptionValueSP
83b9c1b51eSKate Stone OptionValueArray::GetSubValue(const ExecutionContext *exe_ctx, const char *name,
84b9c1b51eSKate Stone                               bool will_modify, Error &error) const {
85b9c1b51eSKate Stone   if (name && name[0] == '[') {
8667cc0636SGreg Clayton     const char *end_bracket = strchr(name + 1, ']');
87b9c1b51eSKate Stone     if (end_bracket) {
88d78c9576SEd Maste       const char *sub_value = nullptr;
8967cc0636SGreg Clayton       if (end_bracket[1])
9067cc0636SGreg Clayton         sub_value = end_bracket + 1;
9167cc0636SGreg Clayton       std::string index_str(name + 1, end_bracket);
9267cc0636SGreg Clayton       const size_t array_count = m_values.size();
93b9c1b51eSKate Stone       int32_t idx =
94b9c1b51eSKate Stone           StringConvert::ToSInt32(index_str.c_str(), INT32_MAX, 0, nullptr);
95b9c1b51eSKate Stone       if (idx != INT32_MAX) {
9667cc0636SGreg Clayton         ;
9767cc0636SGreg Clayton         uint32_t new_idx = UINT32_MAX;
98b9c1b51eSKate Stone         if (idx < 0) {
9967cc0636SGreg Clayton           // Access from the end of the array if the index is negative
10067cc0636SGreg Clayton           new_idx = array_count - idx;
101b9c1b51eSKate Stone         } else {
10267cc0636SGreg Clayton           // Just a standard index
10367cc0636SGreg Clayton           new_idx = idx;
10467cc0636SGreg Clayton         }
10567cc0636SGreg Clayton 
106b9c1b51eSKate Stone         if (new_idx < array_count) {
107b9c1b51eSKate Stone           if (m_values[new_idx]) {
10867cc0636SGreg Clayton             if (sub_value)
109b9c1b51eSKate Stone               return m_values[new_idx]->GetSubValue(exe_ctx, sub_value,
110b9c1b51eSKate Stone                                                     will_modify, error);
11167cc0636SGreg Clayton             else
11267cc0636SGreg Clayton               return m_values[new_idx];
11367cc0636SGreg Clayton           }
114b9c1b51eSKate Stone         } else {
11567cc0636SGreg Clayton           if (array_count == 0)
116b9c1b51eSKate Stone             error.SetErrorStringWithFormat(
117b9c1b51eSKate Stone                 "index %i is not valid for an empty array", idx);
11867cc0636SGreg Clayton           else if (idx > 0)
119b9c1b51eSKate Stone             error.SetErrorStringWithFormat(
120b9c1b51eSKate Stone                 "index %i out of range, valid values are 0 through %" PRIu64,
121b9c1b51eSKate Stone                 idx, (uint64_t)(array_count - 1));
12267cc0636SGreg Clayton           else
123b9c1b51eSKate Stone             error.SetErrorStringWithFormat("negative index %i out of range, "
124b9c1b51eSKate Stone                                            "valid values are -1 through "
125b9c1b51eSKate Stone                                            "-%" PRIu64,
126b9c1b51eSKate Stone                                            idx, (uint64_t)array_count);
12767cc0636SGreg Clayton         }
12867cc0636SGreg Clayton       }
12967cc0636SGreg Clayton     }
130b9c1b51eSKate Stone   } else {
131b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
132b9c1b51eSKate Stone         "invalid value path '%s', %s values only support '[<index>]' subvalues "
133b9c1b51eSKate Stone         "where <index> is a positive or negative array index",
134b9c1b51eSKate Stone         name, GetTypeAsCString());
13567cc0636SGreg Clayton   }
13667cc0636SGreg Clayton   return OptionValueSP();
13767cc0636SGreg Clayton }
13867cc0636SGreg Clayton 
139b9c1b51eSKate Stone size_t OptionValueArray::GetArgs(Args &args) const {
14067cc0636SGreg Clayton   const uint32_t size = m_values.size();
14167cc0636SGreg Clayton   std::vector<const char *> argv;
142b9c1b51eSKate Stone   for (uint32_t i = 0; i < size; ++i) {
14367cc0636SGreg Clayton     const char *string_value = m_values[i]->GetStringValue();
14467cc0636SGreg Clayton     if (string_value)
14567cc0636SGreg Clayton       argv.push_back(string_value);
14667cc0636SGreg Clayton   }
14767cc0636SGreg Clayton 
14867cc0636SGreg Clayton   if (argv.empty())
14967cc0636SGreg Clayton     args.Clear();
15067cc0636SGreg Clayton   else
15167cc0636SGreg Clayton     args.SetArguments(argv.size(), &argv[0]);
15267cc0636SGreg Clayton   return args.GetArgumentCount();
15367cc0636SGreg Clayton }
15467cc0636SGreg Clayton 
155b9c1b51eSKate Stone Error OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) {
15667cc0636SGreg Clayton   Error error;
15767cc0636SGreg Clayton   const size_t argc = args.GetArgumentCount();
158b9c1b51eSKate Stone   switch (op) {
15967cc0636SGreg Clayton   case eVarSetOperationInvalid:
16067cc0636SGreg Clayton     error.SetErrorString("unsupported operation");
16167cc0636SGreg Clayton     break;
16267cc0636SGreg Clayton 
16367cc0636SGreg Clayton   case eVarSetOperationInsertBefore:
16467cc0636SGreg Clayton   case eVarSetOperationInsertAfter:
165b9c1b51eSKate Stone     if (argc > 1) {
166b9c1b51eSKate Stone       uint32_t idx =
167b9c1b51eSKate Stone           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
16867cc0636SGreg Clayton       const uint32_t count = GetSize();
169b9c1b51eSKate Stone       if (idx > count) {
170b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
171b9c1b51eSKate Stone             "invalid insert array index %u, index must be 0 through %u", idx,
172b9c1b51eSKate Stone             count);
173b9c1b51eSKate Stone       } else {
17467cc0636SGreg Clayton         if (op == eVarSetOperationInsertAfter)
17567cc0636SGreg Clayton           ++idx;
176b9c1b51eSKate Stone         for (size_t i = 1; i < argc; ++i, ++idx) {
177b9c1b51eSKate Stone           lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
178b9c1b51eSKate Stone               args.GetArgumentAtIndex(i), m_type_mask, error));
179b9c1b51eSKate Stone           if (value_sp) {
18067cc0636SGreg Clayton             if (error.Fail())
18167cc0636SGreg Clayton               return error;
18267cc0636SGreg Clayton             if (idx >= m_values.size())
18367cc0636SGreg Clayton               m_values.push_back(value_sp);
18467cc0636SGreg Clayton             else
18567cc0636SGreg Clayton               m_values.insert(m_values.begin() + idx, value_sp);
186b9c1b51eSKate Stone           } else {
187b9c1b51eSKate Stone             error.SetErrorString(
188b9c1b51eSKate Stone                 "array of complex types must subclass OptionValueArray");
18967cc0636SGreg Clayton             return error;
19067cc0636SGreg Clayton           }
19167cc0636SGreg Clayton         }
19267cc0636SGreg Clayton       }
193b9c1b51eSKate Stone     } else {
194b9c1b51eSKate Stone       error.SetErrorString("insert operation takes an array index followed by "
195b9c1b51eSKate Stone                            "one or more values");
19667cc0636SGreg Clayton     }
19767cc0636SGreg Clayton     break;
19867cc0636SGreg Clayton 
19967cc0636SGreg Clayton   case eVarSetOperationRemove:
200b9c1b51eSKate Stone     if (argc > 0) {
20167cc0636SGreg Clayton       const uint32_t size = m_values.size();
20267cc0636SGreg Clayton       std::vector<int> remove_indexes;
20367cc0636SGreg Clayton       bool all_indexes_valid = true;
20467cc0636SGreg Clayton       size_t i;
205b9c1b51eSKate Stone       for (i = 0; i < argc; ++i) {
2063985c8c6SSaleem Abdulrasool         const size_t idx =
2075275aaa0SVince Harron             StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
208b9c1b51eSKate Stone         if (idx >= size) {
20967cc0636SGreg Clayton           all_indexes_valid = false;
21067cc0636SGreg Clayton           break;
211b9c1b51eSKate Stone         } else
21267cc0636SGreg Clayton           remove_indexes.push_back(idx);
21367cc0636SGreg Clayton       }
21467cc0636SGreg Clayton 
215b9c1b51eSKate Stone       if (all_indexes_valid) {
21667cc0636SGreg Clayton         size_t num_remove_indexes = remove_indexes.size();
217b9c1b51eSKate Stone         if (num_remove_indexes) {
21867cc0636SGreg Clayton           // Sort and then erase in reverse so indexes are always valid
219b9c1b51eSKate Stone           if (num_remove_indexes > 1) {
22067cc0636SGreg Clayton             std::sort(remove_indexes.begin(), remove_indexes.end());
221b9c1b51eSKate Stone             for (std::vector<int>::const_reverse_iterator
222b9c1b51eSKate Stone                      pos = remove_indexes.rbegin(),
223b9c1b51eSKate Stone                      end = remove_indexes.rend();
224b9c1b51eSKate Stone                  pos != end; ++pos) {
22567cc0636SGreg Clayton               m_values.erase(m_values.begin() + *pos);
22667cc0636SGreg Clayton             }
227b9c1b51eSKate Stone           } else {
22867cc0636SGreg Clayton             // Only one index
22967cc0636SGreg Clayton             m_values.erase(m_values.begin() + remove_indexes.front());
23067cc0636SGreg Clayton           }
23167cc0636SGreg Clayton         }
232b9c1b51eSKate Stone       } else {
233b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
234b9c1b51eSKate Stone             "invalid array index '%s', aborting remove operation",
235b9c1b51eSKate Stone             args.GetArgumentAtIndex(i));
23667cc0636SGreg Clayton       }
237b9c1b51eSKate Stone     } else {
23867cc0636SGreg Clayton       error.SetErrorString("remove operation takes one or more array indices");
23967cc0636SGreg Clayton     }
24067cc0636SGreg Clayton     break;
24167cc0636SGreg Clayton 
24267cc0636SGreg Clayton   case eVarSetOperationClear:
24367cc0636SGreg Clayton     Clear();
24467cc0636SGreg Clayton     break;
24567cc0636SGreg Clayton 
24667cc0636SGreg Clayton   case eVarSetOperationReplace:
247b9c1b51eSKate Stone     if (argc > 1) {
248b9c1b51eSKate Stone       uint32_t idx =
249b9c1b51eSKate Stone           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
25067cc0636SGreg Clayton       const uint32_t count = GetSize();
251b9c1b51eSKate Stone       if (idx > count) {
252b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
253b9c1b51eSKate Stone             "invalid replace array index %u, index must be 0 through %u", idx,
254b9c1b51eSKate Stone             count);
255b9c1b51eSKate Stone       } else {
256b9c1b51eSKate Stone         for (size_t i = 1; i < argc; ++i, ++idx) {
257b9c1b51eSKate Stone           lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
258b9c1b51eSKate Stone               args.GetArgumentAtIndex(i), m_type_mask, error));
259b9c1b51eSKate Stone           if (value_sp) {
26067cc0636SGreg Clayton             if (error.Fail())
26167cc0636SGreg Clayton               return error;
26267cc0636SGreg Clayton             if (idx < count)
26367cc0636SGreg Clayton               m_values[idx] = value_sp;
26467cc0636SGreg Clayton             else
26567cc0636SGreg Clayton               m_values.push_back(value_sp);
266b9c1b51eSKate Stone           } else {
267b9c1b51eSKate Stone             error.SetErrorString(
268b9c1b51eSKate Stone                 "array of complex types must subclass OptionValueArray");
26967cc0636SGreg Clayton             return error;
27067cc0636SGreg Clayton           }
27167cc0636SGreg Clayton         }
27267cc0636SGreg Clayton       }
273b9c1b51eSKate Stone     } else {
274b9c1b51eSKate Stone       error.SetErrorString("replace operation takes an array index followed by "
275b9c1b51eSKate Stone                            "one or more values");
27667cc0636SGreg Clayton     }
27767cc0636SGreg Clayton     break;
27867cc0636SGreg Clayton 
27967cc0636SGreg Clayton   case eVarSetOperationAssign:
28067cc0636SGreg Clayton     m_values.clear();
28167cc0636SGreg Clayton     // Fall through to append case
28262e0681aSJason Molenda     LLVM_FALLTHROUGH;
28367cc0636SGreg Clayton   case eVarSetOperationAppend:
284b9c1b51eSKate Stone     for (size_t i = 0; i < argc; ++i) {
285b9c1b51eSKate Stone       lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask(
286b9c1b51eSKate Stone           args.GetArgumentAtIndex(i), m_type_mask, error));
287b9c1b51eSKate Stone       if (value_sp) {
28867cc0636SGreg Clayton         if (error.Fail())
28967cc0636SGreg Clayton           return error;
29067cc0636SGreg Clayton         m_value_was_set = true;
29167cc0636SGreg Clayton         AppendValue(value_sp);
292b9c1b51eSKate Stone       } else {
293b9c1b51eSKate Stone         error.SetErrorString(
294b9c1b51eSKate Stone             "array of complex types must subclass OptionValueArray");
29567cc0636SGreg Clayton       }
29667cc0636SGreg Clayton     }
29767cc0636SGreg Clayton     break;
29867cc0636SGreg Clayton   }
29967cc0636SGreg Clayton   return error;
30067cc0636SGreg Clayton }
30167cc0636SGreg Clayton 
302b9c1b51eSKate Stone lldb::OptionValueSP OptionValueArray::DeepCopy() const {
303b9c1b51eSKate Stone   OptionValueArray *copied_array =
304b9c1b51eSKate Stone       new OptionValueArray(m_type_mask, m_raw_value_dump);
30567cc0636SGreg Clayton   lldb::OptionValueSP copied_value_sp(copied_array);
3068f37ca56SIlia K   *static_cast<OptionValue *>(copied_array) = *this;
3078f37ca56SIlia K   copied_array->m_callback = m_callback;
30867cc0636SGreg Clayton   const uint32_t size = m_values.size();
309b9c1b51eSKate Stone   for (uint32_t i = 0; i < size; ++i) {
31067cc0636SGreg Clayton     copied_array->AppendValue(m_values[i]->DeepCopy());
31167cc0636SGreg Clayton   }
31267cc0636SGreg Clayton   return copied_value_sp;
31367cc0636SGreg Clayton }
314