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