15ffd83dbSDimitry Andric //===-- OptionValueFormatEntity.cpp ---------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueFormatEntity.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Core/Module.h"
120b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
130b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
140b57cec5SDimitry Andric #include "lldb/Utility/StringList.h"
150b57cec5SDimitry Andric using namespace lldb;
160b57cec5SDimitry Andric using namespace lldb_private;
170b57cec5SDimitry Andric
OptionValueFormatEntity(const char * default_format)18fe6060f1SDimitry Andric OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format) {
190b57cec5SDimitry Andric if (default_format && default_format[0]) {
200b57cec5SDimitry Andric llvm::StringRef default_format_str(default_format);
210b57cec5SDimitry Andric Status error = FormatEntity::Parse(default_format_str, m_default_entry);
220b57cec5SDimitry Andric if (error.Success()) {
230b57cec5SDimitry Andric m_default_format = default_format;
240b57cec5SDimitry Andric m_current_format = default_format;
250b57cec5SDimitry Andric m_current_entry = m_default_entry;
260b57cec5SDimitry Andric }
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric
Clear()30e8d8bef9SDimitry Andric void OptionValueFormatEntity::Clear() {
310b57cec5SDimitry Andric m_current_entry = m_default_entry;
320b57cec5SDimitry Andric m_current_format = m_default_format;
330b57cec5SDimitry Andric m_value_was_set = false;
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric
EscapeBackticks(llvm::StringRef str,std::string & dst)360b57cec5SDimitry Andric static void EscapeBackticks(llvm::StringRef str, std::string &dst) {
370b57cec5SDimitry Andric dst.clear();
380b57cec5SDimitry Andric dst.reserve(str.size());
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric for (size_t i = 0, e = str.size(); i != e; ++i) {
410b57cec5SDimitry Andric char c = str[i];
420b57cec5SDimitry Andric if (c == '`') {
430b57cec5SDimitry Andric if (i == 0 || str[i - 1] != '\\')
440b57cec5SDimitry Andric dst += '\\';
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric dst += c;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)500b57cec5SDimitry Andric void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx,
510b57cec5SDimitry Andric Stream &strm, uint32_t dump_mask) {
520b57cec5SDimitry Andric if (dump_mask & eDumpOptionType)
530b57cec5SDimitry Andric strm.Printf("(%s)", GetTypeAsCString());
540b57cec5SDimitry Andric if (dump_mask & eDumpOptionValue) {
550b57cec5SDimitry Andric if (dump_mask & eDumpOptionType)
560b57cec5SDimitry Andric strm.PutCString(" = ");
570b57cec5SDimitry Andric std::string escaped;
580b57cec5SDimitry Andric EscapeBackticks(m_current_format, escaped);
590b57cec5SDimitry Andric strm << '"' << escaped << '"';
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
63*bdd1243dSDimitry Andric llvm::json::Value
ToJSON(const ExecutionContext * exe_ctx)64*bdd1243dSDimitry Andric OptionValueFormatEntity::ToJSON(const ExecutionContext *exe_ctx) {
65*bdd1243dSDimitry Andric std::string escaped;
66*bdd1243dSDimitry Andric EscapeBackticks(m_current_format, escaped);
67*bdd1243dSDimitry Andric return escaped;
68*bdd1243dSDimitry Andric }
69*bdd1243dSDimitry Andric
SetValueFromString(llvm::StringRef value_str,VarSetOperationType op)700b57cec5SDimitry Andric Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str,
710b57cec5SDimitry Andric VarSetOperationType op) {
720b57cec5SDimitry Andric Status error;
730b57cec5SDimitry Andric switch (op) {
740b57cec5SDimitry Andric case eVarSetOperationClear:
750b57cec5SDimitry Andric Clear();
760b57cec5SDimitry Andric NotifyValueChanged();
770b57cec5SDimitry Andric break;
780b57cec5SDimitry Andric
790b57cec5SDimitry Andric case eVarSetOperationReplace:
800b57cec5SDimitry Andric case eVarSetOperationAssign: {
810b57cec5SDimitry Andric // Check if the string starts with a quote character after removing leading
820b57cec5SDimitry Andric // and trailing spaces. If it does start with a quote character, make sure
830b57cec5SDimitry Andric // it ends with the same quote character and remove the quotes before we
840b57cec5SDimitry Andric // parse the format string. If the string doesn't start with a quote, leave
850b57cec5SDimitry Andric // the string alone and parse as is.
860b57cec5SDimitry Andric llvm::StringRef trimmed_value_str = value_str.trim();
870b57cec5SDimitry Andric if (!trimmed_value_str.empty()) {
880b57cec5SDimitry Andric const char first_char = trimmed_value_str[0];
890b57cec5SDimitry Andric if (first_char == '"' || first_char == '\'') {
900b57cec5SDimitry Andric const size_t trimmed_len = trimmed_value_str.size();
910b57cec5SDimitry Andric if (trimmed_len == 1 || value_str[trimmed_len - 1] != first_char) {
92e8d8bef9SDimitry Andric error.SetErrorString("mismatched quotes");
930b57cec5SDimitry Andric return error;
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric value_str = trimmed_value_str.substr(1, trimmed_len - 2);
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric FormatEntity::Entry entry;
990b57cec5SDimitry Andric error = FormatEntity::Parse(value_str, entry);
1000b57cec5SDimitry Andric if (error.Success()) {
1010b57cec5SDimitry Andric m_current_entry = std::move(entry);
1025ffd83dbSDimitry Andric m_current_format = std::string(value_str);
1030b57cec5SDimitry Andric m_value_was_set = true;
1040b57cec5SDimitry Andric NotifyValueChanged();
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric } break;
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric case eVarSetOperationInsertBefore:
1090b57cec5SDimitry Andric case eVarSetOperationInsertAfter:
1100b57cec5SDimitry Andric case eVarSetOperationRemove:
1110b57cec5SDimitry Andric case eVarSetOperationAppend:
1120b57cec5SDimitry Andric case eVarSetOperationInvalid:
1130b57cec5SDimitry Andric error = OptionValue::SetValueFromString(value_str, op);
1140b57cec5SDimitry Andric break;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric return error;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric
AutoComplete(CommandInterpreter & interpreter,CompletionRequest & request)1199dba64beSDimitry Andric void OptionValueFormatEntity::AutoComplete(CommandInterpreter &interpreter,
1200b57cec5SDimitry Andric CompletionRequest &request) {
1219dba64beSDimitry Andric FormatEntity::AutoComplete(request);
1220b57cec5SDimitry Andric }
123