183108e75SAdrian Prantl //===-- OptionValueFileSpecList.cpp ---------------------------------------===//
283108e75SAdrian Prantl //
383108e75SAdrian Prantl // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
483108e75SAdrian Prantl // See https://llvm.org/LICENSE.txt for license information.
583108e75SAdrian Prantl // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
683108e75SAdrian Prantl //
783108e75SAdrian Prantl //===----------------------------------------------------------------------===//
883108e75SAdrian Prantl 
983108e75SAdrian Prantl #include "lldb/Interpreter/OptionValueFileSpecList.h"
1083108e75SAdrian Prantl 
1183108e75SAdrian Prantl #include "lldb/Host/StringConvert.h"
1283108e75SAdrian Prantl #include "lldb/Utility/Args.h"
1383108e75SAdrian Prantl #include "lldb/Utility/Stream.h"
1483108e75SAdrian Prantl 
1583108e75SAdrian Prantl using namespace lldb;
1683108e75SAdrian Prantl using namespace lldb_private;
1783108e75SAdrian Prantl 
1883108e75SAdrian Prantl void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx,
1983108e75SAdrian Prantl                                         Stream &strm, uint32_t dump_mask) {
2083108e75SAdrian Prantl   std::lock_guard<std::recursive_mutex> lock(m_mutex);
2183108e75SAdrian Prantl   if (dump_mask & eDumpOptionType)
2283108e75SAdrian Prantl     strm.Printf("(%s)", GetTypeAsCString());
2383108e75SAdrian Prantl   if (dump_mask & eDumpOptionValue) {
2483108e75SAdrian Prantl     const bool one_line = dump_mask & eDumpOptionCommand;
2583108e75SAdrian Prantl     const uint32_t size = m_current_value.GetSize();
2683108e75SAdrian Prantl     if (dump_mask & eDumpOptionType)
2783108e75SAdrian Prantl       strm.Printf(" =%s",
2883108e75SAdrian Prantl                   (m_current_value.GetSize() > 0 && !one_line) ? "\n" : "");
2983108e75SAdrian Prantl     if (!one_line)
3083108e75SAdrian Prantl       strm.IndentMore();
3183108e75SAdrian Prantl     for (uint32_t i = 0; i < size; ++i) {
3283108e75SAdrian Prantl       if (!one_line) {
3383108e75SAdrian Prantl         strm.Indent();
3483108e75SAdrian Prantl         strm.Printf("[%u]: ", i);
3583108e75SAdrian Prantl       }
36*4dac97ebSRaphael Isemann       m_current_value.GetFileSpecAtIndex(i).Dump(strm.AsRawOstream());
3783108e75SAdrian Prantl       if (one_line)
3883108e75SAdrian Prantl         strm << ' ';
3983108e75SAdrian Prantl     }
4083108e75SAdrian Prantl     if (!one_line)
4183108e75SAdrian Prantl       strm.IndentLess();
4283108e75SAdrian Prantl   }
4383108e75SAdrian Prantl }
4483108e75SAdrian Prantl 
4583108e75SAdrian Prantl Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value,
4683108e75SAdrian Prantl                                                    VarSetOperationType op) {
4783108e75SAdrian Prantl   std::lock_guard<std::recursive_mutex> lock(m_mutex);
4883108e75SAdrian Prantl   Status error;
4983108e75SAdrian Prantl   Args args(value.str());
5083108e75SAdrian Prantl   const size_t argc = args.GetArgumentCount();
5183108e75SAdrian Prantl 
5283108e75SAdrian Prantl   switch (op) {
5383108e75SAdrian Prantl   case eVarSetOperationClear:
5483108e75SAdrian Prantl     Clear();
5583108e75SAdrian Prantl     NotifyValueChanged();
5683108e75SAdrian Prantl     break;
5783108e75SAdrian Prantl 
5883108e75SAdrian Prantl   case eVarSetOperationReplace:
5983108e75SAdrian Prantl     if (argc > 1) {
6083108e75SAdrian Prantl       uint32_t idx =
6183108e75SAdrian Prantl           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
6283108e75SAdrian Prantl       const uint32_t count = m_current_value.GetSize();
6383108e75SAdrian Prantl       if (idx > count) {
6483108e75SAdrian Prantl         error.SetErrorStringWithFormat(
6583108e75SAdrian Prantl             "invalid file list index %u, index must be 0 through %u", idx,
6683108e75SAdrian Prantl             count);
6783108e75SAdrian Prantl       } else {
6883108e75SAdrian Prantl         for (size_t i = 1; i < argc; ++i, ++idx) {
6983108e75SAdrian Prantl           FileSpec file(args.GetArgumentAtIndex(i));
7083108e75SAdrian Prantl           if (idx < count)
7183108e75SAdrian Prantl             m_current_value.Replace(idx, file);
7283108e75SAdrian Prantl           else
7383108e75SAdrian Prantl             m_current_value.Append(file);
7483108e75SAdrian Prantl         }
7583108e75SAdrian Prantl         NotifyValueChanged();
7683108e75SAdrian Prantl       }
7783108e75SAdrian Prantl     } else {
7883108e75SAdrian Prantl       error.SetErrorString("replace operation takes an array index followed by "
7983108e75SAdrian Prantl                            "one or more values");
8083108e75SAdrian Prantl     }
8183108e75SAdrian Prantl     break;
8283108e75SAdrian Prantl 
8383108e75SAdrian Prantl   case eVarSetOperationAssign:
8483108e75SAdrian Prantl     m_current_value.Clear();
8583108e75SAdrian Prantl     // Fall through to append case
8683108e75SAdrian Prantl     LLVM_FALLTHROUGH;
8783108e75SAdrian Prantl   case eVarSetOperationAppend:
8883108e75SAdrian Prantl     if (argc > 0) {
8983108e75SAdrian Prantl       m_value_was_set = true;
9083108e75SAdrian Prantl       for (size_t i = 0; i < argc; ++i) {
9183108e75SAdrian Prantl         FileSpec file(args.GetArgumentAtIndex(i));
9283108e75SAdrian Prantl         m_current_value.Append(file);
9383108e75SAdrian Prantl       }
9483108e75SAdrian Prantl       NotifyValueChanged();
9583108e75SAdrian Prantl     } else {
9683108e75SAdrian Prantl       error.SetErrorString(
9783108e75SAdrian Prantl           "assign operation takes at least one file path argument");
9883108e75SAdrian Prantl     }
9983108e75SAdrian Prantl     break;
10083108e75SAdrian Prantl 
10183108e75SAdrian Prantl   case eVarSetOperationInsertBefore:
10283108e75SAdrian Prantl   case eVarSetOperationInsertAfter:
10383108e75SAdrian Prantl     if (argc > 1) {
10483108e75SAdrian Prantl       uint32_t idx =
10583108e75SAdrian Prantl           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
10683108e75SAdrian Prantl       const uint32_t count = m_current_value.GetSize();
10783108e75SAdrian Prantl       if (idx > count) {
10883108e75SAdrian Prantl         error.SetErrorStringWithFormat(
10983108e75SAdrian Prantl             "invalid insert file list index %u, index must be 0 through %u",
11083108e75SAdrian Prantl             idx, count);
11183108e75SAdrian Prantl       } else {
11283108e75SAdrian Prantl         if (op == eVarSetOperationInsertAfter)
11383108e75SAdrian Prantl           ++idx;
11483108e75SAdrian Prantl         for (size_t i = 1; i < argc; ++i, ++idx) {
11583108e75SAdrian Prantl           FileSpec file(args.GetArgumentAtIndex(i));
11683108e75SAdrian Prantl           m_current_value.Insert(idx, file);
11783108e75SAdrian Prantl         }
11883108e75SAdrian Prantl         NotifyValueChanged();
11983108e75SAdrian Prantl       }
12083108e75SAdrian Prantl     } else {
12183108e75SAdrian Prantl       error.SetErrorString("insert operation takes an array index followed by "
12283108e75SAdrian Prantl                            "one or more values");
12383108e75SAdrian Prantl     }
12483108e75SAdrian Prantl     break;
12583108e75SAdrian Prantl 
12683108e75SAdrian Prantl   case eVarSetOperationRemove:
12783108e75SAdrian Prantl     if (argc > 0) {
12883108e75SAdrian Prantl       std::vector<int> remove_indexes;
12983108e75SAdrian Prantl       bool all_indexes_valid = true;
13083108e75SAdrian Prantl       size_t i;
13183108e75SAdrian Prantl       for (i = 0; all_indexes_valid && i < argc; ++i) {
13283108e75SAdrian Prantl         const int idx =
13383108e75SAdrian Prantl             StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
13483108e75SAdrian Prantl         if (idx == INT32_MAX)
13583108e75SAdrian Prantl           all_indexes_valid = false;
13683108e75SAdrian Prantl         else
13783108e75SAdrian Prantl           remove_indexes.push_back(idx);
13883108e75SAdrian Prantl       }
13983108e75SAdrian Prantl 
14083108e75SAdrian Prantl       if (all_indexes_valid) {
14183108e75SAdrian Prantl         size_t num_remove_indexes = remove_indexes.size();
14283108e75SAdrian Prantl         if (num_remove_indexes) {
14383108e75SAdrian Prantl           // Sort and then erase in reverse so indexes are always valid
14483108e75SAdrian Prantl           llvm::sort(remove_indexes.begin(), remove_indexes.end());
14583108e75SAdrian Prantl           for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
14683108e75SAdrian Prantl             m_current_value.Remove(j);
14783108e75SAdrian Prantl           }
14883108e75SAdrian Prantl         }
14983108e75SAdrian Prantl         NotifyValueChanged();
15083108e75SAdrian Prantl       } else {
15183108e75SAdrian Prantl         error.SetErrorStringWithFormat(
15283108e75SAdrian Prantl             "invalid array index '%s', aborting remove operation",
15383108e75SAdrian Prantl             args.GetArgumentAtIndex(i));
15483108e75SAdrian Prantl       }
15583108e75SAdrian Prantl     } else {
15683108e75SAdrian Prantl       error.SetErrorString("remove operation takes one or more array index");
15783108e75SAdrian Prantl     }
15883108e75SAdrian Prantl     break;
15983108e75SAdrian Prantl 
16083108e75SAdrian Prantl   case eVarSetOperationInvalid:
16183108e75SAdrian Prantl     error = OptionValue::SetValueFromString(value, op);
16283108e75SAdrian Prantl     break;
16383108e75SAdrian Prantl   }
16483108e75SAdrian Prantl   return error;
16583108e75SAdrian Prantl }
16683108e75SAdrian Prantl 
16783108e75SAdrian Prantl lldb::OptionValueSP OptionValueFileSpecList::DeepCopy() const {
16883108e75SAdrian Prantl   std::lock_guard<std::recursive_mutex> lock(m_mutex);
16983108e75SAdrian Prantl   return OptionValueSP(new OptionValueFileSpecList(m_current_value));
17083108e75SAdrian Prantl }
171