/* This is -*- C -*- */
/* vim: set sw=2: */
/* $Id: guppi-data-table.c,v 1.6 2002/01/08 06:28:58 trow Exp $ */
/*
* guppi-data-table.c
*
* Copyright (C) 2001 The Free Software Foundation
*
* Developed by Jon Trowbridge <trow@gnu.org>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <config.h>
#include "guppi-data-table.h"
#include <math.h>
#include <guppi-memory.h>
static GtkObjectClass *parent_class = NULL;
enum {
CHANGED_DIMENSIONS,
CHANGED_TABLE_ENTRIES,
CHANGED_TABLE_LABELS,
LAST_SIGNAL
};
static guint guppi_data_table_signals[LAST_SIGNAL] = { 0 };
typedef struct _GuppiDataTableStats GuppiDataTableStats;
struct _GuppiDataTableStats {
gboolean have_sum, have_abs_sum, have_min, have_max;
double sum, abs_sum, min, max;
};
struct _GuppiDataTablePrivate {
GuppiDataTableStats *row_stats;
GuppiDataTableStats *col_stats;
};
#define perp_span(x) ((x) == GUPPI_TABLE_ROW ? GUPPI_TABLE_COL : GUPPI_TABLE_ROW)
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static void
stats_init (GuppiDataTableStats *stats, gint N)
{
gint i;
for (i = 0; i < N; ++i) {
stats[i].have_sum = FALSE;
stats[i].have_abs_sum = FALSE;
stats[i].have_min = FALSE;
stats[i].have_max = FALSE;
}
}
static void
guppi_data_table_finalize (GtkObject *obj)
{
GuppiDataTable *x = GUPPI_DATA_TABLE(obj);
g_free (x->priv);
x->priv = NULL;
guppi_finalized (obj);
if (parent_class->finalize)
parent_class->finalize (obj);
}
static gchar *
get_size_info (GuppiData *data)
{
GuppiDataTable *table = GUPPI_DATA_TABLE (data);
gint R, C;
guppi_data_table_get_dimensions (table, &R, &C);
return guppi_strdup_printf ("%d x %d", R, C);
}
static gboolean
validate_class (GuppiDataClass *klass)
{
GuppiDataTableClass *table_class = GUPPI_DATA_TABLE_CLASS (klass);
gboolean ok = TRUE;
if (table_class->get_bounds == NULL) {
g_warning ("Method GuppiDataTable::get_bounds not defined.");
ok = FALSE;
}
if (table_class->set_bounds == NULL && ! klass->read_only) {
g_warning ("Method GuppiDataTable::set_bounds not defined.");
ok = FALSE;
}
if (table_class->get_entry == NULL) {
g_warning ("Method GuppiDataTable::get_entry not defined.");
ok = FALSE;
}
if (table_class->set_entry == NULL && ! klass->read_only) {
g_warning ("Method GuppiDataTable::set_entry not defined.");
ok = FALSE;
}
if (table_class->get_label == NULL) {
g_warning ("Method GuppiDataTable::get_label not defined.");
ok = FALSE;
}
if (table_class->set_label == NULL && ! klass->read_only) {
g_warning ("Method GuppiDataTable::set_label not defined.");
ok = FALSE;
}
if (GUPPI_DATA_CLASS (parent_class)->validate_class
&& ! GUPPI_DATA_CLASS (parent_class)->validate_class (klass))
ok = FALSE;
return ok;
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/* Table Operations */
typedef struct _GuppiDataOp_Table GuppiDataOp_Table;
struct _GuppiDataOp_Table {
GuppiDataOp op;
gint r, c, i;
GuppiDataTableSpan span;
double x;
const gchar *str;
};
static void
op_set (GuppiData *d, GuppiDataOp *op)
{
GuppiDataTable *tab = GUPPI_DATA_TABLE (d);
GuppiDataTableClass *klass = GUPPI_DATA_TABLE_CLASS (GTK_OBJECT (tab)->klass);
GuppiDataOp_Table *table_op = (GuppiDataOp_Table *) op;
g_assert (klass->set_entry);
klass->set_entry (tab, table_op->r, table_op->c, table_op->x);
}
static void
op_set_label (GuppiData *d, GuppiDataOp *op)
{
GuppiDataTable *tab = GUPPI_DATA_TABLE (d);
GuppiDataTableClass *klass = GUPPI_DATA_TABLE_CLASS (GTK_OBJECT (tab)->klass);
GuppiDataOp_Table *table_op = (GuppiDataOp_Table *) op;
g_assert (klass->set_label);
klass->set_label (tab, table_op->span, table_op->i, table_op->str);
}
static void
op_set_dim (GuppiData *d, GuppiDataOp *op)
{
GuppiDataTable *tab = GUPPI_DATA_TABLE (d);
GuppiDataTableClass *klass = GUPPI_DATA_TABLE_CLASS (GTK_OBJECT (tab)->klass);
GuppiDataOp_Table *table_op = (GuppiDataOp_Table *) op;
g_assert (klass->set_bounds);
klass->set_bounds (tab, table_op->r, table_op->c);
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
gboolean
guppi_data_table_get_dimensions (GuppiDataTable *tab, gint *rows, gint *cols)
{
GuppiDataTableClass *klass;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), FALSE);
if (rows == NULL && cols == NULL)
return TRUE;
klass = GUPPI_DATA_TABLE_CLASS (GTK_OBJECT (tab)->klass);
g_return_val_if_fail (klass->get_bounds, FALSE);
return klass->get_bounds (tab, rows, cols);
}
gint
guppi_data_table_get_span_count (GuppiDataTable *tab, GuppiDataTableSpan span)
{
gint N = -1;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), -1);
switch (span) {
case GUPPI_TABLE_ROW:
guppi_data_table_get_dimensions (tab, &N, NULL);
break;
case GUPPI_TABLE_COL:
guppi_data_table_get_dimensions (tab, NULL, &N);
break;
default:
g_assert_not_reached ();
}
return N;
}
gint
guppi_data_table_get_row_count (GuppiDataTable *tab)
{
gint r;
return guppi_data_table_get_dimensions (tab, &r, NULL) ? r : -1;
}
gint
guppi_data_table_get_col_count (GuppiDataTable *tab)
{
gint c;
return guppi_data_table_get_dimensions (tab, NULL, &c) ? c : -1;
}
gboolean
guppi_data_table_in_bounds (GuppiDataTable *tab, gint r, gint c)
{
gint rows, cols;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), FALSE);
if (r < 0 || c < 0)
return FALSE;
if (! guppi_data_table_get_dimensions (tab, &rows, &cols))
return FALSE;
return r < rows && c < cols;
}
gboolean
guppi_data_table_in_span_bounds (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), FALSE);
if (i < 0)
return FALSE;
return i < guppi_data_table_get_span_count (tab, span);
}
gboolean
guppi_data_table_in_row_bounds (GuppiDataTable *tab, gint r)
{
return guppi_data_table_in_span_bounds (tab, GUPPI_TABLE_ROW, r);
}
gboolean
guppi_data_table_in_col_bounds (GuppiDataTable *tab, gint c)
{
return guppi_data_table_in_span_bounds (tab, GUPPI_TABLE_COL, c);
}
void
guppi_data_table_set_dimensions (GuppiDataTable *tab, gint r, gint c)
{
GuppiDataOp_Table op;
g_return_if_fail (GUPPI_IS_DATA_TABLE (tab));
g_return_if_fail (guppi_data_can_change (GUPPI_DATA (tab)));
op.op.op = op_set_dim;
op.r = r;
op.c = c;
guppi_data_table_changed_dimensions (tab, r, c, (GuppiDataOp *) &op);
}
double
guppi_data_table_get_entry (GuppiDataTable *tab, gint r, gint c)
{
GuppiDataTableClass *klass;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0.0);
g_return_val_if_fail (guppi_data_table_in_bounds (tab, r, c), 0.0);
klass = GUPPI_DATA_TABLE_CLASS (GTK_OBJECT (tab)->klass);
g_assert (klass->get_entry);
return klass->get_entry (tab, r, c);
}
void
guppi_data_table_set_entry (GuppiDataTable *tab, gint r, gint c, double x)
{
GuppiDataOp_Table op;
g_return_if_fail (GUPPI_IS_DATA_TABLE (tab));
g_return_if_fail (guppi_data_can_change (GUPPI_DATA (tab)));
g_return_if_fail (guppi_data_table_in_bounds (tab, r, c));
op.op.op = op_set;
op.r = r;
op.c = c;
op.x = x;
guppi_data_table_changed_table_entries (tab, r, c, r, c, (GuppiDataOp *) &op);
}
const gchar *
guppi_data_table_get_label (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
GuppiDataTableClass *klass;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), NULL);
g_return_val_if_fail (guppi_data_table_in_span_bounds (tab, span, i), NULL);
klass = GUPPI_DATA_TABLE_CLASS (GTK_OBJECT (tab)->klass);
g_assert (klass->get_label);
return klass->get_label (tab, span, i);
}
const gchar *
guppi_data_table_get_row_label (GuppiDataTable *tab, gint i)
{
return guppi_data_table_get_label (tab, GUPPI_TABLE_ROW, i);
}
const gchar *
guppi_data_table_get_col_label (GuppiDataTable *tab, gint i)
{
return guppi_data_table_get_label (tab, GUPPI_TABLE_COL, i);
}
void
guppi_data_table_set_label (GuppiDataTable *tab, GuppiDataTableSpan span, gint i, const gchar *str)
{
GuppiDataOp_Table op;
g_return_if_fail (GUPPI_IS_DATA_TABLE (tab));
g_return_if_fail (guppi_data_can_change (GUPPI_DATA (tab)));
g_return_if_fail (guppi_data_table_in_span_bounds (tab, span, i));
op.op.op = op_set_label;
op.span = span;
op.i = i;
op.str = str;
guppi_data_table_changed_table_labels (tab, span, i, i, (GuppiDataOp *) &op);
}
void
guppi_data_table_set_row_label (GuppiDataTable *tab, gint r, const gchar *str)
{
guppi_data_table_set_label (tab, GUPPI_TABLE_ROW, r, str);
}
void
guppi_data_table_set_col_label (GuppiDataTable *tab, gint c, const gchar *str)
{
guppi_data_table_set_label (tab, GUPPI_TABLE_COL, c, str);
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static GuppiDataTableStats *
get_stats (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
return &(span == GUPPI_TABLE_ROW ? tab->priv->row_stats : tab->priv->col_stats)[i];
}
static void
calc_stats (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
GuppiDataTableClass *klass = GUPPI_DATA_TABLE_CLASS (GTK_OBJECT (tab)->klass);
GuppiDataTableStats *stats;
gint j = 0, N, r, c;
double x, run_sum=0, run_abs_sum=0, run_min=0, run_max=0;
stats = get_stats (tab, span, i);
N = guppi_data_table_get_span_count (tab, perp_span (span));
for (j = 0; j < N; ++j) {
if (span == GUPPI_TABLE_ROW) {
r = i;
c = j;
} else {
r = j;
c = i;
}
x = klass->get_entry (tab, r, c);
run_sum += x;
run_abs_sum += fabs(x);
if (j == 0 || x < run_min)
run_min = x;
if (j == 0 || x > run_max)
run_max = x;
}
stats->have_sum = stats->have_abs_sum = stats->have_min = stats->have_max = TRUE;
stats->sum = run_sum;
stats->abs_sum = run_abs_sum;
stats->min = run_min;
stats->max = run_max;
}
double
guppi_data_table_get_sum (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
GuppiDataTableStats *stats;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
g_return_val_if_fail (guppi_data_table_in_span_bounds (tab, span, i), 0);
stats = get_stats (tab, span, i);
if (! stats->have_sum)
calc_stats (tab, span, i);
return stats->sum;
}
double
guppi_data_table_get_abs_sum (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
GuppiDataTableStats *stats;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
g_return_val_if_fail (guppi_data_table_in_span_bounds (tab, span, i), 0);
stats = get_stats (tab, span, i);
if (! stats->have_abs_sum)
calc_stats (tab, span, i);
return stats->abs_sum;
}
double
guppi_data_table_get_min (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
GuppiDataTableStats *stats;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
g_return_val_if_fail (guppi_data_table_in_span_bounds (tab, span, i), 0);
stats = get_stats (tab, span, i);
if (! stats->have_min)
calc_stats (tab, span, i);
return stats->min;
}
double
guppi_data_table_get_max (GuppiDataTable *tab, GuppiDataTableSpan span, gint i)
{
GuppiDataTableStats *stats;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
g_return_val_if_fail (guppi_data_table_in_span_bounds (tab, span, i), 0);
stats = get_stats (tab, span, i);
if (! stats->have_max)
calc_stats (tab, span, i);
return stats->max;
}
double
guppi_data_table_get_range_sum (GuppiDataTable *tab, gint r0, gint c0, gint r1, gint c1)
{
gint R, C, r, c;
double val;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
guppi_data_table_get_dimensions (tab, &R, &C);
r0 = CLAMP (r0, 0, R-1);
r1 = CLAMP (r1, 0, R-1);
c0 = CLAMP (c0, 0, C-1);
c1 = CLAMP (c1, 0, C-1);
val = 0;
for (r = r0; r <= r1; ++r) {
for (c = c0; c <= c1; ++c) {
val += guppi_data_table_get_entry (tab, r, c);
}
}
return val;
}
double
guppi_data_table_get_range_abs_sum (GuppiDataTable *tab, gint r0, gint c0, gint r1, gint c1)
{
gint R, C, r, c;
double val;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
guppi_data_table_get_dimensions (tab, &R, &C);
r0 = CLAMP (r0, 0, R-1);
r1 = CLAMP (r1, 0, R-1);
c0 = CLAMP (c0, 0, C-1);
c1 = CLAMP (c1, 0, C-1);
val = 0;
for (r = r0; r <= r1; ++r) {
for (c = c0; c <= c1; ++c) {
val += fabs (guppi_data_table_get_entry (tab, r, c));
}
}
return val;
}
double
guppi_data_table_get_range_min (GuppiDataTable *tab, gint r0, gint c0, gint r1, gint c1)
{
gint R, C, r, c;
double val = 0;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
guppi_data_table_get_dimensions (tab, &R, &C);
r0 = CLAMP (r0, 0, R-1);
r1 = CLAMP (r1, 0, R-1);
c0 = CLAMP (c0, 0, C-1);
c1 = CLAMP (c1, 0, C-1);
val = 0;
for (r = r0; r <= r1; ++r) {
for (c = c0; c <= c1; ++c) {
double v = guppi_data_table_get_entry (tab, r, c);
if ((r == r0 && c == c0) || (v < val))
val = v;
}
}
return val;
}
double
guppi_data_table_get_range_max (GuppiDataTable *tab, gint r0, gint c0, gint r1, gint c1)
{
gint R, C, r, c;
double val = 0;
g_return_val_if_fail (GUPPI_IS_DATA_TABLE (tab), 0);
guppi_data_table_get_dimensions (tab, &R, &C);
r0 = CLAMP (r0, 0, R-1);
r1 = CLAMP (r1, 0, R-1);
c0 = CLAMP (c0, 0, C-1);
c1 = CLAMP (c1, 0, C-1);
val = 0;
for (r = r0; r <= r1; ++r) {
for (c = c0; c <= c1; ++c) {
double v = guppi_data_table_get_entry (tab, r, c);
if ((r == r0 && c == c0) || (v > val))
val = v;
}
}
return val;
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
void
guppi_data_table_changed_dimensions (GuppiDataTable *tab, gint r, gint c, GuppiDataOp *op)
{
g_return_if_fail (GUPPI_IS_DATA_TABLE (tab));
g_return_if_fail (op != NULL);
guppi_data_add_pending_op (GUPPI_DATA (tab), op);
gtk_signal_emit (GTK_OBJECT (tab), guppi_data_table_signals[CHANGED_DIMENSIONS], r, c);
}
void
guppi_data_table_changed_table_entries (GuppiDataTable *tab, gint r0, gint c0, gint r1, gint c1, GuppiDataOp *op)
{
g_return_if_fail (GUPPI_IS_DATA_TABLE (tab));
g_return_if_fail (op != NULL);
guppi_data_add_pending_op (GUPPI_DATA (tab), op);
gtk_signal_emit (GTK_OBJECT (tab), guppi_data_table_signals[CHANGED_TABLE_ENTRIES], r0, c0, r1, c1);
}
void
guppi_data_table_changed_table_labels (GuppiDataTable *tab, GuppiDataTableSpan span, gint i0, gint i1, GuppiDataOp *op)
{
g_return_if_fail (GUPPI_IS_DATA_TABLE (tab));
g_return_if_fail (op != NULL);
guppi_data_add_pending_op (GUPPI_DATA (tab), op);
gtk_signal_emit (GTK_OBJECT (tab), guppi_data_table_signals[CHANGED_TABLE_LABELS], span, i0, i1);
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static void
changed (GuppiData *data)
{
GuppiDataTable *tab = GUPPI_DATA_TABLE (data);
gint r, c;
guppi_data_table_get_dimensions (tab, &r, &c);
stats_init (tab->priv->row_stats, r);
stats_init (tab->priv->col_stats, c);
if (GUPPI_DATA_CLASS (parent_class)->changed)
GUPPI_DATA_CLASS (parent_class)->changed (data);
}
static void
changed_dimensions (GuppiDataTable *tab, gint r, gint c)
{
guppi_data_changed (GUPPI_DATA (tab));
guppi_free (tab->priv->row_stats);
guppi_free (tab->priv->col_stats);
tab->priv->row_stats = guppi_new (GuppiDataTableStats, r);
tab->priv->col_stats = guppi_new (GuppiDataTableStats, c);
}
static void
changed_table_entries (GuppiDataTable *tab, gint r0, gint c0, gint r1, gint c1)
{
guppi_data_changed (GUPPI_DATA (tab));
}
static void
changed_table_labels (GuppiDataTable *tab, GuppiDataTableSpan span, gint i0, gint i1)
{
guppi_data_changed (GUPPI_DATA (tab));
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
typedef void (*GuppiSignal_NONE__INT_INT_INT) (GtkObject *, gint, gint, gint, gpointer closure);
static void
guppi_marshal_NONE__INT_INT_INT (GtkObject *object, GtkSignalFunc func, gpointer func_data, GtkArg *args)
{
GuppiSignal_NONE__INT_INT_INT rfunc = (GuppiSignal_NONE__INT_INT_INT) func;
rfunc (object,
GTK_VALUE_INT (args[0]), GTK_VALUE_INT (args[1]), GTK_VALUE_INT (args[2]),
func_data);
}
typedef void (*GuppiSignal_NONE__INT_INT_INT_INT) (GtkObject *, gint, gint, gint, gint, gpointer closure);
static void
guppi_marshal_NONE__INT_INT_INT_INT (GtkObject *object, GtkSignalFunc func, gpointer func_data, GtkArg *args)
{
GuppiSignal_NONE__INT_INT_INT_INT rfunc = (GuppiSignal_NONE__INT_INT_INT_INT) func;
rfunc (object,
GTK_VALUE_INT (args[0]), GTK_VALUE_INT (args[1]), GTK_VALUE_INT (args[2]), GTK_VALUE_INT (args[3]),
func_data);
}
static void
guppi_data_table_class_init (GuppiDataTableClass *klass)
{
GtkObjectClass *object_class = (GtkObjectClass *)klass;
GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);
parent_class = gtk_type_class (GUPPI_TYPE_DATA);
object_class->finalize = guppi_data_table_finalize;
data_class->get_size_info = get_size_info;
data_class->validate_class = validate_class;
data_class->changed = changed;
klass->changed_dimensions = changed_dimensions;
klass->changed_table_entries = changed_table_entries;
klass->changed_table_labels = changed_table_labels;
guppi_data_table_signals[CHANGED_DIMENSIONS] =
gtk_signal_new ("changed_dimensions",
GTK_RUN_FIRST,
object_class->type,
GTK_SIGNAL_OFFSET (GuppiDataTableClass, changed_dimensions),
gtk_marshal_NONE__INT_INT,
GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT);
guppi_data_table_signals[CHANGED_TABLE_ENTRIES] =
gtk_signal_new ("changed_table_entries",
GTK_RUN_FIRST,
object_class->type,
GTK_SIGNAL_OFFSET (GuppiDataTableClass, changed_table_entries),
guppi_marshal_NONE__INT_INT_INT_INT,
GTK_TYPE_NONE, 4, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
guppi_data_table_signals[CHANGED_TABLE_LABELS] =
gtk_signal_new ("changed_table_labels",
GTK_RUN_FIRST,
object_class->type,
GTK_SIGNAL_OFFSET (GuppiDataTableClass, changed_table_labels),
guppi_marshal_NONE__INT_INT_INT,
GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_INT);
gtk_object_class_add_signals (object_class, guppi_data_table_signals, LAST_SIGNAL);
}
static void
guppi_data_table_init (GuppiDataTable *obj)
{
obj->priv = g_new0 (GuppiDataTablePrivate, 1);
}
GtkType
guppi_data_table_get_type (void)
{
static GtkType guppi_data_table_type = 0;
if (!guppi_data_table_type) {
static const GtkTypeInfo guppi_data_table_info = {
"GuppiDataTable",
sizeof (GuppiDataTable),
sizeof (GuppiDataTableClass),
(GtkClassInitFunc)guppi_data_table_class_init,
(GtkObjectInitFunc)guppi_data_table_init,
NULL, NULL, (GtkClassInitFunc)NULL
};
guppi_data_table_type = gtk_type_unique (GUPPI_TYPE_DATA, &guppi_data_table_info);
}
return guppi_data_table_type;
}
syntax highlighted by Code2HTML, v. 0.9.1