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