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) { |
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.SetErrorString("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 | |