210 lines · cpp
1//===-- OptionValuePathMappings.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Interpreter/OptionValuePathMappings.h"10 11#include "lldb/Host/FileSystem.h"12#include "lldb/Interpreter/OptionValue.h"13#include "lldb/Utility/Args.h"14#include "lldb/Utility/FileSpec.h"15#include "lldb/Utility/Stream.h"16 17using namespace lldb;18using namespace lldb_private;19 20static bool VerifyPathExists(const char *path) {21 if (path && path[0])22 return FileSystem::Instance().Exists(path);23 else24 return false;25}26 27void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,28 Stream &strm, uint32_t dump_mask) {29 if (dump_mask & eDumpOptionType)30 strm.Printf("(%s)", GetTypeAsCString());31 if (dump_mask & eDumpOptionValue) {32 if (dump_mask & (eDumpOptionType | eDumpOptionDefaultValue)) {33 strm.Printf(" =");34 if (dump_mask & eDumpOptionDefaultValue && !m_path_mappings.IsEmpty()) {35 DefaultValueFormat label(strm);36 strm.PutCString("empty");37 }38 if (!m_path_mappings.IsEmpty())39 strm.PutCString("\n");40 }41 m_path_mappings.Dump(&strm);42 }43}44 45llvm::json::Value46OptionValuePathMappings::ToJSON(const ExecutionContext *exe_ctx) const {47 return m_path_mappings.ToJSON();48}49 50Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,51 VarSetOperationType op) {52 Status error;53 Args args(value.str());54 const size_t argc = args.GetArgumentCount();55 56 switch (op) {57 case eVarSetOperationClear:58 Clear();59 NotifyValueChanged();60 break;61 62 case eVarSetOperationReplace:63 // Must be at least one index + 1 pair of paths, and the pair count must be64 // even65 if (argc >= 3 && (((argc - 1) & 1) == 0)) {66 uint32_t idx;67 const uint32_t count = m_path_mappings.GetSize();68 if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {69 error = Status::FromErrorStringWithFormat(70 "invalid file list index %s, index must be 0 through %u",71 args.GetArgumentAtIndex(0), count);72 } else {73 bool changed = false;74 for (size_t i = 1; i < argc; idx++, i += 2) {75 const char *orginal_path = args.GetArgumentAtIndex(i);76 const char *replace_path = args.GetArgumentAtIndex(i + 1);77 if (VerifyPathExists(replace_path)) {78 if (!m_path_mappings.Replace(orginal_path, replace_path, idx,79 m_notify_changes))80 m_path_mappings.Append(orginal_path, replace_path,81 m_notify_changes);82 changed = true;83 } else {84 std::string previousError =85 error.Fail() ? std::string(error.AsCString()) + "\n" : "";86 error = Status::FromErrorStringWithFormat(87 "%sthe replacement path doesn't exist: \"%s\"",88 previousError.c_str(), replace_path);89 }90 }91 if (changed)92 NotifyValueChanged();93 }94 } else {95 error = Status::FromErrorString(96 "replace operation takes an array index followed by "97 "one or more path pairs");98 }99 break;100 101 case eVarSetOperationAssign:102 if (argc < 2 || (argc & 1)) {103 error = Status::FromErrorString(104 "assign operation takes one or more path pairs");105 break;106 }107 m_path_mappings.Clear(m_notify_changes);108 // Fall through to append case109 [[fallthrough]];110 case eVarSetOperationAppend:111 if (argc < 2 || (argc & 1)) {112 error = Status::FromErrorString(113 "append operation takes one or more path pairs");114 break;115 } else {116 bool changed = false;117 for (size_t i = 0; i < argc; i += 2) {118 const char *orginal_path = args.GetArgumentAtIndex(i);119 const char *replace_path = args.GetArgumentAtIndex(i + 1);120 if (VerifyPathExists(replace_path)) {121 m_path_mappings.Append(orginal_path, replace_path, m_notify_changes);122 m_value_was_set = true;123 changed = true;124 } else {125 std::string previousError =126 error.Fail() ? std::string(error.AsCString()) + "\n" : "";127 error = Status::FromErrorStringWithFormat(128 "%sthe replacement path doesn't exist: \"%s\"",129 previousError.c_str(), replace_path);130 }131 }132 if (changed)133 NotifyValueChanged();134 }135 break;136 137 case eVarSetOperationInsertBefore:138 case eVarSetOperationInsertAfter:139 // Must be at least one index + 1 pair of paths, and the pair count must be140 // even141 if (argc >= 3 && (((argc - 1) & 1) == 0)) {142 uint32_t idx;143 const uint32_t count = m_path_mappings.GetSize();144 if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {145 error = Status::FromErrorStringWithFormat(146 "invalid file list index %s, index must be 0 through %u",147 args.GetArgumentAtIndex(0), count);148 } else {149 bool changed = false;150 if (op == eVarSetOperationInsertAfter)151 ++idx;152 for (size_t i = 1; i < argc; i += 2) {153 const char *orginal_path = args.GetArgumentAtIndex(i);154 const char *replace_path = args.GetArgumentAtIndex(i + 1);155 if (VerifyPathExists(replace_path)) {156 m_path_mappings.Insert(orginal_path, replace_path, idx,157 m_notify_changes);158 changed = true;159 idx++;160 } else {161 std::string previousError =162 error.Fail() ? std::string(error.AsCString()) + "\n" : "";163 error = Status::FromErrorStringWithFormat(164 "%sthe replacement path doesn't exist: \"%s\"",165 previousError.c_str(), replace_path);166 }167 }168 if (changed)169 NotifyValueChanged();170 }171 } else {172 error = Status::FromErrorString(173 "insert operation takes an array index followed by "174 "one or more path pairs");175 }176 break;177 178 case eVarSetOperationRemove:179 if (argc > 0) {180 std::vector<int> remove_indexes;181 for (size_t i = 0; i < argc; ++i) {182 int idx;183 if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx) || idx < 0 ||184 idx >= (int)m_path_mappings.GetSize()) {185 error = Status::FromErrorStringWithFormat(186 "invalid array index '%s', aborting remove operation",187 args.GetArgumentAtIndex(i));188 break;189 } else190 remove_indexes.push_back(idx);191 }192 193 // Sort and then erase in reverse so indexes are always valid194 llvm::sort(remove_indexes);195 for (auto index : llvm::reverse(remove_indexes))196 m_path_mappings.Remove(index, m_notify_changes);197 NotifyValueChanged();198 } else {199 error = Status::FromErrorString(200 "remove operation takes one or more array index");201 }202 break;203 204 case eVarSetOperationInvalid:205 error = OptionValue::SetValueFromString(value, op);206 break;207 }208 return error;209}210