1 //===-- OptionValuePathMappings.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/OptionValuePathMappings.h"
10
11 #include "lldb/Host/FileSystem.h"
12 #include "lldb/Utility/Args.h"
13 #include "lldb/Utility/FileSpec.h"
14 #include "lldb/Utility/Stream.h"
15
16 using namespace lldb;
17 using namespace lldb_private;
18
VerifyPathExists(const char * path)19 static bool VerifyPathExists(const char *path) {
20 if (path && path[0])
21 return FileSystem::Instance().Exists(path);
22 else
23 return false;
24 }
25
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)26 void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
27 Stream &strm, uint32_t dump_mask) {
28 if (dump_mask & eDumpOptionType)
29 strm.Printf("(%s)", GetTypeAsCString());
30 if (dump_mask & eDumpOptionValue) {
31 if (dump_mask & eDumpOptionType)
32 strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
33 m_path_mappings.Dump(&strm);
34 }
35 }
36
SetValueFromString(llvm::StringRef value,VarSetOperationType op)37 Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
38 VarSetOperationType op) {
39 Status error;
40 Args args(value.str());
41 const size_t argc = args.GetArgumentCount();
42
43 switch (op) {
44 case eVarSetOperationClear:
45 Clear();
46 NotifyValueChanged();
47 break;
48
49 case eVarSetOperationReplace:
50 // Must be at least one index + 1 pair of paths, and the pair count must be
51 // even
52 if (argc >= 3 && (((argc - 1) & 1) == 0)) {
53 uint32_t idx;
54 const uint32_t count = m_path_mappings.GetSize();
55 if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
56 error.SetErrorStringWithFormat(
57 "invalid file list index %s, index must be 0 through %u",
58 args.GetArgumentAtIndex(0), count);
59 } else {
60 bool changed = false;
61 for (size_t i = 1; i < argc; idx++, i += 2) {
62 const char *orginal_path = args.GetArgumentAtIndex(i);
63 const char *replace_path = args.GetArgumentAtIndex(i + 1);
64 if (VerifyPathExists(replace_path)) {
65 if (!m_path_mappings.Replace(orginal_path, replace_path, idx,
66 m_notify_changes))
67 m_path_mappings.Append(orginal_path, replace_path,
68 m_notify_changes);
69 changed = true;
70 } else {
71 std::string previousError =
72 error.Fail() ? std::string(error.AsCString()) + "\n" : "";
73 error.SetErrorStringWithFormat(
74 "%sthe replacement path doesn't exist: \"%s\"",
75 previousError.c_str(), replace_path);
76 }
77 }
78 if (changed)
79 NotifyValueChanged();
80 }
81 } else {
82 error.SetErrorString("replace operation takes an array index followed by "
83 "one or more path pairs");
84 }
85 break;
86
87 case eVarSetOperationAssign:
88 if (argc < 2 || (argc & 1)) {
89 error.SetErrorString("assign operation takes one or more path pairs");
90 break;
91 }
92 m_path_mappings.Clear(m_notify_changes);
93 // Fall through to append case
94 LLVM_FALLTHROUGH;
95 case eVarSetOperationAppend:
96 if (argc < 2 || (argc & 1)) {
97 error.SetErrorString("append operation takes one or more path pairs");
98 break;
99 } else {
100 bool changed = false;
101 for (size_t i = 0; i < argc; i += 2) {
102 const char *orginal_path = args.GetArgumentAtIndex(i);
103 const char *replace_path = args.GetArgumentAtIndex(i + 1);
104 if (VerifyPathExists(replace_path)) {
105 m_path_mappings.Append(orginal_path, replace_path, m_notify_changes);
106 m_value_was_set = true;
107 changed = true;
108 } else {
109 std::string previousError =
110 error.Fail() ? std::string(error.AsCString()) + "\n" : "";
111 error.SetErrorStringWithFormat(
112 "%sthe replacement path doesn't exist: \"%s\"",
113 previousError.c_str(), replace_path);
114 }
115 }
116 if (changed)
117 NotifyValueChanged();
118 }
119 break;
120
121 case eVarSetOperationInsertBefore:
122 case eVarSetOperationInsertAfter:
123 // Must be at least one index + 1 pair of paths, and the pair count must be
124 // even
125 if (argc >= 3 && (((argc - 1) & 1) == 0)) {
126 uint32_t idx;
127 const uint32_t count = m_path_mappings.GetSize();
128 if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
129 error.SetErrorStringWithFormat(
130 "invalid file list index %s, index must be 0 through %u",
131 args.GetArgumentAtIndex(0), count);
132 } else {
133 bool changed = false;
134 if (op == eVarSetOperationInsertAfter)
135 ++idx;
136 for (size_t i = 1; i < argc; i += 2) {
137 const char *orginal_path = args.GetArgumentAtIndex(i);
138 const char *replace_path = args.GetArgumentAtIndex(i + 1);
139 if (VerifyPathExists(replace_path)) {
140 m_path_mappings.Insert(orginal_path, replace_path, idx,
141 m_notify_changes);
142 changed = true;
143 idx++;
144 } else {
145 std::string previousError =
146 error.Fail() ? std::string(error.AsCString()) + "\n" : "";
147 error.SetErrorStringWithFormat(
148 "%sthe replacement path doesn't exist: \"%s\"",
149 previousError.c_str(), replace_path);
150 }
151 }
152 if (changed)
153 NotifyValueChanged();
154 }
155 } else {
156 error.SetErrorString("insert operation takes an array index followed by "
157 "one or more path pairs");
158 }
159 break;
160
161 case eVarSetOperationRemove:
162 if (argc > 0) {
163 std::vector<int> remove_indexes;
164 for (size_t i = 0; i < argc; ++i) {
165 int idx;
166 if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx) || idx < 0 ||
167 idx >= (int)m_path_mappings.GetSize()) {
168 error.SetErrorStringWithFormat(
169 "invalid array index '%s', aborting remove operation",
170 args.GetArgumentAtIndex(i));
171 break;
172 } else
173 remove_indexes.push_back(idx);
174 }
175
176 // Sort and then erase in reverse so indexes are always valid
177 llvm::sort(remove_indexes);
178 for (auto index : llvm::reverse(remove_indexes))
179 m_path_mappings.Remove(index, m_notify_changes);
180 NotifyValueChanged();
181 } else {
182 error.SetErrorString("remove operation takes one or more array index");
183 }
184 break;
185
186 case eVarSetOperationInvalid:
187 error = OptionValue::SetValueFromString(value, op);
188 break;
189 }
190 return error;
191 }
192