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