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 | Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value, |
45 | VarSetOperationType op) { |
46 | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
47 | Status error; |
48 | Args args(value.str()); |
49 | const size_t argc = args.GetArgumentCount(); |
50 | |
51 | switch (op) { |
52 | case eVarSetOperationClear: |
53 | Clear(); |
54 | NotifyValueChanged(); |
55 | break; |
56 | |
57 | case eVarSetOperationReplace: |
58 | if (argc > 1) { |
59 | uint32_t idx; |
60 | const uint32_t count = m_current_value.GetSize(); |
61 | if (!llvm::to_integer(S: args.GetArgumentAtIndex(idx: 0), Num&: idx) || idx > count) { |
62 | error.SetErrorStringWithFormat( |
63 | "invalid file list index %s, index must be 0 through %u" , |
64 | args.GetArgumentAtIndex(idx: 0), count); |
65 | } else { |
66 | for (size_t i = 1; i < argc; ++i, ++idx) { |
67 | FileSpec file(args.GetArgumentAtIndex(idx: i)); |
68 | if (idx < count) |
69 | m_current_value.Replace(idx, file); |
70 | else |
71 | m_current_value.Append(file); |
72 | } |
73 | NotifyValueChanged(); |
74 | } |
75 | } else { |
76 | error.SetErrorString("replace operation takes an array index followed by " |
77 | "one or more values" ); |
78 | } |
79 | break; |
80 | |
81 | case eVarSetOperationAssign: |
82 | m_current_value.Clear(); |
83 | // Fall through to append case |
84 | [[fallthrough]]; |
85 | case eVarSetOperationAppend: |
86 | if (argc > 0) { |
87 | m_value_was_set = true; |
88 | for (size_t i = 0; i < argc; ++i) { |
89 | FileSpec file(args.GetArgumentAtIndex(idx: i)); |
90 | m_current_value.Append(file); |
91 | } |
92 | NotifyValueChanged(); |
93 | } else { |
94 | error.SetErrorString( |
95 | "assign operation takes at least one file path argument" ); |
96 | } |
97 | break; |
98 | |
99 | case eVarSetOperationInsertBefore: |
100 | case eVarSetOperationInsertAfter: |
101 | if (argc > 1) { |
102 | uint32_t idx; |
103 | const uint32_t count = m_current_value.GetSize(); |
104 | if (!llvm::to_integer(S: args.GetArgumentAtIndex(idx: 0), Num&: idx) || idx > count) { |
105 | error.SetErrorStringWithFormat( |
106 | "invalid insert file list index %s, index must be 0 through %u" , |
107 | args.GetArgumentAtIndex(idx: 0), count); |
108 | } else { |
109 | if (op == eVarSetOperationInsertAfter) |
110 | ++idx; |
111 | for (size_t i = 1; i < argc; ++i, ++idx) { |
112 | FileSpec file(args.GetArgumentAtIndex(idx: i)); |
113 | m_current_value.Insert(idx, file); |
114 | } |
115 | NotifyValueChanged(); |
116 | } |
117 | } else { |
118 | error.SetErrorString("insert operation takes an array index followed by " |
119 | "one or more values" ); |
120 | } |
121 | break; |
122 | |
123 | case eVarSetOperationRemove: |
124 | if (argc > 0) { |
125 | std::vector<int> remove_indexes; |
126 | bool all_indexes_valid = true; |
127 | size_t i; |
128 | for (i = 0; all_indexes_valid && i < argc; ++i) { |
129 | int idx; |
130 | if (!llvm::to_integer(S: args.GetArgumentAtIndex(idx: i), Num&: idx)) |
131 | all_indexes_valid = false; |
132 | else |
133 | remove_indexes.push_back(x: idx); |
134 | } |
135 | |
136 | if (all_indexes_valid) { |
137 | size_t num_remove_indexes = remove_indexes.size(); |
138 | if (num_remove_indexes) { |
139 | // Sort and then erase in reverse so indexes are always valid |
140 | llvm::sort(C&: remove_indexes); |
141 | for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) { |
142 | m_current_value.Remove(idx: j); |
143 | } |
144 | } |
145 | NotifyValueChanged(); |
146 | } else { |
147 | error.SetErrorStringWithFormat( |
148 | "invalid array index '%s', aborting remove operation" , |
149 | args.GetArgumentAtIndex(idx: i)); |
150 | } |
151 | } else { |
152 | error.SetErrorString("remove operation takes one or more array index" ); |
153 | } |
154 | break; |
155 | |
156 | case eVarSetOperationInvalid: |
157 | error = OptionValue::SetValueFromString(value, op); |
158 | break; |
159 | } |
160 | return error; |
161 | } |
162 | |
163 | OptionValueSP OptionValueFileSpecList::Clone() const { |
164 | std::lock_guard<std::recursive_mutex> lock(m_mutex); |
165 | return Cloneable::Clone(); |
166 | } |
167 | |