180814287SRaphael Isemann //===-- OptionValuePathMappings.cpp ---------------------------------------===//
267cc0636SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
667cc0636SGreg Clayton //
767cc0636SGreg Clayton //===----------------------------------------------------------------------===//
867cc0636SGreg Clayton 
967cc0636SGreg Clayton #include "lldb/Interpreter/OptionValuePathMappings.h"
1067cc0636SGreg Clayton 
11dbd7fabaSJonas Devlieghere #include "lldb/Host/FileSystem.h"
125275aaa0SVince Harron #include "lldb/Host/StringConvert.h"
13145d95c9SPavel Labath #include "lldb/Utility/Args.h"
145713a05bSZachary Turner #include "lldb/Utility/FileSpec.h"
15bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
1667cc0636SGreg Clayton 
1767cc0636SGreg Clayton using namespace lldb;
1867cc0636SGreg Clayton using namespace lldb_private;
19b9c1b51eSKate Stone namespace {
20b9c1b51eSKate Stone static bool VerifyPathExists(const char *path) {
216a311641SGreg Clayton   if (path && path[0])
22dbd7fabaSJonas Devlieghere     return FileSystem::Instance().Exists(path);
236a311641SGreg Clayton   else
246a311641SGreg Clayton     return false;
256a311641SGreg Clayton }
266a311641SGreg Clayton }
276a311641SGreg Clayton 
28b9c1b51eSKate Stone void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
29b9c1b51eSKate Stone                                         Stream &strm, uint32_t dump_mask) {
3067cc0636SGreg Clayton   if (dump_mask & eDumpOptionType)
3167cc0636SGreg Clayton     strm.Printf("(%s)", GetTypeAsCString());
32b9c1b51eSKate Stone   if (dump_mask & eDumpOptionValue) {
3367cc0636SGreg Clayton     if (dump_mask & eDumpOptionType)
3467cc0636SGreg Clayton       strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
3567cc0636SGreg Clayton     m_path_mappings.Dump(&strm);
3667cc0636SGreg Clayton   }
3767cc0636SGreg Clayton }
3867cc0636SGreg Clayton 
3997206d57SZachary Turner Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
40b9c1b51eSKate Stone                                                    VarSetOperationType op) {
4197206d57SZachary Turner   Status error;
42771ef6d4SMalcolm Parsons   Args args(value.str());
4367cc0636SGreg Clayton   const size_t argc = args.GetArgumentCount();
4467cc0636SGreg Clayton 
45b9c1b51eSKate Stone   switch (op) {
4667cc0636SGreg Clayton   case eVarSetOperationClear:
4767cc0636SGreg Clayton     Clear();
48332e8b1cSGreg Clayton     NotifyValueChanged();
4967cc0636SGreg Clayton     break;
5067cc0636SGreg Clayton 
5167cc0636SGreg Clayton   case eVarSetOperationReplace:
52b9c1b51eSKate Stone     // Must be at least one index + 1 pair of paths, and the pair count must be
53b9c1b51eSKate Stone     // even
54b9c1b51eSKate Stone     if (argc >= 3 && (((argc - 1) & 1) == 0)) {
55b9c1b51eSKate Stone       uint32_t idx =
56b9c1b51eSKate Stone           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
5767cc0636SGreg Clayton       const uint32_t count = m_path_mappings.GetSize();
58b9c1b51eSKate Stone       if (idx > count) {
59b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
60b9c1b51eSKate Stone             "invalid file list index %u, index must be 0 through %u", idx,
61b9c1b51eSKate Stone             count);
62b9c1b51eSKate Stone       } else {
636a311641SGreg Clayton         bool changed = false;
64*ca47ac3dSWalter Erquinigo         for (size_t i = 1; i < argc; idx++, i += 2) {
656a311641SGreg Clayton           const char *orginal_path = args.GetArgumentAtIndex(i);
666a311641SGreg Clayton           const char *replace_path = args.GetArgumentAtIndex(i + 1);
67b9c1b51eSKate Stone           if (VerifyPathExists(replace_path)) {
686a311641SGreg Clayton             ConstString a(orginal_path);
696a311641SGreg Clayton             ConstString b(replace_path);
7067cc0636SGreg Clayton             if (!m_path_mappings.Replace(a, b, idx, m_notify_changes))
7167cc0636SGreg Clayton               m_path_mappings.Append(a, b, m_notify_changes);
726a311641SGreg Clayton             changed = true;
73b9c1b51eSKate Stone           } else {
7430350c25SWalter Erquinigo             std::string previousError =
7530350c25SWalter Erquinigo                 error.Fail() ? std::string(error.AsCString()) + "\n" : "";
76b9c1b51eSKate Stone             error.SetErrorStringWithFormat(
7730350c25SWalter Erquinigo                 "%sthe replacement path doesn't exist: \"%s\"",
7830350c25SWalter Erquinigo                 previousError.c_str(), replace_path);
796a311641SGreg Clayton           }
806a311641SGreg Clayton         }
816a311641SGreg Clayton         if (changed)
82332e8b1cSGreg Clayton           NotifyValueChanged();
8367cc0636SGreg Clayton       }
84b9c1b51eSKate Stone     } else {
85b9c1b51eSKate Stone       error.SetErrorString("replace operation takes an array index followed by "
86b9c1b51eSKate Stone                            "one or more path pairs");
8767cc0636SGreg Clayton     }
8867cc0636SGreg Clayton     break;
8967cc0636SGreg Clayton 
9067cc0636SGreg Clayton   case eVarSetOperationAssign:
91b9c1b51eSKate Stone     if (argc < 2 || (argc & 1)) {
9267cc0636SGreg Clayton       error.SetErrorString("assign operation takes one or more path pairs");
9367cc0636SGreg Clayton       break;
9467cc0636SGreg Clayton     }
9567cc0636SGreg Clayton     m_path_mappings.Clear(m_notify_changes);
9667cc0636SGreg Clayton     // Fall through to append case
9762e0681aSJason Molenda     LLVM_FALLTHROUGH;
9867cc0636SGreg Clayton   case eVarSetOperationAppend:
99b9c1b51eSKate Stone     if (argc < 2 || (argc & 1)) {
10067cc0636SGreg Clayton       error.SetErrorString("append operation takes one or more path pairs");
10167cc0636SGreg Clayton       break;
102b9c1b51eSKate Stone     } else {
1036a311641SGreg Clayton       bool changed = false;
104b9c1b51eSKate Stone       for (size_t i = 0; i < argc; i += 2) {
1056a311641SGreg Clayton         const char *orginal_path = args.GetArgumentAtIndex(i);
1066a311641SGreg Clayton         const char *replace_path = args.GetArgumentAtIndex(i + 1);
107b9c1b51eSKate Stone         if (VerifyPathExists(replace_path)) {
1086a311641SGreg Clayton           ConstString a(orginal_path);
1096a311641SGreg Clayton           ConstString b(replace_path);
11067cc0636SGreg Clayton           m_path_mappings.Append(a, b, m_notify_changes);
11167cc0636SGreg Clayton           m_value_was_set = true;
1126a311641SGreg Clayton           changed = true;
113b9c1b51eSKate Stone         } else {
11430350c25SWalter Erquinigo           std::string previousError =
11530350c25SWalter Erquinigo               error.Fail() ? std::string(error.AsCString()) + "\n" : "";
116b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
11730350c25SWalter Erquinigo               "%sthe replacement path doesn't exist: \"%s\"",
11830350c25SWalter Erquinigo               previousError.c_str(), replace_path);
1196a311641SGreg Clayton         }
1206a311641SGreg Clayton       }
1216a311641SGreg Clayton       if (changed)
122332e8b1cSGreg Clayton         NotifyValueChanged();
12367cc0636SGreg Clayton     }
12467cc0636SGreg Clayton     break;
12567cc0636SGreg Clayton 
12667cc0636SGreg Clayton   case eVarSetOperationInsertBefore:
12767cc0636SGreg Clayton   case eVarSetOperationInsertAfter:
128b9c1b51eSKate Stone     // Must be at least one index + 1 pair of paths, and the pair count must be
129b9c1b51eSKate Stone     // even
130b9c1b51eSKate Stone     if (argc >= 3 && (((argc - 1) & 1) == 0)) {
131b9c1b51eSKate Stone       uint32_t idx =
132b9c1b51eSKate Stone           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
13367cc0636SGreg Clayton       const uint32_t count = m_path_mappings.GetSize();
134b9c1b51eSKate Stone       if (idx > count) {
135b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
136b9c1b51eSKate Stone             "invalid file list index %u, index must be 0 through %u", idx,
137b9c1b51eSKate Stone             count);
138b9c1b51eSKate Stone       } else {
1396a311641SGreg Clayton         bool changed = false;
14067cc0636SGreg Clayton         if (op == eVarSetOperationInsertAfter)
14167cc0636SGreg Clayton           ++idx;
14230350c25SWalter Erquinigo         for (size_t i = 1; i < argc; i += 2) {
1436a311641SGreg Clayton           const char *orginal_path = args.GetArgumentAtIndex(i);
1446a311641SGreg Clayton           const char *replace_path = args.GetArgumentAtIndex(i + 1);
145b9c1b51eSKate Stone           if (VerifyPathExists(replace_path)) {
1466a311641SGreg Clayton             ConstString a(orginal_path);
1476a311641SGreg Clayton             ConstString b(replace_path);
14867cc0636SGreg Clayton             m_path_mappings.Insert(a, b, idx, m_notify_changes);
1496a311641SGreg Clayton             changed = true;
15030350c25SWalter Erquinigo             idx++;
151b9c1b51eSKate Stone           } else {
15230350c25SWalter Erquinigo             std::string previousError =
15330350c25SWalter Erquinigo                 error.Fail() ? std::string(error.AsCString()) + "\n" : "";
154b9c1b51eSKate Stone             error.SetErrorStringWithFormat(
15530350c25SWalter Erquinigo                 "%sthe replacement path doesn't exist: \"%s\"",
15630350c25SWalter Erquinigo                 previousError.c_str(), replace_path);
1576a311641SGreg Clayton           }
1586a311641SGreg Clayton         }
1596a311641SGreg Clayton         if (changed)
160332e8b1cSGreg Clayton           NotifyValueChanged();
16167cc0636SGreg Clayton       }
162b9c1b51eSKate Stone     } else {
163b9c1b51eSKate Stone       error.SetErrorString("insert operation takes an array index followed by "
164b9c1b51eSKate Stone                            "one or more path pairs");
16567cc0636SGreg Clayton     }
16667cc0636SGreg Clayton     break;
16767cc0636SGreg Clayton 
16867cc0636SGreg Clayton   case eVarSetOperationRemove:
169b9c1b51eSKate Stone     if (argc > 0) {
17067cc0636SGreg Clayton       std::vector<int> remove_indexes;
171*ca47ac3dSWalter Erquinigo       for (size_t i = 0; i < argc; ++i) {
172*ca47ac3dSWalter Erquinigo         int idx =
173b9c1b51eSKate Stone             StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
174*ca47ac3dSWalter Erquinigo         if (idx < 0 || idx >= (int)m_path_mappings.GetSize()) {
175b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
176b9c1b51eSKate Stone               "invalid array index '%s', aborting remove operation",
177b9c1b51eSKate Stone               args.GetArgumentAtIndex(i));
178*ca47ac3dSWalter Erquinigo           break;
179*ca47ac3dSWalter Erquinigo         } else
180*ca47ac3dSWalter Erquinigo           remove_indexes.push_back(idx);
18167cc0636SGreg Clayton       }
182*ca47ac3dSWalter Erquinigo 
183*ca47ac3dSWalter Erquinigo       // Sort and then erase in reverse so indexes are always valid
184*ca47ac3dSWalter Erquinigo       llvm::sort(remove_indexes.begin(), remove_indexes.end());
185*ca47ac3dSWalter Erquinigo       for (auto index : llvm::reverse(remove_indexes))
186*ca47ac3dSWalter Erquinigo         m_path_mappings.Remove(index, m_notify_changes);
187*ca47ac3dSWalter Erquinigo       NotifyValueChanged();
188b9c1b51eSKate Stone     } else {
18967cc0636SGreg Clayton       error.SetErrorString("remove operation takes one or more array index");
19067cc0636SGreg Clayton     }
19167cc0636SGreg Clayton     break;
19267cc0636SGreg Clayton 
19367cc0636SGreg Clayton   case eVarSetOperationInvalid:
194c95f7e2aSPavel Labath     error = OptionValue::SetValueFromString(value, op);
19567cc0636SGreg Clayton     break;
19667cc0636SGreg Clayton   }
19767cc0636SGreg Clayton   return error;
19867cc0636SGreg Clayton }
19967cc0636SGreg Clayton 
200b9c1b51eSKate Stone lldb::OptionValueSP OptionValuePathMappings::DeepCopy() const {
20167cc0636SGreg Clayton   return OptionValueSP(new OptionValuePathMappings(*this));
20267cc0636SGreg Clayton }
203