xref: /openbsd-src/gnu/llvm/lldb/source/Interpreter/OptionValuePathMappings.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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