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