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