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