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
/
DispBox.C
< prev
next >
Wrap
C/C++ Source or Header
|
1998-12-04
|
14KB
|
633 lines
// $Id: DispBox.C,v 1.69.4.2 1998/12/04 15:20:09 zeller Exp $
// Display boxes
// Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
// Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>
// and 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 DispBox_rcsid[] =
"$Id: DispBox.C,v 1.69.4.2 1998/12/04 15:20:09 zeller Exp $";
#ifdef __GNUG__
#pragma implementation
#endif
//-----------------------------------------------------------------------------
// Create DispBoxes via VSL
//-----------------------------------------------------------------------------
#include "assert.h"
#include "DispBox.h"
#include "StringBox.h"
#include "ColorBox.h"
#include "DispNode.h"
#include "GDBAgent.h"
#include "VSEFlags.h"
#include "strclass.h"
#include "bool.h"
#include "cook.h"
#include "ddd.h"
#include "status.h"
#include "shorten.h"
#include "string-fun.h"
#include "tabs.h"
#include "version.h"
#include "regexps.h"
#include <ctype.h>
#define assert_ok(x) assert(x)
#ifndef CACHE_BOXES
#define CACHE_BOXES 1
#endif
//-----------------------------------------------------------------------------
VSLLib DispBox::dummylib;
VSLLib* DispBox::vsllib_ptr = &DispBox::dummylib;
string DispBox::vsllib_name = "builtin";
string DispBox::vsllib_path = ".";
string DispBox::vsllib_defs = "";
string DispBox::vsllib_base_defs = "";
int DispBox::max_display_title_length = 20;
bool DispBox::vsllib_initialized = false;
bool DispBox::align_2d_arrays = true;
// ***************************************************************************
//
DispBox::DispBox (int disp_nr, const string& title,
const DispValue *dv, const DispValue *parent)
: mybox(0), title_box(0)
{
// Create display
set_title(disp_nr, title);
set_value(dv, parent);
}
// ***************************************************************************
//
void DispBox::init_vsllib(void (*background)())
{
if (vsllib_initialized)
return; // We already have a library
static bool initializing = false;
if (initializing)
return; // We are already initializing
initializing = true;
static const char builtin_def[] =
#include "ddd.vsl.h"
;
// Set include search path
VSEFlags::include_search_path =
strcpy(new char[vsllib_path.length() + 1], vsllib_path);
// Load library
void (*old_background)() = VSLLib::background;
VSLLib::background = background;
if (string(vsllib_name) == "builtin")
{
string defs = string(builtin_def)
+ "#line 1 \"" Ddd_NAME "*vslBaseDefs\"\n"
+ vsllib_base_defs
+ "#line 1 \"" Ddd_NAME "*vslDefs\"\n"
+ vsllib_defs;
istrstream is(defs.chars());
vsllib_ptr = new VSLLib(is, VSEFlags::optimize_mode());
}
else
{
vsllib_ptr = new VSLLib(vsllib_name, VSEFlags::optimize_mode());
}
VSLLib::background = old_background;
initializing = false;
vsllib_initialized = true;
}
// ***************************************************************************
//
DispBox::~DispBox ()
{
assert_ok(mybox == 0 || mybox->OK());
if (mybox != 0)
mybox->unlink();
assert_ok(title_box == 0 || title_box->OK());
if (title_box != 0)
title_box->unlink();
}
// ***************************************************************************
//
void DispBox::set_value(const DispValue* dv, const DispValue *parent)
{
if (mybox != 0)
{
mybox->unlink();
mybox = 0;
}
VSLArgList args;
if (title_box != 0)
args += title_box->link();
if (dv != 0)
((DispValue *)dv)->validate_box_cache();
args += create_value_box(dv, parent);
mybox = eval("display_box", args);
assert_ok(mybox->OK());
}
void DispBox::shorten_title(string& name)
{
if (name == "")
return;
if (!is_user_command(name))
{
// Strip DBX scope information from title
#if RUNTIME_REGEX
static regex rxdbx_scope("[a-zA-Z_0-9]*`");
#endif
int i = 0;
while (int(name.length()) > max_display_title_length
&& ((i = name.index(rxdbx_scope)) >= 0))
{
name = name.before(i) + name.after('`');
}
}
// Shorten remainder
shorten(name, max_display_title_length);
}
void DispBox::set_title(int disp_nr, string name)
{
if (title_box != 0)
{
title_box->unlink();
title_box = 0;
}
// Create title
if (name != "")
{
VSLArg args[3];
int arg = 0;
if (is_user_command(name))
{
// User command: use NAME
string title = DispValue::make_title(name);
shorten_title(title);
args[arg++] = tag(title);
}
else
{
// Normal title: use NUMBER: NAME
args[arg++] = itostring(disp_nr);
shorten_title(name);
args[arg++] = tag(name);
}
title_box = eval("title", args);
assert_ok(title_box->OK());
}
}
// Return true if DV is a (right-aligned) numeric value
bool DispBox::is_numeric(const DispValue *dv, const DispValue *parent)
{
if (parent != 0 && parent->type() != Array)
return false;
if (dv->value() == "")
return false;
if (dv->value().contains(' '))
return false;
char c = dv->value()[0];
return isdigit(c) || c == '+' || c == '-' || c == '.';
}
// ***************************************************************************
// Create a Box for the value DV
Box *DispBox::_create_value_box(const DispValue *dv, const DispValue *parent)
{
assert(dv != 0);
Box *vbox = 0;
#if CACHE_BOXES
// Check cache first
vbox = dv->cached_box();
if (vbox != 0)
{
vbox = vbox->link();
assert_ok(vbox->OK());
return vbox;
}
#endif
// Rebuild box
switch (dv->type())
{
case Simple:
{
if (dv->collapsed())
vbox = eval("collapsed_simple_value");
else
{
// Flush numeric values to the right, unless in a struct
if (is_numeric(dv, parent))
vbox = eval("numeric_value", dv->value());
else
vbox = eval("simple_value", dv->value());
}
break;
}
case Text:
{
if (dv->collapsed())
vbox = eval("collapsed_text_value");
else
{
string v = dv->value();
strip_space(v);
untabify(v);
int n = v.freq('\n');
string *lines = new string[n + 1];
split(v, lines, n + 1, '\n');
VSLArgList args;
for (int i = 0; i < n + 1; i++)
{
if (lines[i] == "")
lines[i] = " ";
args += eval("text_line", lines[i]);
}
vbox = eval("text_value", args);
delete[] lines;
}
break;
}
case Pointer:
{
if (dv->collapsed())
vbox = eval("collapsed_pointer_value");
else if (dv->dereferenced())
vbox = eval("dereferenced_pointer_value", dv->value());
else
vbox = eval("pointer_value", dv->value());
break;
}
case Array:
{
if (dv->collapsed())
vbox = eval("collapsed_array");
else
{
int count = dv->nchildren();
if (count == 0)
{
vbox = eval("empty_array");
}
else
{
bool have_2d_array = true;
if (dv->repeats() > 1)
have_2d_array = false;
int nchildren = 0;
for (int k = 0; have_2d_array && k < count; k++)
{
DispValue *child = dv->child(k);
if (child->type() != Array)
{
// Child is no array
have_2d_array = false;
break;
}
if (child->repeats() > 1)
{
// Child is a repeated array
have_2d_array = false;
break;
}
if (k == 0)
{
nchildren = child->nchildren();
}
else if (nchildren != child->nchildren())
{
// Children have differing sizes
have_2d_array = false;
break;
}
}
if (have_2d_array && align_2d_arrays)
{
// Two-dimensional array
ListBox *table = new ListBox;
if (dv->vertical_aligned())
{
// Sub-arrays are aligned vertically;
// each sub-array is laid out horizontally
for (int i = 0; i < count; i++)
{
DispValue *c = dv->child(i);
ListBox *row = new ListBox;
for (int j = 0; j < c->nchildren(); j++)
{
DispValue *cc = c->child(j);
Box *b = eval("twodim_array_elem",
create_value_box(cc, c));
*row += b;
b->unlink();
}
*table += row;
row->unlink();
}
}
else
{
// Sub-arrays are aligned horizontally;
// each sub-array is laid out vertically
int max_cc = 0;
for (int j = 0; j < count; j++)
max_cc = max(max_cc, dv->child(j)->nchildren());
for (int i = 0; i < max_cc; i++)
{
ListBox *row = new ListBox;
for (int j = 0; j < count; j++)
{
DispValue *c = dv->child(j);
Box *elem = 0;
if (i < c->nchildren())
{
DispValue *cc = c->child(i);
elem = create_value_box(cc, c);
}
else
{
elem = new ListBox;
}
Box *b = eval("twodim_array_elem", elem);
*row += b;
b->unlink();
}
*table += row;
row->unlink();
}
}
vbox = eval("twodim_array", table);
}
else
{
// One-dimensional array
VSLArgList args;
for (int i = 0; i < count; i++)
args += create_value_box(dv->child(i), dv);
if (dv->vertical_aligned())
vbox = eval("vertical_array", args);
else
vbox = eval("horizontal_array", args);
}
}
}
break;
}
case Sequence:
{
if (dv->collapsed())
vbox = eval("collapsed_sequence_value");
else
{
// Create children
VSLArgList args;
int count = dv->nchildren();
for (int i = 0; i < count; i++)
args += create_value_box(dv->child(i), dv);
vbox = eval("sequence_value", args);
}
break;
}
case List:
case Struct:
{
String collapsed_value = (dv->type() == List ?
"collapsed_list_value" :
"collapsed_struct_value");
String empty_value = (dv->type() == List ?
"empty_list_value" :
"empty_struct_value");
String member_name = (dv->type() == List ?
"list_member_name" :
"struct_member_name");
String value = (dv->type() == List ?
"list_value" :
"struct_value");
if (dv->collapsed())
vbox = eval(collapsed_value);
else
{
int count = dv->nchildren();
if (count == 0)
vbox = eval(empty_value);
else
{
// Determine maximum member name width
int max_member_name_width = 0;
int i;
for (i = 0; i < count; i++)
{
string child_member_name = dv->child(i)->name();
Box *box = eval(member_name, child_member_name);
max_member_name_width =
max(max_member_name_width, box->size(X));
box->unlink();
}
// Create children
VSLArgList args;
for (i = 0; i < count; i++)
args += create_value_box(dv->child(i), dv,
max_member_name_width);
vbox = eval(value, args);
}
}
break;
}
case Reference:
{
if (dv->collapsed())
vbox = eval("collapsed_reference_value");
else
{
VSLArgList args;
for (int i = 0; i < 2; i++)
args += create_value_box(dv->child(i), dv);
vbox = eval("reference_value", args);
}
break;
}
case UnknownType:
assert(0);
abort();
}
// Show repeats
if (dv->repeats() > 1 && !dv->collapsed())
{
vbox = eval("repeated_value", vbox, dv->repeats());
}
// Highlight if value changed
if (dv->is_changed())
{
vbox = eval("changed_value", vbox);
}
assert_ok(vbox->OK());
#if CACHE_BOXES
((DispValue *)dv)->set_cached_box(vbox);
#endif
return vbox;
}
Box *DispBox::create_value_box (const DispValue *dv,
const DispValue *parent,
int member_name_width)
{
Box *vbox = 0;
if (dv == 0)
{
vbox = eval("none");
}
else if (!dv->enabled())
{
vbox = eval("disabled");
}
else
{
vbox = _create_value_box(dv, parent);
}
// Add member name
if (dv != 0 && parent != 0 &&
dv->type() != Text &&
dv->name() != "" &&
!dv->name().matches(rxwhite))
{
switch (parent->type())
{
case List:
vbox = eval("list_member", dv->name(), " = ",
vbox, member_name_width);
break;
case Struct:
vbox = eval("struct_member",
dv->name(), gdb->member_separator(),
vbox, member_name_width);
break;
case Sequence:
case Array:
case Reference:
case Simple:
case Text:
case Pointer:
break;
case UnknownType:
assert(0);
abort();
}
}
if (dv != 0)
{
Data *data = (Data *)dv;
vbox = vbox->tag(data);
}
assert_ok(vbox->OK());
return vbox;
}
// Check evaluation result
Box *DispBox::check(const string& func_name, const Box *box)
{
if (box != 0)
return ((Box *)box);
// Box not found
string bad_func_name = "<?" + func_name + ">";
return new ForegroundColorBox(new StringBox(bad_func_name), "red");
}