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