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 >
C/C++ Source or Header  |  1998-12-06  |  27KB  |  1,145 lines

  1. // $Id: PosBuffer.C,v 1.80.4.1 1998/12/06 12:59:19 zeller Exp $
  2. // Filter position information from GDB output.
  3.  
  4. // Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>
  6. // and Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  7. // 
  8. // This file is part of DDD.
  9. // 
  10. // DDD is free software; you can redistribute it and/or
  11. // modify it under the terms of the GNU General Public
  12. // License as published by the Free Software Foundation; either
  13. // version 2 of the License, or (at your option) any later version.
  14. // 
  15. // DDD is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18. // See the GNU General Public License for more details.
  19. // 
  20. // You should have received a copy of the GNU General Public
  21. // License along with DDD -- see the file COPYING.
  22. // If not, write to the Free Software Foundation, Inc.,
  23. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  24. // 
  25. // DDD is the data display debugger.
  26. // For details, see the DDD World-Wide-Web page, 
  27. // `http://www.cs.tu-bs.de/softech/ddd/',
  28. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  29.  
  30. char PosBuffer_rcsid[] =
  31.     "$Id: PosBuffer.C,v 1.80.4.1 1998/12/06 12:59:19 zeller Exp $";
  32.  
  33. #ifdef __GNUG__
  34. #pragma implementation
  35. #endif
  36.  
  37. // Misc includes
  38. #include "assert.h"
  39. #include "cook.h"
  40.  
  41. // DDD includes
  42. #include "AppData.h"
  43. #include "PosBuffer.h"
  44. #include "comm-manag.h"
  45. #include "string-fun.h"
  46. #include "ddd.h"
  47. #include "GDBAgent.h"
  48. #include "SourceView.h"
  49. #include "regexps.h"
  50. #include "index.h"
  51.  
  52. #if RUNTIME_REGEX
  53. // A regex for C addresses ("0xdead") and Modula-2 addresses ("0BEEFH");
  54. regex rxaddress(RXADDRESS);
  55. regex rxaddress_start(RXADDRESS_START);
  56. #endif
  57.  
  58.  
  59. // Filter all lines from ANSWER beginning with LINE.  This is required
  60. // to suppress the line number output after a `stopping in' message.
  61. static void filter_line(string& answer, int line)
  62. {
  63.     if (line <= 0)
  64.     return;
  65.  
  66.     int pos = 0;
  67.     do {
  68.     if (atoi((char *)answer + pos) == line)
  69.     {
  70.         answer = answer.before(pos) + answer.after('\n', pos);
  71.         break;
  72.     }
  73.     pos = answer.index('\n', pos) + 1;
  74.     } while (pos > 0);
  75. }
  76.  
  77. // Return true iff ANSWER has a line beginning with PREFIX
  78. static bool has_prefix(const string& answer, const string& prefix)
  79. {
  80.     int index = answer.index(prefix);
  81.     return index == 0 || index > 0 && answer[index - 1] == '\n';
  82. }
  83.  
  84. // Store first address in ANSWER after INDEX in BUFFER
  85. static void fetch_address(const string& answer, int index, string& buffer)
  86. {
  87.     if (buffer != "")
  88.     return;            // Already have an address
  89.  
  90.     while (index < int(answer.length()) && !is_address_start(answer[index]))
  91.     index++;
  92.  
  93.     assert (is_address_start(answer[index]));
  94.  
  95.     int start = index;
  96.  
  97.     // Just fetch the first word -- no need to do big address matches here
  98.     while (index < int(answer.length()) && !isspace(answer[index]))
  99.     index++;
  100.  
  101.     buffer = ((string&)answer).at(start, index - start);
  102. }
  103.  
  104. // Store first function name in ANSWER after INDEX in BUFFER
  105. static void fetch_function(const string& answer, int index, string& buffer,
  106.                bool in_required = false)
  107. {
  108.     if (buffer != "")
  109.     return;            // Already have a function
  110.  
  111.     string line = answer.from(index);
  112.     line = line.before('\n');
  113.     if (in_required)
  114.     line = line.after(" in ");
  115.  
  116.     // The function name is the word before the opening parenthesis
  117.     line = line.before('(');
  118.     strip_trailing_space(line);
  119.     int ws_index = line.index(' ', -1) + 1;
  120.     line = line.from(ws_index);
  121.     strip_leading_space(line);
  122.     if (line != "" && line.contains(rxidentifier, 0))
  123.     buffer = line;
  124. }
  125.  
  126. // Same, but requires " in " before function
  127. inline void fetch_in_function(const string& answer, int index, string& buffer)
  128. {
  129.     fetch_function(answer, index, buffer, true);
  130. }
  131.  
  132.  
  133.  
  134. // Fetch position from GDB output ANSWER.
  135. void PosBuffer::filter (string& answer)
  136. {
  137.     if (answer.length() == 0)
  138.     return;
  139.  
  140.     // Check program state
  141.     switch (gdb->type())
  142.     {
  143.     case GDB:
  144.     {
  145.     // If GDB prints a "Current function" line, it overrides whatever
  146.     // came before (e.g. "stopped in").
  147.     if (has_prefix(answer, "Current function is "))
  148.         already_read = Null;
  149.  
  150.     // Check program state
  151.     if (has_prefix(answer, "Starting program: "))
  152.         started = true;
  153.  
  154.     if (has_prefix(answer, "The program no longer exists"))
  155.         terminated = true;
  156.  
  157.     if (has_prefix(answer, "Program received signal"))
  158.         signaled = true;
  159.  
  160.     if (has_prefix(answer, "Program terminated with signal"))
  161.         signaled = terminated = true;
  162.  
  163.     if (answer.contains("has changed; re-reading symbols"))
  164.         recompiled = true;
  165.  
  166.     if (has_prefix(answer, "Current language: "))
  167.         gdb->program_language(answer);
  168.  
  169.     if (has_prefix(answer, "The current source language is "))
  170.         gdb->program_language(answer);
  171.     }
  172.     break;
  173.  
  174.     case DBX:
  175.     {
  176.     if (has_prefix(answer, "Running: "))
  177.         started = true;
  178.  
  179.     if (answer.contains("has been recompiled"))
  180.         recompiled = true;
  181.  
  182.     if (has_prefix(answer, "signal "))
  183.         signaled = true;
  184.     }
  185.     break;
  186.     
  187.     case XDB:
  188.     case JDB:
  189.     case PYDB:
  190.     case PERL:
  191.     break;            // Nothing special
  192.     }
  193.  
  194.     // Check for terminated program
  195.     int i = -1;
  196.     while ((i = answer.index("rogram", i + 1)) > 0)
  197.     {
  198.     int j = i;
  199.     while (j > 0 && answer[j - 1] != '\n')
  200.         j--;
  201.     
  202. #if RUNTIME_REGEX
  203.     static regex rxterminated("([Tt]he )?[Pp]rogram "
  204.                   "(exited|terminated"
  205.                   "|is not being run|no longer exists).*");
  206. #endif
  207.     if (answer.matches(rxterminated, j))
  208.         terminated = true;
  209.     }
  210.  
  211.     if (answer.contains("no active process") 
  212.     || answer.contains("execution completed")
  213.     || answer.contains("application exited"))
  214.     terminated = true;
  215.  
  216.     // Check for auto command
  217.     if (app_data.auto_commands)
  218.     {
  219.     if (auto_cmd_buffer != "" && !auto_cmd_buffer.contains('\n', -1))
  220.     {
  221.         // Complete pending auto command
  222.         if (answer.contains('\n'))
  223.         {
  224.         auto_cmd_buffer += answer.through('\n');
  225.         answer = answer.after('\n');
  226.         }
  227.         else
  228.         {
  229.         auto_cmd_buffer += answer;
  230.         answer = "";
  231.         }
  232.     }
  233.  
  234.     while (has_prefix(answer, app_data.auto_command_prefix))
  235.     {
  236.         int index = answer.index(app_data.auto_command_prefix);
  237.         string cmd = answer.from(index);
  238.         if (cmd.contains('\n'))
  239.         cmd = cmd.through('\n');
  240.         answer = 
  241.         answer.before(index) + answer.from(int(index + cmd.length()));
  242.         cmd = cmd.after(app_data.auto_command_prefix);
  243.         auto_cmd_buffer += cmd;
  244.     }
  245.     }
  246.  
  247.     // Fetch and store position info, return remainder
  248.     switch (already_read)
  249.     {
  250.     case PosComplete:
  251.     // Nothing more to filter
  252.  
  253.     // Skip possible line number info
  254.     switch (gdb->type())
  255.     {
  256.     case GDB:
  257.         break;
  258.  
  259.     case DBX:
  260.     {
  261.         string line_s = pos_buffer;
  262.         if (line_s.contains(':'))
  263.         line_s = line_s.after(':');
  264.         int line = atoi(line_s);
  265.         filter_line(answer, line);
  266.     }
  267.  
  268.     case XDB:
  269.     case JDB:
  270.     case PYDB:
  271.     case PERL:
  272.         break;        // Nothing special
  273.     }
  274.     break;
  275.  
  276.     case PosPart:
  277.     answer.prepend (answer_buffer);
  278.     answer_buffer = "";
  279.     already_read = Null;
  280.     // FALL THROUGH
  281.  
  282.     case Null:
  283.     {
  284.     // Now go for the actual position.
  285.     switch (gdb->type())
  286.     {
  287.     case GDB:
  288.         filter_gdb(answer);
  289.         break;
  290.  
  291.     case DBX:
  292.         filter_dbx(answer);
  293.         break;
  294.  
  295.     case XDB:
  296.         filter_xdb(answer);
  297.         break;
  298.  
  299.     case JDB:
  300.         filter_jdb(answer);
  301.         break;
  302.  
  303.     case PYDB:
  304.         filter_pydb(answer);
  305.         break;
  306.  
  307.     case PERL:
  308.         filter_perl(answer);
  309.         break;
  310.     }
  311.     }
  312.  
  313.     break;
  314.     }
  315. }
  316.  
  317. void PosBuffer::filter_gdb(string& answer)
  318. {
  319.     // Try to find out current PC even for non-existent source
  320.  
  321.     if (check_pc && pc_buffer == "")
  322.     {
  323.     // `$pc = ADDRESS'
  324. #if RUNTIME_REGEX
  325.     static regex rxpc("\\$pc  *=  *" RXADDRESS);
  326. #endif
  327.     int pc_index = index(answer, rxpc, "$pc ");
  328.     if (pc_index >= 0)
  329.     {
  330.         int addr_index = answer.index('=');
  331.         fetch_address(answer, addr_index, pc_buffer);
  332.             
  333.         // Strip this line from ANSWER
  334.         int end_line = answer.index('\n', pc_index);
  335.         int start_line = pc_index;
  336.         while (start_line > 0 
  337.            && answer[start_line - 1] != '\n')
  338.         start_line--;
  339.             
  340.         if (end_line < 0)
  341.         answer.from(start_line) = "";
  342.         else
  343.         answer.at(start_line, end_line - start_line + 1) 
  344.             = "";
  345.     }
  346.     }
  347.         
  348.     if (check_pc && pc_buffer == "" || 
  349.     check_func && func_buffer == "")
  350.     {
  351.     // `Breakpoint N, ADDRESS in FUNCTION (ARGS...)'
  352. #if RUNTIME_REGEX
  353.     static regex rxstopped_addr("Breakpoint  *[1-9][0-9]*,  *"
  354.                     RXADDRESS);
  355. #endif
  356.     int pc_index = index(answer, rxstopped_addr, "Breakpoint");
  357.     if (pc_index >= 0)
  358.     {
  359.         pc_index = answer.index(',');
  360.         fetch_address(answer, pc_index, pc_buffer);
  361.         fetch_in_function(answer, pc_index, func_buffer);
  362.     }
  363.     }
  364.         
  365.     if (check_pc && pc_buffer == "" || 
  366.     check_func && func_buffer == "")
  367.     {
  368.     // `#FRAME ADDRESS in FUNCTION (ARGS...)'
  369. #if RUNTIME_REGEX
  370.     static regex rxframe_addr("#[0-9][0-9]*  *" RXADDRESS);
  371. #endif
  372.         
  373.     int pc_index = index(answer, rxframe_addr, "#");
  374.     if (pc_index == 0
  375.         || pc_index > 0 && answer[pc_index - 1] == '\n')
  376.     {
  377.         pc_index = answer.index(' ');
  378.         fetch_address(answer, pc_index, pc_buffer);
  379.         fetch_in_function(answer, pc_index, func_buffer);
  380.     }
  381.     }
  382.         
  383.     if (check_pc && pc_buffer == "" || 
  384.     check_func && func_buffer == "")
  385.     {
  386.     // `No line number available for 
  387.     // address ADDRESS <FUNCTION>'
  388. #if RUNTIME_REGEX
  389.     static regex rxaddr("address  *" RXADDRESS);
  390. #endif
  391.         
  392.     int pc_index = index(answer, rxaddr, "address ");
  393.     if (pc_index >= 0)
  394.     {
  395.         pc_index = answer.index(' ');
  396.         fetch_address(answer, pc_index, pc_buffer);
  397.         if (func_buffer == "")
  398.         {
  399.         string line = answer.from(pc_index);
  400.         line = line.after('<');
  401.         line = line.before('>');
  402.         if (line != "")
  403.             func_buffer = line;
  404.         }
  405.     }
  406.     }
  407.  
  408.     if (check_pc && pc_buffer == "" && answer != "")
  409.     {
  410.     // `ADDRESS in FUNCTION'
  411. #if RUNTIME_REGEX
  412.     static regex rxaddress_in(RXADDRESS " in ");
  413. #endif
  414.     int pc_index = -1;
  415.     if (is_address_start(answer[0]) 
  416.         && answer.contains(rxaddress_in, 0))
  417.     {
  418.         pc_index = 0;
  419.     }
  420.     else
  421.     {
  422. #if RUNTIME_REGEX
  423.         static regex rxnladdress_in("\n" RXADDRESS " in ");
  424. #endif
  425.         pc_index = index(answer, rxnladdress_in, "\n");
  426.     }
  427.         
  428.     if (pc_index >= 0)
  429.     {
  430.         fetch_address(answer, pc_index, pc_buffer);
  431.         fetch_in_function(answer, pc_index, func_buffer);
  432.     }
  433.     }
  434.  
  435.     // Try to find out current function name, even for
  436.     // non-existing addresses
  437.     if (check_func && func_buffer == "")
  438.     {
  439.     // `Breakpoint N, FUNCTION (ARGS...)'
  440.     // This regex used for PYDB as well.
  441. #if RUNTIME_REGEX
  442.     static regex rxstopped_func("Breakpoint  *[1-9][0-9]*,  *");
  443. #endif
  444.     int bp_index = index(answer, rxstopped_func, "Breakpoint");
  445.     if (bp_index >= 0)
  446.         fetch_function(answer, bp_index, func_buffer);
  447.     }
  448.  
  449.     if (check_func && func_buffer == "")
  450.     {
  451.     // `#FRAME FUNCTION'
  452. #if RUNTIME_REGEX
  453.     static regex rxframe_func("#[0-9][0-9]*  *[a-zA-Z_].*[(]");
  454. #endif
  455.     int frame_index = index(answer, rxframe_addr, "#");
  456.     if (frame_index == 0
  457.         || frame_index > 0 && answer[frame_index - 1] == '\n')
  458.     {
  459.         fetch_function(answer, frame_index, func_buffer);
  460.     }
  461.     }
  462.  
  463.     if (check_func && func_buffer == "")
  464.     {
  465.     // FUNCTION (ARGS...) at FILE:POS
  466.     int at_index = answer.index(" at ");
  467.     if (at_index > 0)
  468.     {
  469.         int nl_index = 
  470.         answer.index('\n', at_index - answer.length() - 1) + 1;
  471.         fetch_function(answer, nl_index, func_buffer);
  472.     }
  473.     }
  474.         
  475.     // Look for regular source info
  476.     int index1 = answer.index ("\032\032");
  477.         
  478.     if (index1 < 0) 
  479.     {
  480.     int index_p = answer.index ("\032");
  481.     if (index_p >= 0 && index_p == int(answer.length()) - 1)
  482.     {
  483.         // Possible begin of position info at end of ANSWER
  484.         answer_buffer = "\032";
  485.         answer = answer.before (index_p);
  486.         already_read = PosPart;
  487.         return;
  488.     }
  489.         
  490.     // Handle erroneous `info line' output like
  491.     // `Line number 10 is out of range for "t1.f".'
  492.     // At least get the file name.
  493. #if RUNTIME_REGEX
  494.     static regex rxout_of_range(
  495.         "Line number [0-9]+ is out of range for ");
  496. #endif
  497.     index_p = index(answer, rxout_of_range, "Line number");
  498.     if (index_p >= 0)
  499.     {
  500.         string file = answer.after('\"', index_p);
  501.         file = file.before('\"');
  502.         pos_buffer = file + ":1";
  503.         already_read = PosComplete;
  504.         return;
  505.     }
  506.         
  507.     // Nothing found
  508.     return;
  509.     }
  510.         
  511.     // ANSWER contains position info
  512.     int index2 = answer.index ("\n", index1);
  513.  
  514.     if (index2 == -1)
  515.     {
  516.     // Position info is incomplete
  517.     answer_buffer = answer.from (index1);
  518.     answer = answer.before (index1);
  519.     already_read = PosPart;
  520.     return;
  521.     }
  522.  
  523.     assert (index1 < index2);
  524.  
  525.     // Position info is complete
  526.     pos_buffer = answer.at(index1 + 2, index2 - (index1 + 2));
  527.  
  528.     if (pos_buffer.contains("source ", 0))
  529.     {
  530.     // This happens with GDB in annotation level 2
  531.     pos_buffer = pos_buffer.after("source ");
  532.     }
  533.  
  534.     int last_colon = pos_buffer.index(':', -1);
  535.     pc_buffer = pos_buffer.after(last_colon);
  536.     if (!pc_buffer.contains(rxaddress_start, 0))
  537.     pc_buffer = "0x" + pc_buffer;
  538.     pc_buffer = pc_buffer.through(rxaddress);
  539.  
  540.     answer.at(index1, index2 - index1 + 1) = "";
  541.     if (pos_buffer != "")
  542.     already_read = PosComplete;
  543. }
  544.  
  545.     
  546. void PosBuffer::filter_dbx(string& answer)
  547. {
  548.     string file;        // File name found
  549.     string line;        // Line number found
  550.  
  551.     // When reaching a breakpoint, DBX issues the breakpoint
  552.     // number before the status line.  Check for this and
  553.     // initialize defaults from breakpoint position.
  554.     if (answer.contains('(', 0) || answer.contains('[', 0))
  555.     {
  556.     // Get breakpoint position
  557.     string ans = answer;
  558.     int num = read_positive_nr(ans);
  559.     string pos = source_view->bp_pos(num);
  560.     if (pos != "")
  561.     {
  562.         file = pos.before(':');
  563.         line = pos.after(':');
  564.     }
  565.     }
  566.  
  567.     // DEC DBX way issue warnings like
  568.     // `warning: "./cxxtest.C":157 has no code associated with it'
  569.     // right within the position info.
  570.  
  571.     int start_of_warning = answer.index("\nwarning");
  572.     if (start_of_warning >= 0)
  573.     {
  574.     int open_bracket  = answer.index('[');
  575.     int close_bracket = answer.index(']');
  576.     if (open_bracket >= 0 && open_bracket < start_of_warning &&
  577.         close_bracket >= 0 && close_bracket > start_of_warning)
  578.     {
  579.         // Remove warning
  580.  
  581.         int end_of_warning = answer.index('\n', start_of_warning + 1);
  582.         while (end_of_warning < int(answer.length()) && 
  583.            answer[end_of_warning] == '\n')
  584.         end_of_warning++;
  585.  
  586.         while (start_of_warning > 0 && 
  587.            answer[start_of_warning - 1] == '\n')
  588.         start_of_warning--;
  589.  
  590.         int warning_length = end_of_warning - start_of_warning;
  591.         answer.at(start_of_warning, warning_length) = "";
  592.     }
  593.     }
  594.  
  595. #if RUNTIME_REGEX
  596.     static regex rxdbxfunc2(
  597.     ".*line  *[1-9][0-9]*  *in  *(file  *)?\"[^\"]*\"\n.*");
  598. #endif
  599.     if (already_read != PosComplete && answer.matches(rxdbxfunc2))
  600.     {
  601.     // AIX DBX issues `up', `down' and `func' output
  602.     // in the format `FUNCTION(ARGS), line LINE in "FILE"'.
  603.     // SUN DBX uses `line LINE in file "FILE"' instead.
  604.     // We check for the `line LINE' part.
  605.  
  606.     line = answer.after("line ");
  607.     line = line.through(rxint);
  608.  
  609.     file = answer.after('\"');
  610.     file = file.before('\"');
  611.  
  612.     if (line != "")
  613.     {
  614.         already_read = PosComplete;
  615.         // answer = answer.after("\n");
  616.     }
  617.     }
  618.  
  619. #if RUNTIME_REGEX
  620.     static regex rxdbxpos("[[][^]]*:[1-9][0-9]*[^]]*[]].*");
  621. #endif
  622.     int dbxpos_index = -1;
  623.     if (already_read != PosComplete && 
  624.     (dbxpos_index = index(answer, rxdbxpos, "[")) >= 0)
  625.     {
  626.     // DEC DBX issues breakpoint lines in the format
  627.     // "[new_tree:113 ,0x400858] \ttree->right = NULL;"
  628.         
  629.     line = answer.from(dbxpos_index);
  630.  
  631.     // Note that the function name may contain "::" sequences.
  632.     while (line.contains("::"))
  633.         line = line.after("::");
  634.     line = line.after(":");
  635.     line = line.through(rxint);
  636.     if (line != "")
  637.     {
  638.         if (answer.index('\n', dbxpos_index) >= 0)
  639.         {
  640.         already_read = PosComplete;
  641.  
  642.         // Strip position info and line
  643.         strip_leading_space(answer);
  644.         if (answer.contains('[', 0))
  645.             answer = answer.after("\n");
  646.         }
  647.         else
  648.         {
  649.         // Wait for `\n' such that we can delete the line
  650.         answer_buffer = answer;
  651.         answer = "";
  652.         already_read = PosPart;
  653.         return;
  654.         }
  655.     }
  656.     }
  657.  
  658.     if (already_read != PosComplete && 
  659.     (answer.contains("stopped in ") || 
  660.      answer.contains("stopped at ")))
  661.     {
  662.     int stopped_index = answer.index("stopped");
  663.     assert(stopped_index >= 0);
  664.  
  665.     // Stop reached
  666.     int in_file_index = answer.index("in file ", stopped_index);
  667.     int bracket_index = answer.index("[", stopped_index);
  668.  
  669.     if (in_file_index >= 0)
  670.     {
  671.         // File name given
  672.         file = answer.from(in_file_index);
  673.         file = file.after("in file ");
  674.         if (file.contains('\n'))
  675.         file = file.before('\n');
  676.         file = unquote(file);
  677.     }
  678.     else if (bracket_index >= 0)
  679.     {
  680.         // DEC DBX and SGI DBX output format:
  681.         // `[3] Process  1852 (cxxtest) 
  682.         // stopped at [::main:266 ,0x1000a028]'
  683.         line = answer.after(bracket_index);
  684.         func_buffer = line;
  685.         while (line.contains("::"))
  686.         line = line.after("::");
  687.         line = line.from(":");
  688.         func_buffer = func_buffer.before(line);
  689.         line = line.after(":");
  690.         line = line.through(rxint);
  691.         // answer = answer.after("\n");
  692.     }
  693.     else
  694.     {
  695.         // Function name given
  696.         string func = answer.after(stopped_index);
  697.         func = func.after("stopped");
  698.         if (func.contains(" at "))
  699.         func = func.before(" at ");
  700.         func_buffer = func;
  701.     }
  702.         
  703.     if (line == "")
  704.     {
  705.         line = answer.after("at line ", stopped_index);
  706.         line = line.through(rxint);
  707.         if ((file != "" || func_buffer != "") &&
  708.         !answer.contains("at line "))
  709.         line = "0";
  710.     }
  711.  
  712.     if (line != "")
  713.     {
  714.         already_read = PosComplete;
  715.         filter_line(answer, atoi(line));
  716.     }
  717.     }
  718.  
  719. #if RUNTIME_REGEX
  720.     static regex rxdbxfunc("[a-zA-Z_][^[]*: *[1-9][0-9]*  *.*");
  721. #endif
  722.     if (already_read != PosComplete && answer.matches(rxdbxfunc))
  723.     {
  724.     // DEC DBX issues `up', `down' and `func' output
  725.     // in the format `FUNCTION: LINE  TEXT'
  726.         
  727.     // Note that the function name may contain "::" sequences.
  728.     line = answer;
  729.     while (line.contains("::"))
  730.         line = line.after("::");
  731.  
  732.     line = line.after(":");
  733.     strip_leading_space(line);
  734.     if (line.contains(rxint, 0))
  735.     {
  736.         line = line.through(rxint);
  737.         if (line != "")
  738.         {
  739.         if (answer.contains('\n'))
  740.         {
  741.             // Got it!
  742.             already_read = PosComplete;
  743.             answer = answer.after("\n");
  744.         }
  745.         else
  746.         {
  747.             // Wait for `\n' such that we can delete the line
  748.             answer_buffer = answer;
  749.             answer = "";
  750.             already_read = PosPart;
  751.             return;
  752.         }
  753.         }
  754.     }
  755.     }
  756.  
  757.     if (already_read != PosComplete && 
  758.     answer.contains("Current function is "))
  759.     {
  760.     // Up/Down command entered
  761.     string nr = answer.after("\n");
  762.     if (nr != "")
  763.     {
  764.         line = itostring(atoi(nr));
  765.         already_read = PosComplete;
  766.             
  767.         // Show current function only
  768.         answer = answer.from("Current function is ");
  769.         answer = answer.through("\n");
  770.         func_buffer = answer.after("function is ");
  771.         func_buffer = func_buffer.before("\n");
  772.     }
  773.     else
  774.     {
  775.         answer_buffer = answer;
  776.         answer = "";
  777.         already_read = PosPart;
  778.         return;
  779.     }
  780.     }
  781.  
  782.     if (already_read != PosComplete && 
  783.     (!answer.contains('\n') ||
  784.      (answer.contains('[') && !answer.contains(']'))))
  785.     {
  786.     // Position info is incomplete
  787.     answer_buffer = answer;
  788.     answer = "";
  789.     already_read = PosPart;
  790.     return;
  791.     }
  792.  
  793.     if (already_read == PosComplete && line != "")
  794.     {
  795.     if (file != "")
  796.         pos_buffer = file + ":" + line;
  797.     else
  798.         pos_buffer = line;
  799.     }
  800.  
  801.     if (already_read == PosComplete && pos_buffer == "")
  802.     already_read = Null;
  803. }
  804.  
  805.     
  806. void PosBuffer::filter_xdb(string& answer)
  807. {
  808.     if (already_read != PosComplete && !answer.contains('\n'))
  809.     {
  810.     // Position info is incomplete
  811.     answer_buffer = answer;
  812.     answer = "";
  813.     already_read = PosPart;
  814.     return;
  815.     }
  816.  
  817.     // INDEX points at the start of a line
  818.     int index = 0;
  819.     while (index >= 0 && answer != "")
  820.     {
  821.     string line = answer.from(index);
  822.     if (line.contains('\n'))
  823.         line = line.before('\n');
  824.     strip_trailing_space(line);
  825.         
  826.     // XDB uses a format like `ctest.c: main: 4: int a = 33;'
  827. #if RUNTIME_REGEX
  828.     static regex rxxdbpos("[^ \t]*:.*: [1-9][0-9]*[: ].*");
  829. #endif
  830.     if (line.matches(rxxdbpos))
  831.     {
  832.         string file = line.before(':');
  833.         line = line.after(':');
  834.             
  835.         // The function name may contain "::"
  836.         string func = line;
  837.         while (line.contains("::"))
  838.         line = line.after("::");
  839.         line = line.from(':');
  840.         func = func.before(line);
  841.             
  842.         line = line.after(':');
  843.         string line_no = line.before(':');
  844.             
  845.         strip_leading_space(func);
  846.         strip_leading_space(line_no);
  847.         line_no = line_no.through(rxint);
  848.             
  849.         pos_buffer   = file + ":" + line_no;
  850.         func_buffer  = func;
  851.         already_read = PosComplete;
  852.             
  853.         // Delete this line from output
  854.         int next_index = answer.index('\n', index);
  855.         if (next_index < 0)
  856.         next_index = answer.length();
  857.         else
  858.         next_index++;
  859.         answer.at(index, next_index - index) = "";
  860.         break;
  861.     }
  862.     else
  863.     {
  864.         // Look at next line
  865.         index = answer.index('\n', index);
  866.         if (index >= 0)
  867.         index++;
  868.     }
  869.     }
  870.         
  871.     // Check for trailing `:' in last line
  872.     index = answer.index('\n', -1) + 1;
  873.     if (already_read != PosComplete 
  874.     && answer.index(':', index) >= 0)
  875.     {
  876.     answer_buffer = answer.from(index);
  877.     answer.from(index) = "";
  878.     already_read = PosPart;
  879.     return;
  880.     }
  881. }
  882.     
  883. void PosBuffer::filter_jdb(string& answer)
  884. {
  885.     if (already_read != PosComplete && !answer.contains('\n'))
  886.     {
  887.     // Position info is incomplete
  888.     answer_buffer = answer;
  889.     answer = "";
  890.     already_read = PosPart;
  891.     return;
  892.     }
  893.  
  894.     int index = 0;
  895.     while (index >= 0 && answer != "")
  896.     {
  897.     string line = answer.from(index);
  898.     if (line.contains('\n'))
  899.         line = line.before('\n');
  900.     strip_trailing_space(line);
  901.  
  902.     // Having reached a breakpoint, JDB uses a format like
  903.     // `(HelloWorld:3)'.
  904.     // Having loaded a class, JDB uses `class(foo.bar.HelloWorld)'.
  905.  
  906.     // This may be prefixed by the fully qualified class
  907.     // name (`path'), as in
  908.     // `GlobalView.Map.MapController.createMap (MapController:53)'.
  909.     // In such a case, prefer the fully qualified name.
  910. #if RUNTIME_REGEX
  911.     static regex 
  912.         rxjdbpos("((class|interface)[(][A-Za-z][A-Za-z0-9.]*[)]|"
  913.              "[(][A-Za-z][A-Za-z0-9.]*:[1-9][0-9]*[)])");
  914. #endif
  915.     if (line.matches(rxjdbpos))
  916.     {
  917.         string file = line.after('(');
  918.         file = file.before(')');
  919.         string line_no = "0";
  920.         if (file.contains(':'))
  921.         {
  922.         line_no = file.after(':');
  923.         file = file.before(':');
  924.         }
  925.  
  926.         // Check whether a fully qualified class name is prepended
  927.         int class_index = line.index('(') - 1;
  928.         while (class_index >= 0 && line[class_index] == ' ')
  929.         class_index--;
  930.         while (class_index >= 1 && line[class_index - 1] != ' ')
  931.         class_index--;
  932.         if (class_index >= 0)
  933.         {
  934.         string class_name = line.from(class_index);
  935.         class_name = class_name.before('(');
  936.         strip_trailing_space(class_name);
  937.         if (class_name.contains('.') && 
  938.             class_name.matches(rxchain))
  939.         {
  940.             // Strip method
  941.             class_name = class_name.before('.', -1);
  942.  
  943.             if (class_name.contains("." + file), -1)
  944.             {
  945.                 // CLASS_NAME is more qualified - use it
  946.             file = class_name;
  947.             }
  948.         }
  949.         }
  950.  
  951.         pos_buffer     = file + ":" + line_no;
  952.         already_read = PosComplete;
  953.  
  954. #if 0
  955.         // Delete this line from output
  956.         int next_index = answer.index('\n', index);
  957.         if (next_index < 0)
  958.         next_index = answer.length();
  959.         else
  960.         next_index++;
  961.         answer.at(index, next_index - index) = "";
  962. #endif
  963.         break;
  964.     }
  965.     else
  966.     {
  967.         // Look at next line
  968.         index = answer.index('\n', index);
  969.         if (index >= 0)
  970.         index++;
  971.     }
  972.     }
  973. }
  974.  
  975. void PosBuffer::filter_pydb(string& answer)
  976. {
  977.     if (already_read != PosComplete && !answer.contains('\n'))
  978.     {
  979.     // Position info is incomplete
  980.     answer_buffer = answer;
  981.     answer = "";
  982.     already_read = PosPart;
  983.     return;
  984.     }
  985.  
  986.     // `Breakpoint N, FUNCTION (ARGS...) at file:line_no'
  987.     // rxstopped_func defined for GDB...if it changes, change here
  988.     int fn_index = index(answer, rxstopped_func, "Breakpoint");
  989.     if (fn_index >= 0)
  990.     {
  991.     fetch_function(answer, fn_index, func_buffer);
  992.     }
  993.     else
  994.     {
  995.     // `#FRAME FUNCTION(args) at file:line_no'
  996.     // Likewise rxframe_func defined for GDB
  997.     int frame_index = index(answer, rxframe_addr, "#");
  998.     if (frame_index == 0
  999.         || frame_index > 0 && answer[frame_index - 1] == '\n')
  1000.     {
  1001.         fetch_function(answer, frame_index, func_buffer);
  1002.     }
  1003.     }
  1004.  
  1005.     int lineinfo  = answer.index("Lineinfo");
  1006.     // Lineinfo <function> at file:lineno
  1007.     if (lineinfo == 0 || (lineinfo > 0 && answer[lineinfo - 1] == '\n'))
  1008.     {
  1009.     answer = answer.after('<');
  1010.     func_buffer = answer.before('>');
  1011.     }
  1012.  
  1013.     string result = answer.after(" at ");
  1014.     result = result.before('\n');
  1015.     if (result.contains(':'))
  1016.     {
  1017.     pos_buffer = result;
  1018.     already_read = PosComplete;
  1019.     }
  1020.  
  1021.     // Don't need the answer anymore when line matches 'Lineinfo'
  1022.     if (lineinfo >= 0)
  1023.     {
  1024.     answer = "";
  1025.     }
  1026. }
  1027.  
  1028. void PosBuffer::filter_perl(string& answer)
  1029. {
  1030.     // Check for regular source info
  1031.     int index1 = answer.index ("\032\032");
  1032.         
  1033.     if (index1 < 0) 
  1034.     {
  1035.     int index_p = answer.index ("\032");
  1036.     if (index_p >= 0 && index_p == int(answer.length()) - 1)
  1037.     {
  1038.         // Possible begin of position info at end of ANSWER
  1039.         answer_buffer = "\032";
  1040.         answer = answer.before (index_p);
  1041.         already_read = PosPart;
  1042.         return;
  1043.     }
  1044.     }
  1045.     else
  1046.     {
  1047.     // ANSWER contains position info
  1048.     int index2 = answer.index("\n", index1);
  1049.         
  1050.     if (index2 == -1)
  1051.     {
  1052.         // Position info is incomplete
  1053.         answer_buffer = answer.from (index1);
  1054.         answer = answer.before (index1);
  1055.         already_read = PosPart;
  1056.         return;
  1057.     }
  1058.     else
  1059.     {
  1060.         assert (index1 < index2);
  1061.         
  1062.         // Position info is complete
  1063.         already_read = PosComplete;
  1064.         pos_buffer = answer.at(index1 + 2, index2 - (index1 + 2));
  1065.         answer.at(index1, index2 - index1 + 1) = "";
  1066.     }
  1067.     }
  1068.  
  1069.     if (already_read != PosComplete)
  1070.     {
  1071.     // Try 'PACKAGE::FUNCTION(FILE:LINE):\n'; FUNCTION is optional
  1072.  
  1073.     // INDEX points at the start of a line
  1074.     int index = 0;
  1075.     while (index >= 0 && answer != "")
  1076.     {
  1077.         string line = answer.from(index);
  1078.         if (line.contains('\n'))
  1079.         line = line.before('\n');
  1080.         strip_trailing_space(line);
  1081.             
  1082. #if RUNTIME_REGEX
  1083.         static regex rxperlpos("[^(]*::[^(]*[(][^:]*:[1-9][0-9]*[)]:");
  1084. #endif
  1085.         if (line.matches(rxperlpos))
  1086.         {
  1087.         // Fetch position
  1088.         pos_buffer = line.after('(');
  1089.         pos_buffer = pos_buffer.before(')');
  1090.         already_read = PosComplete;
  1091.  
  1092.         // Delete this line from output
  1093.         int next_index = answer.index('\n', index);
  1094.         if (next_index < 0)
  1095.             next_index = answer.length();
  1096.         else
  1097.             next_index++;
  1098.         answer.at(index, next_index - index) = "";
  1099.         break;
  1100.         }
  1101.         else
  1102.         {
  1103.         // Look at next line
  1104.         index = answer.index('\n', index);
  1105.         if (index >= 0)
  1106.             index++;
  1107.         }
  1108.     }
  1109.     }
  1110. }
  1111.  
  1112. string PosBuffer::answer_ended ()
  1113. {
  1114.     switch (already_read) 
  1115.     {
  1116.     case PosPart:
  1117.     {
  1118.     assert (pos_buffer == "");
  1119.     string ans = answer_buffer;
  1120.     answer_buffer = "";
  1121.     return ans;
  1122.     }
  1123.  
  1124.     case Null:
  1125.     {
  1126.     assert (pos_buffer == "");
  1127.     return "";
  1128.     }
  1129.  
  1130.     case PosComplete:
  1131.     {
  1132.     assert (pos_buffer != "");
  1133.     return "";
  1134.     }
  1135.  
  1136.     default:
  1137.     {
  1138.     assert(0);        // This can't happen
  1139.     break;
  1140.     }
  1141.     }
  1142.  
  1143.     return "";
  1144. }
  1145.