internationalised data files are now rendered OK.
Fixed a buglet in PRINT command.
+Thu May 25 17:58:51 WST 2006 John Darrington <john@darrington.wattle.id.au>
+
+ * gsheet-column-iface.c gsheet-column-iface.h gsheet-hetero-column.c
+ gsheet-row-iface.c gsheet-row-iface.h gsheet-uniform-row.c
+ gtksheet-extra.h gtksheet.c: Plugged memory leaks. Rationalised the way
+ that GtkSheetButtons are created.
+
Sat May 20 21:02:03 WST 2006 John Darrington <john@darrington.wattle.id.au>
* gsheetmodel.c gsheetmodel.h: Added columns-inserted and columns-deleted
#include <gobject/gvaluecollector.h>
#include "gsheet-column-iface.h"
#include "gtkextra-marshal.h"
-
+#include "gtkextra-sheet.h"
enum {
COLUMNS_CHANGED,
}
-static GtkSheetButton default_button;
-
static void
g_sheet_column_base_init (gpointer g_class)
{
G_TYPE_INT);
- default_button.state = GTK_STATE_NORMAL;
- default_button.label = NULL;
- default_button.label_visible = TRUE;
- default_button.child = NULL;
- default_button.justification = GTK_JUSTIFY_FILL;
-
initialized = TRUE;
}
}
}
-inline const GtkSheetButton *
+inline GtkSheetButton *
g_sheet_column_get_button(const GSheetColumn *column,
gint col, const GtkSheet *sheet)
{
- static GtkSheetButton button ;
+ GtkSheetButton *button = gtk_sheet_button_new();
+
GSheetColumnIface *iface = G_SHEET_COLUMN_GET_IFACE (column);
g_return_val_if_fail (G_IS_SHEET_COLUMN (column), FALSE);
- memcpy(&button, &default_button, sizeof (button));
-
if ( iface->get_button_label)
- button.label = iface->get_button_label(column, col, sheet);
+ button->label = iface->get_button_label(column, col, sheet);
- return &button;
+ return button;
}
inline GtkJustification
GtkStateType (*get_button_state)(const GSheetColumn *geo, gint col, const GtkSheet *);
- const gchar * (*get_button_label)(const GSheetColumn *geo, gint col, const GtkSheet *);
+ gchar * (*get_button_label)(const GSheetColumn *geo, gint col, const GtkSheet *);
gboolean (*get_button_visibility)(const GSheetColumn *geo,
gint col, const GtkSheet *);
const GtkSheetChild * (*get_button_child)(const GSheetColumn *geo,
gint col, const GtkSheet *sheet);
-inline const GtkSheetButton *g_sheet_column_get_button(const GSheetColumn *gcolumn,
+inline GtkSheetButton *g_sheet_column_get_button(const GSheetColumn *gcolumn,
gint col, const GtkSheet *sheet);
inline GtkJustification g_sheet_column_get_justification(const GSheetColumn *gcolumn, gint col, const GtkSheet *sheet);
-static const gchar *
+static gchar *
g_sheet_hetero_column_get_button_label(const GSheetColumn *geom, gint u)
{
GSheetHeteroColumn *hg = G_SHEET_HETERO_COLUMN(geom);
- return hg->col[u].button.label;
+ return g_locale_to_utf8(hg->col[u].button.label, -1, 0, 0, 0);
}
}
-const GtkSheetButton *
+GtkSheetButton *
g_sheet_row_get_button(const GSheetRow *row_geo,
gint row, const GtkSheet *sheet)
{
- static GtkSheetButton button ;
+ GtkSheetButton *button = gtk_sheet_button_new();
GSheetRowIface *iface = G_SHEET_ROW_GET_IFACE (row_geo);
g_return_val_if_fail (G_IS_SHEET_ROW (row_geo), FALSE);
- memcpy(&button, &default_button, sizeof (button));
-
if ( iface->get_button_label)
- button.label = iface->get_button_label(row_geo, row, sheet);
+ button->label = iface->get_button_label(row_geo, row, sheet);
- return &button;
+ return button;
}
GtkStateType (*get_button_state)(const GSheetRow *geo, gint row,
const GtkSheet *);
- const gchar * (*get_button_label)(const GSheetRow *geo, gint row,
- const GtkSheet *);
+ gchar * (*get_button_label)(const GSheetRow *geo, gint row,
+ const GtkSheet *);
gboolean (*get_button_visibility)(const GSheetRow *geo,
gint row, const GtkSheet *);
gint row, const GtkSheet *sheet);
-const GtkSheetButton *g_sheet_row_get_button(const GSheetRow *grow,
+GtkSheetButton *g_sheet_row_get_button(const GSheetRow *grow,
gint row, const GtkSheet *sheet);
static const gchar *
g_sheet_uniform_row_get_button_label(const GSheetRow *geom, gint u)
{
- static gchar *label;
- g_free(label);
- label = g_strdup_printf("%d", u);
+ gchar *label = g_strdup_printf("%d", u);
return label;
}
+GtkSheetButton * gtk_sheet_button_new(void);
+
+inline void gtk_sheet_button_free(GtkSheetButton *button);
#endif /* __GTK_EXTRA_SHEET_H__ */
return (yyy_row_ypixel_to_row(sheet, y));
}
-static inline const GtkSheetButton *
+static inline GtkSheetButton *
xxx_column_button(GtkSheet *sheet, gint col)
{
GSheetColumn *col_geo = sheet->column_geometry;
}
-static inline const GtkSheetButton *
+static inline GtkSheetButton *
yyy_row_button(GtkSheet *sheet, gint row)
{
GSheetRow *row_geo = sheet->row_geometry;
col <= MAX_VISIBLE_COLUMN(sheet);
col++)
{
- const GtkSheetButton *button = xxx_column_button(sheet, col);
+ GtkSheetButton *button = xxx_column_button(sheet, col);
GtkSheetChild *child = button->child;
if(child)
gtk_sheet_child_show(child);
+ gtk_sheet_button_free(button);
}
adjust_scrollbars(sheet);
}
col <= MAX_VISIBLE_COLUMN(sheet);
col++)
{
- const GtkSheetButton *button = xxx_column_button(sheet, col);
+ GtkSheetButton *button = xxx_column_button(sheet, col);
GtkSheetChild *child = button->child;
if(child)
gtk_sheet_child_hide(child);
+ gtk_sheet_button_free(button);
}
adjust_scrollbars(sheet);
}
gint sizel=0, sizer=0;
gint row,col;
GtkJustification justification;
+ gchar *s = NULL;
row=sheet->active_cell.row;
col=sheet->active_cell.col;
case GTK_JUSTIFY_FILL:
case GTK_JUSTIFY_LEFT:
for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
- if(gtk_sheet_cell_get_text(sheet, row, i)) break;
+ if((s = gtk_sheet_cell_get_text(sheet, row, i)))
+ {
+ g_free(s);
+ break;
+ }
size+=xxx_column_width(sheet, i);
}
size = MIN(size, sheet->sheet_window_width - COLUMN_LEFT_XPIXEL(sheet, col));
break;
- case GTK_JUSTIFY_RIGHT:
- for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
- if(gtk_sheet_cell_get_text(sheet, row, i)) break;
- size+=xxx_column_width(sheet, i);
- }
+ case GTK_JUSTIFY_RIGHT:
+ for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--)
+ {
+ if((s = gtk_sheet_cell_get_text(sheet, row, i)))
+ {
+ g_free(s);
+ break;
+ }
+ size+=xxx_column_width(sheet, i);
+ }
break;
case GTK_JUSTIFY_CENTER:
for(i=col+1; i<=MAX_VISIBLE_COLUMN(sheet); i++){
-/* if(gtk_sheet_cell_get_text(sheet, row, i)) break;
+/* if((s = gtk_sheet_cell_get_text(sheet, row, i)))
+ {
+ g_free(s);
+ break;
+ }
*/
sizer+=xxx_column_width(sheet, i);
}
- for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--){
- if(gtk_sheet_cell_get_text(sheet, row, i)) break;
- sizel+=xxx_column_width(sheet, i);
- }
+ for(i=col-1; i>=MIN_VISIBLE_COLUMN(sheet); i--)
+ {
+ if((s = gtk_sheet_cell_get_text(sheet, row, i)))
+ {
+ g_free(s);
+ break;
+ }
+ sizel+=xxx_column_width(sheet, i);
+ }
size=2*MIN(sizel, sizer);
break;
}
- if(size!=0) size+=xxx_column_width(sheet, col);
- GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size=size;
-
+ if(size != 0)
+ size += xxx_column_width(sheet, col);
+ GTK_ITEM_ENTRY(sheet->sheet_entry)->text_max_size = size;
}
static void
gint x = 0, y = 0;
gint index = 0;
gint text_width = 0, text_height = 0;
- const GtkSheetButton *button = NULL;
+ GtkSheetButton *button = NULL;
GtkSheetChild *child = NULL;
GdkRectangle allocation;
gboolean is_sensitive = FALSE;
gtk_widget_queue_draw(child->widget);
}
}
+
+ gtk_sheet_button_free(button);
}
return sheet->model;
}
+
+GtkSheetButton *
+gtk_sheet_button_new(void)
+{
+ GtkSheetButton *button = g_slice_new(GtkSheetButton);
+
+ button->state = GTK_STATE_NORMAL;
+ button->label = NULL;
+ button->label_visible = TRUE;
+ button->child = NULL;
+ button->justification = GTK_JUSTIFY_FILL;
+
+ return button;
+}
+
+
+inline void
+gtk_sheet_button_free(GtkSheetButton *button)
+{
+ g_free(button->label);
+ g_slice_free(GtkSheetButton, button);
+}
+Thu May 25 18:26:26 WST 2006 John Darrington <john@darrington.wattle.id.au>
+
+ * print.c (print_trns_free): Made the code agree with the comment, by
+ not freeing PRT. Has the side effect that the command no longer
+ crashes on invalid syntax.
+
Tue May 9 20:55:46 2006 Ben Pfaff <blp@gnu.org>
* get.c (cmd_match_files): Fix memory leak replacing default_dict.
internal_cmd_print (int f)
{
int table = 0; /* Print table? */
- struct print_trns *trns; /* malloc()'d transformation. */
+ struct print_trns *trns = NULL; /* malloc()'d transformation. */
struct file_handle *fh = NULL;
/* Fill in prt to facilitate error-handling. */
return TRNS_CONTINUE;
}
-/* Frees all the data inside print_trns T. Does not free T. */
+/* Frees all the data inside print_trns PRT. Does not free PRT. */
static bool
print_trns_free (void *prt_)
{
if (prt->writer != NULL)
ok = dfm_close_writer (prt->writer);
free (prt->line);
- free (prt);
return ok;
}
\f
+Thu May 25 18:02:53 WST 2006 John Darrington <john@darrington.wattle.id.au>
+
+ * table.c: Removed redundant extern declaration.
+
Sun May 14 14:03:56 2006 Ben Pfaff <blp@gnu.org>
* output.c (outp_eject_page): Always make sure that a page is open
int col_ofs, row_ofs; /* X and Y offsets. */
};
-extern int tab_hit;
-
/* Number of rows in TABLE. */
#define tab_nr(TABLE) ((TABLE)->nr)
+Thu May 25 18:01:17 WST 2006 John Darrington <john@darrington.wattle.id.au>
+
+ * psppire-var-store.c: Converted strings to utf8 and returned them on the
+ heap.
+
Sat May 20 21:08:18 WST 2006 John Darrington <john@darrington.wattle.id.au>
* data-sheet.c, menu-actions.c menu-actions: Fixed data sheet so that
static void psppire_var_store_sheet_model_init (GSheetModelIface *iface);
static void psppire_var_store_finalize (GObject *object);
-static const gchar *psppire_var_store_get_string(GSheetModel *sheet_model, gint row, gint column);
+static gchar *psppire_var_store_get_string(GSheetModel *sheet_model, gint row, gint column);
static gboolean psppire_var_store_clear(GSheetModel *model, gint row, gint col);
const gchar *text, gint row, gint column);
-static const gchar *text_for_column(const struct PsppireVariable *pv, gint c);
+static gchar *text_for_column(const struct PsppireVariable *pv, gint c, GError **err);
static GObjectClass *parent_class = NULL;
(* parent_class->finalize) (object);
}
-static const gchar *
+static gchar *
psppire_var_store_get_string(GSheetModel *model, gint row, gint column)
{
- const gchar *s ;
-
PsppireVarStore *store = PSPPIRE_VAR_STORE(model);
struct PsppireVariable *pv;
pv = psppire_dict_get_variable (store->dict, row);
- s = text_for_column(pv, column);
-
- return pspp_locale_to_utf8(s, -1, 0);
+ return text_for_column(pv, column, 0);
}
}
-#define MAX_CELL_TEXT_LEN 255
-
-static const gchar *
-text_for_column(const struct PsppireVariable *pv, gint c)
+static gchar *
+text_for_column(const struct PsppireVariable *pv, gint c, GError **err)
{
- static gchar buf[MAX_CELL_TEXT_LEN];
-
static gchar none[]=_("None");
static const gchar *const type_label[] =
switch (c)
{
case COL_NAME:
- return psppire_variable_get_name(pv);
+ return pspp_locale_to_utf8(psppire_variable_get_name(pv), -1, err);
break;
case COL_TYPE:
{
switch ( write_spec->type )
{
case FMT_F:
- return type_label[VT_NUMERIC];
+ return g_locale_to_utf8(type_label[VT_NUMERIC], -1, 0, 0, err);
break;
case FMT_COMMA:
- return type_label[VT_COMMA];
+ return g_locale_to_utf8(type_label[VT_COMMA], -1, 0, 0, err);
break;
case FMT_DOT:
- return type_label[VT_DOT];
+ return g_locale_to_utf8(type_label[VT_DOT], -1, 0, 0, err);
break;
case FMT_E:
- return type_label[VT_SCIENTIFIC];
+ return g_locale_to_utf8(type_label[VT_SCIENTIFIC], -1, 0, 0, err);
break;
case FMT_DATE:
case FMT_EDATE:
case FMT_DTIME:
case FMT_WKDAY:
case FMT_MONTH:
- return type_label[VT_DATE];
+ return g_locale_to_utf8(type_label[VT_DATE], -1, 0, 0, err);
break;
case FMT_DOLLAR:
- return type_label[VT_DOLLAR];
+ return g_locale_to_utf8(type_label[VT_DOLLAR], -1, 0, 0, err);
break;
case FMT_CCA:
case FMT_CCB:
case FMT_CCC:
case FMT_CCD:
case FMT_CCE:
- return type_label[VT_CUSTOM];
+ return g_locale_to_utf8(type_label[VT_CUSTOM], -1, 0, 0, err);
break;
case FMT_A:
- return type_label[VT_STRING];
+ return g_locale_to_utf8(type_label[VT_STRING], -1, 0, 0, err);
break;
default:
g_warning("Unknown format: \"%s\"\n",
break;
case COL_WIDTH:
{
- g_snprintf(buf, MAX_CELL_TEXT_LEN, "%d", write_spec->w);
- return buf;
+ gchar *s;
+ GString *gstr = g_string_sized_new(10);
+ g_string_printf(gstr, "%d", write_spec->w);
+ s = g_locale_to_utf8(gstr->str, gstr->len, 0, 0, err);
+ g_string_free(gstr, TRUE);
+ return s;
}
break;
case COL_DECIMALS:
{
- g_snprintf(buf, MAX_CELL_TEXT_LEN, "%d", write_spec->d);
- return buf;
+ gchar *s;
+ GString *gstr = g_string_sized_new(10);
+ g_string_printf(gstr, "%d", write_spec->d);
+ s = g_locale_to_utf8(gstr->str, gstr->len, 0, 0, err);
+ g_string_free(gstr, TRUE);
+ return s;
}
break;
case COL_COLUMNS:
{
- g_snprintf(buf, MAX_CELL_TEXT_LEN,
- "%d", psppire_variable_get_columns(pv));
- return buf;
+ gchar *s;
+ GString *gstr = g_string_sized_new(10);
+ g_string_printf(gstr, "%d", psppire_variable_get_columns(pv));
+ s = g_locale_to_utf8(gstr->str, gstr->len, 0, 0, err);
+ g_string_free(gstr, TRUE);
+ return s;
}
break;
case COL_LABEL:
- return psppire_variable_get_label(pv);
+ return g_locale_to_utf8(psppire_variable_get_label(pv), -1, 0, 0, err);
break;
+
case COL_MISSING:
{
- const struct missing_values *miss = psppire_variable_get_missing(pv);
- if ( mv_is_empty(miss))
- return none;
- else
- {
- if ( ! mv_has_range (miss))
- {
- const int n = mv_n_values(miss);
- gchar *mv[4] = {0,0,0,0};
- gint i;
- for(i = 0 ; i < n; ++i )
- {
- union value v;
- mv_peek_value(miss, &v, i);
- mv[i] = value_to_text(v, *write_spec);
- }
- g_stpcpy(buf, "");
- for(i = 0 ; i < n; ++i )
- {
- if ( i > 0)
- g_strlcat(buf, ", ", MAX_CELL_TEXT_LEN);
- g_strlcat(buf, mv[i], MAX_CELL_TEXT_LEN);
- g_free(mv[i]);
- }
- }
- else
- {
- gchar *l, *h;
- union value low, high;
- mv_peek_range(miss, &low.f, &high.f);
+ gchar *s;
+ const struct missing_values *miss = psppire_variable_get_missing(pv);
+ if ( mv_is_empty(miss))
+ return g_locale_to_utf8(none, -1, 0, 0, err);
+ else
+ {
+ if ( ! mv_has_range (miss))
+ {
+ GString *gstr = g_string_sized_new(10);
+ const int n = mv_n_values(miss);
+ gchar *mv[4] = {0,0,0,0};
+ gint i;
+ for(i = 0 ; i < n; ++i )
+ {
+ union value v;
+ mv_peek_value(miss, &v, i);
+ mv[i] = value_to_text(v, *write_spec);
+ if ( i > 0 )
+ g_string_append(gstr, ", ");
+ g_string_append(gstr, mv[i]);
+ g_free(mv[i]);
+ }
+ s = pspp_locale_to_utf8(gstr->str, gstr->len, err);
+ g_string_free(gstr, TRUE);
+ }
+ else
+ {
+ GString *gstr = g_string_sized_new(10);
+ gchar *l, *h;
+ union value low, high;
+ mv_peek_range(miss, &low.f, &high.f);
- l = value_to_text(low, *write_spec);
- h = value_to_text(high, *write_spec);
-
- g_snprintf(buf, MAX_CELL_TEXT_LEN, "%s - %s", l, h);
- g_free(l);
- g_free(h);
-
- if ( mv_has_value(miss))
- {
- gchar buf2[MAX_CELL_TEXT_LEN];
- gchar *s = 0;
- union value v;
- mv_peek_value(miss, &v, 0);
-
- s = value_to_text(v, *write_spec);
-
- g_snprintf(buf2, MAX_CELL_TEXT_LEN, "%s, %s", buf, s);
- free(s);
- g_stpcpy(buf, buf2);
- }
- }
-
- return buf;
- }
+ l = value_to_text(low, *write_spec);
+ h = value_to_text(high, *write_spec);
+
+ g_string_printf(gstr, "%s - %s", l, h);
+ g_free(l);
+ g_free(h);
+
+ if ( mv_has_value(miss))
+ {
+ gchar *ss = 0;
+ union value v;
+ mv_peek_value(miss, &v, 0);
+
+ ss = value_to_text(v, *write_spec);
+
+ g_string_append(gstr, ", ");
+ g_string_append(gstr, ss);
+ free(ss);
+ }
+ s = pspp_locale_to_utf8(gstr->str, gstr->len, err);
+ g_string_free(gstr, TRUE);
+ }
+
+ return s;
+ }
}
break;
case COL_VALUES:
{
const struct val_labs *vls = psppire_variable_get_value_labels(pv);
- if ( ! vls || 0 == val_labs_count(vls))
- return none;
+ if ( ! vls || 0 == val_labs_count(vls) )
+ return g_locale_to_utf8(none, -1, 0, 0, err);
else
{
- struct val_labs_iterator *ip=0;
+ gchar *ss;
+ GString *gstr = g_string_sized_new(10);
+ struct val_labs_iterator *ip = 0;
struct val_lab *vl = val_labs_first_sorted (vls, &ip);
g_assert(vl);
{
gchar *const vstr = value_to_text(vl->value, *write_spec);
- g_snprintf(buf, MAX_CELL_TEXT_LEN, "{%s,\"%s\"}_", vstr, vl->label);
+ g_string_printf(gstr, "{%s,\"%s\"}_", vstr, vl->label);
g_free(vstr);
}
val_labs_done(&ip);
-
- return buf;
+
+ ss = pspp_locale_to_utf8(gstr->str, gstr->len, err);
+ g_string_free(gstr, TRUE);
+ return ss;
}
}
break;
case COL_ALIGN:
- return alignments[psppire_variable_get_alignment(pv)];
+ return g_locale_to_utf8(alignments[psppire_variable_get_alignment(pv)],
+ -1, -0, 0, err);
break;
case COL_MEASURE:
- return measures[psppire_variable_get_measure(pv)];
+ return g_locale_to_utf8(measures[psppire_variable_get_measure(pv)],
+ -1, -0, 0, err);
break;
+
}
return 0;
}
+
tests/bugs/computebug.sh \
tests/bugs/compute-lv.sh \
tests/bugs/temp-freq.sh \
+ tests/bugs/print-crash.sh \
tests/xforms/casefile.sh \
tests/stats/descript-basic.sh \
tests/stats/descript-missing.sh \
--- /dev/null
+#!/bin/sh
+
+# This program tests for a bug which crashed when deallocating after a bad
+# PRINT command.
+
+TEMPDIR=/tmp/pspp-tst-$$
+TESTFILE=$TEMPDIR/`basename $0`.sps
+
+# ensure that top_srcdir and top_builddir are absolute
+if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
+if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
+top_srcdir=`cd $top_srcdir; pwd`
+top_builddir=`cd $top_builddir; pwd`
+
+PSPP=$top_builddir/src/ui/terminal/pspp
+
+export STAT_CONFIG_PATH=$top_srcdir/config
+
+
+cleanup()
+{
+ if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then
+ echo "NOT cleaning $TEMPDIR"
+ return ;
+ fi
+ rm -rf $TEMPDIR
+}
+
+
+fail()
+{
+ echo $activity
+ echo FAILED
+ cleanup;
+ exit 1;
+}
+
+
+no_result()
+{
+ echo $activity
+ echo NO RESULT;
+ cleanup;
+ exit 2;
+}
+
+pass()
+{
+ cleanup;
+ exit 0;
+}
+
+mkdir -p $TEMPDIR
+
+cd $TEMPDIR
+
+cat > $TESTFILE << EOF
+DATA LIST LIST /a * b *.
+BEGIN DATA.
+1 2
+3 4
+END DATA.
+
+PRINT F8.2
+LIST.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="run program"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+if [ $? -ne 1 ] ; then fail ; fi
+
+
+pass;