home *** CD-ROM | disk | FTP | other *** search
- // $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 "";
- }
-