From 1ba9ab71de8a6528beaf22de3ee6d2eb697eb61d Mon Sep 17 00:00:00 2001
From: John Darrington <john@darrington.wattle.id.au>
Date: Thu, 25 May 2006 10:29:14 +0000
Subject: [PATCH] Plugged memory leaks in GUI, and converted most of the
 strings to UTF8, so that internationalised data files are now rendered OK.
 Fixed a buglet in PRINT command.

---
 lib/gtksheet/ChangeLog              |   7 +
 lib/gtksheet/gsheet-column-iface.c  |  21 +--
 lib/gtksheet/gsheet-column-iface.h  |   4 +-
 lib/gtksheet/gsheet-hetero-column.c |   4 +-
 lib/gtksheet/gsheet-row-iface.c     |  10 +-
 lib/gtksheet/gsheet-row-iface.h     |   6 +-
 lib/gtksheet/gsheet-uniform-row.c   |   4 +-
 lib/gtksheet/gtkextra-sheet.h       |   3 +
 lib/gtksheet/gtksheet.c             |  83 +++++++++---
 src/language/data-io/ChangeLog      |   6 +
 src/language/data-io/print.c        |   5 +-
 src/output/ChangeLog                |   4 +
 src/output/table.h                  |   2 -
 src/ui/gui/ChangeLog                |   5 +
 src/ui/gui/psppire-var-store.c      | 200 +++++++++++++++-------------
 tests/automake.mk                   |   1 +
 tests/bugs/print-crash.sh           |  75 +++++++++++
 17 files changed, 292 insertions(+), 148 deletions(-)
 create mode 100755 tests/bugs/print-crash.sh

diff --git a/lib/gtksheet/ChangeLog b/lib/gtksheet/ChangeLog
index b4a99709e5..8c2a073d7e 100644
--- a/lib/gtksheet/ChangeLog
+++ b/lib/gtksheet/ChangeLog
@@ -1,3 +1,10 @@
+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 
diff --git a/lib/gtksheet/gsheet-column-iface.c b/lib/gtksheet/gsheet-column-iface.c
index a4cc9f36b3..5abd21bc2a 100644
--- a/lib/gtksheet/gsheet-column-iface.c
+++ b/lib/gtksheet/gsheet-column-iface.c
@@ -25,7 +25,7 @@
 #include <gobject/gvaluecollector.h>
 #include "gsheet-column-iface.h"
 #include "gtkextra-marshal.h"
-
+#include "gtkextra-sheet.h"
 
 enum {
   COLUMNS_CHANGED,
@@ -73,8 +73,6 @@ g_sheet_column_get_type (void)
 }
 
 
-static GtkSheetButton default_button;
-
 static void
 g_sheet_column_base_init (gpointer g_class)
 {
@@ -95,12 +93,6 @@ 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;
     }
 }
@@ -159,21 +151,20 @@ g_sheet_column_get_sensitivity(const GSheetColumn *column,
 }
 
 
-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 
diff --git a/lib/gtksheet/gsheet-column-iface.h b/lib/gtksheet/gsheet-column-iface.h
index 4e3e5a1b9d..6c9970806b 100644
--- a/lib/gtksheet/gsheet-column-iface.h
+++ b/lib/gtksheet/gsheet-column-iface.h
@@ -71,7 +71,7 @@ struct _GSheetColumnIface
 
 
   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, 
@@ -99,7 +99,7 @@ inline gboolean  g_sheet_column_get_sensitivity(const GSheetColumn *gcolumn,
 					     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);
diff --git a/lib/gtksheet/gsheet-hetero-column.c b/lib/gtksheet/gsheet-hetero-column.c
index e4235656bb..1285e9f237 100644
--- a/lib/gtksheet/gsheet-hetero-column.c
+++ b/lib/gtksheet/gsheet-hetero-column.c
@@ -128,12 +128,12 @@ g_sheet_hetero_column_get_visibility(const GSheetColumn *geom, gint u)
 
 
 
-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);
 }
 
 
diff --git a/lib/gtksheet/gsheet-row-iface.c b/lib/gtksheet/gsheet-row-iface.c
index 01a96afe88..7c716d8588 100644
--- a/lib/gtksheet/gsheet-row-iface.c
+++ b/lib/gtksheet/gsheet-row-iface.c
@@ -154,22 +154,20 @@ g_sheet_row_get_sensitivity(const GSheetRow *row_geo,
 }
 
 
-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;
 }
 
 
diff --git a/lib/gtksheet/gsheet-row-iface.h b/lib/gtksheet/gsheet-row-iface.h
index a6a62b2702..8575620a9b 100644
--- a/lib/gtksheet/gsheet-row-iface.h
+++ b/lib/gtksheet/gsheet-row-iface.h
@@ -69,8 +69,8 @@ struct _GSheetRowIface
   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 *);
@@ -101,7 +101,7 @@ gboolean  g_sheet_row_get_sensitivity(const GSheetRow *grow,
 					     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);
 
 
diff --git a/lib/gtksheet/gsheet-uniform-row.c b/lib/gtksheet/gsheet-uniform-row.c
index 6ab1c8ff11..f25480fbed 100644
--- a/lib/gtksheet/gsheet-uniform-row.c
+++ b/lib/gtksheet/gsheet-uniform-row.c
@@ -123,9 +123,7 @@ g_sheet_uniform_row_get_visibility(const GSheetRow *geom, gint u)
 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;
 }
diff --git a/lib/gtksheet/gtkextra-sheet.h b/lib/gtksheet/gtkextra-sheet.h
index bfc714ca34..0bd573c8a0 100644
--- a/lib/gtksheet/gtkextra-sheet.h
+++ b/lib/gtksheet/gtkextra-sheet.h
@@ -68,6 +68,9 @@ typedef struct _GtkSheetButton GtkSheetButton;
 
 
 
+GtkSheetButton * gtk_sheet_button_new(void);
+
+inline void gtk_sheet_button_free(GtkSheetButton *button);
 
 
 #endif /* __GTK_EXTRA_SHEET_H__ */
diff --git a/lib/gtksheet/gtksheet.c b/lib/gtksheet/gtksheet.c
index caed10ba12..bd506728db 100644
--- a/lib/gtksheet/gtksheet.c
+++ b/lib/gtksheet/gtksheet.c
@@ -260,7 +260,7 @@ ROW_FROM_YPIXEL(GtkSheet *sheet, gint y)
   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;
@@ -408,7 +408,7 @@ static inline gint SHEET_HEIGHT(GtkSheet *sheet)
 }
 
 
-static inline const GtkSheetButton *
+static inline GtkSheetButton *
 yyy_row_button(GtkSheet *sheet, gint row)
 {
   GSheetRow *row_geo = sheet->row_geometry;
@@ -1807,10 +1807,11 @@ gtk_sheet_show_column_titles(GtkSheet *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_show(child);
+      gtk_sheet_button_free(button);
     }
   adjust_scrollbars(sheet);
  } 
@@ -1881,10 +1882,11 @@ gtk_sheet_hide_column_titles(GtkSheet *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);
  }
@@ -6248,6 +6250,7 @@ gtk_sheet_entry_set_max_size(GtkSheet *sheet)
  gint sizel=0, sizer=0;
  gint row,col;
  GtkJustification justification;
+ gchar *s = NULL;
 
  row=sheet->active_cell.row;
  col=sheet->active_cell.col;
@@ -6260,34 +6263,52 @@ gtk_sheet_entry_set_max_size(GtkSheet *sheet)
   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
@@ -6467,7 +6488,7 @@ gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
   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;
@@ -6642,6 +6663,8 @@ gtk_sheet_button_draw (GtkSheet *sheet, gint row, gint column)
               gtk_widget_queue_draw(child->widget);
             }
   }
+
+  gtk_sheet_button_free(button);
    
 }
 
@@ -7886,3 +7909,25 @@ gtk_sheet_get_model(const GtkSheet *sheet)
   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);
+}
diff --git a/src/language/data-io/ChangeLog b/src/language/data-io/ChangeLog
index 21b2ed3cb3..23f215cfb4 100644
--- a/src/language/data-io/ChangeLog
+++ b/src/language/data-io/ChangeLog
@@ -1,3 +1,9 @@
+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.
diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c
index 63270160d9..b96ee13be3 100644
--- a/src/language/data-io/print.c
+++ b/src/language/data-io/print.c
@@ -141,7 +141,7 @@ static int
 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. */
@@ -966,7 +966,7 @@ print_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
   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_)
 {
@@ -996,7 +996,6 @@ print_trns_free (void *prt_)
   if (prt->writer != NULL)
     ok = dfm_close_writer (prt->writer);
   free (prt->line);
-  free (prt);
   return ok;
 }
 
diff --git a/src/output/ChangeLog b/src/output/ChangeLog
index e4f21a0074..04d1dd1ae7 100644
--- a/src/output/ChangeLog
+++ b/src/output/ChangeLog
@@ -1,3 +1,7 @@
+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
diff --git a/src/output/table.h b/src/output/table.h
index 51031da23c..6245d12bdb 100644
--- a/src/output/table.h
+++ b/src/output/table.h
@@ -102,8 +102,6 @@ struct tab_table
     int col_ofs, row_ofs;	/* X and Y offsets. */
   };
 
-extern int tab_hit;
-
 /* Number of rows in TABLE. */
 #define tab_nr(TABLE) ((TABLE)->nr)
 
diff --git a/src/ui/gui/ChangeLog b/src/ui/gui/ChangeLog
index 4fe6e3f37c..5782b9b5d3 100644
--- a/src/ui/gui/ChangeLog
+++ b/src/ui/gui/ChangeLog
@@ -1,3 +1,8 @@
+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
diff --git a/src/ui/gui/psppire-var-store.c b/src/ui/gui/psppire-var-store.c
index 09e1e716c8..aba2703452 100644
--- a/src/ui/gui/psppire-var-store.c
+++ b/src/ui/gui/psppire-var-store.c
@@ -49,7 +49,7 @@ static void         psppire_var_store_class_init      (PsppireVarStoreClass *cla
 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);
 
@@ -58,7 +58,7 @@ static gboolean psppire_var_store_set_string(GSheetModel *model,
 					  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;
@@ -297,11 +297,9 @@ psppire_var_store_finalize (GObject *object)
   (* 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;
@@ -311,9 +309,7 @@ psppire_var_store_get_string(GSheetModel *model, gint row, gint column)
   
   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);
 }
 
 
@@ -416,13 +412,9 @@ psppire_var_store_set_string(GSheetModel *model,
 }
 
 
-#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[] = 
@@ -444,23 +436,23 @@ text_for_column(const struct PsppireVariable *pv, gint c)
   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:	
@@ -475,20 +467,20 @@ text_for_column(const struct PsppireVariable *pv, gint c)
 	  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", 
@@ -499,93 +491,109 @@ text_for_column(const struct PsppireVariable *pv, gint c)
       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);
@@ -593,22 +601,27 @@ text_for_column(const struct PsppireVariable *pv, gint c)
 	    {
 	      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;
 }
@@ -636,3 +649,4 @@ psppire_var_store_set_font(PsppireVarStore *store, PangoFontDescription *fd)
 
 
 
+
diff --git a/tests/automake.mk b/tests/automake.mk
index e809448423..033785961e 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -91,6 +91,7 @@ TESTS = \
 	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 \
diff --git a/tests/bugs/print-crash.sh b/tests/bugs/print-crash.sh
new file mode 100755
index 0000000000..d362ede1dd
--- /dev/null
+++ b/tests/bugs/print-crash.sh
@@ -0,0 +1,75 @@
+#!/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;
-- 
2.30.2