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