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.SetErrorStringWithFormat( 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.SetErrorString("replace operation takes an array index followed by " 77 "one or more values"); 78 } 79 break; 80 81 case eVarSetOperationAssign: 82 m_current_value.Clear(); 83 // Fall through to append case 84 LLVM_FALLTHROUGH; 85 case eVarSetOperationAppend: 86 if (argc > 0) { 87 m_value_was_set = true; 88 for (size_t i = 0; i < argc; ++i) { 89 FileSpec file(args.GetArgumentAtIndex(i)); 90 m_current_value.Append(file); 91 } 92 NotifyValueChanged(); 93 } else { 94 error.SetErrorString( 95 "assign operation takes at least one file path argument"); 96 } 97 break; 98 99 case eVarSetOperationInsertBefore: 100 case eVarSetOperationInsertAfter: 101 if (argc > 1) { 102 uint32_t idx; 103 const uint32_t count = m_current_value.GetSize(); 104 if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) { 105 error.SetErrorStringWithFormat( 106 "invalid insert file list index %s, index must be 0 through %u", 107 args.GetArgumentAtIndex(0), count); 108 } else { 109 if (op == eVarSetOperationInsertAfter) 110 ++idx; 111 for (size_t i = 1; i < argc; ++i, ++idx) { 112 FileSpec file(args.GetArgumentAtIndex(i)); 113 m_current_value.Insert(idx, file); 114 } 115 NotifyValueChanged(); 116 } 117 } else { 118 error.SetErrorString("insert operation takes an array index followed by " 119 "one or more values"); 120 } 121 break; 122 123 case eVarSetOperationRemove: 124 if (argc > 0) { 125 std::vector<int> remove_indexes; 126 bool all_indexes_valid = true; 127 size_t i; 128 for (i = 0; all_indexes_valid && i < argc; ++i) { 129 int idx; 130 if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx)) 131 all_indexes_valid = false; 132 else 133 remove_indexes.push_back(idx); 134 } 135 136 if (all_indexes_valid) { 137 size_t num_remove_indexes = remove_indexes.size(); 138 if (num_remove_indexes) { 139 // Sort and then erase in reverse so indexes are always valid 140 llvm::sort(remove_indexes); 141 for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) { 142 m_current_value.Remove(j); 143 } 144 } 145 NotifyValueChanged(); 146 } else { 147 error.SetErrorStringWithFormat( 148 "invalid array index '%s', aborting remove operation", 149 args.GetArgumentAtIndex(i)); 150 } 151 } else { 152 error.SetErrorString("remove operation takes one or more array index"); 153 } 154 break; 155 156 case eVarSetOperationInvalid: 157 error = OptionValue::SetValueFromString(value, op); 158 break; 159 } 160 return error; 161 } 162 163 OptionValueSP OptionValueFileSpecList::Clone() const { 164 std::lock_guard<std::recursive_mutex> lock(m_mutex); 165 return Cloneable::Clone(); 166 } 167