1 //===-- OptionValueFileSpecList.cpp ---------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "lldb/Interpreter/OptionValueFileSpecList.h"
10
11 #include "lldb/Host/StringConvert.h"
12 #include "lldb/Utility/Args.h"
13 #include "lldb/Utility/Stream.h"
14
15 using namespace lldb;
16 using namespace lldb_private;
17
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)18 void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx,
19 Stream &strm, uint32_t dump_mask) {
20 std::lock_guard<std::recursive_mutex> lock(m_mutex);
21 if (dump_mask & eDumpOptionType)
22 strm.Printf("(%s)", GetTypeAsCString());
23 if (dump_mask & eDumpOptionValue) {
24 const bool one_line = dump_mask & eDumpOptionCommand;
25 const uint32_t size = m_current_value.GetSize();
26 if (dump_mask & eDumpOptionType)
27 strm.Printf(" =%s",
28 (m_current_value.GetSize() > 0 && !one_line) ? "\n" : "");
29 if (!one_line)
30 strm.IndentMore();
31 for (uint32_t i = 0; i < size; ++i) {
32 if (!one_line) {
33 strm.Indent();
34 strm.Printf("[%u]: ", i);
35 }
36 m_current_value.GetFileSpecAtIndex(i).Dump(strm.AsRawOstream());
37 if (one_line)
38 strm << ' ';
39 }
40 if (!one_line)
41 strm.IndentLess();
42 }
43 }
44
SetValueFromString(llvm::StringRef value,VarSetOperationType op)45 Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value,
46 VarSetOperationType op) {
47 std::lock_guard<std::recursive_mutex> lock(m_mutex);
48 Status error;
49 Args args(value.str());
50 const size_t argc = args.GetArgumentCount();
51
52 switch (op) {
53 case eVarSetOperationClear:
54 Clear();
55 NotifyValueChanged();
56 break;
57
58 case eVarSetOperationReplace:
59 if (argc > 1) {
60 uint32_t idx =
61 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
62 const uint32_t count = m_current_value.GetSize();
63 if (idx > count) {
64 error.SetErrorStringWithFormat(
65 "invalid file list index %u, index must be 0 through %u", idx,
66 count);
67 } else {
68 for (size_t i = 1; i < argc; ++i, ++idx) {
69 FileSpec file(args.GetArgumentAtIndex(i));
70 if (idx < count)
71 m_current_value.Replace(idx, file);
72 else
73 m_current_value.Append(file);
74 }
75 NotifyValueChanged();
76 }
77 } else {
78 error.SetErrorString("replace operation takes an array index followed by "
79 "one or more values");
80 }
81 break;
82
83 case eVarSetOperationAssign:
84 m_current_value.Clear();
85 // Fall through to append case
86 LLVM_FALLTHROUGH;
87 case eVarSetOperationAppend:
88 if (argc > 0) {
89 m_value_was_set = true;
90 for (size_t i = 0; i < argc; ++i) {
91 FileSpec file(args.GetArgumentAtIndex(i));
92 m_current_value.Append(file);
93 }
94 NotifyValueChanged();
95 } else {
96 error.SetErrorString(
97 "assign operation takes at least one file path argument");
98 }
99 break;
100
101 case eVarSetOperationInsertBefore:
102 case eVarSetOperationInsertAfter:
103 if (argc > 1) {
104 uint32_t idx =
105 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
106 const uint32_t count = m_current_value.GetSize();
107 if (idx > count) {
108 error.SetErrorStringWithFormat(
109 "invalid insert file list index %u, index must be 0 through %u",
110 idx, count);
111 } else {
112 if (op == eVarSetOperationInsertAfter)
113 ++idx;
114 for (size_t i = 1; i < argc; ++i, ++idx) {
115 FileSpec file(args.GetArgumentAtIndex(i));
116 m_current_value.Insert(idx, file);
117 }
118 NotifyValueChanged();
119 }
120 } else {
121 error.SetErrorString("insert operation takes an array index followed by "
122 "one or more values");
123 }
124 break;
125
126 case eVarSetOperationRemove:
127 if (argc > 0) {
128 std::vector<int> remove_indexes;
129 bool all_indexes_valid = true;
130 size_t i;
131 for (i = 0; all_indexes_valid && i < argc; ++i) {
132 const int idx =
133 StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
134 if (idx == INT32_MAX)
135 all_indexes_valid = false;
136 else
137 remove_indexes.push_back(idx);
138 }
139
140 if (all_indexes_valid) {
141 size_t num_remove_indexes = remove_indexes.size();
142 if (num_remove_indexes) {
143 // Sort and then erase in reverse so indexes are always valid
144 llvm::sort(remove_indexes.begin(), remove_indexes.end());
145 for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
146 m_current_value.Remove(j);
147 }
148 }
149 NotifyValueChanged();
150 } else {
151 error.SetErrorStringWithFormat(
152 "invalid array index '%s', aborting remove operation",
153 args.GetArgumentAtIndex(i));
154 }
155 } else {
156 error.SetErrorString("remove operation takes one or more array index");
157 }
158 break;
159
160 case eVarSetOperationInvalid:
161 error = OptionValue::SetValueFromString(value, op);
162 break;
163 }
164 return error;
165 }
166
Clone() const167 OptionValueSP OptionValueFileSpecList::Clone() const {
168 std::lock_guard<std::recursive_mutex> lock(m_mutex);
169 return Cloneable::Clone();
170 }
171