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
/
status.C
< prev
next >
Wrap
C/C++ Source or Header
|
1998-12-06
|
16KB
|
629 lines
// $Id: status.C,v 1.50.4.1 1998/12/06 13:53:41 zeller Exp $ -*- C++ -*-
// Show messages in status line
// 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 status_rcsid[] =
"$Id: status.C,v 1.50.4.1 1998/12/06 13:53:41 zeller Exp $";
#ifdef __GNUG__
#pragma implementation
#endif
#include "status.h"
#include "Command.h"
#include "Delay.h"
#include "DestroyCB.h"
#include "GDBAgent.h"
#include "HelpCB.h"
#include "MakeMenu.h"
#include "charsets.h"
#include "ddd.h"
#include "findParent.h"
#include "mydialogs.h"
#include "post.h"
#include "string-fun.h"
#include "verify.h"
#include <ctype.h>
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/SelectioB.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/MenuShell.h>
#include <X11/IntrinsicP.h> // LessTif hacks
#include "LessTifH.h"
//-----------------------------------------------------------------------------
// Data
//-----------------------------------------------------------------------------
// True if last cmd came from GDB window
bool gdb_keyboard_command = false;
// True if the next line is to be displayed in the status line
bool show_next_line_in_status = false;
// True if GDB is asking `yes or no' right now
bool gdb_asks_yn;
// Current contents of status window
static MString current_status_text;
// Non-zero if status is locked (i.e. unchangeable)
static int status_locked = 0;
// True iff status is to be logged
static bool log_status = true;
//-----------------------------------------------------------------------------
// Status lock
//-----------------------------------------------------------------------------
void lock_status() { status_locked++; }
void unlock_status() { if (status_locked > 0) status_locked--; }
void reset_status_lock() { status_locked = 0; }
//-----------------------------------------------------------------------------
// Prompt recognition
//-----------------------------------------------------------------------------
void set_buttons_from_gdb(Widget buttons, string& text)
{
bool yn = text.contains("(y or n) ", -1)
|| text.contains("(yes or no) ", -1)
|| ((gdb->type() == XDB || gdb->type() == JDB)
&& text.contains("? ", -1));
if (yn)
{
gdb_asks_yn = true;
}
else if (gdb->isReadyWithPrompt())
{
gdb_asks_yn = false;
unpost_gdb_yn();
}
if (yn && !gdb_keyboard_command)
{
// Fetch previous output lines, in case this is a multi-line message.
String s = XmTextGetString(gdb_w);
string prompt(s);
XtFree(s);
// FIXME: Handle JDB
char prompt_start = (gdb->type() == XDB ? '>' : '(');
int pos = prompt.index(prompt_start, -1);
if (pos >= 0)
pos = prompt.index('\n', pos) + 1;
if (pos == 0)
pos = messagePosition;
XmTextReplace(gdb_w, pos, XmTextGetLastPosition(gdb_w), "");
prompt = prompt.from(pos);
if (text.contains('('))
prompt += text.before('(', -1); // Don't repeat `(y or n)'
else
prompt += text;
post_gdb_yn(prompt);
text = "";
return;
}
if (buttons == 0)
return;
static bool last_yn = false;
if (yn == last_yn)
return;
last_yn = yn;
if (XtIsComposite(buttons))
{
set_sensitive(buttons, false);
WidgetList children = 0;
Cardinal num_children = 0;
XtVaGetValues(buttons,
XmNchildren, &children,
XmNnumChildren, &num_children,
NULL);
int i;
for (i = 0; i < int(num_children); i++)
XtManageChild(children[i]);
for (i = 0; i < int(num_children); i++)
{
Widget w = children[i];
string name = XtName(w);
if (yn == (name == "Yes" || name == "No"))
XtManageChild(w);
else
XtUnmanageChild(w);
}
set_sensitive(buttons, true);
}
}
//-----------------------------------------------------------------------------
// Status history
//-----------------------------------------------------------------------------
int status_history_size = 20;
static MString *history = 0;
static int current_history = 0;
static Widget history_label = 0;
static Widget history_row = 0;
static Widget create_status_history(Widget parent)
{
static Widget history_shell = 0;
if (history_shell != 0)
return history_shell;
Arg args[10];
int arg;
arg = 0;
XtSetArg(args[arg], XmNallowShellResize, True); arg++;
XtSetArg(args[arg], XmNwidth, 10); arg++;
XtSetArg(args[arg], XmNheight, 10); arg++;
history_shell = verify(XmCreateMenuShell(parent, "status_history",
args, arg));
arg = 0;
XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
XtSetArg(args[arg], XmNresizeWidth, True); arg++;
XtSetArg(args[arg], XmNresizeHeight, True); arg++;
XtSetArg(args[arg], XmNborderWidth, 0); arg++;
XtSetArg(args[arg], XmNshadowThickness, 0); arg++;
history_row = verify(XmCreateRowColumn(history_shell, "row", args, arg));
XtManageChild(history_row);
arg = 0;
XtSetArg(args[arg], XmNresizable, True); arg++;
XtSetArg(args[arg], XmNalignment, XmALIGNMENT_BEGINNING); arg++;
history_label = verify(XmCreateLabel(history_row, "label", args, arg));
XtManageChild(history_label);
return history_shell;
}
Widget status_history(Widget parent)
{
Widget history_shell = create_status_history(parent);
MString history_msg;
if (history == 0 || status_history_size == 0)
{
history_msg = rm("No history.");
}
else
{
history_msg = bf("Recent messages");
history_msg += rm(" (oldest first)");
history_msg += cr();
int i = current_history;
do {
if (!history[i].isEmpty())
{
if (!history_msg.isEmpty())
history_msg += cr();
history_msg += history[i];
}
i = (i + 1) % status_history_size;
} while (i != current_history);
}
if (lesstif_version < 1000)
{
// LessTif fails to resize the shell properly - the border
// width is zero. Use this hack instead.
XmFontList font_list;
XtVaGetValues(history_label, XmNfontList, &font_list, NULL);
Dimension history_width = history_msg.width(font_list) + 6;
Dimension history_height = history_msg.height(font_list) + 6;
XtResizeWidget(history_label, history_width, history_height, 0);
XtResizeWidget(history_row, history_width, history_height, 0);
XtResizeWidget(history_shell, history_width, history_height, 1);
}
XtVaSetValues(history_label, XmNlabelString, history_msg.xmstring(),
XtPointer(0));
return history_shell;
}
// Return true iff S1 is a prefix of S2
static bool is_prefix(const MString& m1, const MString& m2)
{
XmString s1 = m1.xmstring();
XmString s2 = m2.xmstring();
XmStringContext c1;
XmStringContext c2;
XmStringInitContext(&c1, s1);
XmStringInitContext(&c2, s2);
XmStringComponentType t1 = XmSTRING_COMPONENT_UNKNOWN;
XmStringComponentType t2 = XmSTRING_COMPONENT_UNKNOWN;
while (t1 != XmSTRING_COMPONENT_END && t2 != XmSTRING_COMPONENT_END)
{
char *s_text1 = 0;
XmStringCharSet s_cs1 = 0;
XmStringDirection d1 = XmSTRING_DIRECTION_DEFAULT;
XmStringComponentType u1 = XmSTRING_COMPONENT_UNKNOWN;
unsigned short ul1 = 0;
unsigned char *s_uv1 = 0;
t1 = XmStringGetNextComponent(c1, &s_text1, &s_cs1, &d1,
&u1, &ul1, &s_uv1);
char *s_text2 = 0;
XmStringCharSet s_cs2 = 0;
XmStringDirection d2 = XmSTRING_DIRECTION_DEFAULT;
XmStringComponentType u2 = XmSTRING_COMPONENT_UNKNOWN;
unsigned short ul2 = 0;
unsigned char *s_uv2 = 0;
t2 = XmStringGetNextComponent(c2, &s_text2, &s_cs2, &d2,
&u2, &ul2, &s_uv2);
// Upon EOF in LessTif 0.82, XmStringGetNextComponent()
// returns XmSTRING_COMPONENT_UNKNOWN instead of
// XmSTRING_COMPONENT_END. Work around this.
if (t1 == XmSTRING_COMPONENT_UNKNOWN && s_uv1 == 0)
t1 = XmSTRING_COMPONENT_END;
if (t2 == XmSTRING_COMPONENT_UNKNOWN && s_uv2 == 0)
t2 = XmSTRING_COMPONENT_END;
// Place string values in strings
string text1(s_text1 == 0 ? "" : s_text1);
string text2(s_text2 == 0 ? "" : s_text2);
string cs1(s_cs1 == 0 ? "" : s_cs1);
string cs2(s_cs2 == 0 ? "" : s_cs2);
string uv1;
string uv2;
if (s_uv1 != 0)
uv1 = string((char *)s_uv1, ul1);
if (s_uv2 != 0)
uv2 = string((char *)s_uv2, ul2);
// Free unused memory
XtFree(s_text1);
XtFree(s_text2);
XtFree(s_cs1);
XtFree(s_cs2);
XtFree((char *)s_uv1);
XtFree((char *)s_uv2);
if (t1 != t2)
{
goto done; // Differing tags
}
switch (t1)
{
case XmSTRING_COMPONENT_CHARSET:
{
if (cs1 == "") // In LessTif 0.82, XmStringGetNextComponent()
cs1 = text1; // swaps CS and TEXT. Work around this.
if (cs2 == "")
cs2 = text2;
if (cs1 != cs2)
goto done; // Differing character sets
break;
}
case XmSTRING_COMPONENT_TEXT:
#if XmVersion >= 1002
case XmSTRING_COMPONENT_LOCALE_TEXT:
#endif
#if XmVersion >= 2000
case XmSTRING_COMPONENT_WIDECHAR_TEXT:
#endif
{
if (text1 == "") // In LessTif 0.82, XmStringGetNextComponent()
text1 = cs1; // swaps CS and TEXT. Work around this.
if (text2 == "")
text2 = cs2;
if (!text2.contains(text1, 0))
goto done;
XmStringComponentType next2 = XmStringPeekNextComponent(c2);
// In LessTif 0.82, XmStringPeekNextComponent() returns
// XmSTRING_COMPONENT_UNKNOWN instead of
// XmSTRING_COMPONENT_END. Work around this.
if (next2 != XmSTRING_COMPONENT_END &&
next2 != XmSTRING_COMPONENT_UNKNOWN)
goto done;
break;
}
case XmSTRING_COMPONENT_DIRECTION:
{
if (d1 != d2)
goto done;
break;
}
case XmSTRING_COMPONENT_SEPARATOR:
case XmSTRING_COMPONENT_END:
{
// These are the same by definition
break;
}
case XmSTRING_COMPONENT_UNKNOWN:
{
if (uv1 != uv2)
goto done; // Differing unknown tags
break;
}
default:
{
break; // Skip everything else
}
}
}
done:
XmStringFreeContext(c2);
XmStringFreeContext(c1);
return t1 == XmSTRING_COMPONENT_END;
}
// Return all characters in M
static string str(const MString& _m)
{
string s = "";
XmString m = _m.xmstring();
XmStringContext c;
XmStringInitContext(&c, m);
XmStringComponentType t = XmSTRING_COMPONENT_UNKNOWN;
while (t != XmSTRING_COMPONENT_END)
{
char *s_text = 0;
XmStringCharSet s_cs = 0;
XmStringDirection d = XmSTRING_DIRECTION_DEFAULT;
XmStringComponentType u = XmSTRING_COMPONENT_UNKNOWN;
unsigned short ul = 0;
unsigned char *s_uv = 0;
t = XmStringGetNextComponent(c, &s_text, &s_cs, &d, &u, &ul, &s_uv);
// Upon EOF in LessTif 0.82, XmStringGetNextComponent()
// returns XmSTRING_COMPONENT_UNKNOWN instead of
// XmSTRING_COMPONENT_END. Work around this.
if (t == XmSTRING_COMPONENT_UNKNOWN && s_uv == 0)
t = XmSTRING_COMPONENT_END;
// Place string values in strings
string text(s_text == 0 ? "" : s_text);
string cs(s_cs == 0 ? "" : s_cs);
string uv;
if (s_uv != 0)
uv = string((char *)s_uv, ul);
// Free unused memory
XtFree(s_text);
XtFree(s_cs);
XtFree((char *)s_uv);
switch (t)
{
case XmSTRING_COMPONENT_TEXT:
#if XmVersion >= 1002
case XmSTRING_COMPONENT_LOCALE_TEXT:
#endif
#if XmVersion >= 2000
case XmSTRING_COMPONENT_WIDECHAR_TEXT:
#endif
s += text;
break;
case XmSTRING_COMPONENT_SEPARATOR:
s += "\n";
break;
default:
break;
}
}
XmStringFreeContext(c);
return s;
}
static void add_to_status_history(const MString& message)
{
static MString empty = rm(" ");
if (history == 0)
history = new MString[status_history_size];
int last_history =
(status_history_size + current_history - 1) % status_history_size;
if (message.isNull() || message.isEmpty() || message == empty)
return;
if (is_prefix(history[last_history], message))
{
history[last_history] = message;
return;
}
history[current_history] = message;
current_history = (current_history + 1) % status_history_size;
}
//-----------------------------------------------------------------------------
// Status recognition
//-----------------------------------------------------------------------------
void set_status_from_gdb(const string& text)
{
if (private_gdb_input)
return;
if (!show_next_line_in_status && !text.contains(gdb->prompt(), -1))
return;
// Fetch line before prompt in GDB window
String s = XmTextGetString(gdb_w);
string message = s + messagePosition;
XtFree(s);
if (message == "" && text.contains('\n'))
message = text;
if (show_next_line_in_status &&
(message == "" || message[message.length() - 1] != '\n'))
return;
// Skip prompt and uncomplete lines
int idx = message.index('\n', -1);
if (idx >= 0)
message = message.before(idx);
strip_trailing_newlines(message);
if (message == "" && text.contains('\n'))
message = text;
if (show_next_line_in_status)
{
messagePosition = XmTextGetLastPosition(gdb_w) + text.length();
show_next_line_in_status = false;
message.gsub('\n', ' ');
}
else
{
// Show first line only
while (message != "" && message[0] == '\n')
message = message.after('\n');
if (message.contains('\n'))
message = message.before('\n');
}
strip_trailing_newlines(message);
message.gsub('\t', ' ');
if (message == "")
return;
// Don't log this stuff - it's already logged
bool old_log_status = log_status;
log_status = false;
set_status(message);
log_status = old_log_status;
}
// Show MESSAGE in status window.
// If TEMPORARY is set, override locks and do not add to status history.
void set_status(string message, bool temporary)
{
if (status_w == 0)
return;
if (message.length() > 0
&& !message.contains("=")
&& isascii(message[0])
&& islower(message[0]))
message[0] = toupper(message[0]);
set_status_mstring(rm(message), temporary);
}
// Same, but use an MString.
void set_status_mstring(MString message, bool temporary)
{
if (status_w == 0)
return;
if (!temporary)
add_to_status_history(message);
if (!status_locked)
{
current_status_text = message;
XtVaSetValues(status_w,
XmNlabelString, message.xmstring(),
NULL);
XFlush(XtDisplay(status_w));
XmUpdateDisplay(status_w);
}
if (log_status && !temporary)
{
// Log status message
string s = str(message);
if (s != "" && s != " ")
{
dddlog << "# " << s << "\n";
dddlog.flush();
}
}
}
const MString& current_status()
{
return current_status_text;
}