home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 mARCH
/
PCWK3A99.iso
/
Linux
/
DDD331
/
DDD-3_1_.000
/
DDD-3_1_
/
ddd-3.1.1
/
ddd
/
PosBuffer.C
< prev
next >
Wrap
C/C++ Source or Header
|
1998-12-06
|
27KB
|
1,145 lines
// $Id: PosBuffer.C,v 1.80.4.1 1998/12/06 12:59:19 zeller Exp $
// Filter position information from GDB output.
// Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
// Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>
// and Andreas Zeller <zeller@ips.cs.tu-bs.de>.
//
// This file is part of DDD.
//
// DDD is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// DDD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with DDD -- see the file COPYING.
// If not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page,
// `http://www.cs.tu-bs.de/softech/ddd/',
// or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
char PosBuffer_rcsid[] =
"$Id: PosBuffer.C,v 1.80.4.1 1998/12/06 12:59:19 zeller Exp $";
#ifdef __GNUG__
#pragma implementation
#endif
// Misc includes
#include "assert.h"
#include "cook.h"
// DDD includes
#include "AppData.h"
#include "PosBuffer.h"
#include "comm-manag.h"
#include "string-fun.h"
#include "ddd.h"
#include "GDBAgent.h"
#include "SourceView.h"
#include "regexps.h"
#include "index.h"
#if RUNTIME_REGEX
// A regex for C addresses ("0xdead") and Modula-2 addresses ("0BEEFH");
regex rxaddress(RXADDRESS);
regex rxaddress_start(RXADDRESS_START);
#endif
// Filter all lines from ANSWER beginning with LINE. This is required
// to suppress the line number output after a `stopping in' message.
static void filter_line(string& answer, int line)
{
if (line <= 0)
return;
int pos = 0;
do {
if (atoi((char *)answer + pos) == line)
{
answer = answer.before(pos) + answer.after('\n', pos);
break;
}
pos = answer.index('\n', pos) + 1;
} while (pos > 0);
}
// Return true iff ANSWER has a line beginning with PREFIX
static bool has_prefix(const string& answer, const string& prefix)
{
int index = answer.index(prefix);
return index == 0 || index > 0 && answer[index - 1] == '\n';
}
// Store first address in ANSWER after INDEX in BUFFER
static void fetch_address(const string& answer, int index, string& buffer)
{
if (buffer != "")
return; // Already have an address
while (index < int(answer.length()) && !is_address_start(answer[index]))
index++;
assert (is_address_start(answer[index]));
int start = index;
// Just fetch the first word -- no need to do big address matches here
while (index < int(answer.length()) && !isspace(answer[index]))
index++;
buffer = ((string&)answer).at(start, index - start);
}
// Store first function name in ANSWER after INDEX in BUFFER
static void fetch_function(const string& answer, int index, string& buffer,
bool in_required = false)
{
if (buffer != "")
return; // Already have a function
string line = answer.from(index);
line = line.before('\n');
if (in_required)
line = line.after(" in ");
// The function name is the word before the opening parenthesis
line = line.before('(');
strip_trailing_space(line);
int ws_index = line.index(' ', -1) + 1;
line = line.from(ws_index);
strip_leading_space(line);
if (line != "" && line.contains(rxidentifier, 0))
buffer = line;
}
// Same, but requires " in " before function
inline void fetch_in_function(const string& answer, int index, string& buffer)
{
fetch_function(answer, index, buffer, true);
}
// Fetch position from GDB output ANSWER.
void PosBuffer::filter (string& answer)
{
if (answer.length() == 0)
return;
// Check program state
switch (gdb->type())
{
case GDB:
{
// If GDB prints a "Current function" line, it overrides whatever
// came before (e.g. "stopped in").
if (has_prefix(answer, "Current function is "))
already_read = Null;
// Check program state
if (has_prefix(answer, "Starting program: "))
started = true;
if (has_prefix(answer, "The program no longer exists"))
terminated = true;
if (has_prefix(answer, "Program received signal"))
signaled = true;
if (has_prefix(answer, "Program terminated with signal"))
signaled = terminated = true;
if (answer.contains("has changed; re-reading symbols"))
recompiled = true;
if (has_prefix(answer, "Current language: "))
gdb->program_language(answer);
if (has_prefix(answer, "The current source language is "))
gdb->program_language(answer);
}
break;
case DBX:
{
if (has_prefix(answer, "Running: "))
started = true;
if (answer.contains("has been recompiled"))
recompiled = true;
if (has_prefix(answer, "signal "))
signaled = true;
}
break;
case XDB:
case JDB:
case PYDB:
case PERL:
break; // Nothing special
}
// Check for terminated program
int i = -1;
while ((i = answer.index("rogram", i + 1)) > 0)
{
int j = i;
while (j > 0 && answer[j - 1] != '\n')
j--;
#if RUNTIME_REGEX
static regex rxterminated("([Tt]he )?[Pp]rogram "
"(exited|terminated"
"|is not being run|no longer exists).*");
#endif
if (answer.matches(rxterminated, j))
terminated = true;
}
if (answer.contains("no active process")
|| answer.contains("execution completed")
|| answer.contains("application exited"))
terminated = true;
// Check for auto command
if (app_data.auto_commands)
{
if (auto_cmd_buffer != "" && !auto_cmd_buffer.contains('\n', -1))
{
// Complete pending auto command
if (answer.contains('\n'))
{
auto_cmd_buffer += answer.through('\n');
answer = answer.after('\n');
}
else
{
auto_cmd_buffer += answer;
answer = "";
}
}
while (has_prefix(answer, app_data.auto_command_prefix))
{
int index = answer.index(app_data.auto_command_prefix);
string cmd = answer.from(index);
if (cmd.contains('\n'))
cmd = cmd.through('\n');
answer =
answer.before(index) + answer.from(int(index + cmd.length()));
cmd = cmd.after(app_data.auto_command_prefix);
auto_cmd_buffer += cmd;
}
}
// Fetch and store position info, return remainder
switch (already_read)
{
case PosComplete:
// Nothing more to filter
// Skip possible line number info
switch (gdb->type())
{
case GDB:
break;
case DBX:
{
string line_s = pos_buffer;
if (line_s.contains(':'))
line_s = line_s.after(':');
int line = atoi(line_s);
filter_line(answer, line);
}
case XDB:
case JDB:
case PYDB:
case PERL:
break; // Nothing special
}
break;
case PosPart:
answer.prepend (answer_buffer);
answer_buffer = "";
already_read = Null;
// FALL THROUGH
case Null:
{
// Now go for the actual position.
switch (gdb->type())
{
case GDB:
filter_gdb(answer);
break;
case DBX:
filter_dbx(answer);
break;
case XDB:
filter_xdb(answer);
break;
case JDB:
filter_jdb(answer);
break;
case PYDB:
filter_pydb(answer);
break;
case PERL:
filter_perl(answer);
break;
}
}
break;
}
}
void PosBuffer::filter_gdb(string& answer)
{
// Try to find out current PC even for non-existent source
if (check_pc && pc_buffer == "")
{
// `$pc = ADDRESS'
#if RUNTIME_REGEX
static regex rxpc("\\$pc *= *" RXADDRESS);
#endif
int pc_index = index(answer, rxpc, "$pc ");
if (pc_index >= 0)
{
int addr_index = answer.index('=');
fetch_address(answer, addr_index, pc_buffer);
// Strip this line from ANSWER
int end_line = answer.index('\n', pc_index);
int start_line = pc_index;
while (start_line > 0
&& answer[start_line - 1] != '\n')
start_line--;
if (end_line < 0)
answer.from(start_line) = "";
else
answer.at(start_line, end_line - start_line + 1)
= "";
}
}
if (check_pc && pc_buffer == "" ||
check_func && func_buffer == "")
{
// `Breakpoint N, ADDRESS in FUNCTION (ARGS...)'
#if RUNTIME_REGEX
static regex rxstopped_addr("Breakpoint *[1-9][0-9]*, *"
RXADDRESS);
#endif
int pc_index = index(answer, rxstopped_addr, "Breakpoint");
if (pc_index >= 0)
{
pc_index = answer.index(',');
fetch_address(answer, pc_index, pc_buffer);
fetch_in_function(answer, pc_index, func_buffer);
}
}
if (check_pc && pc_buffer == "" ||
check_func && func_buffer == "")
{
// `#FRAME ADDRESS in FUNCTION (ARGS...)'
#if RUNTIME_REGEX
static regex rxframe_addr("#[0-9][0-9]* *" RXADDRESS);
#endif
int pc_index = index(answer, rxframe_addr, "#");
if (pc_index == 0
|| pc_index > 0 && answer[pc_index - 1] == '\n')
{
pc_index = answer.index(' ');
fetch_address(answer, pc_index, pc_buffer);
fetch_in_function(answer, pc_index, func_buffer);
}
}
if (check_pc && pc_buffer == "" ||
check_func && func_buffer == "")
{
// `No line number available for
// address ADDRESS <FUNCTION>'
#if RUNTIME_REGEX
static regex rxaddr("address *" RXADDRESS);
#endif
int pc_index = index(answer, rxaddr, "address ");
if (pc_index >= 0)
{
pc_index = answer.index(' ');
fetch_address(answer, pc_index, pc_buffer);
if (func_buffer == "")
{
string line = answer.from(pc_index);
line = line.after('<');
line = line.before('>');
if (line != "")
func_buffer = line;
}
}
}
if (check_pc && pc_buffer == "" && answer != "")
{
// `ADDRESS in FUNCTION'
#if RUNTIME_REGEX
static regex rxaddress_in(RXADDRESS " in ");
#endif
int pc_index = -1;
if (is_address_start(answer[0])
&& answer.contains(rxaddress_in, 0))
{
pc_index = 0;
}
else
{
#if RUNTIME_REGEX
static regex rxnladdress_in("\n" RXADDRESS " in ");
#endif
pc_index = index(answer, rxnladdress_in, "\n");
}
if (pc_index >= 0)
{
fetch_address(answer, pc_index, pc_buffer);
fetch_in_function(answer, pc_index, func_buffer);
}
}
// Try to find out current function name, even for
// non-existing addresses
if (check_func && func_buffer == "")
{
// `Breakpoint N, FUNCTION (ARGS...)'
// This regex used for PYDB as well.
#if RUNTIME_REGEX
static regex rxstopped_func("Breakpoint *[1-9][0-9]*, *");
#endif
int bp_index = index(answer, rxstopped_func, "Breakpoint");
if (bp_index >= 0)
fetch_function(answer, bp_index, func_buffer);
}
if (check_func && func_buffer == "")
{
// `#FRAME FUNCTION'
#if RUNTIME_REGEX
static regex rxframe_func("#[0-9][0-9]* *[a-zA-Z_].*[(]");
#endif
int frame_index = index(answer, rxframe_addr, "#");
if (frame_index == 0
|| frame_index > 0 && answer[frame_index - 1] == '\n')
{
fetch_function(answer, frame_index, func_buffer);
}
}
if (check_func && func_buffer == "")
{
// FUNCTION (ARGS...) at FILE:POS
int at_index = answer.index(" at ");
if (at_index > 0)
{
int nl_index =
answer.index('\n', at_index - answer.length() - 1) + 1;
fetch_function(answer, nl_index, func_buffer);
}
}
// Look for regular source info
int index1 = answer.index ("\032\032");
if (index1 < 0)
{
int index_p = answer.index ("\032");
if (index_p >= 0 && index_p == int(answer.length()) - 1)
{
// Possible begin of position info at end of ANSWER
answer_buffer = "\032";
answer = answer.before (index_p);
already_read = PosPart;
return;
}
// Handle erroneous `info line' output like
// `Line number 10 is out of range for "t1.f".'
// At least get the file name.
#if RUNTIME_REGEX
static regex rxout_of_range(
"Line number [0-9]+ is out of range for ");
#endif
index_p = index(answer, rxout_of_range, "Line number");
if (index_p >= 0)
{
string file = answer.after('\"', index_p);
file = file.before('\"');
pos_buffer = file + ":1";
already_read = PosComplete;
return;
}
// Nothing found
return;
}
// ANSWER contains position info
int index2 = answer.index ("\n", index1);
if (index2 == -1)
{
// Position info is incomplete
answer_buffer = answer.from (index1);
answer = answer.before (index1);
already_read = PosPart;
return;
}
assert (index1 < index2);
// Position info is complete
pos_buffer = answer.at(index1 + 2, index2 - (index1 + 2));
if (pos_buffer.contains("source ", 0))
{
// This happens with GDB in annotation level 2
pos_buffer = pos_buffer.after("source ");
}
int last_colon = pos_buffer.index(':', -1);
pc_buffer = pos_buffer.after(last_colon);
if (!pc_buffer.contains(rxaddress_start, 0))
pc_buffer = "0x" + pc_buffer;
pc_buffer = pc_buffer.through(rxaddress);
answer.at(index1, index2 - index1 + 1) = "";
if (pos_buffer != "")
already_read = PosComplete;
}
void PosBuffer::filter_dbx(string& answer)
{
string file; // File name found
string line; // Line number found
// When reaching a breakpoint, DBX issues the breakpoint
// number before the status line. Check for this and
// initialize defaults from breakpoint position.
if (answer.contains('(', 0) || answer.contains('[', 0))
{
// Get breakpoint position
string ans = answer;
int num = read_positive_nr(ans);
string pos = source_view->bp_pos(num);
if (pos != "")
{
file = pos.before(':');
line = pos.after(':');
}
}
// DEC DBX way issue warnings like
// `warning: "./cxxtest.C":157 has no code associated with it'
// right within the position info.
int start_of_warning = answer.index("\nwarning");
if (start_of_warning >= 0)
{
int open_bracket = answer.index('[');
int close_bracket = answer.index(']');
if (open_bracket >= 0 && open_bracket < start_of_warning &&
close_bracket >= 0 && close_bracket > start_of_warning)
{
// Remove warning
int end_of_warning = answer.index('\n', start_of_warning + 1);
while (end_of_warning < int(answer.length()) &&
answer[end_of_warning] == '\n')
end_of_warning++;
while (start_of_warning > 0 &&
answer[start_of_warning - 1] == '\n')
start_of_warning--;
int warning_length = end_of_warning - start_of_warning;
answer.at(start_of_warning, warning_length) = "";
}
}
#if RUNTIME_REGEX
static regex rxdbxfunc2(
".*line *[1-9][0-9]* *in *(file *)?\"[^\"]*\"\n.*");
#endif
if (already_read != PosComplete && answer.matches(rxdbxfunc2))
{
// AIX DBX issues `up', `down' and `func' output
// in the format `FUNCTION(ARGS), line LINE in "FILE"'.
// SUN DBX uses `line LINE in file "FILE"' instead.
// We check for the `line LINE' part.
line = answer.after("line ");
line = line.through(rxint);
file = answer.after('\"');
file = file.before('\"');
if (line != "")
{
already_read = PosComplete;
// answer = answer.after("\n");
}
}
#if RUNTIME_REGEX
static regex rxdbxpos("[[][^]]*:[1-9][0-9]*[^]]*[]].*");
#endif
int dbxpos_index = -1;
if (already_read != PosComplete &&
(dbxpos_index = index(answer, rxdbxpos, "[")) >= 0)
{
// DEC DBX issues breakpoint lines in the format
// "[new_tree:113 ,0x400858] \ttree->right = NULL;"
line = answer.from(dbxpos_index);
// Note that the function name may contain "::" sequences.
while (line.contains("::"))
line = line.after("::");
line = line.after(":");
line = line.through(rxint);
if (line != "")
{
if (answer.index('\n', dbxpos_index) >= 0)
{
already_read = PosComplete;
// Strip position info and line
strip_leading_space(answer);
if (answer.contains('[', 0))
answer = answer.after("\n");
}
else
{
// Wait for `\n' such that we can delete the line
answer_buffer = answer;
answer = "";
already_read = PosPart;
return;
}
}
}
if (already_read != PosComplete &&
(answer.contains("stopped in ") ||
answer.contains("stopped at ")))
{
int stopped_index = answer.index("stopped");
assert(stopped_index >= 0);
// Stop reached
int in_file_index = answer.index("in file ", stopped_index);
int bracket_index = answer.index("[", stopped_index);
if (in_file_index >= 0)
{
// File name given
file = answer.from(in_file_index);
file = file.after("in file ");
if (file.contains('\n'))
file = file.before('\n');
file = unquote(file);
}
else if (bracket_index >= 0)
{
// DEC DBX and SGI DBX output format:
// `[3] Process 1852 (cxxtest)
// stopped at [::main:266 ,0x1000a028]'
line = answer.after(bracket_index);
func_buffer = line;
while (line.contains("::"))
line = line.after("::");
line = line.from(":");
func_buffer = func_buffer.before(line);
line = line.after(":");
line = line.through(rxint);
// answer = answer.after("\n");
}
else
{
// Function name given
string func = answer.after(stopped_index);
func = func.after("stopped");
if (func.contains(" at "))
func = func.before(" at ");
func_buffer = func;
}
if (line == "")
{
line = answer.after("at line ", stopped_index);
line = line.through(rxint);
if ((file != "" || func_buffer != "") &&
!answer.contains("at line "))
line = "0";
}
if (line != "")
{
already_read = PosComplete;
filter_line(answer, atoi(line));
}
}
#if RUNTIME_REGEX
static regex rxdbxfunc("[a-zA-Z_][^[]*: *[1-9][0-9]* *.*");
#endif
if (already_read != PosComplete && answer.matches(rxdbxfunc))
{
// DEC DBX issues `up', `down' and `func' output
// in the format `FUNCTION: LINE TEXT'
// Note that the function name may contain "::" sequences.
line = answer;
while (line.contains("::"))
line = line.after("::");
line = line.after(":");
strip_leading_space(line);
if (line.contains(rxint, 0))
{
line = line.through(rxint);
if (line != "")
{
if (answer.contains('\n'))
{
// Got it!
already_read = PosComplete;
answer = answer.after("\n");
}
else
{
// Wait for `\n' such that we can delete the line
answer_buffer = answer;
answer = "";
already_read = PosPart;
return;
}
}
}
}
if (already_read != PosComplete &&
answer.contains("Current function is "))
{
// Up/Down command entered
string nr = answer.after("\n");
if (nr != "")
{
line = itostring(atoi(nr));
already_read = PosComplete;
// Show current function only
answer = answer.from("Current function is ");
answer = answer.through("\n");
func_buffer = answer.after("function is ");
func_buffer = func_buffer.before("\n");
}
else
{
answer_buffer = answer;
answer = "";
already_read = PosPart;
return;
}
}
if (already_read != PosComplete &&
(!answer.contains('\n') ||
(answer.contains('[') && !answer.contains(']'))))
{
// Position info is incomplete
answer_buffer = answer;
answer = "";
already_read = PosPart;
return;
}
if (already_read == PosComplete && line != "")
{
if (file != "")
pos_buffer = file + ":" + line;
else
pos_buffer = line;
}
if (already_read == PosComplete && pos_buffer == "")
already_read = Null;
}
void PosBuffer::filter_xdb(string& answer)
{
if (already_read != PosComplete && !answer.contains('\n'))
{
// Position info is incomplete
answer_buffer = answer;
answer = "";
already_read = PosPart;
return;
}
// INDEX points at the start of a line
int index = 0;
while (index >= 0 && answer != "")
{
string line = answer.from(index);
if (line.contains('\n'))
line = line.before('\n');
strip_trailing_space(line);
// XDB uses a format like `ctest.c: main: 4: int a = 33;'
#if RUNTIME_REGEX
static regex rxxdbpos("[^ \t]*:.*: [1-9][0-9]*[: ].*");
#endif
if (line.matches(rxxdbpos))
{
string file = line.before(':');
line = line.after(':');
// The function name may contain "::"
string func = line;
while (line.contains("::"))
line = line.after("::");
line = line.from(':');
func = func.before(line);
line = line.after(':');
string line_no = line.before(':');
strip_leading_space(func);
strip_leading_space(line_no);
line_no = line_no.through(rxint);
pos_buffer = file + ":" + line_no;
func_buffer = func;
already_read = PosComplete;
// Delete this line from output
int next_index = answer.index('\n', index);
if (next_index < 0)
next_index = answer.length();
else
next_index++;
answer.at(index, next_index - index) = "";
break;
}
else
{
// Look at next line
index = answer.index('\n', index);
if (index >= 0)
index++;
}
}
// Check for trailing `:' in last line
index = answer.index('\n', -1) + 1;
if (already_read != PosComplete
&& answer.index(':', index) >= 0)
{
answer_buffer = answer.from(index);
answer.from(index) = "";
already_read = PosPart;
return;
}
}
void PosBuffer::filter_jdb(string& answer)
{
if (already_read != PosComplete && !answer.contains('\n'))
{
// Position info is incomplete
answer_buffer = answer;
answer = "";
already_read = PosPart;
return;
}
int index = 0;
while (index >= 0 && answer != "")
{
string line = answer.from(index);
if (line.contains('\n'))
line = line.before('\n');
strip_trailing_space(line);
// Having reached a breakpoint, JDB uses a format like
// `(HelloWorld:3)'.
// Having loaded a class, JDB uses `class(foo.bar.HelloWorld)'.
// This may be prefixed by the fully qualified class
// name (`path'), as in
// `GlobalView.Map.MapController.createMap (MapController:53)'.
// In such a case, prefer the fully qualified name.
#if RUNTIME_REGEX
static regex
rxjdbpos("((class|interface)[(][A-Za-z][A-Za-z0-9.]*[)]|"
"[(][A-Za-z][A-Za-z0-9.]*:[1-9][0-9]*[)])");
#endif
if (line.matches(rxjdbpos))
{
string file = line.after('(');
file = file.before(')');
string line_no = "0";
if (file.contains(':'))
{
line_no = file.after(':');
file = file.before(':');
}
// Check whether a fully qualified class name is prepended
int class_index = line.index('(') - 1;
while (class_index >= 0 && line[class_index] == ' ')
class_index--;
while (class_index >= 1 && line[class_index - 1] != ' ')
class_index--;
if (class_index >= 0)
{
string class_name = line.from(class_index);
class_name = class_name.before('(');
strip_trailing_space(class_name);
if (class_name.contains('.') &&
class_name.matches(rxchain))
{
// Strip method
class_name = class_name.before('.', -1);
if (class_name.contains("." + file), -1)
{
// CLASS_NAME is more qualified - use it
file = class_name;
}
}
}
pos_buffer = file + ":" + line_no;
already_read = PosComplete;
#if 0
// Delete this line from output
int next_index = answer.index('\n', index);
if (next_index < 0)
next_index = answer.length();
else
next_index++;
answer.at(index, next_index - index) = "";
#endif
break;
}
else
{
// Look at next line
index = answer.index('\n', index);
if (index >= 0)
index++;
}
}
}
void PosBuffer::filter_pydb(string& answer)
{
if (already_read != PosComplete && !answer.contains('\n'))
{
// Position info is incomplete
answer_buffer = answer;
answer = "";
already_read = PosPart;
return;
}
// `Breakpoint N, FUNCTION (ARGS...) at file:line_no'
// rxstopped_func defined for GDB...if it changes, change here
int fn_index = index(answer, rxstopped_func, "Breakpoint");
if (fn_index >= 0)
{
fetch_function(answer, fn_index, func_buffer);
}
else
{
// `#FRAME FUNCTION(args) at file:line_no'
// Likewise rxframe_func defined for GDB
int frame_index = index(answer, rxframe_addr, "#");
if (frame_index == 0
|| frame_index > 0 && answer[frame_index - 1] == '\n')
{
fetch_function(answer, frame_index, func_buffer);
}
}
int lineinfo = answer.index("Lineinfo");
// Lineinfo <function> at file:lineno
if (lineinfo == 0 || (lineinfo > 0 && answer[lineinfo - 1] == '\n'))
{
answer = answer.after('<');
func_buffer = answer.before('>');
}
string result = answer.after(" at ");
result = result.before('\n');
if (result.contains(':'))
{
pos_buffer = result;
already_read = PosComplete;
}
// Don't need the answer anymore when line matches 'Lineinfo'
if (lineinfo >= 0)
{
answer = "";
}
}
void PosBuffer::filter_perl(string& answer)
{
// Check for regular source info
int index1 = answer.index ("\032\032");
if (index1 < 0)
{
int index_p = answer.index ("\032");
if (index_p >= 0 && index_p == int(answer.length()) - 1)
{
// Possible begin of position info at end of ANSWER
answer_buffer = "\032";
answer = answer.before (index_p);
already_read = PosPart;
return;
}
}
else
{
// ANSWER contains position info
int index2 = answer.index("\n", index1);
if (index2 == -1)
{
// Position info is incomplete
answer_buffer = answer.from (index1);
answer = answer.before (index1);
already_read = PosPart;
return;
}
else
{
assert (index1 < index2);
// Position info is complete
already_read = PosComplete;
pos_buffer = answer.at(index1 + 2, index2 - (index1 + 2));
answer.at(index1, index2 - index1 + 1) = "";
}
}
if (already_read != PosComplete)
{
// Try 'PACKAGE::FUNCTION(FILE:LINE):\n'; FUNCTION is optional
// INDEX points at the start of a line
int index = 0;
while (index >= 0 && answer != "")
{
string line = answer.from(index);
if (line.contains('\n'))
line = line.before('\n');
strip_trailing_space(line);
#if RUNTIME_REGEX
static regex rxperlpos("[^(]*::[^(]*[(][^:]*:[1-9][0-9]*[)]:");
#endif
if (line.matches(rxperlpos))
{
// Fetch position
pos_buffer = line.after('(');
pos_buffer = pos_buffer.before(')');
already_read = PosComplete;
// Delete this line from output
int next_index = answer.index('\n', index);
if (next_index < 0)
next_index = answer.length();
else
next_index++;
answer.at(index, next_index - index) = "";
break;
}
else
{
// Look at next line
index = answer.index('\n', index);
if (index >= 0)
index++;
}
}
}
}
string PosBuffer::answer_ended ()
{
switch (already_read)
{
case PosPart:
{
assert (pos_buffer == "");
string ans = answer_buffer;
answer_buffer = "";
return ans;
}
case Null:
{
assert (pos_buffer == "");
return "";
}
case PosComplete:
{
assert (pos_buffer != "");
return "";
}
default:
{
assert(0); // This can't happen
break;
}
}
return "";
}