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 >
Wrap
C/C++ Source or Header
|
1998-11-15
|
79KB
|
3,199 lines
// $Id: settings.C,v 1.102 1998/11/15 13:04:24 zeller Exp $ -*- C++ -*-
// Modify debugger settings
// Copyright (C) 1996-1998 Technische Universitaet Braunschweig, Germany.
// Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
//
// This file is part of DDD.
//
// DDD is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// DDD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with DDD -- see the file COPYING.
// If not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page,
// `http://www.cs.tu-bs.de/softech/ddd/',
// or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
char settings_rcsid[] =
"$Id: settings.C,v 1.102 1998/11/15 13:04:24 zeller Exp $";
#ifdef __GNUG__
#pragma implementation
#endif
#include "settings.h"
#include <Xm/Xm.h>
#include <Xm/SelectioB.h>
#include <Xm/DialogS.h>
#include <Xm/ScrolledW.h>
#include <Xm/RowColumn.h>
#include <Xm/ToggleB.h>
#include <Xm/PushB.h>
#include <Xm/TextF.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/Separator.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "AppData.h"
#include "Assoc.h"
#include "ComboBox.h"
#include "Command.h"
#include "DataDisp.h"
#include "Delay.h"
#include "DestroyCB.h"
#include "EntryType.h"
#include "GDBAgent.h"
#include "HelpCB.h"
#include "LessTifH.h"
#include "MakeMenu.h"
#include "SmartC.h"
#include "SourceView.h"
#include "StringSA.h"
#include "UndoBuffer.h"
#include "VarArray.h"
#include "WidgetSA.h"
#include "buttons.h"
#include "cook.h"
#include "comm-manag.h"
#include "ddd.h"
#include "editing.h"
#include "mydialogs.h"
#include "logo.h"
#include "options.h"
#include "question.h"
#include "regexps.h"
#include "shell.h"
#include "status.h"
#include "string-fun.h"
#include "verify.h"
#include "version.h"
#include "wm.h"
//-----------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------
const Dimension EXTRA_SPACE = 10; // Minimum space between label / entry
const Dimension EXTRA_WIDTH = 6; // Additional space for safety
const Dimension MAX_HEIGHT = 300; // Maximum height of window
enum SettingsType { SETTINGS, INFOS, SIGNALS };
//-----------------------------------------------------------------------
// Data
//-----------------------------------------------------------------------
static Widget settings_panel = 0;
static Widget settings_form = 0;
static Widget reset_settings_button = 0;
static WidgetArray settings_entries;
static EntryTypeArray settings_entry_types;
static WidgetStringAssoc settings_values;
static WidgetStringAssoc settings_initial_values;
static bool need_reload_settings = false;
static Widget signals_panel = 0;
static Widget signals_form = 0;
static Widget reset_signals_button = 0;
static WidgetArray signals_entries;
static WidgetStringAssoc signals_values;
static WidgetStringAssoc signals_initial_values;
static bool need_reload_signals = false;
static Widget infos_panel = 0;
static Widget reset_infos_button = 0;
static WidgetArray infos_entries;
//-----------------------------------------------------------------------
// Functions
//-----------------------------------------------------------------------
static void get_setting(ostream& os, DebuggerType type,
const string& base, string value);
static void set_arg();
// Find widget for command COMMAND
static Widget command_to_widget(Widget ref, string command)
{
Widget found = 0;
while (command != "" && (found = XtNameToWidget(ref, command)) == 0)
{
// Strip last word (command argument)
int index = command.index(rxwhite, -1);
command = command.before(index);
}
return found;
}
// Issue `set' command
static void gdb_set_command(string set_command, string value)
{
if (value == "unlimited")
value = "0";
if (set_command == "dir" && value != "")
{
// `dir' in GDB works somewhat special: it prepends its
// argument to the source path instead of simply setting it.
// Hence, first reset `dir' to some initial value.
string confirm_value = "on";
Widget confirm_w = command_to_widget(settings_form, "set confirm");
if (confirm_w)
confirm_value = settings_values[confirm_w];
if (confirm_value == "on")
gdb_command("set confirm off");
gdb_command(set_command);
if (confirm_value == "on")
gdb_command("set confirm on");
}
if (value != "")
{
if (set_command.contains("O ", 0))
gdb_command(set_command + "=" + value); // Perl
else if (set_command.contains("set $", 0) &&
!set_command.contains(" = "))
gdb_command(set_command + " = " + value); // DBX
else
gdb_command(set_command + " " + value); // GDB
}
else
gdb_command(set_command);
}
// TextField reply
static void SetTextCB(Widget w, XtPointer client_data, XtPointer)
{
String value_s = XmTextFieldGetString(w);
string value(value_s);
XtFree(value_s);
gdb_set_command((String)client_data, value);
}
// OptionMenu reply
static void SetOptionCB(Widget w, XtPointer client_data, XtPointer)
{
gdb_set_command((String)client_data, XtName(w));
}
// ToggleButton reply
static void SetOnOffCB(Widget, XtPointer client_data, XtPointer call_data)
{
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *)call_data;
if (cbs->set)
gdb_set_command((String)client_data, "on");
else
gdb_set_command((String)client_data, "off");
}
// ToggleButton reply
static void SetTrueFalseCB(Widget, XtPointer client_data, XtPointer call_data)
{
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *)call_data;
if (cbs->set)
gdb_set_command((String)client_data, "true");
else
gdb_set_command((String)client_data, "false");
}
// ToggleButton reply
static void SetSensitiveCB(Widget, XtPointer client_data, XtPointer call_data)
{
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *)call_data;
if (cbs->set)
gdb_set_command((String)client_data, "sensitive");
else
gdb_set_command((String)client_data, "insensitive");
}
// ToggleButton reply
static void SetNumCB(Widget, XtPointer client_data, XtPointer call_data)
{
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *)call_data;
if (cbs->set)
gdb_set_command((String)client_data, "1");
else
gdb_set_command((String)client_data, "0");
}
// ToggleButton reply
static void SetNoNumCB(Widget, XtPointer client_data, XtPointer call_data)
{
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *)call_data;
if (cbs->set)
gdb_set_command((String)client_data, "0");
else
gdb_set_command((String)client_data, "1");
}
// ToggleButton reply
static void SetDisplayCB(Widget, XtPointer client_data, XtPointer call_data)
{
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *)call_data;
if (cbs->set)
data_disp->new_user_display((String)client_data);
else
data_disp->delete_user_display((String)client_data);
}
// ToggleButton reply
static void SendSignalCB(Widget, XtPointer client_data, XtPointer)
{
gdb_command(string("signal ") + XtName(Widget(client_data)));
}
static string handle_command(Widget w, bool set)
{
string sig = string(XtName(w)).before('-');
string action = string(XtName(w)).after('-');
if (!set)
action.prepend("no");
if (action == "nopass")
action = "ignore";
else if (action == "noignore")
action = "pass";
return "handle " + sig + " " + action;
}
// ToggleButton reply
static void SignalCB(Widget w, XtPointer, XtPointer call_data)
{
XmToggleButtonCallbackStruct *cbs =
(XmToggleButtonCallbackStruct *)call_data;
gdb_command(handle_command(w, cbs->set));
}
// Get help on signal - using `info' on `libc'
static void HelpOnSignalCB(Widget w, XtPointer client_data,
XtPointer call_data)
{
Widget label = Widget(client_data);
string sig = XtName(label);
string s = "";
if (sig == "all")
{
HelpOnThisCB(w, XtPointer(label), call_data);
return;
}
StatusDelay delay("Retrieving Signal Documentation");
// libc info has one common node for SIGUSR1 and SIGUSR2
string sigindex = sig;
if (sigindex == "SIGUSR1")
sigindex = "SIGUSR2";
string cmd = "info -f libc -n 'Variable Index' " + sigindex + " -o -";
FILE *fp = popen(sh_command(cmd), "r");
if (fp != 0)
{
ostrstream info;
int c;
while ((c = getc(fp)) != EOF)
info << char(c);
pclose(fp);
s = info;
int start = s.index(" - Macro: int " + sig);
start = s.index('\n', start);
s = s.after(start);
int end = s.index("\n - ");
if (end >= 0)
s = s.before(end);
s.gsub("ee\n*Note\n", "ee\n`");
s.gsub("ee *Note\n", "ee\n`");
s.gsub("ee\n*Note ", "ee\n`");
s.gsub("ee *Note ", "ee `");
s.gsub("*Note ", "See `");
s.gsub("*Note\n", "See\n`");
s.gsub("::", "' in libc info");
s.gsub("`C-", "`Ctrl+");
strip_space(s);
while (s.contains(" "))
s.gsub(" ", " ");
s.gsub("\n ", "\n");
}
if (s == "")
s = "No help available on this signal.";
XmString xmdoc = 0;
XtVaGetValues(label, XmNlabelString, &xmdoc, NULL);
MString doc(xmdoc, true);
XmStringFree(xmdoc);
MString text = bf(sig + ": ") + doc;
text += cr() + cr() + rm(s);
MStringHelpCB(w, XtPointer(text.xmstring()), call_data);
}
// Update state of `reset' button
static void update_reset_settings_button()
{
if (reset_settings_button == 0)
return;
check_options_file();
for (int i = 0; i < settings_entries.size(); i++)
{
Widget entry = settings_entries[i];
if (settings_initial_values[entry] != settings_values[entry])
{
set_sensitive(reset_settings_button, True);
return;
}
}
set_sensitive(reset_settings_button, False);
}
static void update_reset_signals_button()
{
if (reset_signals_button == 0)
return;
check_options_file();
for (int i = 0; i < signals_entries.size(); i++)
{
Widget entry = signals_entries[i];
if (signals_initial_values[entry] != signals_values[entry])
{
set_sensitive(reset_signals_button, True);
return;
}
}
set_sensitive(reset_signals_button, False);
}
// Update states of `info' buttons
void update_infos()
{
bool have_info = false;
for (int i = 0; i < infos_entries.size(); i++)
{
Widget button = infos_entries[i];
bool set = data_disp->have_user_display(XtName(button));
have_info = have_info || set;
XtVaSetValues(button, XmNset, set, NULL);
}
if (reset_infos_button != 0)
set_sensitive(reset_infos_button, have_info);
}
// Register additional info button
void register_info_button(Widget w)
{
infos_entries += w;
}
// Save `settings' state
void save_settings_state()
{
if (settings_form == 0)
return;
for (int i = 0; i < settings_entries.size(); i++)
{
Widget entry = settings_entries[i];
settings_initial_values[entry] = settings_values[entry];
}
update_reset_settings_button();
set_need_save_defines(false);
}
// Save `signals' state
void save_signals_state()
{
if (signals_form == 0)
return;
for (int i = 0; i < signals_entries.size(); i++)
{
Widget entry = signals_entries[i];
signals_initial_values[entry] = signals_values[entry];
}
update_reset_signals_button();
}
// Process output of `show' command
void process_show(string command, string value, bool init)
{
if (settings_form == 0)
return;
if (gdb->type() == DBX && value.freq('\n') > 1)
{
// In DBX, we always get all values at once. Find the
// appropriate line.
string base = command.after(rxwhite);
if (base.contains(rxwhite))
base = base.before(rxwhite);
int column = 0;
int start_value = -1;
for (int i = 0; i < int(value.length()); i++)
{
if (column == 0
&& value.contains(base, i)
&& value.contains(rxwhite, i + base.length()))
{
start_value = i;
break;
}
if (value[i] == '\n')
column = 0;
else
column++;
}
if (start_value < 0)
{
#if 0
cerr << "Warning: cannot set " << quote(base)
<< " to " << quote(value) << "\n";
#endif
return;
}
value = value.from(start_value);
value = value.after(base);
if (value.contains('\n'))
value = value.before('\n');
strip_space(value);
}
if (value.contains('\n'))
value = value.before('\n');
if (!init)
set_status(value);
if (gdb->type() == GDB)
{
if (value.contains(" is "))
value = value.after(" is ", -1);
if (value.contains(".", -1))
value = value.before(int(value.length()) - 1);
if (value.contains("assumed to be "))
value = value.after("assumed to be ");
if (value.contains("\"auto;", 0) ||
value.contains("set automatically", 0))
value = "auto";
if (value.contains('"', 0))
value = unquote(value);
else if (value.contains(": "))
value = value.after(": ");
}
if (gdb->type() == PERL)
{
if (value.contains('\''))
{
value = value.after('\'');
value = value.before('\'');
}
}
static string empty;
value.gsub(gdb_out_ignore, empty);
string set_command = command;
if (set_command.contains("O ", 0))
{
// Perl
if (set_command.contains('?'))
set_command = set_command.before('?');
else if (set_command.contains('='))
set_command = set_command.before('=');
}
else if (!set_command.contains("set ", 0))
{
// GDB
set_command = "set " + set_command.after(rxwhite);
}
Widget button = command_to_widget(settings_form, set_command);
if (button == 0)
button = command_to_widget(settings_form, command);
if (button == 0)
button = command_to_widget(settings_form, command.after(rxwhite));
if (button != 0)
{
if (!init)
{
// Save current state in undo buffer
ostrstream command;
get_setting(command, gdb->type(), XtName(button),
settings_values[button]);
undo_buffer.add_command(string(command));
}
settings_values[button] = value;
if (init)
settings_initial_values[button] = value;
}
if (!init)
update_reset_settings_button();
if (button != 0 && XmIsRowColumn(button))
{
Widget menu = 0;
XtVaGetValues(button, XmNsubMenuId, &menu, NULL);
if (menu != 0)
{
// Option menu
Widget active = XtNameToWidget(menu, value);
if (active != 0)
{
XtVaSetValues(button, XmNmenuHistory, active, NULL);
return;
}
}
}
else if (button != 0 && XmIsToggleButton(button))
{
bool set = value != "off" && value != "0" && value != "unlimited"
&& value != "false" && value != "insensitive";
for (int i = 0; i < settings_entries.size(); i++)
{
if (settings_entries[i] == button
&& settings_entry_types[i] == NoNumToggleButtonEntry)
{
set = !set;
break;
}
}
XtVaSetValues(button, XmNset, set, NULL);
return;
}
else if (button != 0 && XmIsTextField(button))
{
XtVaSetValues(button,
XmNvalue, value.chars(),
XmNcursorPosition, 0,
XmNcursorPositionVisible, True,
NULL);
return;
}
#if 0
cerr << "Warning: cannot set " << quote(set_command)
<< " to " << quote(value) << "\n";
#endif
}
// Process output of `handle' command
void process_handle(string output, bool init)
{
if (signals_form == 0)
return;
string undo_command = "";
while (output != "")
{
string line = output;
if (line.contains('\n'))
line = line.before('\n');
output = output.after('\n');
string base = line.before(rxwhite);
if (!base.contains("SIG", 0))
continue;
line = line.after(rxwhite);
static String titles[3] = { "stop", "print", "pass" };
for (int word = 0; word <= 2; word++)
{
string value = line.before(rxwhite);
line = line.after(rxwhite);
value.downcase();
bool set = (value == "yes");
string name = base + "-" + titles[word];
Widget w = XtNameToWidget(signals_form, name);
if (w == 0)
{
#if 0
cerr << "Warning: cannot set " << base << " " << titles[word]
<< " to " << quote(value) << "\n";
#endif
continue;
}
if (!init && signals_values[w] != value)
{
// Save undoing command
if (undo_command != "")
undo_command += '\n';
undo_command += handle_command(w, !set);
}
XtVaSetValues(w, XmNset, set, NULL);
signals_values[w] = value;
if (init)
signals_initial_values[w] = value;
}
}
if (undo_command != "")
undo_buffer.add_command(undo_command);
update_reset_signals_button();
}
// Create settings form
// Return TRUE if doc begins with a boolean verb
static bool is_verb(const string& doc)
{
if (doc.contains("whether to"))
return true;
int ing = doc.index("ing");
if (ing < 0)
return false;
int first_space = doc.index(' ');
int second_space = doc.index(' ', first_space + 1);
if (ing < first_space || ing < second_space || second_space < 0)
return true;
return false;
}
// Determine entry type
static EntryType entry_type(DebuggerType type,
const string& base,
const string& doc,
const string& value)
{
#if RUNTIME_REGEX
static regex rxnonzero1("no[nt][ -]?(0|zero|null)");
static regex rxnonzero2("!= *(0|zero|null)");
#endif
switch (type)
{
case GDB:
if (base.contains("check", 0))
return CheckOptionMenuEntry;
if (base.contains("endian", 0) ||
base.contains("architecture", 0))
return TargetOptionMenuEntry;
if (base.contains("language", 0) ||
base.contains("demangle", 0))
return OtherOptionMenuEntry;
if (value.contains("on.\n", -1) || value.contains("off.\n", -1))
return OnOffToggleButtonEntry;
if ((value.contains("0.\n", -1) || value.contains("1.\n", -1))
&& (is_verb(doc)))
return NumToggleButtonEntry;
break;
case DBX:
if ((value == "0" || value == "1") &&
!doc.contains("number") && !doc.contains(" > 1"))
{
if (doc.contains(" 1") && !doc.contains(" 2"))
return NumToggleButtonEntry;
if (doc.contains(rxnonzero1) || doc.contains(rxnonzero2))
return NumToggleButtonEntry;
}
if (value.contains("on", 0) || value.contains("off", 0))
return OnOffToggleButtonEntry;
if (value.contains("true", 0) || value.contains("false", 0))
return TrueFalseToggleButtonEntry;
if (value.contains("sensitive", 0)
|| value.contains("insensitive", 0))
return SensitiveToggleButtonEntry;
if (has_nr(value))
return TextFieldEntry;
if (base.contains("version")
|| base.contains("run_io")
|| base.contains("follow_fork_mode"))
return OtherOptionMenuEntry;
break;
case XDB:
case JDB:
case PYDB:
case PERL:
break; // FIXME
}
// When all else fails, display a text
return TextFieldEntry;
}
// The GDB question cache
static StringStringAssoc gdb_question_cache;
static string cached_gdb_question(const string& question, int timeout = 0)
{
string& answer = gdb_question_cache[question];
if (answer == "")
answer = gdb_question(question, timeout);
return answer;
}
static void clear_gdb_question_cache()
{
static StringStringAssoc empty;
gdb_question_cache = empty;
}
static void strip_leading(string& doc, const string& key)
{
if (doc.contains(key, 0))
doc = doc.after(key);
strip_leading_space(doc);
}
static void strip_from(string& doc, const string& key)
{
if (doc.contains(key))
doc = doc.before(key);
strip_leading_space(doc);
}
static void munch_doc(string& doc)
{
strip_leading_space(doc);
// Sun DBX 3.0
strip_leading(doc, "#");
strip_leading(doc, "If on,");
strip_leading(doc, "If true,");
strip_leading(doc, "When on,");
strip_leading(doc, "When `on',");
strip_leading(doc, "Set ");
strip_leading(doc, "Sets ");
strip_leading(doc, "Governs ");
strip_leading(doc, "Limit ");
strip_leading(doc, "Enable/disable ");
strip_leading(doc, "Allow/disallow ");
strip_leading(doc, "whether the ");
strip_leading(doc, "debugger will ");
strip_leading(doc, "Automatically ");
strip_leading(doc, "Name of ");
// SGI DBX
strip_leading(doc, "-");
if (doc.contains("0 =>"))
doc = "Don't" + doc.after("0 =>");
// DEC and SGI DBX
strip_leading(doc, "$");
strip_leading(doc, "if");
strip_leading(doc, "If");
strip_leading(doc, "when");
strip_leading(doc, "When");
strip_leading(doc, "this ");
strip_leading(doc, "is ");
strip_leading(doc, "==");
strip_leading(doc, "!=");
strip_leading(doc, "0");
strip_leading(doc, "1");
strip_leading(doc, "set");
strip_leading(doc, "zero");
strip_leading(doc, "non-zero");
strip_leading(doc, "non-0");
strip_leading(doc, "(default)");
strip_leading(doc, "(the default)");
strip_leading(doc, ",");
strip_leading(doc, "=>");
strip_leading(doc, "implies ");
strip_leading(doc, "then ");
strip_leading(doc, "contains ");
strip_leading(doc, "the ");
strip_leading(doc, "name of ");
strip_leading(doc, "specify ");
strip_leading(doc, "which ");
strip_leading(doc, "after ");
strip_leading(doc, "String with ");
// GDB
strip_leading(doc, "whether to ");
strip_leading(doc, "the ");
// More DEC DBX
strip_from(doc, "we're looking at");
strip_from(doc, "we're debugging");
strip_from(doc, "Default:");
strip_from(doc, ", default");
strip_from(doc, " to $DBX");
strip_from(doc, " entirely");
strip_from(doc, " rather than");
strip_from(doc, ", else");
strip_from(doc, " next to");
strip_from(doc, " used to");
strip_from(doc, " that was");
strip_from(doc, " accessing");
// More SGI DBX
strip_from(doc, " if none");
strip_from(doc, " (init");
strip_from(doc, " (default");
strip_from(doc, " ($");
strip_from(doc, " ( $");
strip_from(doc, " (with");
strip_from(doc, " However ");
strip_from(doc, " This ");
strip_from(doc, " Defaults ");
strip_from(doc, " $");
doc.gsub(" " + downcase(gdb->title()), " " + gdb->title());
if (doc.contains(downcase(gdb->title()), 0))
doc = gdb->title() + doc.after(downcase(gdb->title()));
if (doc.length() > 0)
doc[0] = toupper(doc[0]);
if (gdb->type() == GDB)
doc.gsub('_', ' ');
if (doc.length() > 60)
doc = doc.before(57) + "...";
}
// Get DBX documentation
static string _get_dbx_help(string dbxenv, string base)
{
string dbx_help;
if (dbxenv == "dbxenv")
dbx_help = cached_gdb_question("help dbxenv", -1);
if (dbx_help.freq('\n') <= 2)
dbx_help = cached_gdb_question("help variable", -1);
if (dbx_help.freq('\n') <= 2)
dbx_help = cached_gdb_question("help $variables", -1);
// Find documentation in DBX_HELP
int column = 0;
int start_help = -1;
int i;
for (i = 0; i < int(dbx_help.length()); i++)
{
if (column == 0
&& (dbx_help.contains(base, i)
|| dbx_help.contains(dbxenv + " " + base, i)))
{
start_help = i;
break;
}
if (dbx_help[i] == '\n')
column = 0;
else
column++;
}
if (start_help < 0)
{
dbx_help = base;
dbx_help.gsub('_', ' ');
return dbx_help; // Simple default
}
int end_help = -1;
for (i++, column++; i < int(dbx_help.length()); i++)
{
if (column == 0 && !isspace(dbx_help[i]))
{
end_help = i;
break;
}
if (dbx_help[i] == '\n')
column = 0;
else
column++;
}
if (end_help >= 0)
dbx_help = dbx_help.at(start_help, end_help - start_help);
else
dbx_help = dbx_help.from(start_help);
return dbx_help;
}
static void compress_spaces(string& s, int width)
{
char *buffer = new char[s.length() + 1];
char *t = buffer;
int column = 0;
for (int i = 0; i < int(s.length()); i++)
{
if (isspace(s[i]))
{
while (i < int(s.length()) && isspace(s[i]))
i++;
if (width > 0 && column >= width)
{
*t++ = '\n';
column = 0;
}
else
{
*t++ = ' ';
column++;
}
}
if (i < int(s.length()))
{
*t++ = s[i];
column++;
}
}
*t++ = '\0';
s = buffer;
delete[] buffer;
}
// Same, but for usage in help messages
static string get_dbx_help(string dbxenv, string base, int width)
{
string dbx_help = _get_dbx_help(dbxenv, base);
dbx_help = dbx_help.after(base);
strip_leading_space(dbx_help);
if (dbx_help.contains(" - "))
{
dbx_help = dbx_help.after(" - ");
strip_leading_space(dbx_help);
}
else if (dbx_help.contains(" # "))
{
dbx_help = dbx_help.after(" # ");
strip_leading_space(dbx_help);
}
// Remove remaining `# ' prefixes (Solaris DBX)
dbx_help.gsub(" # ", "");
dbx_help.gsub(" # ", " number ");
// Reduce spaces (Solaris DBX & DEC DBX)
compress_spaces(dbx_help, width);
return dbx_help;
}
string get_dbx_help(string dbxenv, string base)
{
return get_dbx_help(dbxenv, base, 60);
}
struct DBXTranslation {
String base;
String doc;
};
static DBXTranslation dbx_translations[] =
{
{"$addrfmt64", "C format for address printing (64bit)"},
{"$assignverify", "Verify assignments"},
{"$byteaccess", "Access memory items less than 4 bytes"},
{"$ctypenames", "Support C type names"},
{"$dispix", "Display pixie instructions"},
{"$fp_precise", "Floating point precise mode"},
{"$framereg", "Registers are with respect to the current frame"},
{"$groupforktoo", "Group fork too"},
{"$hexdoubles", "Display float values as float and hex"},
{"$newevent", "Last new event number"},
{"$newpgrpevent", "Last new pgrp event number"},
{"$newrecord", "Last record number"},
{"$nonstop", "Stop the debugged process"},
{"$pager", "Pager"},
{"$pendingtraps", "Pending traps"},
{"$piaddtohist", "Add playback commands to history"},
{"$print_exception_frame", "Print exception frames"},
{"$shellparameters", "Shell parameters"},
{"$showbreakaddrs", "Show the address of placed breakpoints"},
{"$showfilename", "Show file name when stopping"},
{"$sourcepathrule", "Rule for accessing source paths"},
{"$stacktracelimit", "Stack trace limit"},
{"$stdc", "Support Standard C"},
{"$stepintoall", "Step into all procedures"},
{"$stopformat", "Stop format"},
{"$whereisdsolimit", "Whereis limit"},
{"disassembler_version", "Disassembler version"},
{"follow_fork_inherit", "When following child, inherit events"},
{"follow_fork_mode", "When process forks"},
{"output_list_size", "Lines to print in the `list' command"},
{"rtc_biu_at_exit", "Produce memory report at exit"},
{"run_autostart", "Let `step' and `next' implicitly start the program"},
{"run_io", "Redirect I/O to"},
{"suppress_startup_message", "Suppress startup message below release"}
};
static string get_dbx_doc(string dbxenv, string base)
{
// Some specials
for (int i = 0; i < int(XtNumber(dbx_translations)); i++)
{
if (base == dbx_translations[i].base)
return dbx_translations[i].doc;
}
// Generic help
string dbx_doc = get_dbx_help(dbxenv, base, -1);
strip_leading_space(dbx_doc);
dbx_doc.gsub("etc. ", "etc ");
if (dbx_doc.contains(". "))
dbx_doc = dbx_doc.before(". ");
if (dbx_doc.contains("; "))
dbx_doc = dbx_doc.before("; ");
dbx_doc.gsub("etc ", "etc. ");
#if 0
if (dbx_doc == "")
{
dbx_doc = base;
dbx_doc.gsub('_', ' ');
}
#endif
munch_doc(dbx_doc);
return dbx_doc;
}
static Dimension preferred_width(Widget w)
{
if (w == 0)
return 0;
XtWidgetGeometry size;
size.request_mode = CWWidth;
XtQueryGeometry(w, NULL, &size);
int left_offset = 0;
int right_offset = 0;
XtVaGetValues(w, XmNleftOffset, &left_offset,
XmNrightOffset, &right_offset, NULL);
return size.width + left_offset + right_offset;
}
static Dimension preferred_height(Widget w)
{
if (w == 0)
return 0;
XtWidgetGeometry size;
size.request_mode = CWHeight;
XtQueryGeometry(w, NULL, &size);
return size.height;
}
static void add_settings(Widget form, int& row, Dimension& max_width,
DebuggerType type, EntryType entry_filter,
string gdb_class = "set");
static Widget create_signal_button(Widget label,
string name,
int row,
Widget rightmost = 0)
{
Arg args[15];
Cardinal arg = 0;
MString lbl(capitalize(name));
XtSetArg(args[arg], XmNlabelString, lbl.xmstring()); arg++;
if (rightmost != 0)
{
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_WIDGET); arg++;
XtSetArg(args[arg], XmNrightWidget, rightmost); arg++;
}
else
{
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_FORM); arg++;
}
XtSetArg(args[arg], XmNtopAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNtopPosition, row); arg++;
XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNbottomPosition, row + 1); arg++;
XtSetArg(args[arg], XmNalignment, XmALIGNMENT_CENTER); arg++;
Widget w = 0;
if (name == "send")
{
w = verify(XmCreatePushButton(XtParent(label), name, args, arg));
XtManageChild(w);
XtAddCallback(w, XmNactivateCallback, SendSignalCB, XtPointer(label));
}
else
{
string fullname = string(XtName(label)) + "-" + name;
w = verify(XmCreateToggleButton(XtParent(label), fullname, args, arg));
XtManageChild(w);
XtAddCallback(w, XmNvalueChangedCallback, SignalCB, XtPointer(label));
}
return w;
}
// Get `show' command for settings command CMD
string show_command(const string& cmd, DebuggerType type)
{
string show = "";
switch (type)
{
case GDB:
case PYDB:
show = "show ";
if (cmd.contains("set ", 0))
show += cmd.after("set ");
else if (cmd.contains("directory ", 0))
show += "directories";
else if (cmd.contains("path ", 0))
show += "paths";
else
show += cmd;
if (show.freq(' ') >= 2)
{
// Strip last argument from `show' command
int index = show.index(' ', -1);
show = show.before(index);
}
break;
case DBX:
show = cmd.before(rxwhite);
break;
case PERL:
if (cmd.contains('='))
show = cmd.before('=') + "?";
else
show = cmd + "?";
break;
case JDB:
case XDB:
break;
}
return show;
}
// Add single button
static void add_button(Widget form, int& row, Dimension& max_width,
DebuggerType type, EntryType entry_filter,
string line)
{
if (line == "")
return;
string set_command; // Command to create the setting
string show_command; // Command to display the value
string doc; // Documentation string
string base; // Common base of set_command and show_command
string value; // Current variable value
EntryType e_type; // Type of the entry
bool is_set = true; // Command sets a value
bool is_add = false; // Command adds a value
switch (type)
{
case GDB:
case PYDB:
{
if (!line.contains(" -- ") &&
(entry_filter != SignalEntry || (!line.contains("SIG", 0) &&
!line.contains("all", 0))))
return; // No help line
set_command = line.before(" -- ");
doc = line.after(" -- ");
base = set_command.after(' ');
if (base == "")
base = set_command;
show_command = "show " + base;
if (entry_filter == SignalEntry)
{
if (!line.contains("all", 0) && !line.contains("SIG", 0))
return; // No signal line
// Special handling for signal tables
base = line.before(rxwhite);
doc = line.after(rxwhite);
doc = doc.after(rxwhite);
doc = doc.after(rxwhite);
doc = doc.after(rxwhite);
e_type = SignalEntry;
}
else if (entry_filter != DisplayToggleButtonEntry)
{
if (base == "args")
return; // Already handled in `Run...' editor
if (base == "radix")
return; // Already handled in input- and output-radix
is_set = doc.contains("Set ", 0);
is_add = doc.contains("Add ", 0);
if (!is_set && !is_add)
{
// Generic command or `set variable' - list `set'
// subcommands
add_settings(form, row, max_width,
type, entry_filter, set_command);
return;
}
value = cached_gdb_question(show_command);
if (is_set && value.freq('\n') > 1)
{
// Generic command - list `set' subcommands
add_settings(form, row, max_width,
type, entry_filter, set_command);
return;
}
if (is_set &&
!value.contains(" is ") &&
!value.contains(".\n", -1))
return;
e_type = entry_type(type, base, doc, value);
if (e_type != entry_filter)
return;
if (is_set)
doc = doc.after("Set ");
else if (is_add)
doc = doc.after("Add ");
if (is_add && doc.contains("of "))
doc = doc.after("of ");
}
else
{
if (base == "signals")
return; // We already have `info handle'.
if (base == "watchpoints")
return; // We already have `info breakpoints'.
if (base == "target")
return; // We already have `info files'.
if (base == "address")
return; // `info address' requires an argument.
if (base == "line")
return; // `info line' requires an argument.
// These infos produce too much output for the data window
// to be of any use. Even worse, a data display as large
// as the one generated by `info functions' causes my X
// terminal to crash. - AZ
if (base == "types")
return;
if (base == "functions")
return;
if (base == "variables")
return;
e_type = DisplayToggleButtonEntry;
if (e_type != entry_filter)
return;
strip_leading(doc, "Show ");
strip_leading(doc, "Print ");
strip_leading(doc, "out ");
strip_leading(doc, "the ");
}
munch_doc(doc);
break;
}
case DBX:
{
if (!line.contains("$", 0)
&& !(line.contains(rxidentifier, 0) && islower(line[0])))
return; // No help line
base = line.before(rxwhite);
if (base == "")
return;
if (base == "run_savetty")
return; // Makes no sense under a GUI
value = line.after(rxwhite);
string dbxenv;
if (base[0] == '$')
dbxenv = "set";
else
dbxenv = "dbxenv";
e_type = entry_type(type, base, get_dbx_help(dbxenv, base), value);
if (e_type != entry_filter)
return;
set_command = dbxenv + " " + base;
show_command = set_command + " " + value;
doc = get_dbx_doc(dbxenv, base);
#if RUNTIME_REGEX
static regex rxdont("Do ?n['o]t");
#endif
if (doc.contains(rxdont, 0) && e_type == NumToggleButtonEntry)
{
doc = doc.after(rxdont);
munch_doc(doc);
e_type = NoNumToggleButtonEntry;
}
break;
}
case JDB:
{
// All we have is the `use' command.
e_type = TextFieldEntry;
set_command = "use";
show_command = "use";
doc = "Class path";
value = source_view->class_path();
break;
}
case XDB:
return; // FIXME
case PERL:
{
e_type = TextFieldEntry;
base = line.before(" = ");
strip_space(base);
value = unquote(line.after(" = "));
set_command = "O " + base;
show_command = "O " + base + "?";
doc = base;
break;
}
}
if (e_type != entry_filter)
return;
if (doc == "")
return; // No need to support undocumented stuff
Arg args[15];
int arg;
// Add label
Widget label = 0;
Widget entry = 0;
String set_command_s = new char[set_command.length() + 1];
strcpy(set_command_s, set_command);
MString labelString(doc);
arg = 0;
XtSetArg(args[arg], XmNlabelString, labelString.xmstring()); arg++;
XtSetArg(args[arg], XmNleftAttachment, XmATTACH_FORM); arg++;
XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNbottomPosition, row + 1); arg++;
XtSetArg(args[arg], XmNalignment, XmALIGNMENT_BEGINNING); arg++;
XtCallbackProc callback = 0;
switch (e_type)
{
case OnOffToggleButtonEntry:
callback = SetOnOffCB;
break;
case TrueFalseToggleButtonEntry:
callback = SetTrueFalseCB;
break;
case SensitiveToggleButtonEntry:
callback = SetSensitiveCB;
break;
case NumToggleButtonEntry:
callback = SetNumCB;
break;
case NoNumToggleButtonEntry:
callback = SetNoNumCB;
break;
case DisplayToggleButtonEntry:
callback = SetDisplayCB;
break;
default:
callback = 0;
break;
}
if (callback == 0)
{
if (is_set)
label = verify(XmCreateLabel(form, base, args, arg));
else
label = verify(XmCreateLabel(form, "the" + base, args, arg));
XtManageChild(label);
}
else
{
entry = label =
verify(XmCreateToggleButton(form, set_command, args, arg));
XtManageChild(label);
XtAddCallback(entry, XmNvalueChangedCallback,
callback, XtPointer(set_command_s));
}
// Add help button
arg = 0;
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_FORM); arg++;
XtSetArg(args[arg], XmNtopAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNtopPosition, row); arg++;
XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNbottomPosition, row + 1); arg++;
XtSetArg(args[arg], XmNalignment, XmALIGNMENT_CENTER); arg++;
Widget help = verify(XmCreatePushButton(form, "help", args, arg));
XtManageChild(help);
Widget send = 0;
Widget pass = 0;
Widget print = 0;
Widget stop = 0;
if (e_type == SignalEntry)
{
send = create_signal_button(label, "send", row, help);
pass = create_signal_button(label, "pass", row, send);
print = create_signal_button(label, "print", row, pass);
stop = create_signal_button(label, "stop", row, print);
if (base == "all")
{
set_sensitive(send, False);
XtVaSetValues(pass, XmNset, True, NULL);
XtVaSetValues(print, XmNset, True, NULL);
XtVaSetValues(stop, XmNset, True, NULL);
}
}
// Add entry
switch (e_type)
{
case OnOffToggleButtonEntry:
case TrueFalseToggleButtonEntry:
case SensitiveToggleButtonEntry:
case NumToggleButtonEntry:
case NoNumToggleButtonEntry:
case DisplayToggleButtonEntry:
case SignalEntry:
// All is done
break;
case CheckOptionMenuEntry:
{
// `set check'
arg = 0;
Widget menu = verify(XmCreatePulldownMenu(form, "menu", args, arg));
// Possible options are contained in the help string
string options = cached_gdb_question("help " + set_command);
options = options.from('(');
options = options.before(')');
while (options != "")
{
string option = options.after(0);
option = option.through(rxalpha);
options = options.after(rxalpha);
arg = 0;
Widget button =
verify(XmCreatePushButton(menu, option, args, arg));
XtManageChild(button);
XtAddCallback(button, XmNactivateCallback, SetOptionCB,
set_command_s);
}
MString empty;
arg = 0;
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_WIDGET); arg++;
XtSetArg(args[arg], XmNrightWidget, help); arg++;
XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNbottomPosition, row + 1); arg++;
XtSetArg(args[arg], XmNlabelString, empty.xmstring()); arg++;
XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
XtSetArg(args[arg], XmNspacing, 0); arg++;
XtSetArg(args[arg], XmNsubMenuId, menu); arg++;
entry = verify(XmCreateOptionMenu(form, set_command, args, arg));
XtManageChild(entry);
Widget option_label = XmOptionLabelGadget(entry);
XtUnmanageChild(option_label);
break;
}
case OtherOptionMenuEntry:
case TargetOptionMenuEntry:
{
// set language / set demangle / set architecture / set endian
arg = 0;
Widget menu = verify(XmCreatePulldownMenu(form, "menu", args, arg));
string options;
char separator = '\n';
switch (gdb->type())
{
case GDB:
if (base == "architecture")
{
// Possible options are listed upon `info architecture'
// and separated by ` '.
options = cached_gdb_question("info " + base);
options = "auto" + options.from('\n');
separator = ' ';
}
else if (base == "endian")
{
// Hardwired options
options = "auto\nbig endian\nlittle endian\n";
}
else
{
// Possible options are listed upon `set BASE'
options = cached_gdb_question("set " + base);
}
break;
case DBX:
options = _get_dbx_help("dbxenv", base);
options = options.after('<');
options = options.before('>');
if (options == "")
{
if (base == "follow_fork_mode")
options = "parent|child|both|ask";
}
separator = '|';
break;
case XDB:
case JDB:
case PYDB:
case PERL:
return; // FIXME
}
while (options != "")
{
string option = options;
if (option.contains(separator))
option = option.before(separator);
options = options.after(separator);
strip_space(option);
string label = option;
if (gdb->type() == GDB && option.contains(" "))
{
label = option.after(" ");
label = label.after(rxwhite);
if (option.contains(" auto"))
option = "auto";
else
option = option.before(rxwhite);
}
if (option == "" || option.contains(':', -1))
continue;
MString xmlabel(label);
arg = 0;
if (gdb->type() == GDB)
{
XtSetArg(args[arg], XmNlabelString,
xmlabel.xmstring()); arg++;
}
Widget button =
verify(XmCreatePushButton(menu, option, args, arg));
XtManageChild(button);
XtAddCallback(button, XmNactivateCallback, SetOptionCB,
set_command_s);
}
MString empty;
arg = 0;
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_WIDGET); arg++;
XtSetArg(args[arg], XmNrightWidget, help); arg++;
XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNbottomPosition, row + 1); arg++;
XtSetArg(args[arg], XmNlabelString, empty.xmstring()); arg++;
XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
XtSetArg(args[arg], XmNspacing, 0); arg++;
XtSetArg(args[arg], XmNsubMenuId, menu); arg++;
entry = verify(XmCreateOptionMenu(form, set_command, args, arg));
XtManageChild(entry);
Widget option_label = XmOptionLabelGadget(entry);
XtUnmanageChild(option_label);
break;
}
case TextFieldEntry:
{
// Some other value
arg = 0;
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_WIDGET); arg++;
XtSetArg(args[arg], XmNrightWidget, help); arg++;
XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNbottomPosition, row + 1); arg++;
entry = verify(XmCreateTextField(form, set_command, args, arg));
XtManageChild(entry);
XtAddCallback(entry, XmNactivateCallback,
SetTextCB, XtPointer(set_command_s));
}
}
Widget rightmost = help;
if (entry != label)
rightmost = entry;
if (stop != 0)
rightmost = stop;
Dimension width = preferred_width(label);
if (entry != label)
width += preferred_width(entry);
width += preferred_width(send);
width += preferred_width(stop);
width += preferred_width(print);
width += preferred_width(pass);
width += preferred_width(help);
// Add leader
// Align leader with label font baseline
XmFontList font_list = 0;
XmString xmlabel = 0;
Dimension marginHeight = 0;
Dimension marginTop = 0;
XtVaGetValues(label,
XmNfontList, &font_list,
XmNlabelString, &xmlabel,
XmNmarginHeight, &marginHeight,
XmNmarginTop, &marginTop,
NULL);
Dimension baseline = XmStringBaseline(font_list, xmlabel);
static const Dimension leaderHeight = 2;
Dimension top_offset = baseline + marginHeight + marginTop - leaderHeight;
XmStringFree(xmlabel);
arg = 0;
XtSetArg(args[arg], XmNseparatorType, XmSINGLE_DASHED_LINE); arg++;
XtSetArg(args[arg], XmNleftAttachment, XmATTACH_WIDGET); arg++;
XtSetArg(args[arg], XmNleftWidget, label); arg++;
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_WIDGET); arg++;
XtSetArg(args[arg], XmNrightWidget, rightmost); arg++;
XtSetArg(args[arg], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); arg++;
XtSetArg(args[arg], XmNtopWidget, label); arg++;
XtSetArg(args[arg], XmNtopOffset, top_offset); arg++;
Widget leader = verify(XmCreateSeparator(form, "leader", args, arg));
XtManageChild(leader);
// Add help callback
if (e_type == SignalEntry)
{
XtAddCallback(help, XmNactivateCallback,
HelpOnSignalCB, XtPointer(label));
}
else
{
XtAddCallback(help, XmNactivateCallback,
HelpOnThisCB, XtPointer(entry));
}
if (e_type == SignalEntry)
{
if (base != "all")
{
// Initialize button
process_handle(line, true);
// Register buttons
signals_entries += stop;
signals_entries += print;
signals_entries += pass;
}
}
else if (e_type != DisplayToggleButtonEntry)
{
// Make entry insensitive if part of initialization commands.
string init = app_data.gdb_init_commands;
int idx = init.index(set_command);
if (idx == 0 || idx > 0 && init[idx - 1] == '\n')
{
set_sensitive(entry, False);
set_sensitive(label, False);
set_sensitive(leader, False);
}
// Initialize button
process_show(show_command, value, true);
// Register entry
settings_entries += entry;
settings_entry_types += e_type;
}
else
{
// Register entry
infos_entries += entry;
}
max_width = max(width, max_width);
row++;
}
// Add separator
static void add_separator(Widget form, int& row)
{
Arg args[10];
int arg = 0;
XtSetArg(args[arg], XmNleftAttachment, XmATTACH_FORM); arg++;
XtSetArg(args[arg], XmNrightAttachment, XmATTACH_FORM); arg++;
XtSetArg(args[arg], XmNtopAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNtopPosition, row); arg++;
XtSetArg(args[arg], XmNbottomAttachment, XmATTACH_POSITION); arg++;
XtSetArg(args[arg], XmNbottomPosition, row + 1); arg++;
Widget sep = verify(XmCreateSeparator(form, "sep", args, arg));
XtManageChild(sep);
row++;
}
// Add buttons
static void add_settings(Widget form, int& row, Dimension& max_width,
DebuggerType type, EntryType entry_filter,
string gdb_class)
{
string commands;
switch (type)
{
case GDB:
case PYDB:
if (entry_filter == SignalEntry)
commands = cached_gdb_question("info handle");
else
commands = cached_gdb_question("help " + gdb_class);
break;
case XDB:
commands = cached_gdb_question("I");
break;
case DBX:
{
// Some DBXes know `dbxenv'; others know `set'. We cannot use
// is_valid() or likewise here, since the output may contain
// `error' strings that would cause is_valid() to fail. Just
// try both and use the longer reply (may take time).
// Exception: on Sun DBX, `set' causes a dump of all
// environment variables. Don't use this.
string dbxenv = cached_gdb_question("dbxenv", -1);
string set = cached_gdb_question("set", -1);
if (dbxenv.length() > set.length() ||
set.contains(DDD_NAME "=" ddd_NAME))
{
commands = dbxenv;
}
else
{
commands = set;
}
break;
}
case JDB:
{
// In JDB, all we have is the `use' command.
add_button(form, row, max_width, type, entry_filter, "use");
break;
}
case PERL:
commands = cached_gdb_question("O");
break;
}
if (type == GDB && entry_filter == SignalEntry)
{
// Add an entry for `handle all'
add_button(form, row, max_width, type, entry_filter,
"all\tYes\tYes\tYes\tAll Signals");
// add_separator(form, row);
}
while (commands != "")
{
string line = commands.before('\n');
commands = commands.after('\n');
add_button(form, row, max_width, type, entry_filter, line);
}
}
// Reload all settings
static void reload_all_settings()
{
for (int i = 0; i < settings_entries.size(); i++)
{
Widget entry = settings_entries[i];
string cmd = string(XtName(entry)) + " dummy";
string show = show_command(cmd, gdb->type());
string value = gdb_question(show);
if (value != NO_GDB_ANSWER)
process_show(show, value, true);
}
}
void update_settings()
{
if (settings_panel != 0 && XtIsManaged(settings_panel))
{
reload_all_settings();
need_reload_settings = false;
}
}
// Reset settings
static void ResetSettingsCB (Widget, XtPointer, XtPointer)
{
for (int i = 0; i < settings_entries.size(); i++)
{
Widget entry = settings_entries[i];
if (settings_initial_values[entry] != settings_values[entry])
gdb_set_command(XtName(entry), settings_initial_values[entry]);
}
}
// Reset signals
static void ResetSignalsCB (Widget, XtPointer, XtPointer)
{
for (int i = 0; i < signals_entries.size(); i++)
{
Widget entry = signals_entries[i];
if (signals_initial_values[entry] != signals_values[entry])
{
bool set = (signals_initial_values[entry] == "yes");
gdb_command(handle_command(entry, set));
}
}
}
// Delete all infos
static void DeleteAllInfosCB (Widget, XtPointer, XtPointer)
{
for (int i = 0; i < infos_entries.size(); i++)
{
Widget entry = infos_entries[i];
XmToggleButtonSetState(entry, False, True);
}
}
// Fetch help for specific COMMAND
static string get_help_line(string command, DebuggerType type)
{
(void) type;
string reply = cached_gdb_question("help " + command);
reply = reply.before('\n');
if (reply.contains('.'))
reply = reply.before('.');
reply = command + " -- " + reply;
return reply;
}
// ClipWindow translation stuff
static void ClipDo(Widget w, XEvent *event,
String *params, Cardinal *num_params)
{
Widget scroll = XtParent(w);
Widget scrollbar = 0;
XtVaGetValues(scroll, XmNverticalScrollBar, &scrollbar, NULL);
XtCallActionProc(scrollbar, params[0], event, params + 1, *num_params - 1);
}
static void fix_clip_window_translations(Widget scroll)
{
// The scrolled clip window grabs translations for osfBeginLine
// and osfEndLine, which we need in our text fields. Since we
// cannot selectively disable these translations, we disable all
// translations ...
Widget clip = 0;
XtVaGetValues(scroll, XmNclipWindow, &clip, NULL);
XtUninstallTranslations(clip);
// ... and provide a minimal set instead.
static bool have_clip_actions = false;
if (!have_clip_actions)
{
static XtActionsRec clip_actions[] = {
{"clip-do", ClipDo}
};
XtAppAddActions(XtWidgetToApplicationContext(scroll),
clip_actions, XtNumber(clip_actions));
have_clip_actions = true;
}
static char clip_translations[] =
"<Key>osfPageUp: clip-do(PageUpOrLeft, 0)\n"
"<Key>osfPageDown: clip-do(PageDownOrRight, 0)\n"
"Ctrl <Key>osfBeginLine: clip-do(TopOrBottom)\n"
"Ctrl <Key>osfEndLine: clip-do(TopOrBottom)\n";
XtTranslations tr = XtParseTranslationTable(clip_translations);
XtVaSetValues(clip, XmNtranslations, tr, NULL);
}
// Create settings or infos editor
static Widget create_panel(DebuggerType type, SettingsType stype)
{
string title_msg;
string dialog_name;
switch (stype)
{
case SETTINGS:
title_msg = gdb->title() + " Settings";
dialog_name = "settings";
break;
case INFOS:
title_msg = gdb->title() + " Status Displays";
dialog_name = "infos";
break;
case SIGNALS:
title_msg = gdb->title() + " Signal Handling";
dialog_name = "signals";
break;
}
StatusDelay delay("Retrieving " + title_msg);
Arg args[10];
int arg;
arg = 0;
XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
Widget panel = verify(XmCreatePromptDialog(find_shell(),
dialog_name, args, arg));
Delay::register_shell(panel);
if (lesstif_version <= 79)
XtUnmanageChild(XmSelectionBoxGetChild(panel, XmDIALOG_APPLY_BUTTON));
// Remove old prompt
XtUnmanageChild(XmSelectionBoxGetChild(panel, XmDIALOG_TEXT));
XtUnmanageChild(XmSelectionBoxGetChild(panel, XmDIALOG_SELECTION_LABEL));
XtAddCallback(panel, XmNhelpCallback, ImmediateHelpCB, 0);
XtAddCallback(panel, XmNokCallback, UnmanageThisCB,
XtPointer(panel));
Widget cancel = XmSelectionBoxGetChild(panel, XmDIALOG_CANCEL_BUTTON);
switch (stype)
{
case SETTINGS:
XtRemoveAllCallbacks(cancel, XmNactivateCallback);
XtAddCallback(cancel, XmNactivateCallback, ResetSettingsCB, 0);
XtVaSetValues(panel, XmNdefaultButton, Widget(0), NULL);
break;
case INFOS:
XtRemoveAllCallbacks(cancel, XmNactivateCallback);
XtAddCallback(cancel, XmNactivateCallback, DeleteAllInfosCB, 0);
break;
case SIGNALS:
XtRemoveAllCallbacks(cancel, XmNactivateCallback);
XtAddCallback(cancel, XmNactivateCallback, ResetSignalsCB, 0);
XtVaSetValues(panel, XmNdefaultButton, Widget(0), NULL);
break;
}
// Add a rowcolumn widget
arg = 0;
XtSetArg(args[arg], XmNborderWidth, 0); arg++;
XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
XtSetArg(args[arg], XmNspacing, 0); arg++;
Widget column =
verify(XmCreateRowColumn(panel, "column", args, arg));
XtManageChild(column);
// Add a label
arg = 0;
MString xmtitle(title_msg);
XtSetArg(args[arg], XmNlabelString, xmtitle.xmstring()); arg++;
Widget title = verify(XmCreateLabel(column, "title", args, arg));
XtManageChild(title);
// Add a scrolled window.
arg = 0;
XtSetArg(args[arg], XmNscrollingPolicy, XmAUTOMATIC); arg++;
Widget scroll =
verify(XmCreateScrolledWindow(column, "scroll", args, arg));
fix_clip_window_translations(scroll);
// Add a form.
arg = 0;
Widget form = verify(XmCreateForm(scroll, "form", args, arg));
switch (stype)
{
case SETTINGS:
settings_form = form;
break;
case SIGNALS:
signals_form = form;
break;
case INFOS:
break;
}
// Add setting buttons to the button box.
Dimension max_width = 0;
int row = 0;
int last_row = row;
switch (stype)
{
case SETTINGS:
add_settings(form, row, max_width, type, OnOffToggleButtonEntry);
add_settings(form, row, max_width, type, TrueFalseToggleButtonEntry);
add_settings(form, row, max_width, type, SensitiveToggleButtonEntry);
add_settings(form, row, max_width, type, NumToggleButtonEntry);
add_settings(form, row, max_width, type, NoNumToggleButtonEntry);
if (row != last_row)
add_separator(form, row);
last_row = row;
add_settings(form, row, max_width, type, TargetOptionMenuEntry);
if (row != last_row)
add_separator(form, row);
last_row = row;
add_settings(form, row, max_width, type, OtherOptionMenuEntry);
if (row != last_row)
add_separator(form, row);
last_row = row;
add_settings(form, row, max_width, type, CheckOptionMenuEntry);
if (row != last_row)
add_separator(form, row);
if (type == GDB)
{
last_row = row;
add_button(form, row, max_width, type, TextFieldEntry,
get_help_line("dir", type));
add_button(form, row, max_width, type, TextFieldEntry,
get_help_line("path", type));
if (row != last_row)
add_separator(form, row);
}
add_settings(form, row, max_width, type, TextFieldEntry);
break;
case INFOS:
add_settings(form, row, max_width, type,
DisplayToggleButtonEntry, "info");
break;
case SIGNALS:
add_settings(form, row, max_width, type, SignalEntry, "signals");
break;
}
// Clean up cached documentation stuff
clear_gdb_question_cache();
// Setup values
switch (stype)
{
case SETTINGS:
reset_settings_button = cancel;
update_reset_settings_button();
break;
case INFOS:
reset_infos_button = cancel;
update_infos();
break;
case SIGNALS:
reset_signals_button = cancel;
update_reset_signals_button();
break;
}
// Set number of rows
if (row > 0)
XtVaSetValues(form, XmNfractionBase, row, NULL);
XtManageChild(form);
// Set sizes
max_width += EXTRA_SPACE;
XtVaSetValues(form,
XmNwidth, max_width, NULL);
#if XmVersion > 1001
Dimension height = preferred_height(form);
#else
// OSF/Motif 1.1 returns a bad value in PREFERRED_HEIGHT
(void) preferred_height;
Dimension height = MAX_HEIGHT + 1;
#endif
Widget vertical_scroll_bar = 0;
Dimension spacing = 4;
XtVaGetValues(scroll,
XmNverticalScrollBar, &vertical_scroll_bar,
XmNspacing, &spacing,
NULL);
if (height + spacing > MAX_HEIGHT)
{
// Form must be scrolled
Dimension scrollbar_width = 15; // Additional space for scrollbar
if (vertical_scroll_bar != 0)
{
XtWidgetGeometry size;
size.request_mode = CWWidth;
XtQueryGeometry(vertical_scroll_bar, NULL, &size);
scrollbar_width = size.width;
}
XtVaSetValues(scroll,
XmNheight, MAX_HEIGHT,
XmNwidth, max_width +
spacing + scrollbar_width + EXTRA_WIDTH,
NULL);
}
else
{
// Form need not be scrolled
XtVaSetValues(scroll,
XmNheight, height + spacing,
XmNwidth, max_width + spacing,
NULL);
}
XtManageChild(scroll);
InstallButtonTips(panel);
return panel;
}
// Create settings editor
static Widget create_settings(DebuggerType type)
{
check_options_file();
if (settings_panel == 0 && gdb->isReadyWithPrompt() && gdb->type() == type)
{
// We place a delay here such that we show only one delay for
// both getting the settings and the command definitions.
StatusDelay delay("Retrieving " + gdb->title() + " Settings");
settings_panel = create_panel(type, SETTINGS);
// Get the command definitions, too. These must be included
// in saving GDB state.
get_defines(type);
}
else if (settings_panel != 0 && need_reload_settings)
{
reload_all_settings();
need_reload_settings = false;
}
return settings_panel;
}
// Create infos editor
static Widget create_infos(DebuggerType type)
{
check_options_file();
if (infos_panel == 0 && gdb->isReadyWithPrompt() && gdb->type() == type)
infos_panel = create_panel(type, INFOS);
return infos_panel;
}
// Reload all signals
static void reload_all_signals()
{
check_options_file();
string info = gdb_question("info handle");
if (info != NO_GDB_ANSWER)
process_handle(info, true);
}
void update_signals()
{
if (signals_panel != 0 && XtIsManaged(signals_panel))
{
reload_all_signals();
need_reload_signals = false;
}
}
// Create signal editor
static Widget create_signals(DebuggerType type)
{
check_options_file();
if (signals_panel == 0 && gdb->isReadyWithPrompt() && gdb->type() == type)
{
signals_panel = create_panel(type, SIGNALS);
}
else if (signals_panel != 0 && need_reload_signals)
{
reload_all_signals();
need_reload_signals = false;
}
return signals_panel;
}
// Popup editor for debugger settings
void dddPopupSettingsCB (Widget, XtPointer, XtPointer)
{
Widget settings = create_settings(gdb->type());
if (settings == 0)
return;
manage_and_raise(settings);
}
// Popup editor for debugger infos
void dddPopupInfosCB (Widget, XtPointer, XtPointer)
{
Widget infos = create_infos(gdb->type());
if (infos == 0)
return;
manage_and_raise(infos);
}
// Popup editor for debugger infos
void dddPopupSignalsCB (Widget, XtPointer, XtPointer)
{
Widget signals = create_signals(gdb->type());
if (signals == 0)
return;
manage_and_raise(signals);
}
// True iff settings might have changed
bool need_settings()
{
return settings_panel != 0;
}
// Reset it all
void reset_settings()
{
if (settings_panel != 0)
need_reload_settings = true;
}
// True iff signals might have changed
bool need_signals()
{
return signals_panel != 0;
}
// Reset it all
void reset_signals()
{
if (signals_panel != 0)
need_reload_signals = true;
}
static void get_setting(ostream& os, DebuggerType type,
const string& base, string value)
{
if (value == "unlimited")
value = "0";
switch (type)
{
case GDB:
case DBX:
if (base == "dbxenv disassembler_version" ||
base == "dbxenv rtc_error_log_file_name" ||
base == "dbxenv output_log_file_name")
{
// Do nothing (DBX) - dependent on the current machine etc.
}
else if (base == "set remotelogfile" && value == "")
{
// This is the default setting - do nothing (GDB)
}
else if (base == "set remotedevice" && value == "")
{
// This is the default setting - do nothing (GDB)
}
else if (base == "set solib-absolute-prefix" && value == "")
{
// GDB 4.17 bug: `set solib-absolute-prefix' without arg
// does not work. Just leave it as default setting.
}
else if (base.contains("set $cur", 0) ||
base.contains("set $new", 0) ||
base.contains("set $pid", 0))
{
// Do nothing - dependent on the current file (DEC DBX)
}
else if (base == "set $defaultin" ||
base == "set $defaultout" ||
base == "set $historyevent")
{
// Do nothing - dependent on the current state (SGI DBX)
}
else if (base.contains("set $", 0))
{
// Add setting (DBX).
os << base << " = " << value << '\n';
}
else if (base.contains("set ", 0))
{
// Add setting (GDB).
// Jonathan Edwards <edwards@intranet.com> states:
// DDD gets all confused with gdb radix settings. When
// it configures gdb it assumes a decimal radix. But
// if you specify a non-decimal radix, then all
// settings made after that are incorrect. I would
// suggest prefixing "0d" to all decimal numbers.
if (value.matches(rxint) && atoi(value) > 1)
value.prepend("0d");
os << base << " " << value << '\n';
}
else if (base.contains("dbxenv ", 0))
{
// Add setting (DBX).
os << base << " " << value << '\n';
}
else
{
// `dir' and `path' values are not saved, since they are
// dependent on the current machine and the current
// executable (GDB).
}
break;
case PERL:
// Add setting
os << base << '=' << value << '\n';
break;
case XDB:
case JDB:
case PYDB:
// Add setting
os << base << ' ' << value << '\n';
break;
}
}
// Fetch GDB settings string
string get_settings(DebuggerType type)
{
Widget settings = create_settings(type);
if (settings == 0)
return "";
ostrstream command;
for (int i = 0; i < settings_entries.size(); i++)
{
Widget entry = settings_entries[i];
string value = settings_values[entry];
get_setting(command, type, XtName(entry), value);
}
return string(command);
}
// Fetch GDB signal handling string
string get_signals(DebuggerType type)
{
if (type != GDB)
return ""; // Not supported yet
create_signals(type);
string commands = "";
for (int i = 0; i < signals_entries.size(); i++)
{
Widget entry = signals_entries[i];
bool set = (signals_values[entry] == "yes");
commands += handle_command(entry, set) + "\n";
}
return commands;
}
//-----------------------------------------------------------------------
// Trace Command Definitions
//-----------------------------------------------------------------------
static bool save_defines_needed = false;
static bool load_defines_needed = true;
// Call this function if command definitions have changed
void set_need_save_defines(bool val)
{
save_defines_needed = val;
}
bool need_save_defines()
{
return save_defines_needed;
}
void set_need_load_defines(bool val)
{
load_defines_needed = val;
}
bool need_load_defines()
{
return load_defines_needed;
}
static StringStringAssoc defs;
static bool update_define(const string& command, bool undo = false)
{
// We have a new command - update user buttons.
clear_help_cache(command);
update_user_buttons();
string text = gdb_question("show user " + command);
if (text == NO_GDB_ANSWER)
return false;
if (undo)
{
// Add `undoing' command
undo_buffer.add_command("define " + command + "\n" +
defs[command] + "end");
}
// `Undefined' means command is undefined; `Not a user command'
// means this is a built-in command.
if (text.contains("Undefined", 0) || text.contains("Not a", 0))
{
defs.remove(command);
return true;
}
string def = "";
while (text != "")
{
string line = text.before('\n');
text = text.after('\n');
if (line.length() > 0 && isspace(line[0]))
{
line = line.after(rxwhite);
strip_auto_command_prefix(line);
def += line + "\n";
}
}
defs[command] = def;
return true;
}
static void update_defines()
{
if (!need_load_defines())
return;
StatusDelay delay("Retrieving Command Definitions");
string commands = gdb_question("help user-defined");
if (commands == NO_GDB_ANSWER)
return;
while (commands != "")
{
string line = commands.before('\n');
commands = commands.after('\n');
if (!line.contains(" -- "))
continue; // No help line
string command = line.before(" -- ");
bool ok = update_define(command);
if (!ok)
return;
}
set_need_load_defines(false);
}
// Get current definitions
string get_defines(DebuggerType type)
{
if (type != GDB)
return ""; // Not supported yet
update_defines();
// We have to get the current value of the `confirm' setting
create_settings(type);
string defines = "";
// We have to turn off confirmation during command (re-)definition
string confirm_value = "on";
if (settings_form != 0)
{
Widget confirm_w = command_to_widget(settings_form, "set confirm");
if (confirm_w != 0)
confirm_value = settings_values[confirm_w];
}
if (confirm_value == "on")
defines += "set confirm off\n";
for (StringStringAssocIter iter(defs); iter.ok(); iter++)
{
string def = iter.value();
if (def == "")
{
// We don't save empty definitions, such that users have a
// way to get rid of them.
}
else
{
defines += "define " + iter.key() + "\n" + def + "end\n";
}
}
if (confirm_value == "on")
defines += "set confirm on\n";
return defines;
}
// True iff COMMAND is a defined command
bool is_defined_cmd(const string& command)
{
if (gdb->type() != GDB)
return false; // Not supported yet
update_defines();
string word = command;
strip_space(word);
if (word.contains(' '))
word = word.before(' ');
return defs.has(word);
}
//-----------------------------------------------------------------------
// Edit Command Definitions
//-----------------------------------------------------------------------
// Data
static Widget name_w; // Name of defined command
static Widget arg_w; // `()' toggle
static Widget record_w; // `Record' button
static Widget end_w; // `End' button
static Widget edit_w; // `Edit>>' button
static Widget editor_w; // Command definition editor
static Widget apply_w; // `Apply' button
static string current_name()
{
String name_s = XmTextFieldGetString(name_w);
string name(name_s);
XtFree(name_s);
strip_space(name);
return name;
}
// Button stuff
// Name of GDB argument
static const string arg0 = "$arg0";
static bool is_arg_command(const string& name)
{
return defs.has(name) && defs[name].contains(arg0);
}
static void add_button(string name, String& menu)
{
if (XmToggleButtonGetState(arg_w) || is_arg_command(name))
name += " ()";
string s = menu;
if (s != "" && !s.contains('\n', -1))
s += '\n';
s += name + "\n";
menu = (String)XtNewString(s.chars());
}
static void remove_button(string name, String& menu)
{
string s = string("\n") + menu;
s.gsub("\n" + name + "\n", string("\n"));
s.gsub("\n" + name + " ()\n", string("\n"));
menu = (String)XtNewString(s.chars() + 1);
}
enum ButtonTarget { ConsoleTarget, SourceTarget, DataTarget };
static String &target_string(ButtonTarget t)
{
switch (t)
{
case ConsoleTarget:
return app_data.console_buttons;
case SourceTarget:
return app_data.source_buttons;
case DataTarget:
return app_data.data_buttons;
}
static String null = 0;
return null;
}
static void ToggleButtonCB(Widget, XtPointer client_data, XtPointer call_data)
{
string name = current_name();
ButtonTarget target = (ButtonTarget) (long) client_data;
XmToggleButtonCallbackStruct *info =
(XmToggleButtonCallbackStruct *)call_data;
String& str = target_string(target);
if (info->set)
{
add_button(name, str);
}
else
{
remove_button(name, str);
}
update_user_buttons();
}
MMDesc button_menu[] =
{
{ "console", MMToggle,
{ ToggleButtonCB, XtPointer(ConsoleTarget) }, 0, 0, 0, 0},
{ "source", MMToggle,
{ ToggleButtonCB, XtPointer(SourceTarget) }, 0, 0, 0, 0},
{ "data", MMToggle,
{ ToggleButtonCB, XtPointer(DataTarget) }, 0, 0, 0, 0},
MMEnd
};
static void refresh_toggle(ButtonTarget t)
{
Widget& w = button_menu[t].widget;
string s = string("\n") + target_string(t);
string name = current_name();
Boolean old_state;
XtVaGetValues(w, XmNset, &old_state, NULL);
Boolean new_state =
s.contains("\n" + name + "\n") || s.contains("\n" + name + " ()\n");
if (old_state != new_state)
XtVaSetValues(w, XmNset, new_state, NULL);
#if 1
set_sensitive(w, name != "");
#else
string answer = gdbHelp(name);
if (answer != NO_GDB_ANSWER)
{
set_sensitive(w, is_known_command(answer));
}
#endif
}
static void refresh_toggles()
{
refresh_toggle(SourceTarget);
refresh_toggle(DataTarget);
refresh_toggle(ConsoleTarget);
}
static void refresh_combo_box()
{
if (name_w == 0)
return; // Not yet created
// Refresh combo box
StringArray commands;
for (StringStringAssocIter iter(defs); iter.ok(); iter++)
commands += iter.key();
smart_sort(commands);
ComboBoxSetList(name_w, commands);
}
// Editing stuff
// Text field has changed -- update buttons
void UpdateDefinePanelCB(Widget w, XtPointer, XtPointer)
{
if (name_w == 0)
return; // Not yet created
string name = current_name();
set_sensitive(record_w, !gdb->recording() && name != "");
set_sensitive(apply_w, !gdb->recording() && name != "");
set_sensitive(end_w, gdb->recording());
set_sensitive(edit_w, !gdb->recording() && name != "");
set_sensitive(name_w, !gdb->recording());
set_sensitive(XtParent(name_w), !gdb->recording());
set_sensitive(editor_w, !gdb->recording());
set_arg();
if (w != 0 && !gdb->recording() && defs.has(name))
XmToggleButtonSetState(arg_w, is_arg_command(name), False);
refresh_toggles();
}
static void update_defineHP(Agent *, void *client_data, void *call_data)
{
bool gdb_ready = bool(call_data);
if (gdb_ready && !gdb->recording())
{
char *c = (char *)client_data;
bool ok = update_define(c, true);
if (ok)
{
// Update buttons
UpdateDefinePanelCB();
refresh_combo_box();
// Don't get called again
gdb->removeHandler(ReadyForQuestion, update_defineHP, client_data);
delete[] c;
}
}
else
{
UpdateDefinePanelCB();
}
}
// This one is called by send_gdb_command() when seeing `define'
void update_define_later(const string& command)
{
char *c = new char[command.length() + 1];
strcpy(c, (char *)command);
gdb->addHandler(ReadyForQuestion, update_defineHP, (void *)c);
UpdateDefinePanelCB();
}
static void RecordCommandDefinitionCB(Widget w, XtPointer, XtPointer)
{
string name = current_name();
gdb_command("define " + name, w);
}
// Activate the button given in CLIENT_DATA
static void ActivateCB(Widget, XtPointer client_data,
XtPointer call_data)
{
XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *)call_data;
Widget button = Widget(client_data);
XtCallActionProc(button, "ArmAndActivate", cbs->event, (String *)0, 0);
}
static void EndCommandDefinitionCB(Widget w, XtPointer, XtPointer)
{
gdb_command("end", w);
}
static void DoneEditCommandDefinitionCB(Widget w, XtPointer, XtPointer)
{
if (!XtIsManaged(XtParent(editor_w)))
return;
string name = current_name();
XtUnmanageChild(XtParent(editor_w));
set_sensitive(name_w, True);
set_sensitive(XtParent(name_w), True);
MString label = "Edit " + MString(">>", "small");
set_label(edit_w, label);
String _commands = XmTextGetString(editor_w);
string cmd = _commands;
XtFree(_commands);
if (!cmd.contains('\n', -1))
cmd += '\n';
if ((cmd != "" && !defs.has(name)) || cmd != defs[name])
{
StringArray commands;
while (cmd != "")
{
string c = cmd.before('\n');
if (c != "")
commands += c;
cmd = cmd.after('\n');
}
// This might require confirmation. Don't change anything.
set_sensitive(edit_w, false);
set_sensitive(record_w, false);
set_sensitive(end_w, false);
gdb_command("define " + name, w);
for (int j = 0; j < commands.size(); j++)
gdb_command(commands[j], w);
gdb_command("end", w);
update_define_later(name);
}
}
static void EditCommandDefinitionCB(Widget, XtPointer, XtPointer)
{
if (XtIsManaged(XtParent(editor_w)))
return;
string name = current_name();
// update_define(name);
set_sensitive(name_w, False);
set_sensitive(XtParent(name_w), False);
string def = "";
if (defs.has(name))
def = defs[name];
XmTextSetString(editor_w, (String)def);
XtManageChild(XtParent(editor_w));
MString label = "Edit " + MString("<<", "small");
set_label(edit_w, label);
}
static void ToggleEditCommandDefinitionCB(Widget w, XtPointer client_data,
XtPointer call_data)
{
if (XtIsManaged(XtParent(editor_w)))
DoneEditCommandDefinitionCB(w, client_data, call_data);
else
EditCommandDefinitionCB(w, client_data, call_data);
}
// Apply the given command
static void ApplyCB(Widget, XtPointer, XtPointer)
{
string cmd = current_name();
if (cmd == "")
return;
if (XmToggleButtonGetState(arg_w))
cmd += " " + source_arg->get_string();
gdb_command(cmd);
}
// Force argument to `()'
static void ForceArg0HP(void *, void *, void *)
{
static bool called = false;
if (called)
return;
called = true;
set_arg();
called = false;
}
static void set_arg()
{
static string saved_arg;
static bool have_saved_arg = false;
if (gdb->recording() && XmToggleButtonGetState(arg_w))
{
if (!have_saved_arg)
{
saved_arg = source_arg->get_string();
have_saved_arg = true;
source_arg->set_string(arg0);
reset_status_lock();
MString msg =
rm("Using ") + bf("()") + rm(" as symbolic argument");
set_status_mstring(msg);
}
source_arg->addHandler(Changed, ForceArg0HP);
set_sensitive(source_arg->top(), False);
}
else
{
source_arg->removeHandler(Changed, ForceArg0HP);
set_sensitive(source_arg->top(), True);
if (have_saved_arg)
{
source_arg->set_string(saved_arg);
have_saved_arg = false;
reset_status_lock();
MString msg =
rm("Using ") + bf("()") + rm(" as literal argument");
set_status_mstring(msg);
}
}
}
static void ToggleArgCB(Widget, XtPointer, XtPointer)
{
set_arg();
}
static MMDesc commands_menu[] =
{
{ "record", MMPush,
{ RecordCommandDefinitionCB, 0 }, 0, &record_w, 0, 0 },
{ "end", MMPush | MMInsensitive,
{ EndCommandDefinitionCB, 0 }, 0, &end_w, 0, 0},
{ "edit", MMPush,
{ ToggleEditCommandDefinitionCB, 0 }, 0, &edit_w, 0, 0 },
MMEnd
};
static MMDesc name_menu[] =
{
{ "name", MMComboBox | MMUnmanagedLabel,
{ UpdateDefinePanelCB, 0 }, 0, &name_w, 0, 0 },
{ "arg", MMToggle, { ToggleArgCB, 0 }, 0, &arg_w, 0, 0 },
MMEnd
};
static MMDesc panel_menu[] =
{
{ "name", MMButtonPanel, MMNoCB, name_menu, 0, 0, 0 },
{ "commands", MMButtonPanel, MMNoCB, commands_menu, 0, 0, 0 },
{ "button", MMButtonPanel, MMNoCB, button_menu, 0, 0, 0 },
MMEnd
};
// Define command
void dddDefineCommandCB(Widget w, XtPointer, XtPointer)
{
static Widget dialog = 0;
if (dialog == 0)
{
Arg args[10];
int arg = 0;
XtSetArg(args[arg], XmNautoUnmanage, False); arg++;
dialog = verify(XmCreatePromptDialog(find_shell(w),
"define_command",
args, arg));
XtVaSetValues(dialog, XmNdefaultButton, Widget(0), NULL);
// Remove old prompt
Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
XtUnmanageChild(text);
Widget old_label =
XmSelectionBoxGetChild(dialog, XmDIALOG_SELECTION_LABEL);
XtUnmanageChild(old_label);
Delay::register_shell(dialog);
XtUnmanageChild(XmSelectionBoxGetChild(dialog,
XmDIALOG_CANCEL_BUTTON));
apply_w = XmSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON);
XtManageChild(apply_w);
arg = 0;
XtSetArg(args[arg], XmNorientation, XmHORIZONTAL); arg++;
Widget form = XmCreateRowColumn(dialog, "form", args, arg);
XtManageChild(form);
Widget panel = MMcreatePanel(form, "panel", panel_menu);
XtVaSetValues(panel,
XmNmarginWidth, 0,
XmNmarginHeight, 0,
NULL);
arg = 0;
XtSetArg(args[arg], XmNeditMode, XmMULTI_LINE_EDIT); arg++;
editor_w = XmCreateScrolledText(form, "text", args, arg);
XtUnmanageChild(XtParent(editor_w));
XtManageChild(editor_w);
MMaddCallbacks(panel_menu);
InstallButtonTips(panel);
MMadjustPanel(panel_menu);
XtAddCallback(dialog, XmNokCallback, UnmanageThisCB,
XtPointer(dialog));
XtAddCallback(dialog, XmNokCallback, DoneEditCommandDefinitionCB,
XtPointer(0));
XtAddCallback(dialog, XmNapplyCallback, ApplyCB, NULL);
XtAddCallback(dialog, XmNhelpCallback, ImmediateHelpCB, NULL);
XtAddCallback(name_w, XmNactivateCallback, ActivateCB,
XtPointer(record_w));
set_need_load_defines(true);
update_defines();
}
UpdateDefinePanelCB();
refresh_combo_box();
manage_and_raise(dialog);
}