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 / BreakPoint.C < prev    next >
C/C++ Source or Header  |  1998-12-04  |  24KB  |  1,040 lines

  1. // $Id: BreakPoint.C,v 1.66.4.1 1998/12/04 10:39:02 zeller Exp $
  2. // Breakpoint management
  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 BreakPoint_rcsid[] =
  31.     "$Id: BreakPoint.C,v 1.66.4.1 1998/12/04 10:39:02 zeller Exp $";
  32.  
  33. #ifdef __GNUG__
  34. #pragma implementation
  35. #endif
  36.  
  37.  
  38. //-----------------------------------------------------------------------------
  39. // Breakpoint management
  40. //-----------------------------------------------------------------------------
  41.  
  42. #include "BreakPoint.h"
  43. #include <ctype.h>
  44.  
  45. // Misc includes
  46. #include "assert.h"
  47. #include "cook.h"
  48.  
  49. // DDD includes
  50. #include "string-fun.h"
  51. #include "comm-manag.h"
  52. #include "ddd.h"
  53. #include "dbx-lookup.h"
  54. #include "question.h"
  55. #include "GDBAgent.h"
  56. #include "regexps.h"
  57. #include "index.h"
  58.  
  59. #if RUNTIME_REGEX
  60. static regex rxnl_int ("\n[1-9]");
  61. static regex rxname_colon_int_nl ("[^ ]+:[0-9]+\n");
  62. #endif
  63.  
  64. // Create new breakpoint from INFO_OUTPUT
  65. BreakPoint::BreakPoint(string& info_output, const string& arg, 
  66.                int number, string& file)
  67.     : mynumber(number),
  68.       mytype(BREAKPOINT),
  69.       mydispo(BPKEEP),
  70.       myenabled(true),
  71.       myfile_name(file),
  72.       myline_nr(0),
  73.       myaddress(""),
  74.       myfunc(""),
  75.       myexpr(""),
  76.       myinfos(""),
  77.       myignore_count(0),
  78.       mycondition(""),
  79.       mycommands(0),
  80.       myarg(arg),
  81.       mywatch_mode(WATCH_CHANGE),
  82.       myenabled_changed(true),
  83.       myfile_changed(true),
  84.       myposition_changed(true),
  85.       myaddress_changed(true),
  86.       myselected(false),
  87.       mysource_glyph(0),
  88.       mycode_glyph(0)
  89. {
  90.     if (gdb->has_numbered_breakpoints())
  91.     {
  92.     // Read leading breakpoint number
  93.     strip_leading_space(info_output);
  94.     string number_str = read_nr_str (info_output);
  95.     int number = get_positive_nr (number_str);
  96.     if (number < 0)
  97.         return;
  98.  
  99.     mynumber = number;
  100.     }
  101.  
  102.     if (gdb->type() != PERL)
  103.     strip_leading_space(info_output);
  104.  
  105.     switch(gdb->type())
  106.     {
  107.     case GDB:
  108.     process_gdb(info_output);
  109.     break;
  110.  
  111.     case DBX:
  112.     process_dbx(info_output);
  113.     break;
  114.  
  115.     case XDB:
  116.     process_xdb(info_output);
  117.     break;
  118.  
  119.     case JDB:
  120.     process_jdb(info_output);
  121.     break;
  122.  
  123.     case PYDB:
  124.     process_pydb(info_output);
  125.     break;
  126.  
  127.     case PERL:
  128.     process_perl(info_output);
  129.     break;
  130.     }
  131.  
  132.     // If we found a file name, propagate it to next breakpoint
  133.     file = file_name();
  134. }
  135.  
  136. void BreakPoint::process_gdb(string& info_output)
  137. {
  138.     // Read type (`breakpoint' or `watchpoint')
  139.     // The type may be prefixed by `hw ' or other details.
  140.     string word1 = info_output.before('\n');
  141.     string word2 = word1.after(rxblanks_or_tabs);
  142.  
  143.     if (word1.contains("watchpoint", 0) || 
  144.     word2.contains("watchpoint", 0))
  145.     {
  146.     mytype = WATCHPOINT;
  147.  
  148.     // Fetch breakpoint mode detail (`acc' or `read')
  149.     if (word1.contains("acc ", 0))
  150.         mywatch_mode = WATCH_ACCESS;
  151.     else if (word1.contains("read ", 0))
  152.         mywatch_mode = WATCH_READ;
  153.     else
  154.         mywatch_mode = WATCH_CHANGE;
  155.     }
  156.     else if (word1.contains("breakpoint", 0) || 
  157.          word2.contains("breakpoint", 0))
  158.     {
  159.     mytype = BREAKPOINT;
  160.     }
  161.     info_output = info_output.after("point");
  162.     info_output = info_output.after(rxblanks_or_tabs);
  163.  
  164.     // Read disposition (`dis', `del', or `keep')
  165.     if (info_output.contains("dis", 0))
  166.     {
  167.     mydispo = BPDIS;
  168.     }
  169.     else if (info_output.contains("del", 0))
  170.     {
  171.     mydispo = BPDEL;
  172.     }
  173.     else if (info_output.contains("keep", 0))
  174.     {
  175.     mydispo = BPKEEP;
  176.     }
  177.     info_output = info_output.after(rxblanks_or_tabs);
  178.  
  179.     // Read enabled flag (`y' or `n')
  180.     if (info_output.contains('y', 0))
  181.     {
  182.     myenabled = true;
  183.     }
  184.     else if (info_output.contains('n', 0))
  185.     {
  186.     myenabled = false;
  187.     }
  188.     info_output = info_output.after(rxblanks_or_tabs);
  189.  
  190.     string new_info = "";
  191.     if (mytype == BREAKPOINT) 
  192.     {
  193.     // Read address
  194.     myaddress = info_output.through(rxalphanum);
  195.  
  196.     info_output = info_output.after(myaddress);
  197.     strip_leading_space(info_output);
  198.  
  199.     if (info_output.contains("in ", 0))
  200.     {
  201.         // Function name
  202.         string func = info_output.after("in ");
  203.         if (func.contains('\n'))
  204.         func = func.before('\n');
  205.         if (func.contains(" at "))
  206.         func = func.before(" at ");
  207.         strip_space(func);
  208.  
  209.         myfunc = func;
  210.     }
  211.  
  212.     // Location
  213.     info_output = info_output.from(rxname_colon_int_nl);
  214.     myfile_name = info_output.before(":");
  215.  
  216.     info_output = info_output.after (":");
  217.     if (info_output != "" && isdigit(info_output[0]))
  218.         myline_nr = get_positive_nr(info_output);
  219.     }
  220.     else if (mytype == WATCHPOINT)
  221.     {
  222.     // Read watched expression
  223.     myexpr = info_output.before('\n');
  224.     }
  225.  
  226.     // That's all in this line
  227.     info_output = info_output.after('\n');
  228.  
  229.     int ignore_count = 0;
  230.     string cond      = "";
  231.     StringArray commands;
  232.  
  233.     if (info_output != "" && !isdigit(info_output[0]))
  234.     {
  235.     // Extra info follows
  236.     int next_nl = index(info_output, rxnl_int, "\n");
  237.     if (next_nl == -1)
  238.     {
  239.         new_info += info_output;
  240.         info_output = "";
  241.     }
  242.     else
  243.     {
  244.         new_info += info_output.through(next_nl);
  245.         info_output = info_output.after(next_nl);
  246.     }
  247.  
  248.     int n = new_info.freq('\n');
  249.     string *lines = new string[n + 1];
  250.     split(new_info, lines, n + 1, '\n');
  251.     string newer_info = "";
  252.  
  253.     for (int i = 0; i < n; i++)
  254.     {
  255.         bool save_info = true;
  256.  
  257.         string line = lines[i];
  258.         bool starts_with_space = (line != "" && isspace(line[0]));
  259.         strip_leading_space(line);
  260.  
  261.         if (line.contains("ignore next ", 0))
  262.         {
  263.         // Fetch ignore count
  264.         string count = line.after("ignore next ");
  265.         count = count.before(" hits");
  266.         ignore_count = atoi(count);
  267.         }
  268.         else if (line.contains("stop only if ", 0))
  269.         {
  270.         // Fetch condition
  271.         cond = line.after("stop only if ");
  272.         }
  273.         else if (line.contains("stop ", 0))
  274.         {
  275.         // Any info (no GDB command starts with `stop')
  276.         }
  277.         else if (line.contains("breakpoint ", 0))
  278.         {
  279.         // Any info (no GDB command starts with `breakpoint')
  280.         }
  281.         else if (starts_with_space)
  282.         {
  283.         // A command (GDB indents all commands)
  284.         commands += line;
  285.         save_info = false;
  286.         }
  287.         else
  288.         {
  289.         // Some other info
  290.         }
  291.  
  292.         if (save_info)
  293.         newer_info += line + '\n';
  294.     }
  295.  
  296.     new_info = newer_info;
  297.     delete[] lines;
  298.     }
  299.  
  300.     myinfos = new_info;
  301.     myignore_count = ignore_count;
  302.     mycondition = cond;
  303.     mycommands = commands;
  304. }
  305.  
  306. void BreakPoint::process_pydb(string& info_output)
  307. {
  308.     // PYDB has the same output format as GDB.
  309.     process_gdb(info_output);
  310. }
  311.  
  312. void BreakPoint::process_dbx(string& info_output)
  313. {
  314.     if (info_output.contains("stop ", 0) || 
  315.     info_output.contains("stopped ", 0))
  316.     {
  317.     info_output = info_output.after(rxblanks_or_tabs);
  318.     strip_leading_space (info_output);
  319.     if (info_output.contains ("at ", 0))
  320.     {
  321.         info_output = info_output.after(rxblanks_or_tabs);
  322.         string file_name;
  323.         if (info_output.contains('"', 0))
  324.         {
  325.         // `stop at "FILE":LINE'
  326.         file_name = unquote(info_output.before(":"));
  327.         info_output = info_output.after (":");
  328.         }
  329.         else if (info_output.contains('[', 0))
  330.         {
  331.         // `stop at [file:line ...]'
  332.         file_name = info_output.before(":");
  333.         file_name = file_name.after('[');
  334.         info_output = info_output.after (":");
  335.         }
  336.         else
  337.         {
  338.         // `stop at LINE'
  339.         file_name = "";
  340.         }
  341.  
  342.         int new_line_nr = 0;
  343.         if (info_output != "" && isdigit(info_output[0]))
  344.         new_line_nr = get_positive_nr(info_output);
  345.  
  346.         if (file_name != "")
  347.         myfile_name = file_name;
  348.  
  349.         if (new_line_nr != 0)
  350.         myline_nr = new_line_nr;
  351.  
  352.         // DBX issues either locations or functions
  353.         myfunc = "";
  354.     }
  355.     else if (info_output.contains ("in ", 0))
  356.     {
  357.         // `stop in FUNC'
  358.         string func = info_output.after(rxblanks_or_tabs);
  359.         if (func.contains('\n'))
  360.         func = func.before('\n');
  361.         strip_space(func);
  362.         myfunc = func;
  363.  
  364.         myfile_name = "";
  365.         myline_nr = 0;
  366.  
  367.         // Attempt to get exact position
  368.         string pos = dbx_lookup(func);
  369.         if (pos != "")
  370.         {
  371.         string file_name = pos.before(":");
  372.         string line_s    = pos.after(":");
  373.         int new_line_nr  = get_positive_nr(line_s);
  374.  
  375.         myfile_name = file_name;
  376.         if (new_line_nr != 0)
  377.             myline_nr = new_line_nr;
  378.         }
  379.     }
  380.     else
  381.     {
  382.         // `stop VAR'
  383.         mytype       = WATCHPOINT;
  384.         mywatch_mode = WATCH_CHANGE;
  385.  
  386.         string expr = info_output;
  387.         if (expr.contains('\n'))
  388.         expr = expr.before('\n');
  389.         if (expr.contains(rxblanks_or_tabs))
  390.         expr = expr.before(rxblanks_or_tabs);
  391.  
  392.         myexpr = expr;
  393.     }
  394.  
  395.     // Sun DBX 3.0 issues extra characters like 
  396.     // (2) stop in main -count 0/10
  397.     // [3] stop in main -disable
  398.     string options;
  399.     if (info_output.contains('\n'))
  400.         options = info_output.before('\n');
  401.     else
  402.         options = info_output;
  403.     bool new_enabled = !options.contains(" -disable");
  404.     myenabled = new_enabled;
  405.  
  406.     myinfos = "";
  407.     if (options.contains(" -count "))
  408.     {
  409.         string count = options.after(" -count ");
  410.         strip_leading_space(count);
  411.         if (count.contains(' '))
  412.         count = count.before(' ');
  413.  
  414.         myinfos = "count " + count;
  415.         if (count.contains('/'))
  416.         count = count.after('/');
  417.         myignore_count = atoi(count);
  418.     }
  419.  
  420.     if (options.contains(" if ") || options.contains(" -if "))
  421.     {
  422.         string cond = options.after("if ");
  423.         if (myinfos != "")
  424.         myinfos += '\n';
  425.         myinfos += "stop only if " + cond;
  426.         mycondition = cond;
  427.     }
  428.     }
  429.     info_output = info_output.after('\n');
  430. }
  431.  
  432.  
  433. void BreakPoint::process_xdb(string& info_output)
  434. {
  435.     // Strip leading `:'.
  436.     // Bob Wiegand <robert.e.wiegand.1@gsfc.nasa.gov>
  437.     if (info_output.contains(':', 0))
  438.     info_output = info_output.after(0);
  439.  
  440.     strip_leading_space(info_output);
  441.  
  442.     // Skip `count: N'
  443.     if (info_output.contains("count:", 0))
  444.     {
  445.     info_output = info_output.after("count:");
  446.     strip_leading_space(info_output);
  447.     string count = info_output.before(rxblanks_or_tabs);
  448.     info_output = info_output.after(rxblanks_or_tabs);
  449.  
  450.     myignore_count = atoi(count);
  451.     }
  452.         
  453.     // Check for `Active' or `Suspended' and strip them
  454.     // Bob Wiegand <robert.e.wiegand.1@gsfc.nasa.gov>
  455.     if (info_output.contains("Active", 0))
  456.     {
  457.     info_output = info_output.after("Active");
  458.     myenabled   = true;
  459.     }
  460.     else if (info_output.contains("Suspended", 0))
  461.     {
  462.     info_output = info_output.after("Suspended");
  463.     myenabled   = false;
  464.     }
  465.  
  466.     // Get function name and position
  467.     info_output = info_output.after(rxblanks_or_tabs);
  468.     myfunc = info_output.before(": ");
  469.  
  470.     string pos = dbx_lookup(myfunc);
  471.     if (pos != "")
  472.     {
  473.     myfile_name = pos.before(":");
  474.     }
  475.  
  476.     info_output = info_output.after(": ");
  477.     myline_nr = get_positive_nr(info_output);
  478.  
  479.     info_output = info_output.after('\n');
  480.  
  481.     // Examine commands for condition
  482.     string commands = info_output;
  483.     strip_leading_space(commands);
  484.     if (commands.contains('{', 0))
  485.     {
  486.     // A condition has the form `{if COND {} {Q; c}}'.
  487.     if (commands.contains("{if ", 0))
  488.     {
  489.         string cond = commands.after("{if ");
  490.         cond = cond.before('{');
  491.         strip_space(cond);
  492.         mycondition = cond;
  493.     }
  494.  
  495.     // Skip this line, too
  496.     info_output = info_output.after('\n');
  497.     }
  498. }
  499.  
  500. void BreakPoint::process_jdb(string& info_output)
  501. {
  502.     int colon = info_output.index(':');
  503.     if (colon >= 0)
  504.     {
  505.     string class_name = info_output.before(colon);
  506.     int line_no = get_positive_nr(info_output.after(colon));
  507.     if (line_no >= 0 && class_name != "")
  508.     {
  509.         myfile_name = class_name;
  510.         myline_nr   = line_no;
  511.  
  512.         // Kill this line
  513.         int beginning_of_line = colon;
  514.         while (beginning_of_line >= 0 && 
  515.            info_output[beginning_of_line] != '\n')
  516.         beginning_of_line--;
  517.         beginning_of_line++;
  518.  
  519.         int next_nl = info_output.index('\n', colon);
  520.         if (next_nl >= 0)
  521.         info_output = info_output.before(beginning_of_line)
  522.             + info_output.from(next_nl);
  523.         else
  524.         info_output = info_output.before(beginning_of_line);
  525.     }
  526.     }
  527. }
  528.  
  529. void BreakPoint::process_perl(string& info_output)
  530. {
  531.     // Format: [FILE:]
  532.     //          LINE_NO: LINE
  533.     //           INFO 1
  534.     //           INFO 2 ...
  535.  
  536.     if (!info_output.contains(' ', 0))
  537.     {
  538.     string first_line = info_output.before('\n');
  539.     if (first_line.contains(':', -1))
  540.     {
  541.         // Get leading file name
  542.         myfile_name = first_line.before(':');
  543.         info_output = info_output.after('\n');
  544.     }
  545.     }
  546.  
  547.     myline_nr = atoi(info_output);
  548.     info_output = info_output.after('\n');
  549.     while (info_output.contains("  ", 0))
  550.     {
  551.     string info = info_output.before('\n');
  552.     info_output = info_output.after('\n');
  553.  
  554.     strip_space(info);
  555.     if (info.contains("break if ", 0))
  556.     {
  557.         string cond = info.after(" if ");
  558.         while (cond.contains('(', 0) && cond.contains(')', -1))
  559.         cond = unquote(cond);
  560.         if (cond == "1")
  561.         cond = "";
  562.         mycondition = cond;
  563.     }
  564.     else if (info.contains("action: ", 0))
  565.     {
  566.         string command = info.after(':');
  567.         strip_space(command);
  568.         mycommands += command;
  569.     }
  570.     else
  571.     {
  572.         myinfos += info + '\n';
  573.     }
  574.     }
  575. }
  576.  
  577. static bool equal(const StringArray& s1, const StringArray& s2)
  578. {
  579.     if (s1.size() != s2.size())
  580.     return false;
  581.     for (int i = 0; i < s1.size(); i++)
  582.     if (s1[i] != s2[i])
  583.         return false;
  584.  
  585.     return true;
  586. }
  587.  
  588. // Update breakpoint information
  589. bool BreakPoint::update(string& info_output,
  590.             ostream& undo_commands,
  591.             bool& need_total_undo)
  592. {
  593.     string file = file_name();
  594.     BreakPoint new_bp(info_output, arg(), number(), file);
  595.  
  596.     bool changed       = false;
  597.     myenabled_changed  = false;
  598.     myposition_changed = false;
  599.     myfile_changed     = false;
  600.     myaddress_changed  = false;
  601.     need_total_undo    = false;
  602.  
  603.     string num = "@" + itostring(number()) + "@";
  604.  
  605.     if (new_bp.number() != number())
  606.     {
  607.     mynumber = new_bp.number();
  608.     need_total_undo = changed = true;
  609.     }
  610.  
  611.     if (new_bp.type() != type())
  612.     {
  613.     mytype = new_bp.type();
  614.     need_total_undo = changed = myenabled_changed = true;
  615.     }
  616.  
  617.     if (new_bp.dispo() != dispo())
  618.     {
  619.     need_total_undo = changed = myenabled_changed = true;
  620.     mydispo = new_bp.dispo();
  621.     }
  622.  
  623.     if (new_bp.watch_mode() != watch_mode())
  624.     {
  625.     need_total_undo = changed = myenabled_changed = true;
  626.     mywatch_mode = new_bp.watch_mode();
  627.     }
  628.  
  629.     if (new_bp.myenabled != myenabled)
  630.     {
  631.     changed = myenabled_changed = true;
  632.     myenabled = new_bp.myenabled;
  633.  
  634.     if (myenabled)
  635.     {
  636.         if (gdb->has_disable_command())
  637.         undo_commands << gdb->disable_command(num) << "\n";
  638.         else
  639.         need_total_undo = true;
  640.     }
  641.     else
  642.     {
  643.         if (gdb->has_enable_command())
  644.         undo_commands << gdb->enable_command(num) << "\n";
  645.         else
  646.         need_total_undo = true;
  647.     }
  648.     }
  649.  
  650.     if (type() == BREAKPOINT)
  651.     {
  652.     if (new_bp.address() != address())
  653.     {
  654.         changed = myaddress_changed = true;
  655.         myaddress = new_bp.address();
  656.     }
  657.  
  658.     if (new_bp.func() != func())
  659.     {
  660.         changed = myposition_changed = true;
  661.         myfunc = new_bp.func();
  662.     }
  663.  
  664.     if (new_bp.file_name() != file_name())
  665.     {
  666.         changed = myposition_changed = myfile_changed = true;
  667.         myfile_name = new_bp.file_name();
  668.     }
  669.  
  670.     if (new_bp.line_nr() != line_nr())
  671.     {
  672.         changed = myposition_changed = true;
  673.         myline_nr = new_bp.line_nr();
  674.     }
  675.     }
  676.     else if (type() == WATCHPOINT)
  677.     {
  678.     if (new_bp.expr() != expr())
  679.     {
  680.         changed = true;
  681.         myexpr = new_bp.expr();
  682.     }
  683.     }
  684.  
  685.     if (new_bp.infos() != infos())
  686.     {
  687.     changed = true;
  688.     myinfos = new_bp.infos();
  689.     }
  690.  
  691.     if (new_bp.ignore_count() != ignore_count())
  692.     {
  693.     if (gdb->has_ignore_command())
  694.         undo_commands << gdb->ignore_command(num, myignore_count) << "\n";
  695.     else
  696.         need_total_undo = true;
  697.  
  698.     changed = myenabled_changed = true;
  699.     myignore_count = new_bp.ignore_count();
  700.     }
  701.  
  702.     if (new_bp.mycondition != mycondition)
  703.     {
  704.     if (gdb->has_condition_command())
  705.         undo_commands << gdb->condition_command(num, condition()) << "\n";
  706.     else
  707.         need_total_undo = true;
  708.  
  709.     changed = myenabled_changed = true;
  710.     mycondition = new_bp.mycondition;
  711.     }
  712.  
  713.     if (!equal(new_bp.commands(), commands()))
  714.     {
  715.     if (gdb->type() == GDB)
  716.     {
  717.         undo_commands << "commands " << num << '\n';
  718.         for (int i = 0; i < commands().size(); i++)
  719.         undo_commands << commands()[i] << '\n';
  720.         undo_commands << "end\n";
  721.     }
  722.  
  723.     changed = myenabled_changed = true;
  724.     mycommands = new_bp.commands();
  725.     }
  726.  
  727.     return changed;
  728. }
  729.  
  730.  
  731. //-----------------------------------------------------------------------------
  732. // Resources
  733. //-----------------------------------------------------------------------------
  734.  
  735. string BreakPoint::pos() const
  736. {
  737.     if (line_nr() == 0)
  738.     return "*" + address();
  739.     else if (file_name() == "")
  740.     return itostring(line_nr());
  741.     else
  742.     return file_name() + ":" + itostring(line_nr());
  743. }
  744.  
  745. string BreakPoint::symbol() const
  746. {
  747.     char c;
  748.     if (!enabled())
  749.     c = '_';
  750.     else if (condition() != "" || ignore_count() != 0)
  751.     c = '?';
  752.     else
  753.     c = '#';
  754.  
  755.     return c + itostring(number()) + c;
  756. }
  757.  
  758. string BreakPoint::condition() const
  759. {
  760.     if (is_false(real_condition()))
  761.     return real_condition().after(and_op());
  762.     else
  763.     return real_condition();
  764. }
  765.  
  766. bool BreakPoint::enabled() const
  767. {
  768.     if (is_false(real_condition()))
  769.     return false;
  770.     else
  771.     return myenabled;
  772. }
  773.  
  774.  
  775.  
  776. //-----------------------------------------------------------------------------
  777. // Condition stuff
  778. //-----------------------------------------------------------------------------
  779.  
  780. // Return "0" (or appropriate)
  781. string BreakPoint::false_value()
  782. {
  783.     switch (gdb->program_language())
  784.     {
  785.     case LANGUAGE_C:
  786.     case LANGUAGE_PYTHON:
  787.     case LANGUAGE_OTHER:
  788.     return "0";
  789.  
  790.     case LANGUAGE_PERL:
  791.     // In Perl, giving a breakpoint a condition of `0' is not
  792.     // accepted by the debugger.  So, we use the string "0"
  793.     // instead, which Perl also evaluates to False.
  794.     return "\"0\"";
  795.  
  796.     case LANGUAGE_FORTRAN:
  797.     return ".FALSE.";
  798.  
  799.     case LANGUAGE_JAVA:
  800.     return "false";
  801.  
  802.     case LANGUAGE_CHILL:    // ??
  803.     case LANGUAGE_PASCAL:
  804.     case LANGUAGE_ADA:
  805.     return "FALSE";
  806.     }
  807.  
  808.     return "0";
  809. }
  810.  
  811. // Return " && " (or appropriate)
  812. string BreakPoint::and_op()
  813. {
  814.     switch (gdb->program_language())
  815.     {
  816.     case LANGUAGE_C:
  817.     case LANGUAGE_PERL:
  818.     case LANGUAGE_JAVA:
  819.     case LANGUAGE_OTHER:
  820.     return " && ";
  821.  
  822.     case LANGUAGE_FORTRAN:
  823.     return " .AND. ";
  824.  
  825.     case LANGUAGE_CHILL:    // ??
  826.     case LANGUAGE_PASCAL:
  827.     case LANGUAGE_ADA:
  828.     return " AND ";
  829.  
  830.     case LANGUAGE_PYTHON:
  831.     return " and ";
  832.     }
  833.  
  834.     return " && ";
  835. }
  836.  
  837. // True if COND is `false' or starts with `false and'
  838. bool BreakPoint::is_false(const string& cond)
  839. {
  840.     if (cond == false_value())
  841.     return true;
  842.  
  843.     string c = downcase(cond);
  844.     string prefix = downcase(false_value() + and_op());
  845.  
  846.     return c.contains(prefix, 0);
  847. }
  848.  
  849. // Make COND `false' or `false and COND'
  850. string BreakPoint::make_false(const string& cond)
  851. {
  852.     if (is_false(cond))
  853.     return cond;
  854.     else if (cond == "")
  855.     return false_value();
  856.     else
  857.     return false_value() + and_op() + cond;
  858. }
  859.  
  860. //-----------------------------------------------------------------------------
  861. // Session stuff
  862. //-----------------------------------------------------------------------------
  863.  
  864. // Return commands to restore this breakpoint, using the dummy number
  865. // NR.  If AS_DUMMY is set, delete the breakpoint immediately in order
  866. // to increase the breakpoint number.  If ADDR is set, use ADDR as
  867. // (fake) address.  If COND is set, use COND as (fake) condition.
  868. // Return true iff successful.
  869. bool BreakPoint::get_state(ostream& os, int nr, bool as_dummy,
  870.                string pos, string cond)
  871. {
  872.     if (pos == "")
  873.     { 
  874.     if (line_nr() > 0)
  875.         pos = file_name() + ":" + itostring(line_nr());
  876.     else
  877.         pos = string('*') + address();
  878.     }
  879.  
  880.     if (cond == char(-1))
  881.     cond = real_condition();
  882.  
  883.     string num = "@" + itostring(nr) + "@";
  884.  
  885.     switch (gdb->type())
  886.     {
  887.     case GDB:
  888.     case PYDB:
  889.     {
  890.     switch (type())
  891.     {
  892.     case BREAKPOINT:
  893.     {
  894.         switch (dispo())
  895.         {
  896.         case BPKEEP:
  897.         case BPDIS:
  898.         os << "break " << pos << "\n";
  899.         break;
  900.  
  901.         case BPDEL:
  902.         os << "tbreak " << pos << "\n";
  903.         break;
  904.         }
  905.         break;
  906.     }
  907.  
  908.     case WATCHPOINT:
  909.     {
  910.         os << gdb->watch_command(expr(), watch_mode()) << "\n";
  911.         break;
  912.     }
  913.     }
  914.  
  915.     if (!as_dummy)
  916.     {
  917.         // Extra infos
  918.         if (!enabled() && gdb->has_disable_command())
  919.         os << gdb->disable_command(num) << "\n";
  920.         int ignore = ignore_count();
  921.         if (ignore > 0 && gdb->has_ignore_command())
  922.         os << gdb->ignore_command(num, ignore) << "\n";
  923.         if (cond != "" && gdb->has_condition_command())
  924.         os << gdb->condition_command(num, cond) << "\n";
  925.         if (commands().size() != 0)
  926.         {
  927.         os << "commands " << num << "\n";
  928.         for (int i = 0; i < commands().size(); i++)
  929.             os << commands()[i] << "\n";
  930.         os << "end\n";
  931.         }
  932.     }
  933.     break;
  934.     }
  935.  
  936.     case DBX:
  937.     {
  938.     string cond_suffix = "";
  939.     if (cond != "")
  940.     {
  941.         if (gdb->has_handler_command())
  942.         cond_suffix = " -if " + cond;
  943.         else
  944.         cond_suffix = " if " + cond;
  945.     }
  946.  
  947.     switch (type())
  948.     {
  949.     case BREAKPOINT:
  950.         if (func() != "")
  951.         {
  952.         os << "stop in " << func() << "\n";
  953.         }
  954.         else if (pos.contains('*', 0))
  955.         {
  956.         os << "stop at " << pos.after('*') << cond_suffix << '\n';
  957.         }
  958.         else
  959.         {
  960.         os << "file "    << pos.before(':') << "\n";
  961.         os << "stop at " << pos.after(':')  << cond_suffix << "\n";
  962.         }
  963.         break;
  964.  
  965.     case WATCHPOINT:
  966.         os << "stop " << expr() << cond_suffix << '\n';
  967.         break;
  968.     }
  969.  
  970.     if (!as_dummy)
  971.     {
  972.         // Extra infos
  973.         if (!enabled() && gdb->has_disable_command())
  974.         os << gdb->disable_command(num) << "\n";
  975.         int ignore = ignore_count();
  976.         if (ignore > 0 && gdb->has_ignore_command())
  977.         os << gdb->ignore_command(num, ignore) << "\n";
  978.     }
  979.     break;
  980.     }
  981.  
  982.     case JDB:
  983.     {
  984.     os << "stop at " << pos << "\n";
  985.     break;
  986.     }
  987.  
  988.     case XDB:
  989.     {
  990.     string cond_suffix;
  991.     if (cond != "" && !gdb->has_condition_command())
  992.         cond_suffix = " {if " + cond + " {} {Q;c}}";
  993.  
  994.     if (pos.contains('*', 0))
  995.         os << "ba " << pos.after('*') << cond_suffix << '\n';
  996.     else
  997.         os << "b " << pos << cond_suffix << "\n";
  998.  
  999.     if (!as_dummy)
  1000.     {
  1001.         // Extra infos
  1002.         if (!enabled() && gdb->has_disable_command())
  1003.         os << gdb->disable_command(num) << "\n";
  1004.         int ignore = ignore_count();
  1005.         if (ignore > 0 && gdb->has_ignore_command())
  1006.         os << gdb->ignore_command(num, ignore) << "\n";
  1007.     }
  1008.     break;
  1009.     }
  1010.  
  1011.     case PERL:
  1012.     {
  1013.     string cond_suffix;
  1014.     if (cond != "")
  1015.         cond_suffix = " " + cond;
  1016.  
  1017.     os << "f " << pos.before(':') << "\n";
  1018.     os << "b " << pos.after(':')  << cond_suffix << "\n";
  1019.  
  1020.     if (commands().size() != 0)
  1021.     {
  1022.         os << "a " << pos.after(':') << " ";
  1023.         for (int i = 0; i < commands().size(); i++)
  1024.         os << commands()[i] << ";";
  1025.         os << "\n";
  1026.     }
  1027.  
  1028.     break;
  1029.     }
  1030.     }
  1031.  
  1032.     if (as_dummy && gdb->has_delete_command())
  1033.     {
  1034.     // Delete the breakpoint just created
  1035.     os << gdb->delete_command(num) << "\n";
  1036.     }
  1037.  
  1038.     return true;
  1039. }
  1040.