1e8d8bef9SDimitry Andric //===-- OptionValueFileColonLine.cpp---------------------------------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric #include "lldb/Interpreter/OptionValueFileColonLine.h" 10e8d8bef9SDimitry Andric 11e8d8bef9SDimitry Andric #include "lldb/DataFormatters/FormatManager.h" 12e8d8bef9SDimitry Andric #include "lldb/Interpreter/CommandCompletions.h" 13e8d8bef9SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 14e8d8bef9SDimitry Andric #include "lldb/Utility/Args.h" 15e8d8bef9SDimitry Andric #include "lldb/Utility/State.h" 16e8d8bef9SDimitry Andric 17e8d8bef9SDimitry Andric using namespace lldb; 18e8d8bef9SDimitry Andric using namespace lldb_private; 19e8d8bef9SDimitry Andric 20e8d8bef9SDimitry Andric // This is an OptionValue for parsing file:line:column specifications. 21e8d8bef9SDimitry Andric // I set the completer to "source file" which isn't quite right, but we can 22e8d8bef9SDimitry Andric // only usefully complete in the file name part of it so it should be good 23e8d8bef9SDimitry Andric // enough. 24*fe6060f1SDimitry Andric OptionValueFileColonLine::OptionValueFileColonLine() = default; 25e8d8bef9SDimitry Andric 26e8d8bef9SDimitry Andric OptionValueFileColonLine::OptionValueFileColonLine(llvm::StringRef input) 27*fe6060f1SDimitry Andric : m_line_number(LLDB_INVALID_LINE_NUMBER), 28e8d8bef9SDimitry Andric m_column_number(LLDB_INVALID_COLUMN_NUMBER), 29e8d8bef9SDimitry Andric m_completion_mask(CommandCompletions::eSourceFileCompletion) { 30e8d8bef9SDimitry Andric SetValueFromString(input, eVarSetOperationAssign); 31e8d8bef9SDimitry Andric } 32e8d8bef9SDimitry Andric 33e8d8bef9SDimitry Andric void OptionValueFileColonLine::DumpValue(const ExecutionContext *exe_ctx, 34e8d8bef9SDimitry Andric Stream &strm, uint32_t dump_mask) { 35e8d8bef9SDimitry Andric if (dump_mask & eDumpOptionType) 36e8d8bef9SDimitry Andric strm.Printf("(%s)", GetTypeAsCString()); 37e8d8bef9SDimitry Andric if (dump_mask & eDumpOptionValue) { 38e8d8bef9SDimitry Andric if (dump_mask & eDumpOptionType) 39e8d8bef9SDimitry Andric strm.PutCString(" = "); 40e8d8bef9SDimitry Andric 41e8d8bef9SDimitry Andric if (m_file_spec) 42e8d8bef9SDimitry Andric strm << '"' << m_file_spec.GetPath().c_str() << '"'; 43e8d8bef9SDimitry Andric if (m_line_number != LLDB_INVALID_LINE_NUMBER) 44e8d8bef9SDimitry Andric strm.Printf(":%d", m_line_number); 45e8d8bef9SDimitry Andric if (m_column_number != LLDB_INVALID_COLUMN_NUMBER) 46e8d8bef9SDimitry Andric strm.Printf(":%d", m_column_number); 47e8d8bef9SDimitry Andric } 48e8d8bef9SDimitry Andric } 49e8d8bef9SDimitry Andric 50e8d8bef9SDimitry Andric Status OptionValueFileColonLine::SetValueFromString(llvm::StringRef value, 51e8d8bef9SDimitry Andric VarSetOperationType op) { 52e8d8bef9SDimitry Andric Status error; 53e8d8bef9SDimitry Andric switch (op) { 54e8d8bef9SDimitry Andric case eVarSetOperationClear: 55e8d8bef9SDimitry Andric Clear(); 56e8d8bef9SDimitry Andric NotifyValueChanged(); 57e8d8bef9SDimitry Andric break; 58e8d8bef9SDimitry Andric 59e8d8bef9SDimitry Andric case eVarSetOperationReplace: 60e8d8bef9SDimitry Andric case eVarSetOperationAssign: 61e8d8bef9SDimitry Andric if (value.size() > 0) { 62e8d8bef9SDimitry Andric // This is in the form filename:linenumber:column. 63e8d8bef9SDimitry Andric // I wish we could use filename:linenumber.column, that would make the 64e8d8bef9SDimitry Andric // parsing unambiguous and so much easier... 65e8d8bef9SDimitry Andric // But clang & gcc both print the output with two : so we're stuck with 66e8d8bef9SDimitry Andric // the two colons. Practically, the only actual ambiguity this introduces 67e8d8bef9SDimitry Andric // is with files like "foo:10", which doesn't seem terribly likely. 68e8d8bef9SDimitry Andric 69e8d8bef9SDimitry Andric // Providing the column is optional, so the input value might have one or 70e8d8bef9SDimitry Andric // two colons. First pick off the last colon separated piece. 71e8d8bef9SDimitry Andric // It has to be there, since the line number is required: 72e8d8bef9SDimitry Andric llvm::StringRef last_piece; 73e8d8bef9SDimitry Andric llvm::StringRef left_of_last_piece; 74e8d8bef9SDimitry Andric 75e8d8bef9SDimitry Andric std::tie(left_of_last_piece, last_piece) = value.rsplit(':'); 76e8d8bef9SDimitry Andric if (last_piece.empty()) { 77e8d8bef9SDimitry Andric error.SetErrorStringWithFormat("Line specifier must include file and " 78e8d8bef9SDimitry Andric "line: '%s'", 79e8d8bef9SDimitry Andric value.str().c_str()); 80e8d8bef9SDimitry Andric return error; 81e8d8bef9SDimitry Andric } 82e8d8bef9SDimitry Andric 83e8d8bef9SDimitry Andric // Now see if there's another colon and if so pull out the middle piece: 84e8d8bef9SDimitry Andric // Then check whether the middle piece is an integer. If it is, then it 85e8d8bef9SDimitry Andric // was the line number, and if it isn't we're going to assume that there 86e8d8bef9SDimitry Andric // was a colon in the filename (see note at the beginning of the function) 87e8d8bef9SDimitry Andric // and ignore it. 88e8d8bef9SDimitry Andric llvm::StringRef file_name; 89e8d8bef9SDimitry Andric llvm::StringRef middle_piece; 90e8d8bef9SDimitry Andric 91e8d8bef9SDimitry Andric std::tie(file_name, middle_piece) = left_of_last_piece.rsplit(':'); 92*fe6060f1SDimitry Andric if (middle_piece.empty() || 93*fe6060f1SDimitry Andric !llvm::to_integer(middle_piece, m_line_number)) { 94e8d8bef9SDimitry Andric // The middle piece was empty or not an integer, so there were only two 95e8d8bef9SDimitry Andric // legit pieces; our original division was right. Reassign the file 96e8d8bef9SDimitry Andric // name and pull out the line number: 97e8d8bef9SDimitry Andric file_name = left_of_last_piece; 98e8d8bef9SDimitry Andric if (!llvm::to_integer(last_piece, m_line_number)) { 99e8d8bef9SDimitry Andric error.SetErrorStringWithFormat("Bad line number value '%s' in: '%s'", 100e8d8bef9SDimitry Andric last_piece.str().c_str(), 101e8d8bef9SDimitry Andric value.str().c_str()); 102e8d8bef9SDimitry Andric return error; 103e8d8bef9SDimitry Andric } 104e8d8bef9SDimitry Andric } else { 105e8d8bef9SDimitry Andric // There were three pieces, and we've got the line number. So now 106e8d8bef9SDimitry Andric // we just need to check the column number which was the last peice. 107e8d8bef9SDimitry Andric if (!llvm::to_integer(last_piece, m_column_number)) { 108e8d8bef9SDimitry Andric error.SetErrorStringWithFormat("Bad column value '%s' in: '%s'", 109e8d8bef9SDimitry Andric last_piece.str().c_str(), 110e8d8bef9SDimitry Andric value.str().c_str()); 111e8d8bef9SDimitry Andric return error; 112e8d8bef9SDimitry Andric } 113e8d8bef9SDimitry Andric } 114e8d8bef9SDimitry Andric 115e8d8bef9SDimitry Andric m_value_was_set = true; 116e8d8bef9SDimitry Andric m_file_spec.SetFile(file_name, FileSpec::Style::native); 117e8d8bef9SDimitry Andric NotifyValueChanged(); 118e8d8bef9SDimitry Andric } else { 119e8d8bef9SDimitry Andric error.SetErrorString("invalid value string"); 120e8d8bef9SDimitry Andric } 121e8d8bef9SDimitry Andric break; 122e8d8bef9SDimitry Andric 123e8d8bef9SDimitry Andric case eVarSetOperationInsertBefore: 124e8d8bef9SDimitry Andric case eVarSetOperationInsertAfter: 125e8d8bef9SDimitry Andric case eVarSetOperationRemove: 126e8d8bef9SDimitry Andric case eVarSetOperationAppend: 127e8d8bef9SDimitry Andric case eVarSetOperationInvalid: 128e8d8bef9SDimitry Andric error = OptionValue::SetValueFromString(value, op); 129e8d8bef9SDimitry Andric break; 130e8d8bef9SDimitry Andric } 131e8d8bef9SDimitry Andric return error; 132e8d8bef9SDimitry Andric } 133e8d8bef9SDimitry Andric 134e8d8bef9SDimitry Andric void OptionValueFileColonLine::AutoComplete(CommandInterpreter &interpreter, 135e8d8bef9SDimitry Andric CompletionRequest &request) { 136e8d8bef9SDimitry Andric CommandCompletions::InvokeCommonCompletionCallbacks( 137e8d8bef9SDimitry Andric interpreter, m_completion_mask, request, nullptr); 138e8d8bef9SDimitry Andric } 139