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 / settings.C < prev    next >
C/C++ Source or Header  |  1998-11-15  |  79KB  |  3,199 lines

  1. // $Id: settings.C,v 1.102 1998/11/15 13:04:24 zeller Exp $ -*- C++ -*-
  2. // Modify debugger settings
  3.  
  4. // Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char settings_rcsid[] = 
  30.     "$Id: settings.C,v 1.102 1998/11/15 13:04:24 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "settings.h"
  37.  
  38. #include <Xm/Xm.h>
  39. #include <Xm/SelectioB.h>
  40. #include <Xm/DialogS.h>
  41. #include <Xm/ScrolledW.h>
  42. #include <Xm/RowColumn.h>
  43. #include <Xm/ToggleB.h>
  44. #include <Xm/PushB.h>
  45. #include <Xm/TextF.h>
  46. #include <Xm/Form.h>
  47. #include <Xm/Label.h>
  48. #include <Xm/Separator.h>
  49. #include <ctype.h>
  50. #include <string.h>
  51. #include <stdio.h>
  52.  
  53. #include "AppData.h"
  54. #include "Assoc.h"
  55. #include "ComboBox.h"
  56. #include "Command.h"
  57. #include "DataDisp.h"
  58. #include "Delay.h"
  59. #include "DestroyCB.h"
  60. #include "EntryType.h"
  61. #include "GDBAgent.h"
  62. #include "HelpCB.h"
  63. #include "LessTifH.h"
  64. #include "MakeMenu.h"
  65. #include "SmartC.h"
  66. #include "SourceView.h"
  67. #include "StringSA.h"
  68. #include "UndoBuffer.h"
  69. #include "VarArray.h"
  70. #include "WidgetSA.h"
  71. #include "buttons.h"
  72. #include "cook.h"
  73. #include "comm-manag.h"
  74. #include "ddd.h"
  75. #include "editing.h"
  76. #include "mydialogs.h"
  77. #include "logo.h"
  78. #include "options.h"
  79. #include "question.h"
  80. #include "regexps.h"
  81. #include "shell.h"
  82. #include "status.h"
  83. #include "string-fun.h"
  84. #include "verify.h"
  85. #include "version.h"
  86. #include "wm.h"
  87.  
  88.  
  89. //-----------------------------------------------------------------------
  90. // Constants
  91. //-----------------------------------------------------------------------
  92.  
  93. const Dimension EXTRA_SPACE     = 10;   // Minimum space between label / entry
  94. const Dimension EXTRA_WIDTH     =  6;   // Additional space for safety
  95. const Dimension MAX_HEIGHT     = 300;   // Maximum height of window
  96.  
  97. enum SettingsType { SETTINGS, INFOS, SIGNALS };
  98.  
  99.  
  100. //-----------------------------------------------------------------------
  101. // Data
  102. //-----------------------------------------------------------------------
  103.  
  104. static Widget            settings_panel = 0;
  105. static Widget            settings_form  = 0;
  106. static Widget            reset_settings_button = 0;
  107. static WidgetArray       settings_entries;
  108. static EntryTypeArray    settings_entry_types;
  109. static WidgetStringAssoc settings_values;
  110. static WidgetStringAssoc settings_initial_values;
  111. static bool              need_reload_settings = false;
  112.  
  113. static Widget            signals_panel = 0;
  114. static Widget            signals_form  = 0;
  115. static Widget            reset_signals_button = 0;
  116. static WidgetArray       signals_entries;
  117. static WidgetStringAssoc signals_values;
  118. static WidgetStringAssoc signals_initial_values;
  119. static bool              need_reload_signals = false;
  120.  
  121. static Widget            infos_panel        = 0;
  122. static Widget            reset_infos_button = 0;
  123. static WidgetArray       infos_entries;
  124.  
  125.  
  126.  
  127. //-----------------------------------------------------------------------
  128. // Functions
  129. //-----------------------------------------------------------------------
  130.  
  131. static void get_setting(ostream& os, DebuggerType type,
  132.             const string& base, string value);
  133. static void set_arg();
  134.  
  135.  
  136. // Find widget for command COMMAND
  137. static Widget command_to_widget(Widget ref, string command)
  138. {
  139.     Widget found = 0;
  140.     while (command != "" && (found = XtNameToWidget(ref, command)) == 0)
  141.     {
  142.     // Strip last word (command argument)
  143.     int index = command.index(rxwhite, -1);
  144.     command   = command.before(index);
  145.     }
  146.  
  147.     return found;
  148. }
  149.  
  150. // Issue `set' command
  151. static void gdb_set_command(string set_command, string value)
  152. {
  153.     if (value == "unlimited")
  154.     value = "0";
  155.  
  156.     if (set_command == "dir" && value != "")
  157.     {
  158.     // `dir' in GDB works somewhat special: it prepends its
  159.     // argument to the source path instead of simply setting it.
  160.     // Hence, first reset `dir' to some initial value.
  161.  
  162.     string confirm_value = "on";
  163.     Widget confirm_w = command_to_widget(settings_form, "set confirm");
  164.     if (confirm_w)
  165.         confirm_value = settings_values[confirm_w];
  166.  
  167.     if (confirm_value == "on")
  168.         gdb_command("set confirm off");
  169.     gdb_command(set_command);
  170.     if (confirm_value == "on")
  171.         gdb_command("set confirm on");
  172.     }
  173.  
  174.     if (value != "")
  175.     {
  176.     if (set_command.contains("O ", 0))
  177.         gdb_command(set_command + "=" + value); // Perl
  178.     else if (set_command.contains("set $", 0) && 
  179.          !set_command.contains(" = "))
  180.         gdb_command(set_command + " = " + value); // DBX
  181.     else
  182.         gdb_command(set_command + " " + value); // GDB
  183.     }
  184.     else
  185.     gdb_command(set_command);
  186. }
  187.  
  188. // TextField reply
  189. static void SetTextCB(Widget w, XtPointer client_data, XtPointer)
  190. {
  191.     String value_s = XmTextFieldGetString(w);
  192.     string value(value_s);
  193.     XtFree(value_s);
  194.  
  195.     gdb_set_command((String)client_data, value);
  196. }
  197.  
  198. // OptionMenu reply
  199. static void SetOptionCB(Widget w, XtPointer client_data, XtPointer)
  200. {
  201.     gdb_set_command((String)client_data, XtName(w));
  202. }
  203.  
  204. // ToggleButton reply
  205. static void SetOnOffCB(Widget, XtPointer client_data, XtPointer call_data)
  206. {
  207.     XmToggleButtonCallbackStruct *cbs = 
  208.     (XmToggleButtonCallbackStruct *)call_data;
  209.  
  210.     if (cbs->set)
  211.     gdb_set_command((String)client_data, "on");
  212.     else
  213.     gdb_set_command((String)client_data, "off");
  214. }
  215.  
  216. // ToggleButton reply
  217. static void SetTrueFalseCB(Widget, XtPointer client_data, XtPointer call_data)
  218. {
  219.     XmToggleButtonCallbackStruct *cbs = 
  220.     (XmToggleButtonCallbackStruct *)call_data;
  221.  
  222.     if (cbs->set)
  223.     gdb_set_command((String)client_data, "true");
  224.     else
  225.     gdb_set_command((String)client_data, "false");
  226. }
  227.  
  228. // ToggleButton reply
  229. static void SetSensitiveCB(Widget, XtPointer client_data, XtPointer call_data)
  230. {
  231.     XmToggleButtonCallbackStruct *cbs = 
  232.     (XmToggleButtonCallbackStruct *)call_data;
  233.  
  234.     if (cbs->set)
  235.     gdb_set_command((String)client_data, "sensitive");
  236.     else
  237.     gdb_set_command((String)client_data, "insensitive");
  238. }
  239.  
  240. // ToggleButton reply
  241. static void SetNumCB(Widget, XtPointer client_data, XtPointer call_data)
  242. {
  243.     XmToggleButtonCallbackStruct *cbs = 
  244.     (XmToggleButtonCallbackStruct *)call_data;
  245.  
  246.     if (cbs->set)
  247.     gdb_set_command((String)client_data, "1");
  248.     else
  249.     gdb_set_command((String)client_data, "0");
  250. }
  251.  
  252. // ToggleButton reply
  253. static void SetNoNumCB(Widget, XtPointer client_data, XtPointer call_data)
  254. {
  255.     XmToggleButtonCallbackStruct *cbs = 
  256.     (XmToggleButtonCallbackStruct *)call_data;
  257.  
  258.     if (cbs->set)
  259.     gdb_set_command((String)client_data, "0");
  260.     else
  261.     gdb_set_command((String)client_data, "1");
  262. }
  263.  
  264. // ToggleButton reply
  265. static void SetDisplayCB(Widget, XtPointer client_data, XtPointer call_data)
  266. {
  267.     XmToggleButtonCallbackStruct *cbs = 
  268.     (XmToggleButtonCallbackStruct *)call_data;
  269.  
  270.     if (cbs->set)
  271.     data_disp->new_user_display((String)client_data);
  272.     else
  273.     data_disp->delete_user_display((String)client_data);
  274. }
  275.  
  276. // ToggleButton reply
  277. static void SendSignalCB(Widget, XtPointer client_data, XtPointer)
  278. {
  279.     gdb_command(string("signal ") + XtName(Widget(client_data)));
  280. }
  281.  
  282. static string handle_command(Widget w, bool set)
  283. {
  284.     string sig    = string(XtName(w)).before('-');
  285.     string action = string(XtName(w)).after('-');
  286.     if (!set)
  287.     action.prepend("no");
  288.  
  289.     if (action == "nopass")
  290.     action = "ignore";
  291.     else if (action == "noignore")
  292.     action = "pass";
  293.  
  294.     return "handle " + sig + " " + action;
  295. }
  296.  
  297. // ToggleButton reply
  298. static void SignalCB(Widget w, XtPointer, XtPointer call_data)
  299. {
  300.     XmToggleButtonCallbackStruct *cbs = 
  301.     (XmToggleButtonCallbackStruct *)call_data;
  302.  
  303.     gdb_command(handle_command(w, cbs->set));
  304. }
  305.  
  306. // Get help on signal - using `info' on `libc'
  307. static void HelpOnSignalCB(Widget w, XtPointer client_data, 
  308.                XtPointer call_data)
  309. {
  310.     Widget label = Widget(client_data);
  311.     string sig = XtName(label);
  312.  
  313.     string s = "";
  314.  
  315.     if (sig == "all")
  316.     {
  317.     HelpOnThisCB(w, XtPointer(label), call_data);
  318.     return;
  319.     }
  320.  
  321.     StatusDelay delay("Retrieving Signal Documentation");
  322.  
  323.     // libc info has one common node for SIGUSR1 and SIGUSR2
  324.     string sigindex = sig;
  325.     if (sigindex == "SIGUSR1")
  326.     sigindex = "SIGUSR2";
  327.  
  328.     string cmd = "info -f libc -n 'Variable Index' " + sigindex + " -o -";
  329.  
  330.     FILE *fp = popen(sh_command(cmd), "r");
  331.     if (fp != 0)
  332.     {
  333.     ostrstream info;
  334.     int c;
  335.     while ((c = getc(fp)) != EOF)
  336.         info << char(c);
  337.     pclose(fp);
  338.     
  339.     s = info;
  340.     int start = s.index(" - Macro: int " + sig);
  341.     start = s.index('\n', start);
  342.     s = s.after(start);
  343.     int end = s.index("\n - ");
  344.     if (end >= 0)
  345.         s = s.before(end);
  346.  
  347.     s.gsub("ee\n*Note\n", "ee\n`");
  348.     s.gsub("ee *Note\n",  "ee\n`");
  349.     s.gsub("ee\n*Note ",  "ee\n`");
  350.     s.gsub("ee *Note ",   "ee `");
  351.     s.gsub("*Note ",      "See `");
  352.     s.gsub("*Note\n",     "See\n`");
  353.     s.gsub("::", "' in libc info");
  354.     s.gsub("`C-", "`Ctrl+");
  355.  
  356.     strip_space(s);
  357.     while (s.contains("  "))
  358.         s.gsub("  ", " ");
  359.     s.gsub("\n ", "\n");
  360.     }
  361.  
  362.     if (s == "")
  363.     s = "No help available on this signal.";
  364.  
  365.     XmString xmdoc = 0;
  366.     XtVaGetValues(label, XmNlabelString, &xmdoc, NULL);
  367.     MString doc(xmdoc, true);
  368.     XmStringFree(xmdoc);
  369.  
  370.     MString text = bf(sig + ": ") + doc;
  371.     text += cr() + cr() + rm(s);
  372.  
  373.     MStringHelpCB(w, XtPointer(text.xmstring()), call_data);
  374. }
  375.  
  376.  
  377. // Update state of `reset' button
  378. static void update_reset_settings_button()
  379. {
  380.     if (reset_settings_button == 0)
  381.     return;
  382.  
  383.     check_options_file();
  384.  
  385.     for (int i = 0; i < settings_entries.size(); i++)
  386.     {
  387.     Widget entry = settings_entries[i];
  388.     if (settings_initial_values[entry] != settings_values[entry])
  389.     {
  390.         set_sensitive(reset_settings_button, True);
  391.         return;
  392.     }
  393.     }
  394.  
  395.     set_sensitive(reset_settings_button, False);
  396. }
  397.  
  398. static void update_reset_signals_button()
  399. {
  400.     if (reset_signals_button == 0)
  401.     return;
  402.  
  403.     check_options_file();
  404.  
  405.     for (int i = 0; i < signals_entries.size(); i++)
  406.     {
  407.     Widget entry = signals_entries[i];
  408.     if (signals_initial_values[entry] != signals_values[entry])
  409.     {
  410.         set_sensitive(reset_signals_button, True);
  411.         return;
  412.     }
  413.     }
  414.  
  415.     set_sensitive(reset_signals_button, False);
  416. }
  417.  
  418. // Update states of `info' buttons
  419. void update_infos()
  420. {
  421.     bool have_info = false;
  422.  
  423.     for (int i = 0; i < infos_entries.size(); i++)
  424.     {
  425.     Widget button = infos_entries[i];
  426.     bool set = data_disp->have_user_display(XtName(button));
  427.     have_info = have_info || set;
  428.     XtVaSetValues(button, XmNset, set, NULL);
  429.     }
  430.  
  431.     if (reset_infos_button != 0)
  432.     set_sensitive(reset_infos_button, have_info);
  433. }
  434.  
  435. // Register additional info button
  436. void register_info_button(Widget w)
  437. {
  438.     infos_entries += w;
  439. }
  440.  
  441. // Save `settings' state
  442. void save_settings_state()
  443. {
  444.     if (settings_form == 0)
  445.     return;
  446.  
  447.     for (int i = 0; i < settings_entries.size(); i++)
  448.     {
  449.     Widget entry = settings_entries[i];
  450.     settings_initial_values[entry] = settings_values[entry];
  451.     }
  452.  
  453.     update_reset_settings_button();
  454.     set_need_save_defines(false);
  455. }
  456.  
  457. // Save `signals' state
  458. void save_signals_state()
  459. {
  460.     if (signals_form == 0)
  461.     return;
  462.  
  463.     for (int i = 0; i < signals_entries.size(); i++)
  464.     {
  465.     Widget entry = signals_entries[i];
  466.     signals_initial_values[entry] = signals_values[entry];
  467.     }
  468.  
  469.     update_reset_signals_button();
  470. }
  471.  
  472. // Process output of `show' command
  473. void process_show(string command, string value, bool init)
  474. {
  475.     if (settings_form == 0)
  476.     return;
  477.  
  478.     if (gdb->type() == DBX && value.freq('\n') > 1)
  479.     {
  480.     // In DBX, we always get all values at once.  Find the
  481.     // appropriate line.
  482.     string base = command.after(rxwhite);
  483.     if (base.contains(rxwhite))
  484.         base = base.before(rxwhite);
  485.  
  486.     int column = 0;
  487.     int start_value = -1;
  488.     for (int i = 0; i < int(value.length()); i++)
  489.     {
  490.         if (column == 0
  491.         && value.contains(base, i) 
  492.         && value.contains(rxwhite, i + base.length()))
  493.         {
  494.         start_value = i;
  495.         break;
  496.         }
  497.  
  498.         if (value[i] == '\n')
  499.         column = 0;
  500.         else
  501.         column++;
  502.     }
  503.  
  504.     if (start_value < 0)
  505.     {
  506. #if 0
  507.         cerr << "Warning: cannot set " << quote(base)
  508.          << " to " << quote(value) << "\n";
  509. #endif
  510.         return;
  511.     }
  512.  
  513.     value = value.from(start_value);
  514.     value = value.after(base);
  515.     if (value.contains('\n'))
  516.         value = value.before('\n');
  517.     strip_space(value);
  518.     }
  519.  
  520.     if (value.contains('\n'))
  521.     value = value.before('\n');
  522.  
  523.     if (!init)
  524.     set_status(value);
  525.  
  526.     if (gdb->type() == GDB)
  527.     {
  528.     if (value.contains(" is "))
  529.         value = value.after(" is ", -1);
  530.     if (value.contains(".", -1))
  531.         value = value.before(int(value.length()) - 1);
  532.  
  533.     if (value.contains("assumed to be "))
  534.         value = value.after("assumed to be ");
  535.     if (value.contains("\"auto;", 0) || 
  536.         value.contains("set automatically", 0))
  537.         value = "auto";
  538.     if (value.contains('"', 0))
  539.         value = unquote(value);
  540.     else if (value.contains(": "))
  541.         value = value.after(": ");
  542.     }
  543.  
  544.     if (gdb->type() == PERL)
  545.     {
  546.     if (value.contains('\''))
  547.     {
  548.         value = value.after('\'');
  549.         value = value.before('\'');
  550.     }
  551.     }
  552.  
  553.     static string empty;
  554.     value.gsub(gdb_out_ignore, empty);
  555.  
  556.     string set_command = command;
  557.     if (set_command.contains("O ", 0))
  558.     {
  559.     // Perl
  560.     if (set_command.contains('?'))
  561.         set_command = set_command.before('?');
  562.     else if (set_command.contains('='))
  563.         set_command = set_command.before('=');
  564.     }
  565.     else if (!set_command.contains("set ", 0))
  566.     {
  567.     // GDB
  568.     set_command = "set " + set_command.after(rxwhite);
  569.     }
  570.  
  571.     Widget button = command_to_widget(settings_form, set_command);
  572.     if (button == 0)
  573.     button = command_to_widget(settings_form, command);
  574.     if (button == 0)
  575.     button = command_to_widget(settings_form, command.after(rxwhite));
  576.  
  577.     if (button != 0)
  578.     {
  579.     if (!init)
  580.     {
  581.         // Save current state in undo buffer
  582.         ostrstream command;
  583.         get_setting(command, gdb->type(), XtName(button), 
  584.             settings_values[button]);
  585.         undo_buffer.add_command(string(command));
  586.     }
  587.  
  588.     settings_values[button] = value;
  589.     if (init)
  590.         settings_initial_values[button] = value;
  591.     }
  592.  
  593.     if (!init)
  594.     update_reset_settings_button();
  595.  
  596.     if (button != 0 && XmIsRowColumn(button))
  597.     {
  598.     Widget menu = 0;
  599.     XtVaGetValues(button, XmNsubMenuId, &menu, NULL);
  600.     if (menu != 0)
  601.     {
  602.         // Option menu
  603.         Widget active = XtNameToWidget(menu, value);
  604.         if (active != 0)
  605.         {
  606.         XtVaSetValues(button, XmNmenuHistory, active, NULL);
  607.         return;
  608.         }
  609.     }
  610.     }
  611.     else if (button != 0 && XmIsToggleButton(button))
  612.     {
  613.     bool set = value != "off" && value != "0" && value != "unlimited" 
  614.         && value != "false" && value != "insensitive";
  615.  
  616.     for (int i = 0; i < settings_entries.size(); i++)
  617.     {
  618.         if (settings_entries[i] == button
  619.         && settings_entry_types[i] == NoNumToggleButtonEntry)
  620.         {
  621.         set = !set;
  622.         break;
  623.         }
  624.     }
  625.  
  626.     XtVaSetValues(button, XmNset, set, NULL);
  627.     return;
  628.     }
  629.     else if (button != 0 && XmIsTextField(button))
  630.     {
  631.     XtVaSetValues(button, 
  632.               XmNvalue,                 value.chars(),
  633.               XmNcursorPosition,        0,
  634.               XmNcursorPositionVisible, True,
  635.               NULL);
  636.     return;
  637.     }
  638.  
  639. #if 0
  640.     cerr << "Warning: cannot set " << quote(set_command)
  641.      << " to " << quote(value) << "\n";
  642. #endif
  643. }
  644.  
  645. // Process output of `handle' command
  646. void process_handle(string output, bool init)
  647. {
  648.     if (signals_form == 0)
  649.     return;
  650.  
  651.     string undo_command = "";
  652.  
  653.     while (output != "")
  654.     {
  655.     string line = output;
  656.     if (line.contains('\n'))
  657.         line = line.before('\n');
  658.     output = output.after('\n');
  659.  
  660.     string base = line.before(rxwhite);
  661.     if (!base.contains("SIG", 0))
  662.         continue;
  663.  
  664.     line = line.after(rxwhite);
  665.     static String titles[3] = { "stop", "print", "pass" };
  666.  
  667.     for (int word = 0; word <= 2; word++)
  668.     {
  669.         string value = line.before(rxwhite);
  670.         line = line.after(rxwhite);
  671.  
  672.         value.downcase();
  673.         bool set = (value == "yes");
  674.         string name = base + "-" + titles[word];
  675.         Widget w = XtNameToWidget(signals_form, name);
  676.  
  677.         if (w == 0)
  678.         {
  679. #if 0
  680.         cerr << "Warning: cannot set " << base << " " << titles[word]
  681.              << " to " << quote(value) << "\n";
  682. #endif
  683.         continue;
  684.         }
  685.  
  686.         if (!init && signals_values[w] != value)
  687.         {
  688.         // Save undoing command
  689.         if (undo_command != "")
  690.             undo_command += '\n';
  691.         undo_command += handle_command(w, !set);
  692.         }
  693.  
  694.         XtVaSetValues(w, XmNset, set, NULL);
  695.  
  696.         signals_values[w] = value;
  697.         if (init)
  698.         signals_initial_values[w] = value;
  699.     }
  700.     }
  701.  
  702.     if (undo_command != "")
  703.     undo_buffer.add_command(undo_command);
  704.  
  705.     update_reset_signals_button();
  706. }
  707.  
  708.  
  709.  
  710. // Create settings form
  711.  
  712. // Return TRUE if doc begins with a boolean verb
  713. static bool is_verb(const string& doc)
  714. {
  715.     if (doc.contains("whether to"))
  716.     return true;
  717.     int ing = doc.index("ing");
  718.     if (ing < 0)
  719.     return false;
  720.     int first_space  = doc.index(' ');
  721.     int second_space = doc.index(' ', first_space + 1);
  722.     if (ing < first_space || ing < second_space || second_space < 0)
  723.     return true;
  724.  
  725.     return false;
  726. }
  727.  
  728. // Determine entry type
  729. static EntryType entry_type(DebuggerType type,
  730.                 const string& base, 
  731.                 const string& doc,
  732.                 const string& value)
  733. {
  734. #if RUNTIME_REGEX
  735.     static regex rxnonzero1("no[nt][ -]?(0|zero|null)");
  736.     static regex rxnonzero2("!= *(0|zero|null)");
  737. #endif
  738.  
  739.     switch (type)
  740.     {
  741.     case GDB:
  742.     if (base.contains("check", 0))
  743.         return CheckOptionMenuEntry;
  744.     if (base.contains("endian", 0) ||
  745.         base.contains("architecture", 0))
  746.         return TargetOptionMenuEntry;
  747.     if (base.contains("language", 0) || 
  748.         base.contains("demangle", 0))
  749.         return OtherOptionMenuEntry;
  750.     if (value.contains("on.\n", -1) || value.contains("off.\n", -1))
  751.         return OnOffToggleButtonEntry;
  752.     if ((value.contains("0.\n", -1) || value.contains("1.\n", -1))
  753.         && (is_verb(doc)))
  754.         return NumToggleButtonEntry;
  755.     break;
  756.  
  757.     case DBX:
  758.     if ((value == "0" || value == "1") &&
  759.         !doc.contains("number") && !doc.contains(" > 1"))
  760.     {
  761.         if (doc.contains(" 1") && !doc.contains(" 2"))
  762.         return NumToggleButtonEntry;
  763.         if (doc.contains(rxnonzero1) || doc.contains(rxnonzero2))
  764.         return NumToggleButtonEntry;
  765.     }
  766.     if (value.contains("on", 0) || value.contains("off", 0))
  767.         return OnOffToggleButtonEntry;
  768.     if (value.contains("true", 0) || value.contains("false", 0))
  769.         return TrueFalseToggleButtonEntry;
  770.     if (value.contains("sensitive", 0) 
  771.         || value.contains("insensitive", 0))
  772.         return SensitiveToggleButtonEntry;
  773.     if (has_nr(value))
  774.         return TextFieldEntry;
  775.     if (base.contains("version")
  776.         || base.contains("run_io")
  777.         || base.contains("follow_fork_mode"))
  778.         return OtherOptionMenuEntry;
  779.     break;
  780.  
  781.     case XDB:
  782.     case JDB:
  783.     case PYDB:
  784.     case PERL:
  785.     break;            // FIXME
  786.     }
  787.  
  788.     // When all else fails, display a text
  789.     return TextFieldEntry;
  790. }
  791.  
  792.  
  793. // The GDB question cache
  794. static StringStringAssoc gdb_question_cache;
  795.  
  796. static string cached_gdb_question(const string& question, int timeout = 0)
  797. {
  798.     string& answer = gdb_question_cache[question];
  799.     if (answer == "")
  800.     answer = gdb_question(question, timeout);
  801.     return answer;
  802. }
  803.  
  804. static void clear_gdb_question_cache()
  805. {
  806.     static StringStringAssoc empty;
  807.     gdb_question_cache = empty;
  808. }
  809.  
  810. static void strip_leading(string& doc, const string& key)
  811. {
  812.     if (doc.contains(key, 0))
  813.     doc = doc.after(key);
  814.     strip_leading_space(doc);
  815. }
  816.  
  817. static void strip_from(string& doc, const string& key)
  818. {
  819.     if (doc.contains(key))
  820.     doc = doc.before(key);
  821.     strip_leading_space(doc);
  822. }
  823.  
  824. static void munch_doc(string& doc)
  825. {
  826.     strip_leading_space(doc);
  827.  
  828.     // Sun DBX 3.0
  829.     strip_leading(doc, "#");
  830.     strip_leading(doc, "If on,");
  831.     strip_leading(doc, "If true,");
  832.     strip_leading(doc, "When on,");
  833.     strip_leading(doc, "When `on',");
  834.     strip_leading(doc, "Set ");
  835.     strip_leading(doc, "Sets ");
  836.     strip_leading(doc, "Governs ");
  837.     strip_leading(doc, "Limit ");
  838.     strip_leading(doc, "Enable/disable ");
  839.     strip_leading(doc, "Allow/disallow ");
  840.     strip_leading(doc, "whether the ");
  841.     strip_leading(doc, "debugger will ");
  842.     strip_leading(doc, "Automatically ");
  843.     strip_leading(doc, "Name of ");
  844.  
  845.     // SGI DBX
  846.     strip_leading(doc, "-");
  847.  
  848.     if (doc.contains("0 =>"))
  849.     doc = "Don't" + doc.after("0 =>");
  850.  
  851.     // DEC and SGI DBX
  852.     strip_leading(doc, "$");
  853.     strip_leading(doc, "if");
  854.     strip_leading(doc, "If");
  855.     strip_leading(doc, "when");
  856.     strip_leading(doc, "When");
  857.     strip_leading(doc, "this ");
  858.     strip_leading(doc, "is ");
  859.     strip_leading(doc, "==");
  860.     strip_leading(doc, "!=");
  861.     strip_leading(doc, "0");
  862.     strip_leading(doc, "1");
  863.     strip_leading(doc, "set");
  864.     strip_leading(doc, "zero");
  865.     strip_leading(doc, "non-zero");
  866.     strip_leading(doc, "non-0");
  867.     strip_leading(doc, "(default)");
  868.     strip_leading(doc, "(the default)");
  869.     strip_leading(doc, ",");
  870.     strip_leading(doc, "=>");
  871.     strip_leading(doc, "implies ");
  872.     strip_leading(doc, "then ");
  873.     strip_leading(doc, "contains ");
  874.     strip_leading(doc, "the ");
  875.     strip_leading(doc, "name of ");
  876.     strip_leading(doc, "specify ");
  877.     strip_leading(doc, "which ");
  878.     strip_leading(doc, "after ");
  879.     strip_leading(doc, "String with ");
  880.  
  881.     // GDB
  882.     strip_leading(doc, "whether to ");
  883.     strip_leading(doc, "the ");
  884.  
  885.     // More DEC DBX
  886.     strip_from(doc, "we're looking at");
  887.     strip_from(doc, "we're debugging");
  888.     strip_from(doc, "Default:");
  889.     strip_from(doc, ", default");
  890.     strip_from(doc, " to $DBX");
  891.     strip_from(doc, " entirely");
  892.     strip_from(doc, " rather than");
  893.     strip_from(doc, ", else");
  894.     strip_from(doc, " next to");
  895.     strip_from(doc, " used to");
  896.     strip_from(doc, " that was");
  897.     strip_from(doc, " accessing");
  898.  
  899.     // More SGI DBX
  900.     strip_from(doc, " if none");
  901.     strip_from(doc, " (init");
  902.     strip_from(doc, " (default");
  903.     strip_from(doc, " ($");
  904.     strip_from(doc, " ( $");
  905.     strip_from(doc, " (with");
  906.     strip_from(doc, " However ");
  907.     strip_from(doc, " This ");
  908.     strip_from(doc, " Defaults ");
  909.     strip_from(doc, " $");
  910.  
  911.     doc.gsub(" " + downcase(gdb->title()), " " + gdb->title());
  912.     if (doc.contains(downcase(gdb->title()), 0))
  913.     doc = gdb->title() + doc.after(downcase(gdb->title()));
  914.  
  915.     if (doc.length() > 0)
  916.     doc[0] = toupper(doc[0]);
  917.  
  918.     if (gdb->type() == GDB)
  919.     doc.gsub('_', ' ');
  920.  
  921.     if (doc.length() > 60)
  922.     doc = doc.before(57) + "...";
  923. }
  924.  
  925.  
  926. // Get DBX documentation
  927. static string _get_dbx_help(string dbxenv, string base)
  928. {
  929.     string dbx_help;
  930.     if (dbxenv == "dbxenv")
  931.     dbx_help = cached_gdb_question("help dbxenv", -1);
  932.     if (dbx_help.freq('\n') <= 2)
  933.     dbx_help = cached_gdb_question("help variable", -1);
  934.     if (dbx_help.freq('\n') <= 2)
  935.     dbx_help = cached_gdb_question("help $variables", -1);
  936.  
  937.     // Find documentation in DBX_HELP
  938.     int column = 0;
  939.     int start_help = -1;
  940.     int i;
  941.     for (i = 0; i < int(dbx_help.length()); i++)
  942.     {
  943.     if (column == 0 
  944.         && (dbx_help.contains(base, i) 
  945.         || dbx_help.contains(dbxenv + " " + base, i)))
  946.     {
  947.         start_help = i;
  948.         break;
  949.     }
  950.  
  951.     if (dbx_help[i] == '\n')
  952.         column = 0;
  953.     else
  954.         column++;
  955.     }
  956.  
  957.     if (start_help < 0)
  958.     {
  959.     dbx_help = base;
  960.     dbx_help.gsub('_', ' ');
  961.     return dbx_help;        // Simple default
  962.     }
  963.  
  964.     int end_help = -1;
  965.     for (i++, column++; i < int(dbx_help.length()); i++)
  966.     {
  967.     if (column == 0 && !isspace(dbx_help[i]))
  968.     {
  969.         end_help = i;
  970.         break;
  971.     }
  972.  
  973.     if (dbx_help[i] == '\n')
  974.         column = 0;
  975.     else
  976.         column++;
  977.     }
  978.  
  979.     if (end_help >= 0)
  980.     dbx_help = dbx_help.at(start_help, end_help - start_help);
  981.     else
  982.     dbx_help = dbx_help.from(start_help);
  983.  
  984.     return dbx_help;
  985. }
  986.  
  987. static void compress_spaces(string& s, int width)
  988. {
  989.     char *buffer = new char[s.length() + 1];
  990.     char *t = buffer;
  991.  
  992.     int column = 0;
  993.     for (int i = 0; i < int(s.length()); i++)
  994.     {
  995.     if (isspace(s[i]))
  996.     {
  997.         while (i < int(s.length()) && isspace(s[i]))
  998.         i++;
  999.  
  1000.         if (width > 0 && column >= width)
  1001.         {
  1002.         *t++ = '\n';
  1003.         column = 0;
  1004.         }
  1005.         else
  1006.         {
  1007.         *t++ = ' ';
  1008.         column++;
  1009.         }
  1010.     }
  1011.  
  1012.     if (i < int(s.length()))
  1013.     {
  1014.         *t++ = s[i];
  1015.         column++;
  1016.     }
  1017.     }
  1018.     *t++ = '\0';
  1019.  
  1020.     s = buffer;
  1021.     delete[] buffer;
  1022. }
  1023.  
  1024. // Same, but for usage in help messages
  1025. static string get_dbx_help(string dbxenv, string base, int width)
  1026. {
  1027.     string dbx_help = _get_dbx_help(dbxenv, base);
  1028.     dbx_help = dbx_help.after(base);
  1029.     strip_leading_space(dbx_help);
  1030.  
  1031.     if (dbx_help.contains("  - "))
  1032.     {
  1033.     dbx_help = dbx_help.after("  - ");
  1034.     strip_leading_space(dbx_help);
  1035.     }
  1036.     else if (dbx_help.contains(" # "))
  1037.     {
  1038.     dbx_help = dbx_help.after(" # ");
  1039.     strip_leading_space(dbx_help);
  1040.     }
  1041.  
  1042.     // Remove remaining `# ' prefixes (Solaris DBX)
  1043.     dbx_help.gsub("  # ", "");
  1044.     dbx_help.gsub(" # ", " number ");
  1045.  
  1046.     // Reduce spaces (Solaris DBX & DEC DBX)
  1047.     compress_spaces(dbx_help, width);
  1048.  
  1049.     return dbx_help;
  1050. }
  1051.  
  1052. string get_dbx_help(string dbxenv, string base)
  1053. {
  1054.     return get_dbx_help(dbxenv, base, 60);
  1055. }
  1056.  
  1057. struct DBXTranslation {
  1058.     String base;
  1059.     String doc;
  1060. };
  1061.  
  1062. static DBXTranslation dbx_translations[] = 
  1063. {
  1064.     {"$addrfmt64", "C format for address printing (64bit)"},
  1065.     {"$assignverify", "Verify assignments"},
  1066.     {"$byteaccess", "Access memory items less than 4 bytes"},
  1067.     {"$ctypenames", "Support C type names"},
  1068.     {"$dispix", "Display pixie instructions"},
  1069.     {"$fp_precise", "Floating point precise mode"},
  1070.     {"$framereg", "Registers are with respect to the current frame"},
  1071.     {"$groupforktoo", "Group fork too"},
  1072.     {"$hexdoubles", "Display float values as float and hex"},
  1073.     {"$newevent", "Last new event number"},
  1074.     {"$newpgrpevent", "Last new pgrp event number"},
  1075.     {"$newrecord", "Last record number"},
  1076.     {"$nonstop", "Stop the debugged process"},
  1077.     {"$pager", "Pager"},
  1078.     {"$pendingtraps", "Pending traps"},
  1079.     {"$piaddtohist", "Add playback commands to history"},
  1080.     {"$print_exception_frame", "Print exception frames"},
  1081.     {"$shellparameters", "Shell parameters"},
  1082.     {"$showbreakaddrs", "Show the address of placed breakpoints"},
  1083.     {"$showfilename", "Show file name when stopping"},
  1084.     {"$sourcepathrule", "Rule for accessing source paths"},
  1085.     {"$stacktracelimit", "Stack trace limit"},
  1086.     {"$stdc", "Support Standard C"},
  1087.     {"$stepintoall", "Step into all procedures"},
  1088.     {"$stopformat", "Stop format"},
  1089.     {"$whereisdsolimit", "Whereis limit"},
  1090.     {"disassembler_version", "Disassembler version"},
  1091.     {"follow_fork_inherit", "When following child, inherit events"},
  1092.     {"follow_fork_mode", "When process forks"},
  1093.     {"output_list_size", "Lines to print in the `list' command"},
  1094.     {"rtc_biu_at_exit", "Produce memory report at exit"},
  1095.     {"run_autostart", "Let `step' and `next' implicitly start the program"},
  1096.     {"run_io", "Redirect I/O to"},
  1097.     {"suppress_startup_message", "Suppress startup message below release"}
  1098. };
  1099.  
  1100. static string get_dbx_doc(string dbxenv, string base)
  1101. {
  1102.     // Some specials
  1103.     for (int i = 0; i < int(XtNumber(dbx_translations)); i++)
  1104.     {
  1105.     if (base == dbx_translations[i].base)
  1106.         return dbx_translations[i].doc;
  1107.     }
  1108.     
  1109.     // Generic help
  1110.     string dbx_doc = get_dbx_help(dbxenv, base, -1);
  1111.     strip_leading_space(dbx_doc);
  1112.  
  1113.     dbx_doc.gsub("etc. ", "etc ");
  1114.     if (dbx_doc.contains(". "))
  1115.     dbx_doc = dbx_doc.before(". ");
  1116.     if (dbx_doc.contains("; "))
  1117.     dbx_doc = dbx_doc.before("; ");
  1118.     dbx_doc.gsub("etc ", "etc. ");
  1119.  
  1120. #if 0
  1121.     if (dbx_doc == "")
  1122.     {
  1123.     dbx_doc = base;
  1124.     dbx_doc.gsub('_', ' ');
  1125.     }
  1126. #endif
  1127.  
  1128.     munch_doc(dbx_doc);
  1129.  
  1130.     return dbx_doc;
  1131. }
  1132.  
  1133. static Dimension preferred_width(Widget w)
  1134. {
  1135.     if (w == 0)
  1136.     return 0;
  1137.  
  1138.     XtWidgetGeometry size;
  1139.     size.request_mode = CWWidth;
  1140.     XtQueryGeometry(w, NULL, &size);
  1141.  
  1142.     int left_offset  = 0;
  1143.     int right_offset = 0;
  1144.     XtVaGetValues(w, XmNleftOffset, &left_offset, 
  1145.           XmNrightOffset, &right_offset, NULL);
  1146.  
  1147.     return size.width + left_offset + right_offset;
  1148. }
  1149.  
  1150. static Dimension preferred_height(Widget w)
  1151. {
  1152.     if (w == 0)
  1153.     return 0;
  1154.  
  1155.     XtWidgetGeometry size;
  1156.     size.request_mode = CWHeight;
  1157.     XtQueryGeometry(w, NULL, &size);
  1158.     return size.height;
  1159. }
  1160.  
  1161. static void add_settings(Widget form, int& row, Dimension& max_width,
  1162.              DebuggerType type, EntryType entry_filter, 
  1163.              string gdb_class = "set");
  1164.  
  1165. static Widget create_signal_button(Widget label,
  1166.                    string name,
  1167.                    int row,
  1168.                    Widget rightmost = 0)
  1169. {
  1170.     Arg args[15];
  1171.     Cardinal arg = 0;
  1172.  
  1173.     MString lbl(capitalize(name));
  1174.     XtSetArg(args[arg], XmNlabelString, lbl.xmstring()); arg++;
  1175.  
  1176.     if (rightmost != 0)
  1177.     {
  1178.     XtSetArg(args[arg], XmNrightAttachment, XmATTACH_WIDGET); arg++;
  1179.     XtSetArg(args[arg], XmNrightWidget,     rightmost);       arg++;
  1180.     }
  1181.     else
  1182.     {
  1183.     XtSetArg(args[arg], XmNrightAttachment, XmATTACH_FORM); arg++;
  1184.     }
  1185.  
  1186.     XtSetArg(args[arg], XmNtopAttachment,    XmATTACH_POSITION);  arg++;
  1187.     XtSetArg(args[arg], XmNtopPosition,      row);                arg++;
  1188.     XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION);  arg++;
  1189.     XtSetArg(args[arg], XmNbottomPosition,   row + 1);            arg++;
  1190.     XtSetArg(args[arg], XmNalignment,        XmALIGNMENT_CENTER); arg++;
  1191.  
  1192.     Widget w = 0;
  1193.     if (name == "send")
  1194.     {
  1195.     w = verify(XmCreatePushButton(XtParent(label), name, args, arg));
  1196.     XtManageChild(w);
  1197.  
  1198.     XtAddCallback(w, XmNactivateCallback, SendSignalCB, XtPointer(label));
  1199.     }
  1200.     else
  1201.     {
  1202.     string fullname = string(XtName(label)) + "-" + name;
  1203.     w = verify(XmCreateToggleButton(XtParent(label), fullname, args, arg));
  1204.     XtManageChild(w);
  1205.  
  1206.     XtAddCallback(w, XmNvalueChangedCallback, SignalCB, XtPointer(label));
  1207.     }
  1208.  
  1209.     return w;
  1210. }
  1211.  
  1212. // Get `show' command for settings command CMD
  1213. string show_command(const string& cmd, DebuggerType type)
  1214. {
  1215.     string show = "";
  1216.     switch (type)
  1217.     {
  1218.     case GDB:
  1219.     case PYDB:
  1220.     show = "show ";
  1221.     if (cmd.contains("set ", 0))
  1222.         show += cmd.after("set ");
  1223.     else if (cmd.contains("directory ", 0))
  1224.         show += "directories";
  1225.     else if (cmd.contains("path ", 0))
  1226.         show += "paths";
  1227.     else
  1228.         show += cmd;
  1229.  
  1230.     if (show.freq(' ') >= 2)
  1231.     {
  1232.         // Strip last argument from `show' command
  1233.         int index = show.index(' ', -1);
  1234.         show = show.before(index);
  1235.     }
  1236.     break;
  1237.  
  1238.     case DBX:
  1239.     show = cmd.before(rxwhite);
  1240.     break;
  1241.  
  1242.     case PERL:
  1243.     if (cmd.contains('='))
  1244.         show = cmd.before('=') + "?";
  1245.     else
  1246.         show = cmd + "?";
  1247.     break;
  1248.  
  1249.     case JDB:
  1250.     case XDB:
  1251.     break;
  1252.     }
  1253.  
  1254.     return show;
  1255. }
  1256.  
  1257.  
  1258. // Add single button
  1259. static void add_button(Widget form, int& row, Dimension& max_width,
  1260.                DebuggerType type, EntryType entry_filter,
  1261.                string line)
  1262. {
  1263.     if (line == "")
  1264.     return;
  1265.  
  1266.     string set_command;        // Command to create the setting
  1267.     string show_command;    // Command to display the value
  1268.     string doc;            // Documentation string
  1269.     string base;        // Common base of set_command and show_command
  1270.     string value;        // Current variable value
  1271.     EntryType e_type;        // Type of the entry
  1272.  
  1273.     bool is_set = true;        // Command sets a value
  1274.     bool is_add = false;    // Command adds a value
  1275.  
  1276.     switch (type)
  1277.     {
  1278.     case GDB:
  1279.     case PYDB:
  1280.     {
  1281.     if (!line.contains(" -- ") && 
  1282.         (entry_filter != SignalEntry || (!line.contains("SIG", 0) &&
  1283.                          !line.contains("all", 0))))
  1284.         return;            // No help line
  1285.  
  1286.     set_command  = line.before(" -- ");
  1287.     doc          = line.after(" -- ");
  1288.     base         = set_command.after(' ');
  1289.     if (base == "")
  1290.         base = set_command;
  1291.     show_command = "show " + base;
  1292.  
  1293.     if (entry_filter == SignalEntry)
  1294.     {
  1295.         if (!line.contains("all", 0) && !line.contains("SIG", 0))
  1296.         return;        // No signal line
  1297.  
  1298.         // Special handling for signal tables
  1299.         base = line.before(rxwhite);
  1300.         doc  = line.after(rxwhite);
  1301.         doc  = doc.after(rxwhite);
  1302.         doc  = doc.after(rxwhite);
  1303.         doc  = doc.after(rxwhite);
  1304.         e_type = SignalEntry;
  1305.     }
  1306.     else if (entry_filter != DisplayToggleButtonEntry)
  1307.     {
  1308.         if (base == "args")
  1309.         return; // Already handled in `Run...' editor
  1310.  
  1311.         if (base == "radix")
  1312.         return; // Already handled in input- and output-radix
  1313.  
  1314.         is_set = doc.contains("Set ", 0);
  1315.         is_add = doc.contains("Add ", 0);
  1316.  
  1317.         if (!is_set && !is_add)
  1318.         {
  1319.         // Generic command or `set variable' - list `set'
  1320.         // subcommands
  1321.         add_settings(form, row, max_width, 
  1322.                  type, entry_filter, set_command);
  1323.         return;
  1324.         }
  1325.  
  1326.         value = cached_gdb_question(show_command);
  1327.         if (is_set && value.freq('\n') > 1)
  1328.         {
  1329.         // Generic command - list `set' subcommands
  1330.         add_settings(form, row, max_width,
  1331.                  type, entry_filter, set_command);
  1332.         return;
  1333.         }
  1334.  
  1335.         if (is_set && 
  1336.         !value.contains(" is ") && 
  1337.         !value.contains(".\n", -1))
  1338.         return;
  1339.  
  1340.         e_type = entry_type(type, base, doc, value);
  1341.         if (e_type != entry_filter)
  1342.         return;
  1343.  
  1344.         if (is_set)
  1345.         doc = doc.after("Set ");
  1346.         else if (is_add)
  1347.         doc = doc.after("Add ");
  1348.  
  1349.         if (is_add && doc.contains("of "))
  1350.         doc = doc.after("of ");
  1351.     }
  1352.     else
  1353.     {
  1354.         if (base == "signals")
  1355.         return;    // We already have `info handle'.
  1356.         if (base == "watchpoints")
  1357.         return;    // We already have `info breakpoints'.
  1358.         if (base == "target")
  1359.         return;    // We already have `info files'.
  1360.         if (base == "address")
  1361.         return;    // `info address' requires an argument.
  1362.         if (base == "line")
  1363.         return;    // `info line' requires an argument.
  1364.  
  1365.         // These infos produce too much output for the data window
  1366.         // to be of any use.  Even worse, a data display as large
  1367.         // as the one generated by `info functions' causes my X
  1368.         // terminal to crash. - AZ
  1369.         if (base == "types")
  1370.         return;
  1371.         if (base == "functions")
  1372.         return;
  1373.         if (base == "variables")
  1374.         return;
  1375.  
  1376.         e_type = DisplayToggleButtonEntry;
  1377.         if (e_type != entry_filter)
  1378.         return;
  1379.  
  1380.         strip_leading(doc, "Show ");
  1381.         strip_leading(doc, "Print ");
  1382.         strip_leading(doc, "out ");
  1383.         strip_leading(doc, "the ");
  1384.     }
  1385.     munch_doc(doc);
  1386.         break;
  1387.     }
  1388.  
  1389.     case DBX:
  1390.     {
  1391.     if (!line.contains("$", 0) 
  1392.         && !(line.contains(rxidentifier, 0) && islower(line[0])))
  1393.         return;            // No help line
  1394.  
  1395.     base = line.before(rxwhite);
  1396.     if (base == "")
  1397.         return;
  1398.     if (base == "run_savetty")
  1399.         return; // Makes no sense under a GUI
  1400.  
  1401.     value = line.after(rxwhite);
  1402.  
  1403.     string dbxenv;
  1404.     if (base[0] == '$')
  1405.         dbxenv = "set";
  1406.     else
  1407.         dbxenv = "dbxenv";
  1408.  
  1409.     e_type = entry_type(type, base, get_dbx_help(dbxenv, base), value);
  1410.     if (e_type != entry_filter)
  1411.         return;
  1412.  
  1413.     set_command = dbxenv + " " + base;
  1414.     show_command = set_command + " " + value;
  1415.     doc = get_dbx_doc(dbxenv, base);
  1416.  
  1417. #if RUNTIME_REGEX
  1418.     static regex rxdont("Do ?n['o]t");
  1419. #endif
  1420.     if (doc.contains(rxdont, 0) && e_type == NumToggleButtonEntry)
  1421.     {
  1422.         doc = doc.after(rxdont);
  1423.         munch_doc(doc);
  1424.         e_type = NoNumToggleButtonEntry;
  1425.     }
  1426.         break;
  1427.     }
  1428.  
  1429.     case JDB:
  1430.     {
  1431.     // All we have is the `use' command.
  1432.     e_type = TextFieldEntry;
  1433.     set_command  = "use";
  1434.     show_command = "use";
  1435.     doc          = "Class path";
  1436.     value = source_view->class_path();
  1437.     break;
  1438.     }
  1439.  
  1440.     case XDB:
  1441.     return;            // FIXME
  1442.  
  1443.     case PERL:
  1444.     {
  1445.     e_type = TextFieldEntry;
  1446.     base  = line.before(" = ");
  1447.     strip_space(base);
  1448.     value = unquote(line.after(" = "));
  1449.     set_command  = "O " + base;
  1450.     show_command = "O " + base + "?";
  1451.     doc = base;
  1452.     break;
  1453.     }
  1454.     }
  1455.  
  1456.     if (e_type != entry_filter)
  1457.     return;
  1458.  
  1459.     if (doc == "")
  1460.     return;            // No need to support undocumented stuff
  1461.  
  1462.     Arg args[15];
  1463.     int arg;
  1464.  
  1465.     // Add label
  1466.     Widget label = 0;
  1467.     Widget entry = 0;
  1468.  
  1469.     String set_command_s = new char[set_command.length() + 1];
  1470.     strcpy(set_command_s, set_command);
  1471.  
  1472.     MString labelString(doc);
  1473.     arg = 0;
  1474.     XtSetArg(args[arg], XmNlabelString,      labelString.xmstring()); arg++;
  1475.     XtSetArg(args[arg], XmNleftAttachment,   XmATTACH_FORM);          arg++;
  1476.     XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION);      arg++;
  1477.     XtSetArg(args[arg], XmNbottomPosition,   row + 1);                arg++;
  1478.     XtSetArg(args[arg], XmNalignment,        XmALIGNMENT_BEGINNING);  arg++;
  1479.  
  1480.     XtCallbackProc callback = 0;
  1481.  
  1482.     switch (e_type)
  1483.     {
  1484.     case OnOffToggleButtonEntry:
  1485.     callback = SetOnOffCB;
  1486.     break;
  1487.  
  1488.     case TrueFalseToggleButtonEntry:
  1489.     callback = SetTrueFalseCB;
  1490.     break;
  1491.  
  1492.     case SensitiveToggleButtonEntry:
  1493.     callback = SetSensitiveCB;
  1494.     break;
  1495.  
  1496.     case NumToggleButtonEntry:
  1497.     callback = SetNumCB;
  1498.     break;
  1499.  
  1500.     case NoNumToggleButtonEntry:
  1501.     callback = SetNoNumCB;
  1502.     break;
  1503.  
  1504.     case DisplayToggleButtonEntry:
  1505.     callback = SetDisplayCB;
  1506.     break;
  1507.  
  1508.     default:
  1509.     callback = 0;
  1510.     break;
  1511.     }
  1512.  
  1513.     if (callback == 0)
  1514.     {
  1515.     if (is_set)
  1516.         label = verify(XmCreateLabel(form, base, args, arg));
  1517.     else
  1518.         label = verify(XmCreateLabel(form, "the" + base, args, arg));
  1519.  
  1520.     XtManageChild(label);
  1521.     }
  1522.     else
  1523.     {
  1524.     entry = label = 
  1525.         verify(XmCreateToggleButton(form, set_command, args, arg));
  1526.     XtManageChild(label);
  1527.  
  1528.     XtAddCallback(entry, XmNvalueChangedCallback,
  1529.               callback, XtPointer(set_command_s));
  1530.     }
  1531.  
  1532.     // Add help button
  1533.     arg = 0;
  1534.     XtSetArg(args[arg], XmNrightAttachment,  XmATTACH_FORM);      arg++;
  1535.     XtSetArg(args[arg], XmNtopAttachment,    XmATTACH_POSITION);  arg++;
  1536.     XtSetArg(args[arg], XmNtopPosition,      row);                arg++;
  1537.     XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION);  arg++;
  1538.     XtSetArg(args[arg], XmNbottomPosition,   row + 1);            arg++;
  1539.     XtSetArg(args[arg], XmNalignment,        XmALIGNMENT_CENTER); arg++;
  1540.     Widget help = verify(XmCreatePushButton(form, "help", args, arg));
  1541.     XtManageChild(help);
  1542.  
  1543.     Widget send  = 0;
  1544.     Widget pass  = 0;
  1545.     Widget print = 0;
  1546.     Widget stop  = 0;
  1547.     if (e_type == SignalEntry)
  1548.     {
  1549.     send  = create_signal_button(label, "send",  row, help);
  1550.     pass  = create_signal_button(label, "pass",  row, send);
  1551.     print = create_signal_button(label, "print", row, pass);
  1552.     stop  = create_signal_button(label, "stop",  row, print);
  1553.  
  1554.     if (base == "all")
  1555.     {
  1556.         set_sensitive(send, False);
  1557.         XtVaSetValues(pass,  XmNset, True, NULL);
  1558.         XtVaSetValues(print, XmNset, True, NULL);
  1559.         XtVaSetValues(stop,  XmNset, True, NULL);
  1560.     }
  1561.     }
  1562.  
  1563.     // Add entry
  1564.     switch (e_type)
  1565.     {
  1566.     case OnOffToggleButtonEntry:
  1567.     case TrueFalseToggleButtonEntry:
  1568.     case SensitiveToggleButtonEntry:
  1569.     case NumToggleButtonEntry:
  1570.     case NoNumToggleButtonEntry:
  1571.     case DisplayToggleButtonEntry:
  1572.     case SignalEntry:
  1573.     // All is done
  1574.     break;
  1575.  
  1576.     case CheckOptionMenuEntry:
  1577.     {
  1578.     // `set check'
  1579.     arg = 0;
  1580.     Widget menu = verify(XmCreatePulldownMenu(form, "menu", args, arg));
  1581.  
  1582.     // Possible options are contained in the help string
  1583.     string options = cached_gdb_question("help " + set_command);
  1584.     options = options.from('(');
  1585.     options = options.before(')');
  1586.  
  1587.     while (options != "")
  1588.     {
  1589.         string option = options.after(0);
  1590.         option = option.through(rxalpha);
  1591.         options = options.after(rxalpha);
  1592.  
  1593.         arg = 0;
  1594.         Widget button = 
  1595.         verify(XmCreatePushButton(menu, option, args, arg));
  1596.         XtManageChild(button);
  1597.         XtAddCallback(button, XmNactivateCallback, SetOptionCB, 
  1598.               set_command_s);
  1599.     }
  1600.  
  1601.     MString empty;
  1602.     arg = 0;
  1603.     XtSetArg(args[arg], XmNrightAttachment,  XmATTACH_WIDGET);   arg++;
  1604.     XtSetArg(args[arg], XmNrightWidget,      help);              arg++;
  1605.     XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
  1606.     XtSetArg(args[arg], XmNbottomPosition,   row + 1);           arg++;
  1607.     XtSetArg(args[arg], XmNlabelString,      empty.xmstring());  arg++;
  1608.     XtSetArg(args[arg], XmNmarginWidth,      0);                 arg++;
  1609.     XtSetArg(args[arg], XmNmarginHeight,     0);                 arg++;
  1610.     XtSetArg(args[arg], XmNspacing,          0);                 arg++;
  1611.     XtSetArg(args[arg], XmNsubMenuId,        menu);              arg++;
  1612.     entry = verify(XmCreateOptionMenu(form, set_command, args, arg));
  1613.     XtManageChild(entry);
  1614.  
  1615.     Widget option_label = XmOptionLabelGadget(entry);
  1616.     XtUnmanageChild(option_label);
  1617.     break;
  1618.     }
  1619.  
  1620.     case OtherOptionMenuEntry:
  1621.     case TargetOptionMenuEntry:
  1622.     {
  1623.     // set language / set demangle / set architecture / set endian
  1624.     arg = 0;
  1625.     Widget menu = verify(XmCreatePulldownMenu(form, "menu", args, arg));
  1626.  
  1627.     string options;
  1628.     char separator = '\n';
  1629.  
  1630.     switch (gdb->type())
  1631.     {
  1632.     case GDB:
  1633.         if (base == "architecture")
  1634.         {
  1635.         // Possible options are listed upon `info architecture'
  1636.         // and separated by ` '.
  1637.         options = cached_gdb_question("info " + base);
  1638.         options = "auto" + options.from('\n');
  1639.         separator = ' ';
  1640.         }
  1641.         else if (base == "endian")
  1642.         {
  1643.         // Hardwired options
  1644.         options = "auto\nbig endian\nlittle endian\n";
  1645.         }
  1646.         else
  1647.         {
  1648.         // Possible options are listed upon `set BASE'
  1649.         options = cached_gdb_question("set " + base);
  1650.         }
  1651.         break;
  1652.  
  1653.     case DBX:
  1654.         options = _get_dbx_help("dbxenv", base);
  1655.         options = options.after('<');
  1656.         options = options.before('>');
  1657.  
  1658.         if (options == "")
  1659.         {
  1660.         if (base == "follow_fork_mode")
  1661.             options = "parent|child|both|ask";
  1662.         }
  1663.         separator = '|';
  1664.         break;
  1665.  
  1666.     case XDB:
  1667.     case JDB:
  1668.     case PYDB:
  1669.     case PERL:
  1670.         return;        // FIXME
  1671.     }
  1672.  
  1673.     while (options != "")
  1674.     {
  1675.         string option = options;
  1676.         if (option.contains(separator))
  1677.         option = option.before(separator);
  1678.         options = options.after(separator);
  1679.  
  1680.         strip_space(option);
  1681.  
  1682.         string label = option;
  1683.         if (gdb->type() == GDB && option.contains("  "))
  1684.         {
  1685.         label = option.after("  ");
  1686.         label = label.after(rxwhite);
  1687.  
  1688.         if (option.contains(" auto"))
  1689.             option = "auto";
  1690.         else
  1691.             option = option.before(rxwhite);
  1692.         }
  1693.  
  1694.         if (option == "" || option.contains(':', -1))
  1695.         continue;
  1696.  
  1697.         MString xmlabel(label);
  1698.         arg = 0;
  1699.         if (gdb->type() == GDB)
  1700.         {
  1701.         XtSetArg(args[arg], XmNlabelString, 
  1702.              xmlabel.xmstring()); arg++;
  1703.         }
  1704.         Widget button = 
  1705.         verify(XmCreatePushButton(menu, option, args, arg));
  1706.         XtManageChild(button);
  1707.         XtAddCallback(button, XmNactivateCallback, SetOptionCB, 
  1708.               set_command_s);
  1709.     }
  1710.  
  1711.     MString empty;
  1712.     arg = 0;
  1713.     XtSetArg(args[arg], XmNrightAttachment,  XmATTACH_WIDGET);   arg++;
  1714.     XtSetArg(args[arg], XmNrightWidget,      help);              arg++;
  1715.     XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
  1716.     XtSetArg(args[arg], XmNbottomPosition,   row + 1);           arg++;
  1717.     XtSetArg(args[arg], XmNlabelString,      empty.xmstring());  arg++;
  1718.     XtSetArg(args[arg], XmNmarginWidth,      0);                 arg++;
  1719.     XtSetArg(args[arg], XmNmarginHeight,     0);                 arg++;
  1720.     XtSetArg(args[arg], XmNspacing,          0);                 arg++;
  1721.     XtSetArg(args[arg], XmNsubMenuId,        menu);              arg++;
  1722.     entry = verify(XmCreateOptionMenu(form, set_command, args, arg));
  1723.     XtManageChild(entry);
  1724.  
  1725.     Widget option_label = XmOptionLabelGadget(entry);
  1726.     XtUnmanageChild(option_label);
  1727.     break;
  1728.     }
  1729.  
  1730.     case TextFieldEntry:
  1731.     {
  1732.     // Some other value
  1733.     arg = 0;
  1734.     XtSetArg(args[arg], XmNrightAttachment,  XmATTACH_WIDGET);   arg++;
  1735.     XtSetArg(args[arg], XmNrightWidget,      help);              arg++;
  1736.     XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
  1737.     XtSetArg(args[arg], XmNbottomPosition,   row + 1);           arg++;
  1738.     entry = verify(XmCreateTextField(form, set_command, args, arg));
  1739.     XtManageChild(entry);
  1740.     XtAddCallback(entry, XmNactivateCallback, 
  1741.               SetTextCB, XtPointer(set_command_s));
  1742.     }
  1743.     }
  1744.  
  1745.     Widget rightmost = help;
  1746.     if (entry != label)
  1747.     rightmost = entry;
  1748.     if (stop != 0)
  1749.         rightmost = stop;
  1750.  
  1751.     Dimension width = preferred_width(label);
  1752.     if (entry != label)
  1753.     width += preferred_width(entry);
  1754.     width += preferred_width(send);
  1755.     width += preferred_width(stop);
  1756.     width += preferred_width(print);
  1757.     width += preferred_width(pass);
  1758.     width += preferred_width(help);
  1759.  
  1760.     // Add leader
  1761.  
  1762.     // Align leader with label font baseline
  1763.     XmFontList font_list   = 0;
  1764.     XmString xmlabel       = 0;
  1765.     Dimension marginHeight = 0;
  1766.     Dimension marginTop    = 0;
  1767.     XtVaGetValues(label,
  1768.           XmNfontList,     &font_list,
  1769.           XmNlabelString,  &xmlabel,
  1770.           XmNmarginHeight, &marginHeight,
  1771.           XmNmarginTop,    &marginTop,
  1772.           NULL);
  1773.  
  1774.     Dimension baseline = XmStringBaseline(font_list, xmlabel);
  1775.     static const Dimension leaderHeight = 2;
  1776.  
  1777.     Dimension top_offset = baseline + marginHeight + marginTop - leaderHeight;
  1778.     XmStringFree(xmlabel);
  1779.  
  1780.     arg = 0;
  1781.     XtSetArg(args[arg], XmNseparatorType,    XmSINGLE_DASHED_LINE); arg++;
  1782.     XtSetArg(args[arg], XmNleftAttachment,   XmATTACH_WIDGET);   arg++;
  1783.     XtSetArg(args[arg], XmNleftWidget,       label);             arg++;
  1784.     XtSetArg(args[arg], XmNrightAttachment,  XmATTACH_WIDGET);   arg++;
  1785.     XtSetArg(args[arg], XmNrightWidget,      rightmost);         arg++;
  1786.     XtSetArg(args[arg], XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET); arg++;
  1787.     XtSetArg(args[arg], XmNtopWidget,        label);             arg++;
  1788.     XtSetArg(args[arg], XmNtopOffset,        top_offset);        arg++;
  1789.     Widget leader = verify(XmCreateSeparator(form, "leader", args, arg));
  1790.     XtManageChild(leader);
  1791.  
  1792.     // Add help callback
  1793.     if (e_type == SignalEntry)
  1794.     {
  1795.     XtAddCallback(help, XmNactivateCallback, 
  1796.               HelpOnSignalCB, XtPointer(label));
  1797.     }
  1798.     else
  1799.     {
  1800.     XtAddCallback(help, XmNactivateCallback, 
  1801.               HelpOnThisCB, XtPointer(entry));
  1802.     }
  1803.  
  1804.     if (e_type == SignalEntry)
  1805.     {
  1806.     if (base != "all")
  1807.     {
  1808.         // Initialize button
  1809.         process_handle(line, true);
  1810.  
  1811.         // Register buttons
  1812.         signals_entries += stop;
  1813.         signals_entries += print;
  1814.         signals_entries += pass;
  1815.     }
  1816.     }
  1817.     else if (e_type != DisplayToggleButtonEntry)
  1818.     {
  1819.     // Make entry insensitive if part of initialization commands.
  1820.     string init = app_data.gdb_init_commands;
  1821.     int idx = init.index(set_command);
  1822.     if (idx == 0 || idx > 0 && init[idx - 1] == '\n')
  1823.     {
  1824.         set_sensitive(entry,  False);
  1825.         set_sensitive(label,  False);
  1826.         set_sensitive(leader, False);
  1827.     }
  1828.  
  1829.     // Initialize button
  1830.     process_show(show_command, value, true);
  1831.  
  1832.     // Register entry
  1833.     settings_entries     += entry;
  1834.     settings_entry_types += e_type;
  1835.     }
  1836.     else
  1837.     {
  1838.     // Register entry
  1839.     infos_entries += entry;
  1840.     }
  1841.  
  1842.     max_width = max(width, max_width);
  1843.  
  1844.     row++;
  1845. }
  1846.  
  1847. // Add separator
  1848. static void add_separator(Widget form, int& row)
  1849. {
  1850.     Arg args[10];
  1851.     int arg = 0;
  1852.     XtSetArg(args[arg], XmNleftAttachment,   XmATTACH_FORM);     arg++;
  1853.     XtSetArg(args[arg], XmNrightAttachment,  XmATTACH_FORM);     arg++;
  1854.     XtSetArg(args[arg], XmNtopAttachment,    XmATTACH_POSITION); arg++;
  1855.     XtSetArg(args[arg], XmNtopPosition,      row);               arg++;
  1856.     XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
  1857.     XtSetArg(args[arg], XmNbottomPosition,   row + 1);           arg++;
  1858.     Widget sep = verify(XmCreateSeparator(form, "sep", args, arg));
  1859.     XtManageChild(sep);
  1860.     row++;
  1861. }
  1862.  
  1863. // Add buttons
  1864. static void add_settings(Widget form, int& row, Dimension& max_width,
  1865.              DebuggerType type, EntryType entry_filter,
  1866.              string gdb_class)
  1867. {
  1868.     string commands;
  1869.  
  1870.     switch (type)
  1871.     {
  1872.     case GDB:
  1873.     case PYDB:
  1874.     if (entry_filter == SignalEntry)
  1875.         commands = cached_gdb_question("info handle");
  1876.     else
  1877.         commands = cached_gdb_question("help " + gdb_class);
  1878.     break;
  1879.  
  1880.     case XDB:
  1881.     commands = cached_gdb_question("I");
  1882.     break;
  1883.  
  1884.     case DBX:
  1885.     {
  1886.     // Some DBXes know `dbxenv'; others know `set'.  We cannot use
  1887.     // is_valid() or likewise here, since the output may contain
  1888.     // `error' strings that would cause is_valid() to fail.  Just
  1889.     // try both and use the longer reply (may take time).
  1890.  
  1891.     // Exception: on Sun DBX, `set' causes a dump of all
  1892.     // environment variables.  Don't use this.
  1893.     string dbxenv = cached_gdb_question("dbxenv", -1);
  1894.     string set    = cached_gdb_question("set", -1);
  1895.     if (dbxenv.length() > set.length() ||
  1896.         set.contains(DDD_NAME "=" ddd_NAME))
  1897.     {
  1898.         commands = dbxenv;
  1899.     }
  1900.     else
  1901.     {
  1902.         commands = set;
  1903.     }
  1904.     break;
  1905.     }
  1906.  
  1907.     case JDB:
  1908.     {
  1909.     // In JDB, all we have is the `use' command.
  1910.     add_button(form, row, max_width, type, entry_filter, "use");
  1911.     break;
  1912.     }
  1913.  
  1914.     case PERL:
  1915.     commands = cached_gdb_question("O");
  1916.     break;
  1917.     }
  1918.  
  1919.     if (type == GDB && entry_filter == SignalEntry)
  1920.     {
  1921.     // Add an entry for `handle all'
  1922.     add_button(form, row, max_width, type, entry_filter,
  1923.            "all\tYes\tYes\tYes\tAll Signals");
  1924.     // add_separator(form, row);
  1925.     }
  1926.  
  1927.     while (commands != "")
  1928.     {
  1929.     string line = commands.before('\n');
  1930.     commands    = commands.after('\n');
  1931.     add_button(form, row, max_width, type, entry_filter, line);
  1932.     }
  1933. }
  1934.  
  1935. // Reload all settings
  1936. static void reload_all_settings()
  1937. {
  1938.     for (int i = 0; i < settings_entries.size(); i++)
  1939.     {
  1940.     Widget entry = settings_entries[i];
  1941.     string cmd = string(XtName(entry)) + " dummy";
  1942.     string show = show_command(cmd, gdb->type());
  1943.     string value = gdb_question(show);
  1944.     if (value != NO_GDB_ANSWER)
  1945.         process_show(show, value, true);
  1946.     }
  1947. }
  1948.  
  1949. void update_settings()
  1950. {
  1951.     if (settings_panel != 0 && XtIsManaged(settings_panel))
  1952.     {
  1953.     reload_all_settings();
  1954.     need_reload_settings = false;
  1955.     }
  1956. }
  1957.  
  1958. // Reset settings
  1959. static void ResetSettingsCB (Widget, XtPointer, XtPointer)
  1960. {
  1961.     for (int i = 0; i < settings_entries.size(); i++)
  1962.     {
  1963.     Widget entry = settings_entries[i];
  1964.     if (settings_initial_values[entry] != settings_values[entry])
  1965.         gdb_set_command(XtName(entry), settings_initial_values[entry]);
  1966.     }
  1967. }
  1968.  
  1969. // Reset signals
  1970. static void ResetSignalsCB (Widget, XtPointer, XtPointer)
  1971. {
  1972.     for (int i = 0; i < signals_entries.size(); i++)
  1973.     {
  1974.     Widget entry = signals_entries[i];
  1975.     if (signals_initial_values[entry] != signals_values[entry])
  1976.     {
  1977.         bool set = (signals_initial_values[entry] == "yes");
  1978.         gdb_command(handle_command(entry, set));
  1979.     }
  1980.     }
  1981. }
  1982.  
  1983. // Delete all infos
  1984. static void DeleteAllInfosCB (Widget, XtPointer, XtPointer)
  1985. {
  1986.     for (int i = 0; i < infos_entries.size(); i++)
  1987.     {
  1988.     Widget entry = infos_entries[i];
  1989.     XmToggleButtonSetState(entry, False, True);
  1990.     }
  1991. }
  1992.  
  1993. // Fetch help for specific COMMAND
  1994. static string get_help_line(string command, DebuggerType type)
  1995. {
  1996.     (void) type;
  1997.  
  1998.     string reply = cached_gdb_question("help " + command);
  1999.     reply = reply.before('\n');
  2000.     if (reply.contains('.'))
  2001.     reply = reply.before('.');
  2002.     reply = command + " -- " + reply;
  2003.     return reply;
  2004. }
  2005.  
  2006. // ClipWindow translation stuff
  2007. static void ClipDo(Widget w, XEvent *event, 
  2008.            String *params, Cardinal *num_params)
  2009. {
  2010.     Widget scroll = XtParent(w);
  2011.     Widget scrollbar = 0;
  2012.     XtVaGetValues(scroll, XmNverticalScrollBar, &scrollbar, NULL);
  2013.     XtCallActionProc(scrollbar, params[0], event, params + 1, *num_params - 1);
  2014. }
  2015.  
  2016. static void fix_clip_window_translations(Widget scroll)
  2017. {
  2018.     // The scrolled clip window grabs translations for osfBeginLine
  2019.     // and osfEndLine, which we need in our text fields.  Since we
  2020.     // cannot selectively disable these translations, we disable all
  2021.     // translations ...
  2022.  
  2023.     Widget clip = 0;
  2024.     XtVaGetValues(scroll, XmNclipWindow, &clip, NULL);
  2025.     XtUninstallTranslations(clip);
  2026.  
  2027.     // ... and provide a minimal set instead.
  2028.     static bool have_clip_actions = false;
  2029.     if (!have_clip_actions)
  2030.     {
  2031.     static XtActionsRec clip_actions[] = {
  2032.         {"clip-do", ClipDo}
  2033.     };
  2034.  
  2035.     XtAppAddActions(XtWidgetToApplicationContext(scroll), 
  2036.             clip_actions, XtNumber(clip_actions));
  2037.     have_clip_actions = true;
  2038.     }
  2039.  
  2040.     static char clip_translations[] = 
  2041.     "<Key>osfPageUp:         clip-do(PageUpOrLeft, 0)\n"
  2042.     "<Key>osfPageDown:       clip-do(PageDownOrRight, 0)\n"
  2043.     "Ctrl <Key>osfBeginLine: clip-do(TopOrBottom)\n"
  2044.     "Ctrl <Key>osfEndLine:   clip-do(TopOrBottom)\n";
  2045.  
  2046.     XtTranslations tr = XtParseTranslationTable(clip_translations);
  2047.     XtVaSetValues(clip, XmNtranslations, tr, NULL);
  2048. }
  2049.  
  2050. // Create settings or infos editor
  2051. static Widget create_panel(DebuggerType type, SettingsType stype)
  2052. {
  2053.     string title_msg;
  2054.     string dialog_name;
  2055.     switch (stype)
  2056.     {
  2057.     case SETTINGS:
  2058.     title_msg = gdb->title() + " Settings";
  2059.     dialog_name = "settings";
  2060.     break;
  2061.  
  2062.     case INFOS:
  2063.     title_msg = gdb->title() + " Status Displays";
  2064.     dialog_name = "infos";
  2065.     break;
  2066.  
  2067.     case SIGNALS:
  2068.     title_msg = gdb->title() + " Signal Handling";
  2069.     dialog_name = "signals";
  2070.     break;
  2071.     }
  2072.  
  2073.     StatusDelay delay("Retrieving " + title_msg);
  2074.  
  2075.     Arg args[10];
  2076.     int arg;
  2077.  
  2078.     arg = 0;
  2079.     XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
  2080.     Widget panel = verify(XmCreatePromptDialog(find_shell(), 
  2081.                            dialog_name, args, arg));
  2082.     Delay::register_shell(panel);
  2083.  
  2084.     if (lesstif_version <= 79)
  2085.     XtUnmanageChild(XmSelectionBoxGetChild(panel, XmDIALOG_APPLY_BUTTON));
  2086.  
  2087.     // Remove old prompt
  2088.     XtUnmanageChild(XmSelectionBoxGetChild(panel, XmDIALOG_TEXT));
  2089.     XtUnmanageChild(XmSelectionBoxGetChild(panel, XmDIALOG_SELECTION_LABEL));
  2090.  
  2091.     XtAddCallback(panel, XmNhelpCallback, ImmediateHelpCB, 0);
  2092.     XtAddCallback(panel, XmNokCallback, UnmanageThisCB, 
  2093.               XtPointer(panel));
  2094.  
  2095.     Widget cancel = XmSelectionBoxGetChild(panel, XmDIALOG_CANCEL_BUTTON);
  2096.  
  2097.     switch (stype)
  2098.     {
  2099.     case SETTINGS:
  2100.     XtRemoveAllCallbacks(cancel, XmNactivateCallback);
  2101.     XtAddCallback(cancel, XmNactivateCallback, ResetSettingsCB, 0);
  2102.     XtVaSetValues(panel, XmNdefaultButton, Widget(0), NULL);
  2103.     break;
  2104.  
  2105.     case INFOS:
  2106.     XtRemoveAllCallbacks(cancel, XmNactivateCallback);
  2107.     XtAddCallback(cancel, XmNactivateCallback, DeleteAllInfosCB, 0);
  2108.     break;
  2109.  
  2110.     case SIGNALS:
  2111.     XtRemoveAllCallbacks(cancel, XmNactivateCallback);
  2112.     XtAddCallback(cancel, XmNactivateCallback, ResetSignalsCB, 0);
  2113.     XtVaSetValues(panel, XmNdefaultButton, Widget(0), NULL);
  2114.     break;
  2115.     }
  2116.  
  2117.     // Add a rowcolumn widget
  2118.     arg = 0;
  2119.     XtSetArg(args[arg], XmNborderWidth,  0); arg++;
  2120.     XtSetArg(args[arg], XmNmarginWidth,  0); arg++;
  2121.     XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
  2122.     XtSetArg(args[arg], XmNspacing,      0); arg++;
  2123.     Widget column =
  2124.         verify(XmCreateRowColumn(panel, "column", args, arg));
  2125.     XtManageChild(column);
  2126.  
  2127.     // Add a label
  2128.     arg = 0;
  2129.     MString xmtitle(title_msg);
  2130.     XtSetArg(args[arg], XmNlabelString, xmtitle.xmstring()); arg++;
  2131.     Widget title = verify(XmCreateLabel(column, "title", args, arg));
  2132.     XtManageChild(title);
  2133.  
  2134.     // Add a scrolled window.
  2135.     arg = 0;
  2136.     XtSetArg(args[arg], XmNscrollingPolicy, XmAUTOMATIC); arg++;
  2137.     Widget scroll = 
  2138.     verify(XmCreateScrolledWindow(column, "scroll", args, arg));
  2139.     fix_clip_window_translations(scroll);
  2140.  
  2141.     // Add a form.
  2142.     arg = 0;
  2143.     Widget form = verify(XmCreateForm(scroll, "form", args, arg));
  2144.  
  2145.     switch (stype)
  2146.     {
  2147.     case SETTINGS:
  2148.     settings_form  = form;
  2149.     break;
  2150.  
  2151.     case SIGNALS:
  2152.     signals_form = form;
  2153.     break;
  2154.  
  2155.     case INFOS:
  2156.     break;
  2157.     }
  2158.  
  2159.     // Add setting buttons to the button box.
  2160.     Dimension max_width = 0;
  2161.     int row = 0;
  2162.     int last_row = row;
  2163.  
  2164.     switch (stype)
  2165.     {
  2166.     case SETTINGS:
  2167.     add_settings(form, row, max_width, type, OnOffToggleButtonEntry);
  2168.     add_settings(form, row, max_width, type, TrueFalseToggleButtonEntry);
  2169.     add_settings(form, row, max_width, type, SensitiveToggleButtonEntry);
  2170.     add_settings(form, row, max_width, type, NumToggleButtonEntry);
  2171.     add_settings(form, row, max_width, type, NoNumToggleButtonEntry);
  2172.     if (row != last_row)
  2173.         add_separator(form, row);
  2174.  
  2175.     last_row = row;
  2176.     add_settings(form, row, max_width, type, TargetOptionMenuEntry);
  2177.     if (row != last_row)
  2178.         add_separator(form, row);
  2179.  
  2180.     last_row = row;
  2181.     add_settings(form, row, max_width, type, OtherOptionMenuEntry);
  2182.     if (row != last_row)
  2183.         add_separator(form, row);
  2184.  
  2185.     last_row = row;
  2186.     add_settings(form, row, max_width, type, CheckOptionMenuEntry);
  2187.     if (row != last_row)
  2188.         add_separator(form, row);
  2189.  
  2190.     if (type == GDB)
  2191.     {
  2192.         last_row = row;
  2193.         add_button(form, row, max_width, type, TextFieldEntry, 
  2194.                get_help_line("dir", type));
  2195.         add_button(form, row, max_width, type, TextFieldEntry, 
  2196.                get_help_line("path", type));
  2197.         if (row != last_row)
  2198.         add_separator(form, row);
  2199.     }
  2200.  
  2201.     add_settings(form, row, max_width, type, TextFieldEntry);
  2202.     break;
  2203.  
  2204.     case INFOS:
  2205.     add_settings(form, row, max_width, type, 
  2206.              DisplayToggleButtonEntry, "info");
  2207.     break;
  2208.  
  2209.     case SIGNALS:
  2210.     add_settings(form, row, max_width, type, SignalEntry, "signals");
  2211.     break;
  2212.     }
  2213.  
  2214.     // Clean up cached documentation stuff
  2215.     clear_gdb_question_cache();
  2216.  
  2217.     // Setup values
  2218.     switch (stype)
  2219.     {
  2220.     case SETTINGS:
  2221.     reset_settings_button = cancel;
  2222.     update_reset_settings_button();
  2223.     break;
  2224.  
  2225.     case INFOS:
  2226.     reset_infos_button = cancel;
  2227.     update_infos();
  2228.     break;
  2229.  
  2230.     case SIGNALS:
  2231.     reset_signals_button = cancel;
  2232.     update_reset_signals_button();
  2233.     break;
  2234.     }
  2235.  
  2236.     // Set number of rows
  2237.     if (row > 0)
  2238.     XtVaSetValues(form, XmNfractionBase, row, NULL);
  2239.     XtManageChild(form);
  2240.  
  2241.     // Set sizes
  2242.     max_width += EXTRA_SPACE;
  2243.     XtVaSetValues(form, 
  2244.           XmNwidth, max_width, NULL);
  2245.  
  2246. #if XmVersion > 1001
  2247.     Dimension height = preferred_height(form);
  2248. #else
  2249.     // OSF/Motif 1.1 returns a bad value in PREFERRED_HEIGHT
  2250.     (void) preferred_height;
  2251.     Dimension height = MAX_HEIGHT + 1;
  2252. #endif
  2253.  
  2254.     Widget vertical_scroll_bar = 0;
  2255.     Dimension spacing = 4;
  2256.     XtVaGetValues(scroll, 
  2257.           XmNverticalScrollBar, &vertical_scroll_bar,
  2258.           XmNspacing, &spacing,
  2259.           NULL);
  2260.  
  2261.     if (height + spacing > MAX_HEIGHT)
  2262.     {
  2263.     // Form must be scrolled
  2264.     Dimension scrollbar_width = 15;   // Additional space for scrollbar
  2265.  
  2266.     if (vertical_scroll_bar != 0)
  2267.     {
  2268.         XtWidgetGeometry size;
  2269.         size.request_mode = CWWidth;
  2270.         XtQueryGeometry(vertical_scroll_bar, NULL, &size);
  2271.         scrollbar_width = size.width;
  2272.     }
  2273.     
  2274.     XtVaSetValues(scroll,
  2275.               XmNheight, MAX_HEIGHT,
  2276.               XmNwidth, max_width + 
  2277.                         spacing + scrollbar_width + EXTRA_WIDTH,
  2278.               NULL);
  2279.     }
  2280.     else
  2281.     {
  2282.     // Form need not be scrolled
  2283.     XtVaSetValues(scroll,
  2284.               XmNheight, height + spacing,
  2285.               XmNwidth, max_width + spacing,
  2286.               NULL);
  2287.     }
  2288.  
  2289.     XtManageChild(scroll);
  2290.  
  2291.     InstallButtonTips(panel);
  2292.  
  2293.     return panel;
  2294. }
  2295.  
  2296.  
  2297. // Create settings editor
  2298. static Widget create_settings(DebuggerType type)
  2299. {
  2300.     check_options_file();
  2301.  
  2302.     if (settings_panel == 0 && gdb->isReadyWithPrompt() && gdb->type() == type)
  2303.     {
  2304.     // We place a delay here such that we show only one delay for
  2305.     // both getting the settings and the command definitions.
  2306.     StatusDelay delay("Retrieving " + gdb->title() + " Settings");
  2307.  
  2308.     settings_panel = create_panel(type, SETTINGS);
  2309.  
  2310.     // Get the command definitions, too.  These must be included
  2311.     // in saving GDB state.
  2312.     get_defines(type);
  2313.     }
  2314.     else if (settings_panel != 0 && need_reload_settings)
  2315.     {
  2316.     reload_all_settings();
  2317.     need_reload_settings = false;
  2318.     }
  2319.  
  2320.     return settings_panel;
  2321. }
  2322.  
  2323. // Create infos editor
  2324. static Widget create_infos(DebuggerType type)
  2325. {
  2326.     check_options_file();
  2327.  
  2328.     if (infos_panel == 0 && gdb->isReadyWithPrompt() && gdb->type() == type)
  2329.     infos_panel = create_panel(type, INFOS);
  2330.  
  2331.     return infos_panel;
  2332. }
  2333.  
  2334. // Reload all signals
  2335. static void reload_all_signals()
  2336. {
  2337.     check_options_file();
  2338.  
  2339.     string info = gdb_question("info handle");
  2340.     if (info != NO_GDB_ANSWER)
  2341.     process_handle(info, true);
  2342. }
  2343.  
  2344. void update_signals()
  2345. {
  2346.     if (signals_panel != 0 && XtIsManaged(signals_panel))
  2347.     {
  2348.     reload_all_signals();
  2349.     need_reload_signals = false;
  2350.     }
  2351. }
  2352.  
  2353. // Create signal editor
  2354. static Widget create_signals(DebuggerType type)
  2355. {
  2356.     check_options_file();
  2357.  
  2358.     if (signals_panel == 0 && gdb->isReadyWithPrompt() && gdb->type() == type)
  2359.     {
  2360.     signals_panel = create_panel(type, SIGNALS);
  2361.     }
  2362.     else if (signals_panel != 0 && need_reload_signals)
  2363.     {
  2364.     reload_all_signals();
  2365.     need_reload_signals = false;
  2366.     }
  2367.  
  2368.     return signals_panel;
  2369. }
  2370.  
  2371.  
  2372. // Popup editor for debugger settings
  2373. void dddPopupSettingsCB (Widget, XtPointer, XtPointer)
  2374. {
  2375.     Widget settings = create_settings(gdb->type());
  2376.     if (settings == 0)
  2377.     return;
  2378.  
  2379.     manage_and_raise(settings);
  2380. }
  2381.  
  2382. // Popup editor for debugger infos
  2383. void dddPopupInfosCB (Widget, XtPointer, XtPointer)
  2384. {
  2385.     Widget infos = create_infos(gdb->type());
  2386.     if (infos == 0)
  2387.     return;
  2388.  
  2389.     manage_and_raise(infos);
  2390. }
  2391.  
  2392. // Popup editor for debugger infos
  2393. void dddPopupSignalsCB (Widget, XtPointer, XtPointer)
  2394. {
  2395.     Widget signals = create_signals(gdb->type());
  2396.     if (signals == 0)
  2397.     return;
  2398.  
  2399.     manage_and_raise(signals);
  2400. }
  2401.  
  2402. // True iff settings might have changed
  2403. bool need_settings()
  2404. {
  2405.     return settings_panel != 0;
  2406. }
  2407.  
  2408. // Reset it all
  2409. void reset_settings()
  2410. {
  2411.     if (settings_panel != 0)
  2412.     need_reload_settings = true;
  2413. }
  2414.  
  2415. // True iff signals might have changed
  2416. bool need_signals()
  2417. {
  2418.     return signals_panel != 0;
  2419. }
  2420.  
  2421. // Reset it all
  2422. void reset_signals()
  2423. {
  2424.     if (signals_panel != 0)
  2425.     need_reload_signals = true;
  2426. }
  2427.  
  2428. static void get_setting(ostream& os, DebuggerType type,
  2429.             const string& base, string value)
  2430. {
  2431.     if (value == "unlimited")
  2432.     value = "0";
  2433.  
  2434.     switch (type)
  2435.     {
  2436.     case GDB:
  2437.     case DBX:
  2438.     if (base == "dbxenv disassembler_version" ||
  2439.         base == "dbxenv rtc_error_log_file_name" ||
  2440.         base == "dbxenv output_log_file_name")
  2441.     {
  2442.         // Do nothing (DBX) - dependent on the current machine etc.
  2443.     }
  2444.     else if (base == "set remotelogfile" && value == "")
  2445.     {
  2446.         // This is the default setting - do nothing (GDB)
  2447.     }
  2448.     else if (base == "set remotedevice" && value == "")
  2449.     {
  2450.         // This is the default setting - do nothing (GDB)
  2451.     }
  2452.     else if (base == "set solib-absolute-prefix" && value == "")
  2453.     {
  2454.         // GDB 4.17 bug: `set solib-absolute-prefix' without arg
  2455.         // does not work.  Just leave it as default setting.
  2456.     }
  2457.     else if (base.contains("set $cur", 0) ||
  2458.          base.contains("set $new", 0) ||
  2459.          base.contains("set $pid", 0))
  2460.     {
  2461.         // Do nothing - dependent on the current file (DEC DBX)
  2462.     }
  2463.     else if (base == "set $defaultin" ||
  2464.          base == "set $defaultout" ||
  2465.          base == "set $historyevent")
  2466.     {
  2467.         // Do nothing - dependent on the current state (SGI DBX)
  2468.     }
  2469.     else if (base.contains("set $", 0))
  2470.     {
  2471.         // Add setting (DBX).
  2472.         os << base << " = " << value << '\n';
  2473.     }
  2474.     else if (base.contains("set ", 0))
  2475.     {
  2476.         // Add setting (GDB).
  2477.  
  2478.         // Jonathan Edwards <edwards@intranet.com> states:
  2479.         // DDD gets all confused with gdb radix settings. When
  2480.         // it configures gdb it assumes a decimal radix. But
  2481.         // if you specify a non-decimal radix, then all
  2482.         // settings made after that are incorrect.  I would
  2483.         // suggest prefixing "0d" to all decimal numbers.
  2484.         if (value.matches(rxint) && atoi(value) > 1)
  2485.         value.prepend("0d");
  2486.  
  2487.         os << base << " " << value << '\n';
  2488.     }
  2489.     else if (base.contains("dbxenv ", 0))
  2490.     {
  2491.         // Add setting (DBX).
  2492.         os << base << " " << value << '\n';
  2493.     }
  2494.     else
  2495.     {
  2496.         // `dir' and `path' values are not saved, since they are
  2497.         // dependent on the current machine and the current
  2498.         // executable (GDB).
  2499.     }
  2500.     break;
  2501.  
  2502.     case PERL:
  2503.     // Add setting
  2504.     os << base << '=' << value << '\n';
  2505.     break;
  2506.  
  2507.     case XDB:
  2508.     case JDB:
  2509.     case PYDB:
  2510.     // Add setting
  2511.     os << base << ' ' << value << '\n';
  2512.     break;
  2513.     }
  2514. }
  2515.  
  2516. // Fetch GDB settings string
  2517. string get_settings(DebuggerType type)
  2518. {
  2519.     Widget settings = create_settings(type);
  2520.     if (settings == 0)
  2521.     return "";
  2522.  
  2523.     ostrstream command;
  2524.     for (int i = 0; i < settings_entries.size(); i++)
  2525.     {
  2526.     Widget entry = settings_entries[i];
  2527.     string value = settings_values[entry];
  2528.  
  2529.     get_setting(command, type, XtName(entry), value);
  2530.     }
  2531.  
  2532.     return string(command);
  2533. }
  2534.  
  2535. // Fetch GDB signal handling string
  2536. string get_signals(DebuggerType type)
  2537. {
  2538.     if (type != GDB)
  2539.     return "";        // Not supported yet
  2540.  
  2541.     create_signals(type);
  2542.     string commands = "";
  2543.  
  2544.     for (int i = 0; i < signals_entries.size(); i++)
  2545.     {
  2546.     Widget entry = signals_entries[i];
  2547.     bool set = (signals_values[entry] == "yes");
  2548.     commands += handle_command(entry, set) + "\n";
  2549.     }
  2550.  
  2551.     return commands;
  2552. }
  2553.  
  2554.  
  2555. //-----------------------------------------------------------------------
  2556. // Trace Command Definitions
  2557. //-----------------------------------------------------------------------
  2558.  
  2559. static bool save_defines_needed = false;
  2560. static bool load_defines_needed = true;
  2561.  
  2562. // Call this function if command definitions have changed
  2563. void set_need_save_defines(bool val)
  2564. {
  2565.     save_defines_needed = val;
  2566. }
  2567.  
  2568. bool need_save_defines()
  2569. {
  2570.     return save_defines_needed;
  2571. }
  2572.  
  2573. void set_need_load_defines(bool val)
  2574. {
  2575.     load_defines_needed = val;
  2576. }
  2577.  
  2578. bool need_load_defines()
  2579. {
  2580.     return load_defines_needed;
  2581. }
  2582.  
  2583. static StringStringAssoc defs;
  2584.  
  2585. static bool update_define(const string& command, bool undo = false)
  2586. {
  2587.     // We have a new command - update user buttons.
  2588.     clear_help_cache(command);
  2589.     update_user_buttons();
  2590.  
  2591.     string text = gdb_question("show user " + command);
  2592.     if (text == NO_GDB_ANSWER)
  2593.     return false;
  2594.  
  2595.     if (undo)
  2596.     {
  2597.     // Add `undoing' command
  2598.     undo_buffer.add_command("define " + command + "\n" + 
  2599.                 defs[command] + "end");
  2600.     }
  2601.  
  2602.     // `Undefined' means command is undefined; `Not a user command'
  2603.     // means this is a built-in command.
  2604.     if (text.contains("Undefined", 0) || text.contains("Not a", 0))
  2605.     {
  2606.     defs.remove(command);
  2607.     return true;
  2608.     }
  2609.  
  2610.     string def  = "";
  2611.  
  2612.     while (text != "")
  2613.     {
  2614.     string line = text.before('\n');
  2615.     text        = text.after('\n');
  2616.  
  2617.     if (line.length() > 0 && isspace(line[0]))
  2618.     {
  2619.         line = line.after(rxwhite);
  2620.         strip_auto_command_prefix(line);
  2621.         def += line + "\n";
  2622.     }
  2623.     }
  2624.  
  2625.     defs[command] = def;
  2626.     return true;
  2627. }
  2628.  
  2629. static void update_defines()
  2630. {
  2631.     if (!need_load_defines())
  2632.     return;
  2633.  
  2634.     StatusDelay delay("Retrieving Command Definitions");
  2635.  
  2636.     string commands = gdb_question("help user-defined");
  2637.     if (commands == NO_GDB_ANSWER)
  2638.     return;
  2639.  
  2640.     while (commands != "")
  2641.     {
  2642.     string line = commands.before('\n');
  2643.     commands    = commands.after('\n');
  2644.  
  2645.     if (!line.contains(" -- "))
  2646.         continue;            // No help line
  2647.  
  2648.     string command = line.before(" -- ");
  2649.     bool ok = update_define(command);
  2650.     if (!ok)
  2651.         return;
  2652.     }
  2653.  
  2654.     set_need_load_defines(false);
  2655. }
  2656.  
  2657. // Get current definitions
  2658. string get_defines(DebuggerType type)
  2659. {
  2660.     if (type != GDB)
  2661.     return "";        // Not supported yet
  2662.  
  2663.     update_defines();
  2664.  
  2665.     // We have to get the current value of the `confirm' setting
  2666.     create_settings(type);
  2667.  
  2668.     string defines = "";
  2669.  
  2670.     // We have to turn off confirmation during command (re-)definition
  2671.     string confirm_value = "on";
  2672.     if (settings_form != 0)
  2673.     {
  2674.     Widget confirm_w = command_to_widget(settings_form, "set confirm");
  2675.     if (confirm_w != 0)
  2676.         confirm_value = settings_values[confirm_w];
  2677.     }
  2678.     if (confirm_value == "on")
  2679.     defines += "set confirm off\n";
  2680.  
  2681.     for (StringStringAssocIter iter(defs); iter.ok(); iter++)
  2682.     {
  2683.     string def = iter.value();
  2684.     if (def == "")
  2685.     {
  2686.         // We don't save empty definitions, such that users have a
  2687.         // way to get rid of them.
  2688.     }
  2689.     else
  2690.     {
  2691.         defines += "define " + iter.key() + "\n" + def + "end\n";
  2692.     }
  2693.     }
  2694.  
  2695.     if (confirm_value == "on")
  2696.     defines += "set confirm on\n";
  2697.  
  2698.     return defines;
  2699. }
  2700.  
  2701. // True iff COMMAND is a defined command
  2702. bool is_defined_cmd(const string& command)
  2703. {
  2704.     if (gdb->type() != GDB)
  2705.     return false;        // Not supported yet
  2706.  
  2707.     update_defines();
  2708.  
  2709.     string word = command;
  2710.     strip_space(word);
  2711.     if (word.contains(' '))
  2712.     word = word.before(' ');
  2713.  
  2714.     return defs.has(word);
  2715. }
  2716.  
  2717.  
  2718. //-----------------------------------------------------------------------
  2719. // Edit Command Definitions
  2720. //-----------------------------------------------------------------------
  2721.  
  2722. // Data
  2723.  
  2724. static Widget name_w;        // Name of defined command
  2725. static Widget arg_w;        // `()' toggle
  2726. static Widget record_w;        // `Record' button
  2727. static Widget end_w;        // `End' button
  2728. static Widget edit_w;        // `Edit>>' button
  2729. static Widget editor_w;        // Command definition editor
  2730. static Widget apply_w;        // `Apply' button
  2731.  
  2732. static string current_name()
  2733. {
  2734.     String name_s = XmTextFieldGetString(name_w);
  2735.     string name(name_s);
  2736.     XtFree(name_s);
  2737.     strip_space(name);
  2738.     return name;
  2739. }
  2740.  
  2741.  
  2742. // Button stuff
  2743.  
  2744. // Name of GDB argument
  2745. static const string arg0 = "$arg0";
  2746.  
  2747. static bool is_arg_command(const string& name)
  2748. {
  2749.     return defs.has(name) && defs[name].contains(arg0);
  2750. }
  2751.  
  2752. static void add_button(string name, String& menu)
  2753. {
  2754.     if (XmToggleButtonGetState(arg_w) || is_arg_command(name))
  2755.     name += " ()";
  2756.  
  2757.     string s = menu;
  2758.     if (s != "" && !s.contains('\n', -1))
  2759.     s += '\n';
  2760.     s += name + "\n";
  2761.     menu = (String)XtNewString(s.chars());
  2762. }
  2763.  
  2764. static void remove_button(string name, String& menu)
  2765. {
  2766.     string s = string("\n") + menu;
  2767.     s.gsub("\n" + name + "\n", string("\n"));
  2768.     s.gsub("\n" + name + " ()\n", string("\n"));
  2769.     menu = (String)XtNewString(s.chars() + 1);
  2770. }
  2771.  
  2772. enum ButtonTarget { ConsoleTarget, SourceTarget, DataTarget };
  2773.  
  2774. static String &target_string(ButtonTarget t)
  2775. {
  2776.     switch (t)
  2777.     {
  2778.     case ConsoleTarget:
  2779.     return app_data.console_buttons;
  2780.  
  2781.     case SourceTarget:
  2782.     return app_data.source_buttons;
  2783.  
  2784.     case DataTarget:
  2785.     return app_data.data_buttons;
  2786.     }
  2787.  
  2788.     static String null = 0;
  2789.     return null;
  2790. }
  2791.  
  2792. static void ToggleButtonCB(Widget, XtPointer client_data, XtPointer call_data)
  2793. {
  2794.     string name = current_name();
  2795.     ButtonTarget target = (ButtonTarget) (long) client_data;
  2796.  
  2797.     XmToggleButtonCallbackStruct *info = 
  2798.     (XmToggleButtonCallbackStruct *)call_data;
  2799.  
  2800.     String& str = target_string(target);
  2801.  
  2802.     if (info->set)
  2803.     {
  2804.     add_button(name, str);
  2805.     }
  2806.     else
  2807.     {
  2808.     remove_button(name, str);
  2809.     }
  2810.  
  2811.     update_user_buttons();
  2812. }
  2813.  
  2814. MMDesc button_menu[] =
  2815. {
  2816.     { "console", MMToggle, 
  2817.       { ToggleButtonCB, XtPointer(ConsoleTarget) }, 0, 0, 0, 0},
  2818.     { "source",  MMToggle, 
  2819.       { ToggleButtonCB, XtPointer(SourceTarget) }, 0, 0, 0, 0},
  2820.     { "data",    MMToggle, 
  2821.       { ToggleButtonCB, XtPointer(DataTarget) }, 0, 0, 0, 0},
  2822.     MMEnd
  2823. };
  2824.  
  2825. static void refresh_toggle(ButtonTarget t)
  2826. {
  2827.     Widget& w = button_menu[t].widget;
  2828.     string s = string("\n") + target_string(t);
  2829.     string name = current_name();
  2830.  
  2831.     Boolean old_state;
  2832.     XtVaGetValues(w, XmNset, &old_state, NULL);
  2833.  
  2834.     Boolean new_state = 
  2835.     s.contains("\n" + name + "\n") || s.contains("\n" + name + " ()\n");
  2836.     if (old_state != new_state)
  2837.     XtVaSetValues(w, XmNset, new_state, NULL);
  2838.  
  2839. #if 1
  2840.     set_sensitive(w, name != "");
  2841. #else
  2842.     string answer = gdbHelp(name);
  2843.     if (answer != NO_GDB_ANSWER)
  2844.     {
  2845.     set_sensitive(w, is_known_command(answer));
  2846.     }
  2847. #endif
  2848. }
  2849.  
  2850. static void refresh_toggles()
  2851. {
  2852.     refresh_toggle(SourceTarget);
  2853.     refresh_toggle(DataTarget);
  2854.     refresh_toggle(ConsoleTarget);
  2855. }
  2856.  
  2857. static void refresh_combo_box()
  2858. {
  2859.     if (name_w == 0)
  2860.     return;            // Not yet created
  2861.  
  2862.     // Refresh combo box
  2863.     StringArray commands;
  2864.     for (StringStringAssocIter iter(defs); iter.ok(); iter++)
  2865.     commands += iter.key();
  2866.     smart_sort(commands);
  2867.     ComboBoxSetList(name_w, commands);
  2868. }
  2869.  
  2870. // Editing stuff
  2871.  
  2872. // Text field has changed -- update buttons
  2873. void UpdateDefinePanelCB(Widget w, XtPointer, XtPointer)
  2874. {
  2875.     if (name_w == 0)
  2876.     return;            // Not yet created
  2877.  
  2878.     string name = current_name();
  2879.  
  2880.     set_sensitive(record_w, !gdb->recording() && name != "");
  2881.     set_sensitive(apply_w,  !gdb->recording() && name != "");
  2882.     set_sensitive(end_w,    gdb->recording());
  2883.     set_sensitive(edit_w,   !gdb->recording() && name != "");
  2884.  
  2885.     set_sensitive(name_w, !gdb->recording());
  2886.     set_sensitive(XtParent(name_w), !gdb->recording());
  2887.     set_sensitive(editor_w, !gdb->recording());
  2888.  
  2889.     set_arg();
  2890.  
  2891.     if (w != 0 && !gdb->recording() && defs.has(name))
  2892.     XmToggleButtonSetState(arg_w, is_arg_command(name), False);
  2893.  
  2894.     refresh_toggles();
  2895. }
  2896.  
  2897. static void update_defineHP(Agent *, void *client_data, void *call_data)
  2898. {
  2899.     bool gdb_ready = bool(call_data);
  2900.     if (gdb_ready && !gdb->recording())
  2901.     {
  2902.     char *c = (char *)client_data;
  2903.     bool ok = update_define(c, true);
  2904.  
  2905.     if (ok)
  2906.     {
  2907.         // Update buttons
  2908.         UpdateDefinePanelCB();
  2909.         refresh_combo_box();
  2910.  
  2911.         // Don't get called again
  2912.         gdb->removeHandler(ReadyForQuestion, update_defineHP, client_data);
  2913.         delete[] c;
  2914.     }
  2915.     }
  2916.     else
  2917.     {
  2918.     UpdateDefinePanelCB();
  2919.     }
  2920. }
  2921.  
  2922. // This one is called by send_gdb_command() when seeing `define'
  2923. void update_define_later(const string& command)
  2924. {
  2925.     char *c = new char[command.length() + 1];
  2926.     strcpy(c, (char *)command);
  2927.  
  2928.     gdb->addHandler(ReadyForQuestion, update_defineHP, (void *)c);
  2929.  
  2930.     UpdateDefinePanelCB();
  2931. }
  2932.  
  2933. static void RecordCommandDefinitionCB(Widget w, XtPointer, XtPointer)
  2934. {
  2935.     string name = current_name();
  2936.     gdb_command("define " + name, w);
  2937. }
  2938.  
  2939. // Activate the button given in CLIENT_DATA
  2940. static void ActivateCB(Widget, XtPointer client_data, 
  2941.                XtPointer call_data)
  2942. {
  2943.     XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *)call_data;
  2944.     
  2945.     Widget button = Widget(client_data);
  2946.     XtCallActionProc(button, "ArmAndActivate", cbs->event, (String *)0, 0);
  2947. }
  2948.  
  2949. static void EndCommandDefinitionCB(Widget w, XtPointer, XtPointer)
  2950. {
  2951.     gdb_command("end", w);
  2952. }
  2953.  
  2954. static void DoneEditCommandDefinitionCB(Widget w, XtPointer, XtPointer)
  2955. {
  2956.     if (!XtIsManaged(XtParent(editor_w)))
  2957.     return;
  2958.  
  2959.     string name = current_name();
  2960.  
  2961.     XtUnmanageChild(XtParent(editor_w));
  2962.     set_sensitive(name_w, True);
  2963.     set_sensitive(XtParent(name_w), True);
  2964.  
  2965.     MString label = "Edit " + MString(">>", "small");
  2966.     set_label(edit_w, label);
  2967.  
  2968.     String _commands = XmTextGetString(editor_w);
  2969.     string cmd = _commands;
  2970.     XtFree(_commands);
  2971.  
  2972.     if (!cmd.contains('\n', -1))
  2973.     cmd += '\n';
  2974.  
  2975.     if ((cmd != "" && !defs.has(name)) || cmd != defs[name])
  2976.     {
  2977.     StringArray commands;
  2978.     while (cmd != "")
  2979.     {
  2980.         string c = cmd.before('\n');
  2981.         if (c != "")
  2982.         commands += c;
  2983.         cmd = cmd.after('\n');
  2984.     }
  2985.  
  2986.     // This might require confirmation.  Don't change anything.
  2987.     set_sensitive(edit_w,   false);
  2988.     set_sensitive(record_w, false);
  2989.     set_sensitive(end_w,    false);
  2990.  
  2991.     gdb_command("define " + name, w);
  2992.     for (int j = 0; j < commands.size(); j++)
  2993.         gdb_command(commands[j], w);
  2994.     gdb_command("end", w);
  2995.  
  2996.     update_define_later(name);
  2997.     }
  2998. }
  2999.  
  3000. static void EditCommandDefinitionCB(Widget, XtPointer, XtPointer)
  3001. {
  3002.     if (XtIsManaged(XtParent(editor_w)))
  3003.     return;
  3004.  
  3005.     string name = current_name();
  3006.  
  3007.     // update_define(name);
  3008.     set_sensitive(name_w, False);
  3009.     set_sensitive(XtParent(name_w), False);
  3010.  
  3011.     string def = "";
  3012.     if (defs.has(name))
  3013.     def = defs[name];
  3014.  
  3015.     XmTextSetString(editor_w, (String)def);
  3016.  
  3017.     XtManageChild(XtParent(editor_w));
  3018.     MString label = "Edit " + MString("<<", "small");
  3019.     set_label(edit_w, label);
  3020. }
  3021.  
  3022. static void ToggleEditCommandDefinitionCB(Widget w, XtPointer client_data, 
  3023.                       XtPointer call_data)
  3024. {
  3025.     if (XtIsManaged(XtParent(editor_w)))
  3026.     DoneEditCommandDefinitionCB(w, client_data, call_data);
  3027.     else
  3028.     EditCommandDefinitionCB(w, client_data, call_data);
  3029. }
  3030.  
  3031. // Apply the given command
  3032. static void ApplyCB(Widget, XtPointer, XtPointer)
  3033. {
  3034.     string cmd = current_name();
  3035.     if (cmd == "")
  3036.     return;
  3037.  
  3038.     if (XmToggleButtonGetState(arg_w))
  3039.     cmd += " " + source_arg->get_string();
  3040.  
  3041.     gdb_command(cmd);
  3042. }
  3043.  
  3044. // Force argument to `()'
  3045. static void ForceArg0HP(void *, void *, void *)
  3046. {
  3047.     static bool called = false;
  3048.     if (called)
  3049.     return;
  3050.  
  3051.     called = true;
  3052.     set_arg();
  3053.     called = false;
  3054. }
  3055.  
  3056. static void set_arg()
  3057. {
  3058.     static string saved_arg;
  3059.     static bool have_saved_arg = false;
  3060.  
  3061.     if (gdb->recording() && XmToggleButtonGetState(arg_w))
  3062.     {
  3063.     if (!have_saved_arg)
  3064.     {
  3065.         saved_arg = source_arg->get_string();
  3066.         have_saved_arg = true;
  3067.  
  3068.         source_arg->set_string(arg0);
  3069.  
  3070.         reset_status_lock();
  3071.         MString msg = 
  3072.         rm("Using ") + bf("()") + rm(" as symbolic argument");
  3073.         set_status_mstring(msg);
  3074.     }
  3075.  
  3076.     source_arg->addHandler(Changed, ForceArg0HP);
  3077.     set_sensitive(source_arg->top(), False);
  3078.     }
  3079.     else
  3080.     {
  3081.     source_arg->removeHandler(Changed, ForceArg0HP);
  3082.     set_sensitive(source_arg->top(), True);
  3083.  
  3084.     if (have_saved_arg)
  3085.     {
  3086.         source_arg->set_string(saved_arg);
  3087.         have_saved_arg = false;
  3088.  
  3089.         reset_status_lock();
  3090.         MString msg = 
  3091.         rm("Using ") + bf("()") + rm(" as literal argument");
  3092.         set_status_mstring(msg);
  3093.     }
  3094.     }
  3095. }
  3096.  
  3097. static void ToggleArgCB(Widget, XtPointer, XtPointer)
  3098. {
  3099.     set_arg();
  3100. }
  3101.  
  3102. static MMDesc commands_menu[] =
  3103. {
  3104.     { "record", MMPush, 
  3105.       { RecordCommandDefinitionCB, 0 }, 0, &record_w, 0, 0 },
  3106.     { "end",    MMPush | MMInsensitive, 
  3107.       { EndCommandDefinitionCB, 0 }, 0, &end_w, 0, 0},
  3108.     { "edit",   MMPush, 
  3109.       { ToggleEditCommandDefinitionCB, 0 }, 0, &edit_w, 0, 0 },
  3110.     MMEnd
  3111. };
  3112.  
  3113. static MMDesc name_menu[] =
  3114. {
  3115.     { "name",     MMComboBox | MMUnmanagedLabel, 
  3116.       { UpdateDefinePanelCB, 0 }, 0, &name_w, 0, 0 },
  3117.     { "arg",      MMToggle, { ToggleArgCB, 0 }, 0, &arg_w, 0, 0 },
  3118.     MMEnd
  3119. };
  3120.  
  3121. static MMDesc panel_menu[] = 
  3122. {
  3123.     { "name",     MMButtonPanel, MMNoCB, name_menu, 0, 0, 0 },
  3124.     { "commands", MMButtonPanel, MMNoCB, commands_menu, 0, 0, 0 },
  3125.     { "button",   MMButtonPanel, MMNoCB, button_menu, 0, 0, 0 },
  3126.     MMEnd
  3127. };
  3128.  
  3129.  
  3130. // Define command
  3131. void dddDefineCommandCB(Widget w, XtPointer, XtPointer)
  3132. {
  3133.     static Widget dialog = 0;
  3134.  
  3135.     if (dialog == 0)
  3136.     {
  3137.     Arg args[10];
  3138.     int arg = 0;
  3139.     XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
  3140.     dialog = verify(XmCreatePromptDialog(find_shell(w),
  3141.                          "define_command",
  3142.                          args, arg));
  3143.     XtVaSetValues(dialog, XmNdefaultButton, Widget(0), NULL);
  3144.  
  3145.     // Remove old prompt
  3146.     Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
  3147.     XtUnmanageChild(text);
  3148.     Widget old_label = 
  3149.         XmSelectionBoxGetChild(dialog, XmDIALOG_SELECTION_LABEL);
  3150.     XtUnmanageChild(old_label);
  3151.  
  3152.     Delay::register_shell(dialog);
  3153.  
  3154.     XtUnmanageChild(XmSelectionBoxGetChild(dialog, 
  3155.                            XmDIALOG_CANCEL_BUTTON));
  3156.     apply_w = XmSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON);
  3157.     XtManageChild(apply_w);
  3158.  
  3159.     arg = 0;
  3160.     XtSetArg(args[arg], XmNorientation, XmHORIZONTAL); arg++;
  3161.     Widget form = XmCreateRowColumn(dialog, "form", args, arg);
  3162.     XtManageChild(form);
  3163.  
  3164.     Widget panel = MMcreatePanel(form, "panel", panel_menu);
  3165.  
  3166.     XtVaSetValues(panel,
  3167.               XmNmarginWidth,    0,
  3168.               XmNmarginHeight,   0,
  3169.               NULL);
  3170.  
  3171.     arg = 0;
  3172.     XtSetArg(args[arg], XmNeditMode, XmMULTI_LINE_EDIT); arg++;
  3173.         editor_w = XmCreateScrolledText(form, "text", args, arg);
  3174.     XtUnmanageChild(XtParent(editor_w));
  3175.     XtManageChild(editor_w);
  3176.  
  3177.     MMaddCallbacks(panel_menu);
  3178.     InstallButtonTips(panel);
  3179.  
  3180.     MMadjustPanel(panel_menu);
  3181.  
  3182.     XtAddCallback(dialog, XmNokCallback, UnmanageThisCB, 
  3183.               XtPointer(dialog));
  3184.     XtAddCallback(dialog, XmNokCallback, DoneEditCommandDefinitionCB, 
  3185.               XtPointer(0));
  3186.     XtAddCallback(dialog, XmNapplyCallback, ApplyCB, NULL);
  3187.     XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, NULL);
  3188.     XtAddCallback(name_w, XmNactivateCallback, ActivateCB, 
  3189.               XtPointer(record_w));
  3190.  
  3191.     set_need_load_defines(true);
  3192.     update_defines();
  3193.     }
  3194.  
  3195.     UpdateDefinePanelCB();
  3196.     refresh_combo_box();
  3197.     manage_and_raise(dialog);
  3198. }
  3199.