1 //===-- OptionValueFileSpecList.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/OptionValueFileSpecList.h" 10 11 #include "lldb/Host/StringConvert.h" 12 #include "lldb/Utility/Args.h" 13 #include "lldb/Utility/Stream.h" 14 15 using namespace lldb; 16 using namespace lldb_private; 17 18 void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx, 19 Stream &strm, uint32_t dump_mask) { 20 std::lock_guard<std::recursive_mutex> lock(m_mutex); 21 if (dump_mask & eDumpOptionType) 22 strm.Printf("(%s)", GetTypeAsCString()); 23 if (dump_mask & eDumpOptionValue) { 24 const bool one_line = dump_mask & eDumpOptionCommand; 25 const uint32_t size = m_current_value.GetSize(); 26 if (dump_mask & eDumpOptionType) 27 strm.Printf(" =%s", 28 (m_current_value.GetSize() > 0 && !one_line) ? "\n" : ""); 29 if (!one_line) 30 strm.IndentMore(); 31 for (uint32_t i = 0; i < size; ++i) { 32 if (!one_line) { 33 strm.Indent(); 34 strm.Printf("[%u]: ", i); 35 } 36 m_current_value.GetFileSpecAtIndex(i).Dump(strm.AsRawOstream()); 37 if (one_line) 38 strm << ' '; 39 } 40 if (!one_line) 41 strm.IndentLess(); 42 } 43 } 44 45 Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value, 46 VarSetOperationType op) { 47 std::lock_guard<std::recursive_mutex> lock(m_mutex); 48 Status error; 49 Args args(value.str()); 50 const size_t argc = args.GetArgumentCount(); 51 52 switch (op) { 53 case eVarSetOperationClear: 54 Clear(); 55 NotifyValueChanged(); 56 break; 57 58 case eVarSetOperationReplace: 59 if (argc > 1) { 60 uint32_t idx = 61 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 62 const uint32_t count = m_current_value.GetSize(); 63 if (idx > count) { 64 error.SetErrorStringWithFormat( 65 "invalid file list index %u, index must be 0 through %u", idx, 66 count); 67 } else { 68 for (size_t i = 1; i < argc; ++i, ++idx) { 69 FileSpec file(args.GetArgumentAtIndex(i)); 70 if (idx < count) 71 m_current_value.Replace(idx, file); 72 else 73 m_current_value.Append(file); 74 } 75 NotifyValueChanged(); 76 } 77 } else { 78 error.SetErrorString("replace operation takes an array index followed by " 79 "one or more values"); 80 } 81 break; 82 83 case eVarSetOperationAssign: 84 m_current_value.Clear(); 85 // Fall through to append case 86 LLVM_FALLTHROUGH; 87 case eVarSetOperationAppend: 88 if (argc > 0) { 89 m_value_was_set = true; 90 for (size_t i = 0; i < argc; ++i) { 91 FileSpec file(args.GetArgumentAtIndex(i)); 92 m_current_value.Append(file); 93 } 94 NotifyValueChanged(); 95 } else { 96 error.SetErrorString( 97 "assign operation takes at least one file path argument"); 98 } 99 break; 100 101 case eVarSetOperationInsertBefore: 102 case eVarSetOperationInsertAfter: 103 if (argc > 1) { 104 uint32_t idx = 105 StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); 106 const uint32_t count = m_current_value.GetSize(); 107 if (idx > count) { 108 error.SetErrorStringWithFormat( 109 "invalid insert file list index %u, index must be 0 through %u", 110 idx, count); 111 } else { 112 if (op == eVarSetOperationInsertAfter) 113 ++idx; 114 for (size_t i = 1; i < argc; ++i, ++idx) { 115 FileSpec file(args.GetArgumentAtIndex(i)); 116 m_current_value.Insert(idx, file); 117 } 118 NotifyValueChanged(); 119 } 120 } else { 121 error.SetErrorString("insert operation takes an array index followed by " 122 "one or more values"); 123 } 124 break; 125 126 case eVarSetOperationRemove: 127 if (argc > 0) { 128 std::vector<int> remove_indexes; 129 bool all_indexes_valid = true; 130 size_t i; 131 for (i = 0; all_indexes_valid && i < argc; ++i) { 132 const int idx = 133 StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); 134 if (idx == INT32_MAX) 135 all_indexes_valid = false; 136 else 137 remove_indexes.push_back(idx); 138 } 139 140 if (all_indexes_valid) { 141 size_t num_remove_indexes = remove_indexes.size(); 142 if (num_remove_indexes) { 143 // Sort and then erase in reverse so indexes are always valid 144 llvm::sort(remove_indexes.begin(), remove_indexes.end()); 145 for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) { 146 m_current_value.Remove(j); 147 } 148 } 149 NotifyValueChanged(); 150 } else { 151 error.SetErrorStringWithFormat( 152 "invalid array index '%s', aborting remove operation", 153 args.GetArgumentAtIndex(i)); 154 } 155 } else { 156 error.SetErrorString("remove operation takes one or more array index"); 157 } 158 break; 159 160 case eVarSetOperationInvalid: 161 error = OptionValue::SetValueFromString(value, op); 162 break; 163 } 164 return error; 165 } 166 167 OptionValueSP OptionValueFileSpecList::Clone() const { 168 std::lock_guard<std::recursive_mutex> lock(m_mutex); 169 return Cloneable::Clone(); 170 } 171