| 1 | //===-- OptionValueFormatEntity.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/OptionValueFormatEntity.h" |
| 10 | |
| 11 | #include "lldb/Core/Module.h" |
| 12 | #include "lldb/Interpreter/CommandInterpreter.h" |
| 13 | #include "lldb/Utility/Stream.h" |
| 14 | #include "lldb/Utility/StringList.h" |
| 15 | using namespace lldb; |
| 16 | using namespace lldb_private; |
| 17 | |
| 18 | OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format) { |
| 19 | if (default_format && default_format[0]) { |
| 20 | llvm::StringRef default_format_str(default_format); |
| 21 | Status error = FormatEntity::Parse(format: default_format_str, entry&: m_default_entry); |
| 22 | if (error.Success()) { |
| 23 | m_default_format = default_format; |
| 24 | m_current_format = default_format; |
| 25 | m_current_entry = m_default_entry; |
| 26 | } |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | void OptionValueFormatEntity::Clear() { |
| 31 | m_current_entry = m_default_entry; |
| 32 | m_current_format = m_default_format; |
| 33 | m_value_was_set = false; |
| 34 | } |
| 35 | |
| 36 | static void EscapeBackticks(llvm::StringRef str, std::string &dst) { |
| 37 | dst.clear(); |
| 38 | dst.reserve(res: str.size()); |
| 39 | |
| 40 | for (size_t i = 0, e = str.size(); i != e; ++i) { |
| 41 | char c = str[i]; |
| 42 | if (c == '`') { |
| 43 | if (i == 0 || str[i - 1] != '\\') |
| 44 | dst += '\\'; |
| 45 | } |
| 46 | dst += c; |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx, |
| 51 | Stream &strm, uint32_t dump_mask) { |
| 52 | if (dump_mask & eDumpOptionType) |
| 53 | strm.Printf(format: "(%s)" , GetTypeAsCString()); |
| 54 | if (dump_mask & eDumpOptionValue) { |
| 55 | if (dump_mask & eDumpOptionType) |
| 56 | strm.PutCString(cstr: " = " ); |
| 57 | std::string escaped; |
| 58 | EscapeBackticks(str: m_current_format, dst&: escaped); |
| 59 | strm << '"' << escaped << '"'; |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | llvm::json::Value |
| 64 | OptionValueFormatEntity::ToJSON(const ExecutionContext *exe_ctx) const { |
| 65 | std::string escaped; |
| 66 | EscapeBackticks(str: m_current_format, dst&: escaped); |
| 67 | return escaped; |
| 68 | } |
| 69 | |
| 70 | Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str, |
| 71 | VarSetOperationType op) { |
| 72 | Status error; |
| 73 | switch (op) { |
| 74 | case eVarSetOperationClear: |
| 75 | Clear(); |
| 76 | NotifyValueChanged(); |
| 77 | break; |
| 78 | |
| 79 | case eVarSetOperationReplace: |
| 80 | case eVarSetOperationAssign: { |
| 81 | // Check if the string starts with a quote character after removing leading |
| 82 | // and trailing spaces. If it does start with a quote character, make sure |
| 83 | // it ends with the same quote character and remove the quotes before we |
| 84 | // parse the format string. If the string doesn't start with a quote, leave |
| 85 | // the string alone and parse as is. |
| 86 | llvm::StringRef trimmed_value_str = value_str.trim(); |
| 87 | if (!trimmed_value_str.empty()) { |
| 88 | const char first_char = trimmed_value_str[0]; |
| 89 | if (first_char == '"' || first_char == '\'') { |
| 90 | const size_t trimmed_len = trimmed_value_str.size(); |
| 91 | if (trimmed_len == 1 || value_str[trimmed_len - 1] != first_char) { |
| 92 | error = Status::FromErrorString(str: "mismatched quotes" ); |
| 93 | return error; |
| 94 | } |
| 95 | value_str = trimmed_value_str.substr(Start: 1, N: trimmed_len - 2); |
| 96 | } |
| 97 | } |
| 98 | FormatEntity::Entry entry; |
| 99 | error = FormatEntity::Parse(format: value_str, entry); |
| 100 | if (error.Success()) { |
| 101 | m_current_entry = std::move(entry); |
| 102 | m_current_format = std::string(value_str); |
| 103 | m_value_was_set = true; |
| 104 | NotifyValueChanged(); |
| 105 | } |
| 106 | } break; |
| 107 | |
| 108 | case eVarSetOperationInsertBefore: |
| 109 | case eVarSetOperationInsertAfter: |
| 110 | case eVarSetOperationRemove: |
| 111 | case eVarSetOperationAppend: |
| 112 | case eVarSetOperationInvalid: |
| 113 | error = OptionValue::SetValueFromString(value: value_str, op); |
| 114 | break; |
| 115 | } |
| 116 | return error; |
| 117 | } |
| 118 | |
| 119 | void OptionValueFormatEntity::AutoComplete(CommandInterpreter &interpreter, |
| 120 | CompletionRequest &request) { |
| 121 | FormatEntity::AutoComplete(request); |
| 122 | } |
| 123 | |