1dda28197Spatrick //===-- OptionValuePathMappings.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Interpreter/OptionValuePathMappings.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Host/FileSystem.h"
12061da546Spatrick #include "lldb/Utility/Args.h"
13061da546Spatrick #include "lldb/Utility/FileSpec.h"
14061da546Spatrick #include "lldb/Utility/Stream.h"
15061da546Spatrick
16061da546Spatrick using namespace lldb;
17061da546Spatrick using namespace lldb_private;
18*f6aab3d8Srobert
VerifyPathExists(const char * path)19061da546Spatrick static bool VerifyPathExists(const char *path) {
20061da546Spatrick if (path && path[0])
21061da546Spatrick return FileSystem::Instance().Exists(path);
22061da546Spatrick else
23061da546Spatrick return false;
24061da546Spatrick }
25061da546Spatrick
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)26061da546Spatrick void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
27061da546Spatrick Stream &strm, uint32_t dump_mask) {
28061da546Spatrick if (dump_mask & eDumpOptionType)
29061da546Spatrick strm.Printf("(%s)", GetTypeAsCString());
30061da546Spatrick if (dump_mask & eDumpOptionValue) {
31061da546Spatrick if (dump_mask & eDumpOptionType)
32061da546Spatrick strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
33061da546Spatrick m_path_mappings.Dump(&strm);
34061da546Spatrick }
35061da546Spatrick }
36061da546Spatrick
37*f6aab3d8Srobert llvm::json::Value
ToJSON(const ExecutionContext * exe_ctx)38*f6aab3d8Srobert OptionValuePathMappings::ToJSON(const ExecutionContext *exe_ctx) {
39*f6aab3d8Srobert return m_path_mappings.ToJSON();
40*f6aab3d8Srobert }
41*f6aab3d8Srobert
SetValueFromString(llvm::StringRef value,VarSetOperationType op)42061da546Spatrick Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
43061da546Spatrick VarSetOperationType op) {
44061da546Spatrick Status error;
45061da546Spatrick Args args(value.str());
46061da546Spatrick const size_t argc = args.GetArgumentCount();
47061da546Spatrick
48061da546Spatrick switch (op) {
49061da546Spatrick case eVarSetOperationClear:
50061da546Spatrick Clear();
51061da546Spatrick NotifyValueChanged();
52061da546Spatrick break;
53061da546Spatrick
54061da546Spatrick case eVarSetOperationReplace:
55061da546Spatrick // Must be at least one index + 1 pair of paths, and the pair count must be
56061da546Spatrick // even
57061da546Spatrick if (argc >= 3 && (((argc - 1) & 1) == 0)) {
58*f6aab3d8Srobert uint32_t idx;
59061da546Spatrick const uint32_t count = m_path_mappings.GetSize();
60*f6aab3d8Srobert if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
61061da546Spatrick error.SetErrorStringWithFormat(
62*f6aab3d8Srobert "invalid file list index %s, index must be 0 through %u",
63*f6aab3d8Srobert args.GetArgumentAtIndex(0), count);
64061da546Spatrick } else {
65061da546Spatrick bool changed = false;
66dda28197Spatrick for (size_t i = 1; i < argc; idx++, i += 2) {
67061da546Spatrick const char *orginal_path = args.GetArgumentAtIndex(i);
68061da546Spatrick const char *replace_path = args.GetArgumentAtIndex(i + 1);
69061da546Spatrick if (VerifyPathExists(replace_path)) {
70*f6aab3d8Srobert if (!m_path_mappings.Replace(orginal_path, replace_path, idx,
71*f6aab3d8Srobert m_notify_changes))
72*f6aab3d8Srobert m_path_mappings.Append(orginal_path, replace_path,
73*f6aab3d8Srobert m_notify_changes);
74061da546Spatrick changed = true;
75061da546Spatrick } else {
76dda28197Spatrick std::string previousError =
77dda28197Spatrick error.Fail() ? std::string(error.AsCString()) + "\n" : "";
78061da546Spatrick error.SetErrorStringWithFormat(
79dda28197Spatrick "%sthe replacement path doesn't exist: \"%s\"",
80dda28197Spatrick previousError.c_str(), replace_path);
81061da546Spatrick }
82061da546Spatrick }
83061da546Spatrick if (changed)
84061da546Spatrick NotifyValueChanged();
85061da546Spatrick }
86061da546Spatrick } else {
87061da546Spatrick error.SetErrorString("replace operation takes an array index followed by "
88061da546Spatrick "one or more path pairs");
89061da546Spatrick }
90061da546Spatrick break;
91061da546Spatrick
92061da546Spatrick case eVarSetOperationAssign:
93061da546Spatrick if (argc < 2 || (argc & 1)) {
94061da546Spatrick error.SetErrorString("assign operation takes one or more path pairs");
95061da546Spatrick break;
96061da546Spatrick }
97061da546Spatrick m_path_mappings.Clear(m_notify_changes);
98061da546Spatrick // Fall through to append case
99*f6aab3d8Srobert [[fallthrough]];
100061da546Spatrick case eVarSetOperationAppend:
101061da546Spatrick if (argc < 2 || (argc & 1)) {
102061da546Spatrick error.SetErrorString("append operation takes one or more path pairs");
103061da546Spatrick break;
104061da546Spatrick } else {
105061da546Spatrick bool changed = false;
106061da546Spatrick for (size_t i = 0; i < argc; i += 2) {
107061da546Spatrick const char *orginal_path = args.GetArgumentAtIndex(i);
108061da546Spatrick const char *replace_path = args.GetArgumentAtIndex(i + 1);
109061da546Spatrick if (VerifyPathExists(replace_path)) {
110*f6aab3d8Srobert m_path_mappings.Append(orginal_path, replace_path, m_notify_changes);
111061da546Spatrick m_value_was_set = true;
112061da546Spatrick changed = true;
113061da546Spatrick } else {
114dda28197Spatrick std::string previousError =
115dda28197Spatrick error.Fail() ? std::string(error.AsCString()) + "\n" : "";
116061da546Spatrick error.SetErrorStringWithFormat(
117dda28197Spatrick "%sthe replacement path doesn't exist: \"%s\"",
118dda28197Spatrick previousError.c_str(), replace_path);
119061da546Spatrick }
120061da546Spatrick }
121061da546Spatrick if (changed)
122061da546Spatrick NotifyValueChanged();
123061da546Spatrick }
124061da546Spatrick break;
125061da546Spatrick
126061da546Spatrick case eVarSetOperationInsertBefore:
127061da546Spatrick case eVarSetOperationInsertAfter:
128061da546Spatrick // Must be at least one index + 1 pair of paths, and the pair count must be
129061da546Spatrick // even
130061da546Spatrick if (argc >= 3 && (((argc - 1) & 1) == 0)) {
131*f6aab3d8Srobert uint32_t idx;
132061da546Spatrick const uint32_t count = m_path_mappings.GetSize();
133*f6aab3d8Srobert if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
134061da546Spatrick error.SetErrorStringWithFormat(
135*f6aab3d8Srobert "invalid file list index %s, index must be 0 through %u",
136*f6aab3d8Srobert args.GetArgumentAtIndex(0), count);
137061da546Spatrick } else {
138061da546Spatrick bool changed = false;
139061da546Spatrick if (op == eVarSetOperationInsertAfter)
140061da546Spatrick ++idx;
141dda28197Spatrick for (size_t i = 1; i < argc; i += 2) {
142061da546Spatrick const char *orginal_path = args.GetArgumentAtIndex(i);
143061da546Spatrick const char *replace_path = args.GetArgumentAtIndex(i + 1);
144061da546Spatrick if (VerifyPathExists(replace_path)) {
145*f6aab3d8Srobert m_path_mappings.Insert(orginal_path, replace_path, idx,
146*f6aab3d8Srobert m_notify_changes);
147061da546Spatrick changed = true;
148dda28197Spatrick idx++;
149061da546Spatrick } else {
150dda28197Spatrick std::string previousError =
151dda28197Spatrick error.Fail() ? std::string(error.AsCString()) + "\n" : "";
152061da546Spatrick error.SetErrorStringWithFormat(
153dda28197Spatrick "%sthe replacement path doesn't exist: \"%s\"",
154dda28197Spatrick previousError.c_str(), replace_path);
155061da546Spatrick }
156061da546Spatrick }
157061da546Spatrick if (changed)
158061da546Spatrick NotifyValueChanged();
159061da546Spatrick }
160061da546Spatrick } else {
161061da546Spatrick error.SetErrorString("insert operation takes an array index followed by "
162061da546Spatrick "one or more path pairs");
163061da546Spatrick }
164061da546Spatrick break;
165061da546Spatrick
166061da546Spatrick case eVarSetOperationRemove:
167061da546Spatrick if (argc > 0) {
168061da546Spatrick std::vector<int> remove_indexes;
169dda28197Spatrick for (size_t i = 0; i < argc; ++i) {
170*f6aab3d8Srobert int idx;
171*f6aab3d8Srobert if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx) || idx < 0 ||
172*f6aab3d8Srobert idx >= (int)m_path_mappings.GetSize()) {
173061da546Spatrick error.SetErrorStringWithFormat(
174061da546Spatrick "invalid array index '%s', aborting remove operation",
175061da546Spatrick args.GetArgumentAtIndex(i));
176dda28197Spatrick break;
177dda28197Spatrick } else
178dda28197Spatrick remove_indexes.push_back(idx);
179061da546Spatrick }
180dda28197Spatrick
181dda28197Spatrick // Sort and then erase in reverse so indexes are always valid
182*f6aab3d8Srobert llvm::sort(remove_indexes);
183dda28197Spatrick for (auto index : llvm::reverse(remove_indexes))
184dda28197Spatrick m_path_mappings.Remove(index, m_notify_changes);
185dda28197Spatrick NotifyValueChanged();
186061da546Spatrick } else {
187061da546Spatrick error.SetErrorString("remove operation takes one or more array index");
188061da546Spatrick }
189061da546Spatrick break;
190061da546Spatrick
191061da546Spatrick case eVarSetOperationInvalid:
192061da546Spatrick error = OptionValue::SetValueFromString(value, op);
193061da546Spatrick break;
194061da546Spatrick }
195061da546Spatrick return error;
196061da546Spatrick }
197