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