Merge master into output branch.
authorBen Pfaff <blp@gnu.org>
Tue, 11 Aug 2009 21:18:26 +0000 (14:18 -0700)
committerBen Pfaff <blp@gnu.org>
Tue, 11 Aug 2009 21:18:26 +0000 (14:18 -0700)
142 files changed:
AUTHORS
Smake
configure.ac
doc/dev/concepts.texi
doc/dev/i18n.texi
doc/statistics.texi
lib/gtk-contrib/psppire-sheet.c
lib/gtk-contrib/psppire-sheet.h
perl-module/PSPP.xs
perl-module/lib/PSPP.pm
po/en_GB.po
po/nl.po
src/data/case-map.c
src/data/case.c
src/data/case.h
src/data/casereader-translator.c
src/data/casereader.h
src/data/data-in.c
src/data/data-in.h
src/data/data-out.c
src/data/data-out.h
src/data/file-handle-def.c
src/data/file-handle-def.h
src/data/gnumeric-reader.c
src/data/missing-values.c
src/data/missing-values.h
src/data/por-file-reader.c
src/data/subcase.c
src/data/subcase.h
src/data/sys-file-reader.c
src/data/sys-file-writer.c
src/data/value.c
src/data/value.h
src/data/variable.c
src/data/variable.h
src/language/command.c
src/language/command.def
src/language/data-io/data-list.c
src/language/data-io/data-parser.c
src/language/data-io/data-parser.h
src/language/data-io/data-reader.c
src/language/data-io/data-reader.h
src/language/data-io/data-writer.c
src/language/data-io/data-writer.h
src/language/data-io/file-handle.q
src/language/data-io/get-data.c
src/language/data-io/list.q
src/language/data-io/print.c
src/language/dictionary/missing-values.c
src/language/dictionary/split-file.c
src/language/expressions/operations.def
src/language/lexer/lexer.c
src/language/lexer/value-parser.c
src/language/stats/aggregate.c
src/language/stats/automake.mk
src/language/stats/crosstabs.q
src/language/stats/flip.c
src/language/stats/frequencies.q
src/language/stats/regression.q
src/language/stats/roc.c [new file with mode: 0644]
src/language/stats/roc.h [new file with mode: 0644]
src/language/stats/t-test.q
src/language/stats/wilcoxon.c
src/language/syntax-file.c
src/language/utilities/set.q
src/language/xforms/recode.c
src/libpspp/i18n.c
src/libpspp/i18n.h
src/libpspp/legacy-encoding.c
src/libpspp/legacy-encoding.h
src/libpspp/str.c
src/libpspp/str.h
src/math/covariance-matrix.c
src/math/covariance-matrix.h
src/math/interaction.c
src/math/interaction.h
src/math/linreg.c
src/output/automake.mk
src/output/cairo.c
src/output/chart-provider.h
src/output/chart.c
src/output/charts/cartesian.c
src/output/charts/cartesian.h
src/output/charts/plot-chart.c
src/output/charts/plot-chart.h
src/output/charts/roc-chart.c [new file with mode: 0644]
src/output/charts/roc-chart.h [new file with mode: 0644]
src/output/table.c
src/output/table.h
src/ui/gui/about.c
src/ui/gui/comments-dialog.c
src/ui/gui/compute-dialog.c
src/ui/gui/crosstabs-dialog.c
src/ui/gui/descriptives-dialog.c
src/ui/gui/dialog-common.c
src/ui/gui/dict-display.c
src/ui/gui/examine-dialog.c
src/ui/gui/find-dialog.c
src/ui/gui/frequencies-dialog.c
src/ui/gui/helper.c
src/ui/gui/helper.h
src/ui/gui/missing-val-dialog.c
src/ui/gui/missing-val-dialog.h
src/ui/gui/oneway-anova-dialog.c
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-data-window.c
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-dictview.c
src/ui/gui/psppire-output-window.h
src/ui/gui/psppire-var-sheet.c
src/ui/gui/psppire-var-store.c
src/ui/gui/psppire-var-store.h
src/ui/gui/psppire.glade
src/ui/gui/rank-dialog.c
src/ui/gui/recode-dialog.c
src/ui/gui/regression-dialog.c
src/ui/gui/reliability-dialog.c
src/ui/gui/sort-cases-dialog.c
src/ui/gui/split-file-dialog.c
src/ui/gui/t-test-independent-samples-dialog.c
src/ui/gui/t-test-one-sample.c
src/ui/gui/t-test-paired-samples.c
src/ui/gui/text-data-import-dialog.c
src/ui/gui/transpose-dialog.c
src/ui/gui/val-labs-dialog.c
src/ui/gui/val-labs-dialog.h
src/ui/gui/var-display.c
src/ui/gui/var-type-dialog.c
src/ui/gui/variable-info-dialog.c
src/ui/gui/weight-cases-dialog.c
src/ui/syntax-gen.c
tests/automake.mk
tests/bugs/shbang.sh [new file with mode: 0755]
tests/bugs/t-test-paired.sh [new file with mode: 0755]
tests/command/data-list.sh
tests/command/get-data-gnm.sh
tests/command/npar-wilcoxon.sh
tests/command/roc.sh [new file with mode: 0755]
tests/command/roc2.sh [new file with mode: 0755]
tests/data/datasheet-test.c
tests/dissect-sysfile.c

diff --git a/AUTHORS b/AUTHORS
index af7e9075f8da674b0013c55ec974b998ff9db0e8..db7a59105fbe6600eed2136d196ac4e691e710ff 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,9 +6,9 @@ most of the core libraries which ensure that PSPP runs with optimal
 speed are his work.
 
 * John Darrington wrote the graphical user interface, and the T-TEST,
-ONEWAY, EXAMINE, RANK and  NPAR TESTS commands, implemented support
-for long variable names, psql and gnumeric and made numerous revisions
-to other modules.   
+ONEWAY, EXAMINE, RANK and NPAR TESTS commands, implemented support for
+long variable names, PostgreSQL and Gnumeric and made numerous
+revisions to other modules.
 
 * Jason Stover contributed statistical and numerical functionality,
 including lib/gslextras and the linear regression features. Jason 
diff --git a/Smake b/Smake
index 78789d4fed818420b8567a8508ed155dc5fde5b9..79b573b54962d6edec256ea1ddce8fda5c932c02 100644 (file)
--- a/Smake
+++ b/Smake
@@ -76,6 +76,9 @@ GNULIB_MODULES = \
        trunc \
        unilbrk/ulc-width-linebreaks \
        unistd \
+       unistr/u8-cpy \
+       unistr/u8-strlen \
+       unistr/u8-strncat \
        unlocked-io \
        vasprintf-posix \
        vfprintf-posix \
index 77519330b8d54fc926b058395197dff644ff31a6..5ed6d74fa5d704e87be89e7797b62013c56fa309 100644 (file)
@@ -118,7 +118,7 @@ if test x"$with_libpq" != x"no" ; then
 fi
 AM_CONDITIONAL(PSQL_SUPPORT, test -n "$PG_CONFIG")
 
-dnl Checks needed for gnumeric reader
+dnl Checks needed for Gnumeric reader
 gnm_support=yes;
 PKG_CHECK_MODULES(LIBXML2, libxml-2.0,,
                           [PSPP_OPTIONAL_PREREQ([libxml2]); gnm_support=no;]);
index cc6e75226f3ce952f6e0db1dcaa95ae67f07db47..06652d62653b1ec21ccdbc387f8993ae8f762b1f 100644 (file)
@@ -654,19 +654,17 @@ Returns the name of the given format @var{type}.
 These functions provide the ability to convert data fields into
 @union{value}s and vice versa.
 
-@deftypefun bool data_in (struct substring @var{input}, enum legacy_encoding @var{legacy_encoding}, enum fmt_type @var{type}, int @var{implied_decimals}, int @var{first_column}, union value *@var{output}, int @var{width})
+@deftypefun bool data_in (struct substring @var{input}, const char *@var{encoding}, enum fmt_type @var{type}, int @var{implied_decimals}, int @var{first_column}, const struct dictionary *@var{dict}, union value *@var{output}, int @var{width})
 Parses @var{input} as a field containing data in the given format
 @var{type}.  The resulting value is stored in @var{output}, which the
 caller must have initialized with the given @var{width}.  For
 consistency, @var{width} must be 0 if
 @var{type} is a numeric format type and greater than 0 if @var{type}
 is a string format type.
-
-Ordinarily @var{legacy_encoding} should be @code{LEGACY_NATIVE},
-indicating that @var{input} is encoded in the character set
-conventionally used on the host machine.  It may be set to
-@code{LEGACY_EBCDIC} to cause @var{input} to be re-encoded from EBCDIC
-during data parsing.
+@var{encoding} should be set to indicate the character
+encoding of @var{input}.
+@var{dict} must be a pointer to the dictionary with which @var{output}
+is associated.
 
 If @var{input} is the empty string (with length 0), @var{output} is
 set to the value set on SET BLANKS (@pxref{SET BLANKS,,,pspp, PSPP
@@ -701,21 +699,15 @@ not propagated to the caller as errors.
 This function is declared in @file{data/data-in.h}.
 @end deftypefun
 
-@deftypefun void data_out (const union value *@var{input}, const struct fmt_spec *@var{format}, char *@var{output})
-@deftypefunx void data_out_legacy (const union value *@var{input}, enum legacy_encoding @var{legacy_encoding}, const struct fmt_spec *@var{format}, char *@var{output})
-Converts the data pointed to by @var{input} into a data field in
-@var{output} according to output format specifier @var{format}, which
-must be a valid output format.  Exactly @code{@var{format}->w} bytes
-are written to @var{output}.  The width of @var{input} is also
+@deftypefun char * data_out (const union value *@var{input}, const struct fmt_spec *@var{format})
+@deftypefunx char * data_out_legacy (const union value *@var{input}, const char *@var{encoding}, const struct fmt_spec *@var{format})
+Converts the data pointed to by @var{input} into a string value, which
+will be encoded in UTF-8,  according to output format specifier @var{format}.
+Format 
+must be a valid output format.   The width of @var{input} is
 inferred from @var{format} using an algorithm equivalent to
 @func{fmt_var_width}.
 
-If @func{data_out} is called, or @func{data_out_legacy} is called with
-@var{legacy_encoding} set to @code{LEGACY_NATIVE}, @var{output} will
-be encoded in the character set conventionally used on the host
-machine.  If @var{legacy_encoding} is set to @code{LEGACY_EBCDIC},
-@var{output} will be re-encoded from EBCDIC during data output.
-
 When @var{input} contains data that cannot be represented in the given
 @var{format}, @func{data_out} may output a message using @func{msg},
 @c (@pxref{msg}),
index 97077d344e3135548fa4cc91c633062f4e0440e9..3ab86c3d2ec349fb85267ac934bb7c721d9eb304 100644 (file)
@@ -53,7 +53,6 @@ Any string data stored in a @union{value} will be encoded in the
 dictionary's character set.
 
 
-
 @section System files
 @file{*.sav} files contain a field which is supposed to identify the encoding
 of the data they contain (@pxref{Machine Integer Info Record}).  
@@ -103,25 +102,20 @@ It is the caller's responsibility to free the returned string when no
 longer required.
 @end deftypefun
 
+In order to minimise the number of conversions required, and to simplify 
+design, PSPP attempts to store all internal strings in UTF8 encoding.
+Thus, when reading system and portable files (or any other data source),
+the following items are immediately converted to UTF8 encoding:
+@itemize
+@item Variable names
+@item Variable labels
+@item Value labels
+@end itemize
+Conversely, when writing system files, these are converted back to the
+encoding of that system file.
 
-For example, in order to display a string variable's value in a label widget in the psppire gui one would use code similar to
-@example
-
-struct variable *var = /* assigned from somewhere */
-struct case c = /* from somewhere else */
-
-const union value *val = case_data (&c, var);
-
-char *utf8string = recode_string (UTF8, dict_get_encoding (dict), val->s,
-      var_get_width (var));
-
-GtkWidget *entry = gtk_entry_new();
-gtk_entry_set_text (entry, utf8string);
-gtk_widget_show (entry);
-
-free (utf8string);
-
-@end example
+String data stored in union values are left in their original encoding.
+These will be converted by the data_in/data_out functions.
 
 
 
index 921ea8574f77a90b69a160a76238dc52cf93823a..76925d7e954d865d76217b97e79c86fa3a0ca272 100644 (file)
@@ -15,6 +15,7 @@ far.
 * RANK::                        Compute rank scores.
 * REGRESSION::                  Linear regression.
 * RELIABILITY::                 Reliability analysis.
+* ROC::                         Receiver Operating Characteristic.
 @end menu
 
 @node DESCRIPTIVES
@@ -950,3 +951,73 @@ analysis tested against the totals.
 
 
 
+@node ROC
+@section ROC
+
+@vindex ROC
+@cindex Receiver Operating Characterstic
+@cindex Area under curve
+
+@display
+ROC     @var{var_list} BY @var{state_var} (@var{state_value})
+        /PLOT = @{ CURVE [(REFERENCE)], NONE @}
+        /PRINT = [ SE ] [ COORDINATES ]
+        /CRITERIA = [ CUTOFF(@{INCLUDE,EXCLUDE@}) ]
+          [ TESTPOS (@{LARGE,SMALL@}) ]
+          [ CI (@var{confidence}) ]
+          [ DISTRIBUTION (@{FREE, NEGEXPO @}) ]
+        /MISSING=@{EXCLUDE,INCLUDE@}
+@end display
+
+
+The @cmd{ROC} command is used to plot the receiver operating characteristic curve 
+of a dataset, and to estimate the area under the curve.
+This is useful for analysing the efficacy of a variable as a predictor of a state of nature.
+
+The mandatory @var{var_list} is the list of predictor variables.
+The variable @var{state_var} is the variable whose values represent the actual states, 
+and @var{state_value} is the value of this variable which represents the positive state.
+
+The optional subcommand PLOT is used to determine if and how the ROC curve is drawn.
+The keyword CURVE means that the ROC curve should be drawn, and the optional keyword REFERENCE,
+which should be enclosed in parentheses, says that the diagonal reference line should be drawn.
+If the keyword NONE is given, then no ROC curve is drawn.
+By default, the curve is drawn with no reference line.
+
+The optional subcommand PRINT determines which additional tables should be printed.
+Two additional tables are available. 
+The SE keyword says that standard error of the area under the curve should be printed as well as
+the area itself.
+In addition, a p-value under the null hypothesis that the area under the curve equals 0.5 will be
+printed.
+The COORDINATES keyword says that a table of coordinates of the ROC curve should be printed.
+
+The CRITERIA subcommand has four optional parameters:
+@itemize @bullet
+@item The TESTPOS parameter may be LARGE or SMALL.
+LARGE is the default, and says that larger values in the predictor variables are to be 
+considered positive.  SMALL indicates that smaller values should be considered positive.
+
+@item The CI parameter specifies the confidence interval that should be printed.
+It has no effect if the SE keyword in the PRINT subcommand has not been given.
+
+@item The DISTRIBUTION parameter determines the method to be used when estimating the area
+under the curve.  
+There are two possibilities, @i{viz}: FREE and NEGEXPO.
+The FREE method uses a non-parametric estimate, and the NEGEXPO method a bi-negative 
+exponential distribution estimate.
+The NEGEXPO method should only be used when the number of positive actual states is
+equal to the number of negative actual states.
+The default is FREE.
+
+@item The CUTOFF parameter is for compatibility and is ignored.
+@end itemize
+
+The MISSING subcommand determines whether user missing values are to 
+be included or excluded in the analysis.  The default behaviour is to
+exclude them.
+Cases are excluded on a listwise basis; if any of the variables in @var{var_list} 
+or if the variable @var{state_var} is missing, then the entire case will be 
+excluded.
+
+
index 29eba9369167b248b1c2c300bbad2dae2a082b86..6d1c0af9755cdeeeaee47dada8587dbffc81907f 100644 (file)
@@ -1,24 +1,24 @@
 /*
-   Copyright (C) 2006, 2008, 2009 Free Software Foundation
+  Copyright (C) 2006, 2008, 2009 Free Software Foundation
 
-   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 3 of the License, or
-   (at your option) any later version.
+  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 3 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.
+  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, see <http://www.gnu.org/licenses/>.
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
- This file is derived from the gtksheet.c and extensively modified for the
- requirements of PSPPIRE.  The changes are copyright by the
- Free Software Foundation.  The copyright notice for the original work is
- below.
 This file is derived from the gtksheet.c and extensively modified for the
 requirements of PSPPIRE.  The changes are copyright by the
 Free Software Foundation.  The copyright notice for the original work is
 below.
 */
 
 /* GtkSheet widget for Gtk+.
@@ -54,8 +54,6 @@
 #include <config.h>
 
 #include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <glib.h>
 #include <gdk/gdk.h>
 #include <gdk/gdkkeysyms.h>
 #include <ui/gui/sheet/psppire-axis.h>
 #include <libpspp/misc.h>
 
-#include <math.h>
-
 /* sheet flags */
 enum
   {
     PSPPIRE_SHEET_IN_XDRAG = 1 << 1,
     PSPPIRE_SHEET_IN_YDRAG = 1 << 2,
     PSPPIRE_SHEET_IN_DRAG = 1 << 3,
-    PSPPIRE_SHEET_IN_SELECTION = 1 << 4,
-    PSPPIRE_SHEET_IN_RESIZE = 1 << 5
+
+    /* This flag is set when the user is actually in the process
+       of making a selection - ie while the mouse button is
+       depressed.
+    */
+    PSPPIRE_SHEET_IN_SELECTION = 1 << 4
   };
 
 #define PSPPIRE_SHEET_FLAGS(sheet) (PSPPIRE_SHEET (sheet)->flags)
@@ -92,7 +92,6 @@ enum
 #define PSPPIRE_SHEET_IN_YDRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_YDRAG)
 #define PSPPIRE_SHEET_IN_DRAG(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_DRAG)
 #define PSPPIRE_SHEET_IN_SELECTION(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_SELECTION)
-#define PSPPIRE_SHEET_IN_RESIZE(sheet) (PSPPIRE_SHEET_FLAGS (sheet) & PSPPIRE_SHEET_IN_RESIZE)
 
 #define CELL_SPACING 1
 
@@ -117,9 +116,6 @@ static void set_row_height (PsppireSheet *sheet,
 static void destroy_hover_window (PsppireSheetHoverTitle *);
 static PsppireSheetHoverTitle *create_hover_window (void);
 
-static GtkStateType psppire_sheet_cell_get_state (PsppireSheet *sheet, gint row, gint col);
-
-
 static inline  void
 dispose_string (const PsppireSheet *sheet, gchar *text)
 {
@@ -391,25 +387,33 @@ POSSIBLE_RESIZE (const PsppireSheet *sheet, gint x, gint y,
 }
 
 
-static gboolean
+static void
 rectangle_from_range (PsppireSheet *sheet, const PsppireSheetRange *range,
                      GdkRectangle *r)
 {
-  g_return_val_if_fail (range, FALSE);
+  gint col0 = MIN (range->col0, range->coli);
+  gint coli = MAX (range->col0, range->coli);
+  gint row0 = MIN (range->row0, range->rowi);
+  gint rowi = MAX (range->row0, range->rowi);
 
-  r->x = psppire_axis_start_pixel (sheet->haxis, range->col0);
+  if ( row0 == -1 ) row0 = min_visible_row (sheet);
+  if ( rowi == -1 ) rowi = max_visible_row (sheet);
+  if ( col0 == -1 ) col0 = min_visible_column (sheet);
+  if ( coli == -1 ) coli = max_visible_column (sheet);
+
+  r->x = psppire_axis_start_pixel (sheet->haxis, col0);
   r->x -= round (sheet->hadjustment->value);
 
-  r->y = psppire_axis_start_pixel (sheet->vaxis, range->row0);
+  r->y = psppire_axis_start_pixel (sheet->vaxis, row0);
   r->y -= round (sheet->vadjustment->value);
 
-  r->width = psppire_axis_start_pixel (sheet->haxis, range->coli) -
-    psppire_axis_start_pixel (sheet->haxis, range->col0) +
-    psppire_axis_unit_size (sheet->haxis, range->coli);
+  r->width = psppire_axis_start_pixel (sheet->haxis, coli) -
+    psppire_axis_start_pixel (sheet->haxis, col0) +
+    psppire_axis_unit_size (sheet->haxis, coli);
 
-  r->height = psppire_axis_start_pixel (sheet->vaxis, range->rowi) -
-    psppire_axis_start_pixel (sheet->vaxis, range->row0) +
-    psppire_axis_unit_size (sheet->vaxis, range->rowi);
+  r->height = psppire_axis_start_pixel (sheet->vaxis, rowi) -
+    psppire_axis_start_pixel (sheet->vaxis, row0) +
+    psppire_axis_unit_size (sheet->vaxis, rowi);
 
   if ( sheet->column_titles_visible)
     {
@@ -420,22 +424,20 @@ rectangle_from_range (PsppireSheet *sheet, const PsppireSheetRange *range,
     {
       r->x += sheet->row_title_area.width;
     }
-
-  return TRUE;
 }
 
-static gboolean
+static void
 rectangle_from_cell (PsppireSheet *sheet, gint row, gint col,
                     GdkRectangle *r)
 {
   PsppireSheetRange range;
-  g_return_val_if_fail (row >= 0, FALSE);
-  g_return_val_if_fail (col >= 0, FALSE);
+  g_return_if_fail (row >= 0);
+  g_return_if_fail (col >= 0);
 
   range.row0 = range.rowi = row;
   range.col0 = range.coli = col;
 
-  return rectangle_from_range (sheet, &range, r);
+  rectangle_from_range (sheet, &range, r);
 }
 
 
@@ -450,33 +452,33 @@ static void psppire_sheet_unrealize                (GtkWidget *widget);
 static void psppire_sheet_map                   (GtkWidget *widget);
 static void psppire_sheet_unmap                         (GtkWidget *widget);
 static gint psppire_sheet_expose                        (GtkWidget *widget,
-                                                 GdkEventExpose *event);
+                                                         GdkEventExpose *event);
 
 static void psppire_sheet_forall                        (GtkContainer *container,
-                                                 gboolean include_internals,
-                                                 GtkCallback callback,
-                                                 gpointer callback_data);
+                                                         gboolean include_internals,
+                                                         GtkCallback callback,
+                                                         gpointer callback_data);
 
 static gboolean psppire_sheet_set_scroll_adjustments  (PsppireSheet *sheet,
-                                                 GtkAdjustment *hadjustment,
-                                                 GtkAdjustment *vadjustment);
+                                                      GtkAdjustment *hadjustment,
+                                                      GtkAdjustment *vadjustment);
 
 static gint psppire_sheet_button_press                  (GtkWidget *widget,
                                                  GdkEventButton *event);
 static gint psppire_sheet_button_release                (GtkWidget *widget,
-                                                 GdkEventButton *event);
+                                                         GdkEventButton *event);
 static gint psppire_sheet_motion                        (GtkWidget *widget,
-                                                 GdkEventMotion *event);
+                                                         GdkEventMotion *event);
 static gboolean psppire_sheet_crossing_notify           (GtkWidget *widget,
-                                                    GdkEventCrossing *event);
+                                                        GdkEventCrossing *event);
 static gint psppire_sheet_entry_key_press               (GtkWidget *widget,
-                                                 GdkEventKey *key);
+                                                         GdkEventKey *key);
 static gboolean psppire_sheet_key_press                 (GtkWidget *widget,
                                                  GdkEventKey *key);
 static void psppire_sheet_size_request                  (GtkWidget *widget,
                                                  GtkRequisition *requisition);
 static void psppire_sheet_size_allocate                 (GtkWidget *widget,
-                                                 GtkAllocation *allocation);
+                                                         GtkAllocation *allocation);
 
 static gboolean psppire_sheet_focus_in               (GtkWidget     *widget,
                                                      GdkEventFocus *event);
@@ -484,9 +486,9 @@ static gboolean psppire_sheet_focus_in               (GtkWidget     *widget,
 /* Sheet queries */
 
 static gboolean psppire_sheet_range_isvisible (const PsppireSheet *sheet,
-                                          const PsppireSheetRange *range);
+                                              const PsppireSheetRange *range);
 static gboolean psppire_sheet_cell_isvisible  (PsppireSheet *sheet,
-                                          gint row, gint column);
+                                              gint row, gint column);
 /* Drawing Routines */
 
 /* draw cell */
@@ -497,20 +499,7 @@ static void psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint column)
 static void draw_sheet_region (PsppireSheet *sheet, GdkRegion *region);
 
 
-/* highlight the visible part of the selected range */
-static void psppire_sheet_range_draw_selection  (PsppireSheet *sheet,
-                                                 PsppireSheetRange range);
-
 /* Selection */
-
-static void psppire_sheet_real_select_range     (PsppireSheet *sheet,
-                                                 const PsppireSheetRange *range);
-static void psppire_sheet_real_unselect_range   (PsppireSheet *sheet,
-                                                 const PsppireSheetRange *range);
-static void psppire_sheet_extend_selection              (PsppireSheet *sheet,
-                                                 gint row, gint column);
-static void psppire_sheet_new_selection                 (PsppireSheet *sheet,
-                                                 PsppireSheetRange *range);
 static void psppire_sheet_draw_border           (PsppireSheet *sheet,
                                                  PsppireSheetRange range);
 
@@ -521,8 +510,8 @@ static void change_active_cell  (PsppireSheet *sheet, gint row, gint col);
 static gboolean psppire_sheet_draw_active_cell  (PsppireSheet *sheet);
 static void psppire_sheet_show_entry_widget             (PsppireSheet *sheet);
 static gboolean psppire_sheet_click_cell                (PsppireSheet *sheet,
-                                                 gint row,
-                                                 gint column);
+                                                         gint row,
+                                                         gint column);
 
 
 /* Scrollbars */
@@ -561,8 +550,8 @@ static void psppire_sheet_button_size_request        (PsppireSheet *sheet,
                                                  GtkRequisition *requisition);
 
 static void psppire_sheet_real_cell_clear               (PsppireSheet *sheet,
-                                                 gint row,
-                                                 gint column);
+                                                         gint row,
+                                                         gint column);
 
 
 /* Signals */
@@ -763,9 +752,9 @@ static const GtkBorder default_cell_padding = {3, 3, 3, 3};
 
 static void
 psppire_sheet_set_property (GObject         *object,
-                       guint            prop_id,
-                       const GValue    *value,
-                       GParamSpec      *pspec)
+                           guint            prop_id,
+                           const GValue    *value,
+                           GParamSpec      *pspec)
 
 {
   PsppireSheet *sheet = PSPPIRE_SHEET (object);
@@ -778,19 +767,19 @@ psppire_sheet_set_property (GObject         *object,
 
       sheet->cell_padding = g_value_dup_boxed (value);
 
-     if (NULL == sheet->cell_padding)
-       sheet->cell_padding = g_boxed_copy (GTK_TYPE_BORDER,
-                                          &default_cell_padding);
+      if (NULL == sheet->cell_padding)
+       sheet->cell_padding = g_boxed_copy (GTK_TYPE_BORDER,
+                                           &default_cell_padding);
 
-     if (sheet->vaxis)
-       g_object_set (sheet->vaxis, "padding",
-                    sheet->cell_padding->top + sheet->cell_padding->bottom,
-                    NULL);
+      if (sheet->vaxis)
+       g_object_set (sheet->vaxis, "padding",
+                     sheet->cell_padding->top + sheet->cell_padding->bottom,
+                     NULL);
 
-     if (sheet->haxis)
-       g_object_set (sheet->haxis, "padding",
-                    sheet->cell_padding->left + sheet->cell_padding->right,
-                    NULL);
+      if (sheet->haxis)
+       g_object_set (sheet->haxis, "padding",
+                     sheet->cell_padding->left + sheet->cell_padding->right,
+                     NULL);
       break;
     case PROP_VAXIS:
       psppire_sheet_set_vertical_axis (sheet, g_value_get_pointer (value));
@@ -815,9 +804,9 @@ psppire_sheet_set_property (GObject         *object,
 
 static void
 psppire_sheet_get_property (GObject         *object,
-                       guint            prop_id,
-                       GValue          *value,
-                       GParamSpec      *pspec)
+                           guint            prop_id,
+                           GValue          *value,
+                           GParamSpec      *pspec)
 {
   PsppireSheet *sheet = PSPPIRE_SHEET (object);
 
@@ -860,7 +849,7 @@ psppire_sheet_class_init (PsppireSheetClass *klass)
   /**
    * PsppireSheet::select-row
    * @sheet: the sheet widget that emitted the signal
-   * @row: the newly selected row index
+   * @row: the newly selected row index, or -1 if no row is selected.
    *
    * A row has been selected.
    */
@@ -879,7 +868,7 @@ psppire_sheet_class_init (PsppireSheetClass *klass)
   /**
    * PsppireSheet::select - column
    * @sheet: the sheet widget that emitted the signal
-   * @column: the newly selected column index
+   * @column: the newly selected column index, or -1 if no column is selected.
    *
    * A column has been selected.
    */
@@ -1134,7 +1123,6 @@ psppire_sheet_init (PsppireSheet *sheet)
   sheet->vaxis = NULL;
 
   sheet->flags = 0;
-  sheet->selection_mode = GTK_SELECTION_NONE;
   sheet->select_status = PSPPIRE_SHEET_NORMAL;
 
   GTK_WIDGET_UNSET_FLAGS (sheet, GTK_NO_WINDOW);
@@ -1155,8 +1143,6 @@ psppire_sheet_init (PsppireSheet *sheet)
 
   sheet->active_cell.row = 0;
   sheet->active_cell.col = 0;
-  sheet->selection_cell.row = 0;
-  sheet->selection_cell.col = 0;
 
   sheet->range.row0 = 0;
   sheet->range.rowi = 0;
@@ -1198,7 +1184,7 @@ psppire_sheet_init (PsppireSheet *sheet)
 
 /* Cause RANGE to be redrawn. If RANGE is null, then the
    entire visible range will be redrawn.
- */
+*/
 static void
 redraw_range (PsppireSheet *sheet, PsppireSheetRange *range)
 {
@@ -1321,7 +1307,7 @@ range_update_callback (PsppireSheetModel *m, gint row0, gint col0,
       adjust_scrollbars (sheet);
 
       draw_row_title_buttons_range (sheet, min_visible_row (sheet),
-                                      max_visible_row (sheet));
+                                   max_visible_row (sheet));
 
       draw_column_title_buttons_range (sheet, min_visible_column (sheet),
                                       max_visible_column (sheet));
@@ -1407,13 +1393,9 @@ psppire_sheet_set_model (PsppireSheet *sheet, PsppireSheetModel *model)
 void
 psppire_sheet_change_entry (PsppireSheet *sheet, GtkType entry_type)
 {
-  gint state;
-
   g_return_if_fail (sheet != NULL);
   g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
 
-  state = sheet->select_status;
-
   if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
     psppire_sheet_hide_entry_widget (sheet);
 
@@ -1421,11 +1403,8 @@ psppire_sheet_change_entry (PsppireSheet *sheet, GtkType entry_type)
 
   create_sheet_entry (sheet);
 
-  if (state == PSPPIRE_SHEET_NORMAL)
-    {
-      psppire_sheet_show_entry_widget (sheet);
-    }
-
+  if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
+    psppire_sheet_show_entry_widget (sheet);
 }
 
 void
@@ -1575,13 +1554,13 @@ psppire_sheet_hide_row_titles (PsppireSheet *sheet)
    be placed at the {bottom,right}.
    ROW or COL may be -1, in which case scrolling in that dimension
    does not occur.
- */
+*/
 void
 psppire_sheet_moveto (PsppireSheet *sheet,
-                 gint row,
-                 gint col,
-                 gfloat row_align,
-                 gfloat col_align)
+                     gint row,
+                     gint col,
+                     gfloat row_align,
+                     gfloat col_align)
 {
   gint width, height;
 
@@ -1616,57 +1595,11 @@ psppire_sheet_moveto (PsppireSheet *sheet,
 }
 
 
-void
-psppire_sheet_select_row (PsppireSheet *sheet, gint row)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (row < 0 || row >= psppire_axis_unit_count (sheet->vaxis))
-    return;
-
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL)
-    psppire_sheet_real_unselect_range (sheet, NULL);
-
-  sheet->select_status = PSPPIRE_SHEET_ROW_SELECTED;
-  sheet->range.row0 = row;
-  sheet->range.col0 = 0;
-  sheet->range.rowi = row;
-  sheet->range.coli = psppire_axis_unit_count (sheet->haxis) - 1;
-
-  g_signal_emit (sheet, sheet_signals[SELECT_ROW], 0, row);
-  psppire_sheet_real_select_range (sheet, NULL);
-}
-
-
-void
-psppire_sheet_select_column (PsppireSheet *sheet, gint column)
-{
-  g_return_if_fail (sheet != NULL);
-  g_return_if_fail (PSPPIRE_IS_SHEET (sheet));
-
-  if (column < 0 || column >= psppire_axis_unit_count (sheet->haxis))
-    return;
-
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL)
-    psppire_sheet_real_unselect_range (sheet, NULL);
-
-  sheet->select_status = PSPPIRE_SHEET_COLUMN_SELECTED;
-  sheet->range.row0 = 0;
-  sheet->range.col0 = column;
-  sheet->range.rowi = psppire_axis_unit_count (sheet->vaxis) - 1;
-  sheet->range.coli = column;
-
-  g_signal_emit (sheet, sheet_signals[SELECT_COLUMN], 0, column);
-  psppire_sheet_real_select_range (sheet, NULL);
-}
-
-
 
 
 static gboolean
 psppire_sheet_range_isvisible (const PsppireSheet *sheet,
-                          const PsppireSheetRange *range)
+                              const PsppireSheetRange *range)
 {
   g_return_val_if_fail (sheet != NULL, FALSE);
 
@@ -1699,7 +1632,7 @@ psppire_sheet_range_isvisible (const PsppireSheet *sheet,
 
 static gboolean
 psppire_sheet_cell_isvisible (PsppireSheet *sheet,
-                         gint row, gint column)
+                             gint row, gint column)
 {
   PsppireSheetRange range;
 
@@ -1727,8 +1660,8 @@ psppire_sheet_get_visible_range (PsppireSheet *sheet, PsppireSheetRange *range)
 
 static gboolean
 psppire_sheet_set_scroll_adjustments (PsppireSheet *sheet,
-                                 GtkAdjustment *hadjustment,
-                                 GtkAdjustment *vadjustment)
+                                     GtkAdjustment *hadjustment,
+                                     GtkAdjustment *vadjustment)
 {
   if ( sheet->vadjustment != vadjustment )
     {
@@ -1832,7 +1765,7 @@ psppire_sheet_dispose  (GObject *object)
 
 static void
 psppire_sheet_style_set (GtkWidget *widget,
-                    GtkStyle *previous_style)
+                        GtkStyle *previous_style)
 {
   PsppireSheet *sheet;
 
@@ -1979,7 +1912,7 @@ psppire_sheet_realize (GtkWidget *widget)
   gtk_widget_set_parent (sheet->button, GTK_WIDGET (sheet));
 
   sheet->button->style = gtk_style_attach (sheet->button->style,
-                                          sheet->sheet_window);
+                                          sheet->sheet_window);
 
 
   sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_PLUS);
@@ -2116,8 +2049,8 @@ psppire_sheet_map (GtkWidget *widget)
 
       redraw_range (sheet, NULL);
       change_active_cell (sheet,
-                    sheet->active_cell.row,
-                    sheet->active_cell.col);
+                         sheet->active_cell.row,
+                         sheet->active_cell.col);
     }
 }
 
@@ -2247,7 +2180,7 @@ psppire_sheet_cell_draw (PsppireSheet *sheet, gint row, gint col)
       break;
     default:
       g_critical ("Unhandled justification %d in column %d\n",
-                attributes.justification, col);
+                 attributes.justification, col);
       break;
     }
 
@@ -2313,12 +2246,7 @@ draw_sheet_region (PsppireSheet *sheet, GdkRegion *region)
        psppire_sheet_cell_draw (sheet, i, j);
     }
 
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL &&
-      psppire_sheet_range_isvisible (sheet, &sheet->range))
-    psppire_sheet_range_draw_selection (sheet, drawing_range);
-
-
-  if (sheet->select_status == GTK_STATE_NORMAL &&
+  if (sheet->select_status == PSPPIRE_SHEET_NORMAL &&
       sheet->active_cell.row >= drawing_range.row0 &&
       sheet->active_cell.row <= drawing_range.rowi &&
       sheet->active_cell.col >= drawing_range.col0 &&
@@ -2326,83 +2254,10 @@ draw_sheet_region (PsppireSheet *sheet, GdkRegion *region)
     psppire_sheet_show_entry_widget (sheet);
 }
 
-
-static void
-psppire_sheet_range_draw_selection (PsppireSheet *sheet, PsppireSheetRange range)
-{
-  GdkRectangle area;
-  gint i, j;
-  PsppireSheetRange aux;
-
-  if (range.col0 > sheet->range.coli || range.coli < sheet->range.col0 ||
-      range.row0 > sheet->range.rowi || range.rowi < sheet->range.row0)
-    return;
-
-  if (!psppire_sheet_range_isvisible (sheet, &range)) return;
-  if (!GTK_WIDGET_REALIZED (GTK_WIDGET (sheet))) return;
-
-  aux = range;
-
-  range.col0 = MAX (sheet->range.col0, range.col0);
-  range.coli = MIN (sheet->range.coli, range.coli);
-  range.row0 = MAX (sheet->range.row0, range.row0);
-  range.rowi = MIN (sheet->range.rowi, range.rowi);
-
-  range.col0 = MAX (range.col0, min_visible_column (sheet));
-  range.coli = MIN (range.coli, max_visible_column (sheet));
-  range.row0 = MAX (range.row0, min_visible_row (sheet));
-  range.rowi = MIN (range.rowi, max_visible_row (sheet));
-
-  for (i = range.row0; i <= range.rowi; i++)
-    {
-      for (j = range.col0; j <= range.coli; j++)
-       {
-         if (psppire_sheet_cell_get_state (sheet, i, j) == GTK_STATE_SELECTED)
-           {
-             rectangle_from_cell (sheet, i, j, &area);
-
-             if (i == sheet->range.row0)
-               {
-                 area.y = area.y + 2;
-                 area.height = area.height - 2;
-               }
-             if (i == sheet->range.rowi) area.height = area.height - 3;
-             if (j == sheet->range.col0)
-               {
-                 area.x = area.x + 2;
-                 area.width = area.width - 2;
-               }
-             if (j == sheet->range.coli) area.width = area.width - 3;
-
-             if (i != sheet->active_cell.row || j != sheet->active_cell.col)
-               {
-                 gdk_draw_rectangle (sheet->sheet_window,
-                                     sheet->xor_gc,
-                                     TRUE,
-                                     area.x + 1, area.y + 1,
-                                     area.width, area.height);
-               }
-           }
-
-       }
-    }
-
-  psppire_sheet_draw_border (sheet, sheet->range);
-}
-
-static inline gint
-safe_strcmp (const gchar *s1, const gchar *s2)
-{
-  if ( !s1 && !s2) return 0;
-  if ( !s1) return -1;
-  if ( !s2) return +1;
-  return strcmp (s1, s2);
-}
-
 static void
 psppire_sheet_set_cell (PsppireSheet *sheet, gint row, gint col,
-                   GtkJustification justification,
-                   const gchar *text)
+                       GtkJustification justification,
+                       const gchar *text)
 {
   PsppireSheetModel *model ;
   gchar *old_text ;
@@ -2420,7 +2275,7 @@ psppire_sheet_set_cell (PsppireSheet *sheet, gint row, gint col,
 
   old_text = psppire_sheet_model_get_string (model, row, col);
 
-  if (0 != safe_strcmp (old_text, text))
+  if (0 != g_strcmp0 (old_text, text))
     {
       g_signal_handler_block    (sheet->model, sheet->update_handler_id);
       psppire_sheet_model_set_string (model, text, row, col);
@@ -2489,51 +2344,15 @@ psppire_sheet_cell_get_text (const PsppireSheet *sheet, gint row, gint col)
 }
 
 
-static GtkStateType
-psppire_sheet_cell_get_state (PsppireSheet *sheet, gint row, gint col)
-{
-  gint state;
-  PsppireSheetRange *range;
-
-  g_return_val_if_fail (sheet != NULL, 0);
-  g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0);
-  if (col >= psppire_axis_unit_count (sheet->haxis) || row >= psppire_axis_unit_count (sheet->vaxis)) return 0;
-  if (col < 0 || row < 0) return 0;
-
-  state = sheet->select_status;
-  range = &sheet->range;
-
-  switch (state)
-    {
-    case PSPPIRE_SHEET_NORMAL:
-      return GTK_STATE_NORMAL;
-      break;
-    case PSPPIRE_SHEET_ROW_SELECTED:
-      if (row >= range->row0 && row <= range->rowi)
-       return GTK_STATE_SELECTED;
-      break;
-    case PSPPIRE_SHEET_COLUMN_SELECTED:
-      if (col >= range->col0 && col <= range->coli)
-       return GTK_STATE_SELECTED;
-      break;
-    case PSPPIRE_SHEET_RANGE_SELECTED:
-      if (row >= range->row0 && row <= range->rowi && \
-         col >= range->col0 && col <= range->coli)
-       return GTK_STATE_SELECTED;
-      break;
-    }
-  return GTK_STATE_NORMAL;
-}
-
 /* Convert X, Y (in pixels) to *ROW, *COLUMN
    If the function returns FALSE, then the results will be unreliable.
 */
 static gboolean
 psppire_sheet_get_pixel_info (PsppireSheet *sheet,
-                         gint x,
-                         gint y,
-                         gint *row,
-                         gint *column)
+                             gint x,
+                             gint y,
+                             gint *row,
+                             gint *column)
 {
   gint trow, tcol;
   *row = -G_MAXINT;
@@ -2591,9 +2410,9 @@ psppire_sheet_get_pixel_info (PsppireSheet *sheet,
 
 gboolean
 psppire_sheet_get_cell_area (PsppireSheet *sheet,
-                        gint row,
-                        gint column,
-                        GdkRectangle *area)
+                            gint row,
+                            gint column,
+                            GdkRectangle *area)
 {
   g_return_val_if_fail (sheet != NULL, 0);
   g_return_val_if_fail (PSPPIRE_IS_SHEET (sheet), 0);
@@ -2658,7 +2477,7 @@ entry_load_text (PsppireSheet *sheet)
   PsppireSheetCellAttr attributes;
 
   if (!GTK_WIDGET_VISIBLE (sheet->entry_widget)) return;
-  if (sheet->select_status != GTK_STATE_NORMAL) return;
+  if (sheet->select_status != PSPPIRE_SHEET_NORMAL) return;
 
   row = sheet->active_cell.row;
   col = sheet->active_cell.col;
@@ -2705,12 +2524,6 @@ change_active_cell (PsppireSheet *sheet, gint row, gint col)
        || col > psppire_axis_unit_count (sheet->haxis))
     return;
 
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL)
-    {
-      sheet->select_status = PSPPIRE_SHEET_NORMAL;
-      psppire_sheet_real_unselect_range (sheet, NULL);
-    }
-
   old_row = sheet->active_cell.row;
   old_col = sheet->active_cell.col;
 
@@ -2719,14 +2532,8 @@ change_active_cell (PsppireSheet *sheet, gint row, gint col)
   /* Erase the old cell border */
   psppire_sheet_draw_active_cell (sheet);
 
-  sheet->range.row0 = row;
-  sheet->range.col0 = col;
-  sheet->range.rowi = row;
-  sheet->range.coli = col;
   sheet->active_cell.row = row;
   sheet->active_cell.col = col;
-  sheet->selection_cell.row = row;
-  sheet->selection_cell.col = col;
 
   PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
 
@@ -2782,28 +2589,28 @@ psppire_sheet_show_entry_widget (PsppireSheet *sheet)
       
       dispose_string (sheet, text);
 
-       {
-         switch (attributes.justification)
-           {
-           case GTK_JUSTIFY_RIGHT:
-             gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 1.0);
-             break;
-           case GTK_JUSTIFY_CENTER:
-             gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.5);
-             break;
-           case GTK_JUSTIFY_LEFT:
-           default:
-             gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.0);
-             break;
-           }
-       }
+      {
+       switch (attributes.justification)
+         {
+         case GTK_JUSTIFY_RIGHT:
+           gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 1.0);
+           break;
+         case GTK_JUSTIFY_CENTER:
+           gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.5);
+           break;
+         case GTK_JUSTIFY_LEFT:
+         default:
+           gtk_entry_set_alignment (GTK_ENTRY (sheet_entry), 0.0);
+           break;
+         }
+      }
     }
 
   psppire_sheet_size_allocate_entry (sheet);
 
   gtk_widget_set_sensitive (GTK_WIDGET (sheet_entry),
                            psppire_sheet_model_is_editable (sheet->model,
-                                                      row, col));
+                                                            row, col));
   gtk_widget_map (sheet->entry_widget);
 }
 
@@ -2831,250 +2638,6 @@ psppire_sheet_draw_active_cell (PsppireSheet *sheet)
 
 
 
-static void
-psppire_sheet_new_selection (PsppireSheet *sheet, PsppireSheetRange *range)
-{
-  gint i, j, mask1, mask2;
-  gint state, selected;
-  gint x, y, width, height;
-  PsppireSheetRange new_range, aux_range;
-
-  g_return_if_fail (sheet != NULL);
-
-  if (range == NULL) range=&sheet->range;
-
-  new_range=*range;
-
-  range->row0 = MIN (range->row0, sheet->range.row0);
-  range->rowi = MAX (range->rowi, sheet->range.rowi);
-  range->col0 = MIN (range->col0, sheet->range.col0);
-  range->coli = MAX (range->coli, sheet->range.coli);
-
-  range->row0 = MAX (range->row0, min_visible_row (sheet));
-  range->rowi = MIN (range->rowi, max_visible_row (sheet));
-  range->col0 = MAX (range->col0, min_visible_column (sheet));
-  range->coli = MIN (range->coli, max_visible_column (sheet));
-
-  aux_range.row0 = MAX (new_range.row0, min_visible_row (sheet));
-  aux_range.rowi = MIN (new_range.rowi, max_visible_row (sheet));
-  aux_range.col0 = MAX (new_range.col0, min_visible_column (sheet));
-  aux_range.coli = MIN (new_range.coli, max_visible_column (sheet));
-
-  for (i = range->row0; i <= range->rowi; i++)
-    {
-      for (j = range->col0; j <= range->coli; j++)
-       {
-
-         state = psppire_sheet_cell_get_state (sheet, i, j);
-         selected= (i <= new_range.rowi && i >= new_range.row0 &&
-                    j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
-
-         if (state == GTK_STATE_SELECTED && selected &&
-             (i == sheet->range.row0 || i == sheet->range.rowi ||
-              j == sheet->range.col0 || j == sheet->range.coli ||
-              i == new_range.row0 || i == new_range.rowi ||
-              j == new_range.col0 || j == new_range.coli))
-           {
-
-             mask1 = i == sheet->range.row0 ? 1 : 0;
-             mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
-             mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
-             mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
-
-             mask2 = i == new_range.row0 ? 1 : 0;
-             mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
-             mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
-             mask2 = j == new_range.coli ? mask2 + 8 : mask2;
-
-             if (mask1 != mask2)
-               {
-                 x = psppire_axis_start_pixel (sheet->haxis, j);
-                 y = psppire_axis_start_pixel (sheet->vaxis, i);
-                 width = psppire_axis_start_pixel (sheet->haxis, j)- x+
-                   psppire_axis_unit_size (sheet->haxis, j);
-                 height = psppire_axis_start_pixel (sheet->vaxis, i) - y + psppire_axis_unit_size (sheet->vaxis, i);
-
-                 if (i == sheet->range.row0)
-                   {
-                     y = y - 3;
-                     height = height + 3;
-                   }
-                 if (i == sheet->range.rowi) height = height + 3;
-                 if (j == sheet->range.col0)
-                   {
-                     x = x - 3;
-                     width = width + 3;
-                   }
-                 if (j == sheet->range.coli) width = width + 3;
-
-                 if (i != sheet->active_cell.row || j != sheet->active_cell.col)
-                   {
-                     x = psppire_axis_start_pixel (sheet->haxis, j);
-                     y = psppire_axis_start_pixel (sheet->vaxis, i);
-                     width = psppire_axis_start_pixel (sheet->haxis, j)- x+
-                       psppire_axis_unit_size (sheet->haxis, j);
-
-                     height = psppire_axis_start_pixel (sheet->vaxis, i) - y + psppire_axis_unit_size (sheet->vaxis, i);
-
-                     if (i == new_range.row0)
-                       {
-                         y = y+2;
-                         height = height - 2;
-                       }
-                     if (i == new_range.rowi) height = height - 3;
-                     if (j == new_range.col0)
-                       {
-                         x = x+2;
-                         width = width - 2;
-                       }
-                     if (j == new_range.coli) width = width - 3;
-
-                     gdk_draw_rectangle (sheet->sheet_window,
-                                         sheet->xor_gc,
-                                         TRUE,
-                                         x + 1, y + 1,
-                                         width, height);
-                   }
-               }
-           }
-       }
-    }
-
-  for (i = range->row0; i <= range->rowi; i++)
-    {
-      for (j = range->col0; j <= range->coli; j++)
-       {
-
-         state = psppire_sheet_cell_get_state (sheet, i, j);
-         selected= (i <= new_range.rowi && i >= new_range.row0 &&
-                    j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
-
-         if (state == GTK_STATE_SELECTED && !selected)
-           {
-
-             x = psppire_axis_start_pixel (sheet->haxis, j);
-             y = psppire_axis_start_pixel (sheet->vaxis, i);
-             width = psppire_axis_start_pixel (sheet->haxis, j) - x + psppire_axis_unit_size (sheet->haxis, j);
-             height = psppire_axis_start_pixel (sheet->vaxis, i) - y + psppire_axis_unit_size (sheet->vaxis, i);
-
-             if (i == sheet->range.row0)
-               {
-                 y = y - 3;
-                 height = height + 3;
-               }
-             if (i == sheet->range.rowi) height = height + 3;
-             if (j == sheet->range.col0)
-               {
-                 x = x - 3;
-                 width = width + 3;
-               }
-             if (j == sheet->range.coli) width = width + 3;
-
-           }
-       }
-    }
-
-  for (i = range->row0; i <= range->rowi; i++)
-    {
-      for (j = range->col0; j <= range->coli; j++)
-       {
-
-         state = psppire_sheet_cell_get_state (sheet, i, j);
-         selected= (i <= new_range.rowi && i >= new_range.row0 &&
-                    j <= new_range.coli && j >= new_range.col0) ? TRUE : FALSE;
-
-         if (state != GTK_STATE_SELECTED && selected &&
-             (i != sheet->active_cell.row || j != sheet->active_cell.col))
-           {
-
-             x = psppire_axis_start_pixel (sheet->haxis, j);
-             y = psppire_axis_start_pixel (sheet->vaxis, i);
-             width = psppire_axis_start_pixel (sheet->haxis, j) - x + psppire_axis_unit_size (sheet->haxis, j);
-             height = psppire_axis_start_pixel (sheet->vaxis, i) - y + psppire_axis_unit_size (sheet->vaxis, i);
-
-             if (i == new_range.row0)
-               {
-                 y = y+2;
-                 height = height - 2;
-               }
-             if (i == new_range.rowi) height = height - 3;
-             if (j == new_range.col0)
-               {
-                 x = x+2;
-                 width = width - 2;
-               }
-             if (j == new_range.coli) width = width - 3;
-
-             gdk_draw_rectangle (sheet->sheet_window,
-                                 sheet->xor_gc,
-                                 TRUE,
-                                 x + 1, y + 1,
-                                 width, height);
-
-           }
-
-       }
-    }
-
-  for (i = aux_range.row0; i <= aux_range.rowi; i++)
-    {
-      for (j = aux_range.col0; j <= aux_range.coli; j++)
-       {
-         state = psppire_sheet_cell_get_state (sheet, i, j);
-
-         mask1 = i == sheet->range.row0 ? 1 : 0;
-         mask1 = i == sheet->range.rowi ? mask1 + 2 : mask1;
-         mask1 = j == sheet->range.col0 ? mask1 + 4 : mask1;
-         mask1 = j == sheet->range.coli ? mask1 + 8 : mask1;
-
-         mask2 = i == new_range.row0 ? 1 : 0;
-         mask2 = i == new_range.rowi ? mask2 + 2 : mask2;
-         mask2 = j == new_range.col0 ? mask2 + 4 : mask2;
-         mask2 = j == new_range.coli ? mask2 + 8 : mask2;
-         if (mask2 != mask1 || (mask2 == mask1 && state != GTK_STATE_SELECTED))
-           {
-             x = psppire_axis_start_pixel (sheet->haxis, j);
-             y = psppire_axis_start_pixel (sheet->vaxis, i);
-             width = psppire_axis_unit_size (sheet->haxis, j);
-             height = psppire_axis_unit_size (sheet->vaxis, i);
-             if (mask2 & 1)
-               gdk_draw_rectangle (sheet->sheet_window,
-                                   sheet->xor_gc,
-                                   TRUE,
-                                   x + 1, y - 1,
-                                   width, 3);
-
-
-             if (mask2 & 2)
-               gdk_draw_rectangle (sheet->sheet_window,
-                                   sheet->xor_gc,
-                                   TRUE,
-                                   x + 1, y + height - 1,
-                                   width, 3);
-
-             if (mask2 & 4)
-               gdk_draw_rectangle (sheet->sheet_window,
-                                   sheet->xor_gc,
-                                   TRUE,
-                                   x - 1, y + 1,
-                                   3, height);
-
-
-             if (mask2 & 8)
-               gdk_draw_rectangle (sheet->sheet_window,
-                                   sheet->xor_gc,
-                                   TRUE,
-                                   x + width - 1, y + 1,
-                                   3, height);
-           }
-       }
-    }
-
-  *range = new_range;
-}
-
-
-
 static void
 psppire_sheet_draw_border (PsppireSheet *sheet, PsppireSheetRange new_range)
 {
@@ -3102,112 +2665,87 @@ psppire_sheet_draw_border (PsppireSheet *sheet, PsppireSheetRange new_range)
   gdk_gc_set_clip_rectangle (sheet->xor_gc, NULL);
 }
 
+\f
 
-static void
-psppire_sheet_real_select_range (PsppireSheet *sheet,
-                            const PsppireSheetRange *range)
-{
-  gint state;
+/* Selection related functions */
 
-  g_return_if_fail (sheet != NULL);
+void
+psppire_sheet_select_row (PsppireSheet *sheet,  gint row)
+{
+  GdkRectangle area;
+  sheet->select_status = PSPPIRE_SHEET_ROW_SELECTED;
 
-  if (range == NULL) range = &sheet->range;
+  sheet->range.col0 = sheet->range.coli = -1;
+  sheet->range.row0 = sheet->range.rowi = row;
 
-  memcpy (&sheet->range, range, sizeof (*range));
+  rectangle_from_range (sheet, &sheet->range, &area);
+  area.x++;
+  area.y++;
 
-  if (range->row0 < 0 || range->rowi < 0) return;
-  if (range->col0 < 0 || range->coli < 0) return;
+  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
 
-  state = sheet->select_status;
+  g_signal_emit (sheet, sheet_signals [SELECT_ROW], 0, row);
+}
 
-#if 0
-  if (range->coli != sheet->range.coli || range->col0 != sheet->range.col0 ||
-      range->rowi != sheet->range.rowi || range->row0 != sheet->range.row0)
-    {
-      psppire_sheet_new_selection (sheet, &sheet->range);
-    }
-  else
-    {
-      psppire_sheet_range_draw_selection (sheet, sheet->range);
-    }
-#endif
+void
+psppire_sheet_select_column (PsppireSheet *sheet,  gint column)
+{
+  GdkRectangle area;
+  sheet->select_status = PSPPIRE_SHEET_COLUMN_SELECTED;
 
-  psppire_sheet_update_primary_selection (sheet);
+  sheet->range.col0 = sheet->range.coli = column;
+  sheet->range.row0 = sheet->range.rowi = -1;
 
-  g_signal_emit (sheet, sheet_signals[SELECT_RANGE], 0, &sheet->range);
-}
+  rectangle_from_range (sheet, &sheet->range, &area);
+  area.x++;
+  area.y++;
 
+  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
 
-void
-psppire_sheet_get_selected_range (PsppireSheet *sheet, PsppireSheetRange *range)
-{
-  g_return_if_fail (sheet != NULL);
-  *range = sheet->range;
+  g_signal_emit (sheet, sheet_signals [SELECT_COLUMN], 0, column);
 }
 
 
 void
 psppire_sheet_select_range (PsppireSheet *sheet, const PsppireSheetRange *range)
 {
-  g_return_if_fail (sheet != NULL);
-
-  if (range == NULL) range=&sheet->range;
-
-  if (range->row0 < 0 || range->rowi < 0) return;
-  if (range->col0 < 0 || range->coli < 0) return;
-
-
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL)
-    psppire_sheet_real_unselect_range (sheet, NULL);
+  GdkRectangle area;
+  sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
 
-  sheet->range.row0 = range->row0;
-  sheet->range.rowi = range->rowi;
-  sheet->range.col0 = range->col0;
-  sheet->range.coli = range->coli;
-  sheet->selection_cell.row = range->rowi;
-  sheet->selection_cell.col = range->coli;
+  sheet->range = *range;
 
-  sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
-  psppire_sheet_real_select_range (sheet, NULL);
+  rectangle_from_range (sheet, range, &area);
+  area.x++;
+  area.y++;
+  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
 }
 
+
 void
 psppire_sheet_unselect_range (PsppireSheet *sheet)
 {
-  if (! GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
-    return;
+  GdkRectangle area;
+  sheet->select_status = PSPPIRE_SHEET_NORMAL;
 
-  psppire_sheet_real_unselect_range (sheet, NULL);
-  sheet->select_status = GTK_STATE_NORMAL;
-}
+  rectangle_from_range (sheet, &sheet->range, &area);
+  area.x++;
+  area.y++;
+  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);      
 
+  g_signal_emit (sheet, sheet_signals [SELECT_COLUMN], 0, -1);
+  g_signal_emit (sheet, sheet_signals [SELECT_ROW], 0, -1);  
+}
 
-static void
-psppire_sheet_real_unselect_range (PsppireSheet *sheet,
-                              const PsppireSheetRange *range)
+void
+psppire_sheet_get_selected_range (PsppireSheet *sheet, PsppireSheetRange *range)
 {
   g_return_if_fail (sheet != NULL);
-  g_return_if_fail (GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)));
-
-  if ( range == NULL)
-    range = &sheet->range;
-
-  if (range->row0 < 0 || range->rowi < 0) return;
-  if (range->col0 < 0 || range->coli < 0) return;
-
-  g_signal_emit (sheet, sheet_signals[SELECT_COLUMN], 0, -1);
-  g_signal_emit (sheet, sheet_signals[SELECT_ROW], 0, -1);
-
-  sheet->range.row0 = -1;
-  sheet->range.rowi = -1;
-  sheet->range.col0 = -1;
-  sheet->range.coli = -1;
+  *range = sheet->range;
 }
-
+\f
 
 static gint
-psppire_sheet_expose (GtkWidget *widget,
-                 GdkEventExpose *event)
+psppire_sheet_expose (GtkWidget *widget, GdkEventExpose *event)
 {
   PsppireSheet *sheet = PSPPIRE_SHEET (widget);
 
@@ -3237,21 +2775,19 @@ psppire_sheet_expose (GtkWidget *widget,
     {
       draw_sheet_region (sheet, event->region);
 
-#if 0
       if (sheet->select_status != PSPPIRE_SHEET_NORMAL)
        {
-         if (psppire_sheet_range_isvisible (sheet, &sheet->range))
-           psppire_sheet_range_draw (sheet, &sheet->range);
-
-         if (PSPPIRE_SHEET_IN_RESIZE (sheet) || PSPPIRE_SHEET_IN_DRAG (sheet))
-           psppire_sheet_range_draw (sheet, &sheet->drag_range);
-
-         if (psppire_sheet_range_isvisible (sheet, &sheet->range))
-           psppire_sheet_range_draw_selection (sheet, sheet->range);
-         if (PSPPIRE_SHEET_IN_RESIZE (sheet) || PSPPIRE_SHEET_IN_DRAG (sheet))
-           draw_xor_rectangle (sheet, sheet->drag_range);
+         GdkRectangle area;
+
+         rectangle_from_range (sheet, &sheet->range, &area);
+             
+         gdk_draw_rectangle (sheet->sheet_window,
+                             sheet->xor_gc,
+                             TRUE,
+                             area.x + 1, area.y + 1,
+                             area.width, area.height);
        }
-#endif
+
 
       if ((!PSPPIRE_SHEET_IN_XDRAG (sheet)) && (!PSPPIRE_SHEET_IN_YDRAG (sheet)))
        {
@@ -3278,8 +2814,7 @@ psppire_sheet_expose (GtkWidget *widget,
 
 
 static gboolean
-psppire_sheet_button_press (GtkWidget *widget,
-                       GdkEventButton *event)
+psppire_sheet_button_press (GtkWidget *widget, GdkEventButton *event)
 {
   PsppireSheet *sheet;
   GdkModifierType mods;
@@ -3318,7 +2853,8 @@ psppire_sheet_button_press (GtkWidget *widget,
                           sheet_signals[DOUBLE_CLICK_COLUMN], 0, column);
        }
     }
-  else if (event->window == sheet->row_title_window)
+  
+  if (event->window == sheet->row_title_window)
     {
       g_signal_emit (sheet,
                     sheet_signals[BUTTON_EVENT_ROW], 0,
@@ -3389,8 +2925,16 @@ psppire_sheet_button_press (GtkWidget *widget,
                        NULL, NULL, event->time);
       gtk_grab_add (GTK_WIDGET (sheet));
 
-      if (psppire_sheet_click_cell (sheet, row, column))
-       PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
+      if ( sheet->select_status == PSPPIRE_SHEET_NORMAL)
+       {
+         sheet->range.row0 = row;
+         sheet->range.col0 = column;
+       }
+      else
+       {
+         psppire_sheet_unselect_range (sheet);
+       }
+      psppire_sheet_click_cell (sheet, row, column);
     }
 
   if (event->window == sheet->column_title_window)
@@ -3451,7 +2995,7 @@ psppire_sheet_click_cell (PsppireSheet *sheet, gint row, gint column)
 
   if (forbid_move)
     {
-      if (sheet->select_status == GTK_STATE_NORMAL)
+      if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
        return FALSE;
 
       row = sheet->active_cell.row;
@@ -3484,24 +3028,8 @@ psppire_sheet_click_cell (PsppireSheet *sheet, gint row, gint column)
       return TRUE;
     }
 
-  if (sheet->select_status != PSPPIRE_SHEET_NORMAL)
-    {
-      sheet->select_status = PSPPIRE_SHEET_NORMAL;
-      psppire_sheet_real_unselect_range (sheet, NULL);
-    }
-  else
-    {
-      change_active_cell (sheet, row, column);
-    }
-
-  sheet->selection_cell.row = row;
-  sheet->selection_cell.col = column;
-  sheet->range.row0 = row;
-  sheet->range.col0 = column;
-  sheet->range.rowi = row;
-  sheet->range.coli = column;
-  sheet->select_status = PSPPIRE_SHEET_NORMAL;
-  PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
+  if (sheet->select_status == PSPPIRE_SHEET_NORMAL)
+    change_active_cell (sheet, row, column);
 
   gtk_widget_grab_focus (GTK_WIDGET (sheet->entry_widget));
 
@@ -3510,7 +3038,7 @@ psppire_sheet_click_cell (PsppireSheet *sheet, gint row, gint column)
 
 static gint
 psppire_sheet_button_release (GtkWidget *widget,
-                         GdkEventButton *event)
+                             GdkEventButton *event)
 {
   GdkDisplay *display = gtk_widget_get_display (widget);
 
@@ -3560,12 +3088,8 @@ psppire_sheet_button_release (GtkWidget *widget,
       PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_DRAG);
       gdk_display_pointer_ungrab (display, event->time);
 
-      psppire_sheet_real_unselect_range (sheet, NULL);
+      psppire_sheet_unselect_range (sheet);
 
-      sheet->selection_cell.row = sheet->selection_cell.row +
-       (sheet->drag_range.row0 - sheet->range.row0);
-      sheet->selection_cell.col = sheet->selection_cell.col +
-       (sheet->drag_range.col0 - sheet->range.col0);
       old_range = sheet->range;
       sheet->range = sheet->drag_range;
       sheet->drag_range = old_range;
@@ -3574,43 +3098,16 @@ psppire_sheet_button_release (GtkWidget *widget,
       psppire_sheet_select_range (sheet, &sheet->range);
     }
 
-  if (PSPPIRE_SHEET_IN_RESIZE (sheet))
-    {
-      PsppireSheetRange old_range;
-      draw_xor_rectangle (sheet, sheet->drag_range);
-      PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_RESIZE);
-      gdk_display_pointer_ungrab (display, event->time);
-
-      psppire_sheet_real_unselect_range (sheet, NULL);
-
-      if (sheet->drag_range.row0 < sheet->range.row0)
-       sheet->selection_cell.row = sheet->drag_range.row0;
-      if (sheet->drag_range.rowi >= sheet->range.rowi)
-       sheet->selection_cell.row = sheet->drag_range.rowi;
-      if (sheet->drag_range.col0 < sheet->range.col0)
-       sheet->selection_cell.col = sheet->drag_range.col0;
-      if (sheet->drag_range.coli >= sheet->range.coli)
-       sheet->selection_cell.col = sheet->drag_range.coli;
-      old_range = sheet->range;
-      sheet->range = sheet->drag_range;
-      sheet->drag_range = old_range;
-
-      if (sheet->select_status == GTK_STATE_NORMAL) sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
-      g_signal_emit (sheet, sheet_signals[RESIZE_RANGE], 0,
-                    &sheet->drag_range, &sheet->range);
-      psppire_sheet_select_range (sheet, &sheet->range);
-    }
-
-  if (sheet->select_status == PSPPIRE_SHEET_NORMAL && PSPPIRE_SHEET_IN_SELECTION (sheet))
+  if (PSPPIRE_SHEET_IN_SELECTION (sheet))
     {
       PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
-      gdk_display_pointer_ungrab (display, event->time);
+      sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
+
       change_active_cell (sheet, sheet->active_cell.row,
-                              sheet->active_cell.col);
+                         sheet->active_cell.col);
     }
 
-  if (PSPPIRE_SHEET_IN_SELECTION)
-    gdk_display_pointer_ungrab (display, event->time);
+  gdk_display_pointer_ungrab (display, event->time);
   gtk_grab_remove (GTK_WIDGET (sheet));
 
   PSPPIRE_SHEET_UNSET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
@@ -3755,7 +3252,7 @@ motion_timeout_callback (gpointer data)
       if (sheet->column_title_under && column >= 0)
        {
          gchar *text = psppire_sheet_model_get_column_subtitle (sheet->model,
-                                                          column);
+                                                                column);
 
          show_subtitle (sheet, -1, column, text);
 
@@ -3873,7 +3370,6 @@ psppire_sheet_motion (GtkWidget *widget,  GdkEventMotion *event)
        !POSSIBLE_DRAG (sheet, x, y, &row, &column) &&
        !PSPPIRE_SHEET_IN_DRAG (sheet) &&
        !POSSIBLE_RESIZE (sheet, x, y, &row, &column) &&
-       !PSPPIRE_SHEET_IN_RESIZE (sheet) &&
        new_cursor != sheet->cursor_drag->type)
     {
       gdk_cursor_unref (sheet->cursor_drag);
@@ -3883,8 +3379,7 @@ psppire_sheet_motion (GtkWidget *widget,  GdkEventMotion *event)
 
   new_cursor = GDK_TOP_LEFT_ARROW;
   if ( event->window == sheet->sheet_window &&
-       ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
-         PSPPIRE_SHEET_IN_RESIZE (sheet)) &&
+       ! (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ) &&
        (POSSIBLE_DRAG (sheet, x, y, &row, &column) ||
        PSPPIRE_SHEET_IN_DRAG (sheet)) &&
        new_cursor != sheet->cursor_drag->type)
@@ -3894,20 +3389,6 @@ psppire_sheet_motion (GtkWidget *widget,  GdkEventMotion *event)
       gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
     }
 
-  new_cursor = GDK_SIZING;
-  if ( event->window == sheet->sheet_window &&
-       sheet->selection_mode != GTK_SELECTION_NONE &&
-       !PSPPIRE_SHEET_IN_DRAG (sheet) &&
-       (POSSIBLE_RESIZE (sheet, x, y, &row, &column) ||
-       PSPPIRE_SHEET_IN_RESIZE (sheet)) &&
-       new_cursor != sheet->cursor_drag->type)
-    {
-      gdk_cursor_unref (sheet->cursor_drag);
-      sheet->cursor_drag = gdk_cursor_new_for_display (display, GDK_SIZING);
-      gdk_window_set_cursor (sheet->sheet_window, sheet->cursor_drag);
-    }
-
-
   gdk_window_get_pointer (widget->window, &x, &y, &mods);
   if (! (mods & GDK_BUTTON1_MASK)) return FALSE;
 
@@ -3963,94 +3444,36 @@ psppire_sheet_motion (GtkWidget *widget,  GdkEventMotion *event)
       return TRUE;
     }
 
-  if (PSPPIRE_SHEET_IN_RESIZE (sheet))
+  psppire_sheet_get_pixel_info (sheet, x, y, &row, &column);
+
+  if (sheet->select_status == PSPPIRE_SHEET_NORMAL && row == sheet->active_cell.row &&
+      column == sheet->active_cell.col) return TRUE;
+
+  if ( mods & GDK_BUTTON1_MASK)
     {
-      PsppireSheetRange aux;
-      gint v_h, current_col, current_row, col_threshold, row_threshold;
-      v_h = 1;
-      if (abs (x - psppire_axis_start_pixel (sheet->haxis, sheet->drag_cell.col)) >
-         abs (y - psppire_axis_start_pixel (sheet->vaxis, sheet->drag_cell.row))) v_h = 2;
-
-      current_col = column_from_xpixel (sheet, x);
-      current_row = row_from_ypixel (sheet, y);
-      column = current_col - sheet->drag_cell.col;
-      row = current_row - sheet->drag_cell.row;
-
-      /*use half of column width resp. row height as threshold to
-       expand selection*/
-      col_threshold = psppire_axis_start_pixel (sheet->haxis, current_col) +
-       psppire_axis_unit_size (sheet->haxis, current_col) / 2;
-      if (column > 0)
+      if (PSPPIRE_SHEET_IN_SELECTION (sheet) )
        {
-         if (x < col_threshold)
-           column -= 1;
-       }
-      else if (column < 0)
-       {
-         if (x > col_threshold)
-           column +=1;
-       }
-      row_threshold = psppire_axis_start_pixel (sheet->vaxis, current_row) +
-       psppire_axis_unit_size (sheet->vaxis, current_row)/2;
-      if (row > 0)
-       {
-         if (y < row_threshold)
-           row -= 1;
-       }
-      else if (row < 0)
-       {
-         if (y > row_threshold)
-           row +=1;
-       }
+         /* Redraw the old range */
+         psppire_sheet_unselect_range (sheet);
 
-      if (sheet->select_status == PSPPIRE_SHEET_COLUMN_SELECTED) row = 0;
-      if (sheet->select_status == PSPPIRE_SHEET_ROW_SELECTED) column = 0;
-      sheet->x_drag = x;
-      sheet->y_drag = y;
-      aux = sheet->range;
+         sheet->range.rowi = row;
+         sheet->range.coli = column;
 
-      if (v_h == 1)
-       column = 0;
+         /* Redraw the new range */
+         psppire_sheet_select_range (sheet, &sheet->range);
+       }
       else
-       row = 0;
-
-      if (aux.row0 + row >= 0 && aux.rowi + row < psppire_axis_unit_count (sheet->vaxis) &&
-         aux.col0 + column >= 0 && aux.coli + column < psppire_axis_unit_count (sheet->haxis))
        {
-         aux = sheet->drag_range;
-         sheet->drag_range = sheet->range;
-
-         if (row < 0) sheet->drag_range.row0 = sheet->range.row0 + row;
-         if (row > 0) sheet->drag_range.rowi = sheet->range.rowi + row;
-         if (column < 0) sheet->drag_range.col0 = sheet->range.col0 + column;
-         if (column > 0) sheet->drag_range.coli = sheet->range.coli + column;
-
-         if (aux.row0 != sheet->drag_range.row0 ||
-             aux.rowi != sheet->drag_range.rowi ||
-             aux.col0 != sheet->drag_range.col0 ||
-             aux.coli != sheet->drag_range.coli)
-           {
-             draw_xor_rectangle (sheet, aux);
-             draw_xor_rectangle (sheet, sheet->drag_range);
-           }
+         PSPPIRE_SHEET_SET_FLAGS (sheet, PSPPIRE_SHEET_IN_SELECTION);
        }
-      return TRUE;
     }
 
-  psppire_sheet_get_pixel_info (sheet, x, y, &row, &column);
-
-  if (sheet->select_status == PSPPIRE_SHEET_NORMAL && row == sheet->active_cell.row &&
-      column == sheet->active_cell.col) return TRUE;
-
-  if (PSPPIRE_SHEET_IN_SELECTION (sheet) && mods&GDK_BUTTON1_MASK)
-    psppire_sheet_extend_selection (sheet, row, column);
-
   return TRUE;
 }
 
 static gboolean
 psppire_sheet_crossing_notify (GtkWidget *widget,
-                          GdkEventCrossing *event)
+                              GdkEventCrossing *event)
 {
   PsppireSheet *sheet = PSPPIRE_SHEET (widget);
 
@@ -4078,63 +3501,10 @@ psppire_sheet_focus_in (GtkWidget     *w,
 }
 
 
-static void
-psppire_sheet_extend_selection (PsppireSheet *sheet, gint row, gint column)
-{
-  PsppireSheetRange range;
-  gint state;
-  gint r, c;
-
-  if (row == sheet->selection_cell.row && column == sheet->selection_cell.col)
-    return;
-
-  if (sheet->selection_mode == GTK_SELECTION_SINGLE) return;
-
-  gtk_widget_grab_focus (GTK_WIDGET (sheet));
-
-  if (PSPPIRE_SHEET_IN_DRAG (sheet)) return;
-
-  state = sheet->select_status;
-
-  switch (sheet->select_status)
-    {
-    case PSPPIRE_SHEET_ROW_SELECTED:
-      column = psppire_axis_unit_count (sheet->haxis) - 1;
-      break;
-    case PSPPIRE_SHEET_COLUMN_SELECTED:
-      row = psppire_axis_unit_count (sheet->vaxis) - 1;
-      break;
-    case PSPPIRE_SHEET_NORMAL:
-      sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
-      r = sheet->active_cell.row;
-      c = sheet->active_cell.col;
-      sheet->range.col0 = c;
-      sheet->range.row0 = r;
-      sheet->range.coli = c;
-      sheet->range.rowi = r;
-      psppire_sheet_range_draw_selection (sheet, sheet->range);
-    case PSPPIRE_SHEET_RANGE_SELECTED:
-      sheet->select_status = PSPPIRE_SHEET_RANGE_SELECTED;
-    }
-
-  sheet->selection_cell.row = row;
-  sheet->selection_cell.col = column;
-
-  range.col0 = MIN (column, sheet->active_cell.col);
-  range.coli = MAX (column, sheet->active_cell.col);
-  range.row0 = MIN (row, sheet->active_cell.row);
-  range.rowi = MAX (row, sheet->active_cell.row);
-
-  if (range.row0 != sheet->range.row0 || range.rowi != sheet->range.rowi ||
-      range.col0 != sheet->range.col0 || range.coli != sheet->range.coli ||
-      state == PSPPIRE_SHEET_NORMAL)
-    psppire_sheet_real_select_range (sheet, &range);
-
-}
 
 static gint
 psppire_sheet_entry_key_press (GtkWidget *widget,
-                          GdkEventKey *key)
+                              GdkEventKey *key)
 {
   gboolean focus;
   g_signal_emit_by_name (widget, "key_press_event", key, &focus);
@@ -4155,7 +3525,7 @@ page_vertical (PsppireSheet *sheet, GtkScrollType dir)
   gint new_row;
 
   vpixel -= psppire_axis_start_pixel (sheet->vaxis,
-                                    min_visible_row (sheet));
+                                     min_visible_row (sheet));
 
   switch ( dir)
     {
@@ -4177,12 +3547,12 @@ page_vertical (PsppireSheet *sheet, GtkScrollType dir)
 
 
   vpixel += psppire_axis_start_pixel (sheet->vaxis,
-                                    min_visible_row (sheet));
+                                     min_visible_row (sheet));
 
   new_row =  row_from_ypixel (sheet, vpixel);
 
   change_active_cell (sheet, new_row,
-                          sheet->active_cell.col);
+                     sheet->active_cell.col);
 }
 
 
@@ -4259,7 +3629,7 @@ step_sheet (PsppireSheet *sheet, GtkScrollType dir)
     {
       glong hpos  =
        psppire_axis_start_pixel (sheet->haxis,
-                                   new_cell.col + 1);
+                                 new_cell.col + 1);
       hpos -= sheet->hadjustment->page_size;
 
       gtk_adjustment_set_value (sheet->hadjustment,
@@ -4269,7 +3639,7 @@ step_sheet (PsppireSheet *sheet, GtkScrollType dir)
     {
       glong hpos  =
        psppire_axis_start_pixel (sheet->haxis,
-                                   new_cell.col);
+                                 new_cell.col);
 
       gtk_adjustment_set_value (sheet->hadjustment,
                                hpos);
@@ -4280,7 +3650,7 @@ step_sheet (PsppireSheet *sheet, GtkScrollType dir)
     {
       glong vpos  =
        psppire_axis_start_pixel (sheet->vaxis,
-                                   new_cell.row + 1);
+                                 new_cell.row + 1);
       vpos -= sheet->vadjustment->page_size;
 
       gtk_adjustment_set_value (sheet->vadjustment,
@@ -4290,7 +3660,7 @@ step_sheet (PsppireSheet *sheet, GtkScrollType dir)
     {
       glong vpos  =
        psppire_axis_start_pixel (sheet->vaxis,
-                                   new_cell.row);
+                                 new_cell.row);
 
       gtk_adjustment_set_value (sheet->vadjustment,
                                vpos);
@@ -4302,7 +3672,7 @@ step_sheet (PsppireSheet *sheet, GtkScrollType dir)
 
 static gboolean
 psppire_sheet_key_press (GtkWidget *widget,
-                    GdkEventKey *key)
+                        GdkEventKey *key)
 {
   PsppireSheet *sheet = PSPPIRE_SHEET (widget);
 
@@ -4342,7 +3712,7 @@ psppire_sheet_key_press (GtkWidget *widget,
                                sheet->vadjustment->lower);
 
       change_active_cell (sheet,  0,
-                              sheet->active_cell.col);
+                         sheet->active_cell.col);
 
       break;
 
@@ -4371,7 +3741,7 @@ psppire_sheet_key_press (GtkWidget *widget,
 
 static void
 psppire_sheet_size_request (GtkWidget *widget,
-                       GtkRequisition *requisition)
+                           GtkRequisition *requisition)
 {
   PsppireSheet *sheet;
 
@@ -4396,7 +3766,7 @@ psppire_sheet_size_request (GtkWidget *widget,
 
 static void
 psppire_sheet_size_allocate (GtkWidget *widget,
-                        GtkAllocation *allocation)
+                            GtkAllocation *allocation)
 {
   PsppireSheet *sheet;
   GtkAllocation sheet_allocation;
@@ -4588,8 +3958,8 @@ psppire_sheet_size_allocate_entry (PsppireSheet *sheet)
   sheet_entry = psppire_sheet_get_entry (sheet);
 
   if ( ! psppire_sheet_get_attributes (sheet, sheet->active_cell.row,
-                                  sheet->active_cell.col,
-                                  &attributes) )
+                                      sheet->active_cell.col,
+                                      &attributes) )
     return ;
 
   if ( GTK_WIDGET_REALIZED (sheet->entry_widget) )
@@ -4710,8 +4080,8 @@ psppire_sheet_get_entry (PsppireSheet *sheet)
 
 static void
 draw_button (PsppireSheet *sheet, GdkWindow *window,
-                      PsppireSheetButton *button, gboolean is_sensitive,
-                      GdkRectangle allocation)
+            PsppireSheetButton *button, gboolean is_sensitive,
+            GdkRectangle allocation)
 {
   GtkShadowType shadow_type;
   gint text_width = 0, text_height = 0;
@@ -5264,7 +4634,7 @@ set_row_height (PsppireSheet *sheet,
 
 static gboolean
 psppire_sheet_get_attributes (const PsppireSheet *sheet, gint row, gint col,
-                         PsppireSheetCellAttr *attr)
+                             PsppireSheetCellAttr *attr)
 {
   GdkColor *fg, *bg;
   const GtkJustification *j ;
@@ -5312,8 +4682,8 @@ psppire_sheet_get_attributes (const PsppireSheet *sheet, gint row, gint col,
 
 static void
 psppire_sheet_button_size_request       (PsppireSheet *sheet,
-                                 const PsppireSheetButton *button,
-                                 GtkRequisition *button_requisition)
+                                         const PsppireSheetButton *button,
+                                         GtkRequisition *button_requisition)
 {
   GtkRequisition requisition;
   GtkRequisition label_requisition;
@@ -5333,9 +4703,9 @@ psppire_sheet_button_size_request  (PsppireSheet *sheet,
 
 static void
 psppire_sheet_forall (GtkContainer *container,
-                 gboolean include_internals,
-                 GtkCallback callback,
-                 gpointer callback_data)
+                     gboolean include_internals,
+                     GtkCallback callback,
+                     gpointer callback_data)
 {
   PsppireSheet *sheet = PSPPIRE_SHEET (container);
 
@@ -5494,7 +4864,7 @@ primary_clear_cb (GtkClipboard *clipboard,
   if ( ! GTK_WIDGET_REALIZED (GTK_WIDGET (sheet)))
     return;
 
-  psppire_sheet_real_unselect_range (sheet, NULL);
+  psppire_sheet_unselect_range (sheet);
 }
 
 static void
index e3f77aa82e932b13cb864a6c9d66cf2f66dab1ff..db58d4bdf3ea4429dcc35637cc61df28d089ab5f 100644 (file)
@@ -112,8 +112,6 @@ struct _PsppireSheet
 
   PsppireSheetModel *model;
 
-  GtkSelectionMode selection_mode;
-
   /* Component colors */
   GdkColor color[n_COLORS];
   gboolean show_grid;
@@ -127,9 +125,6 @@ struct _PsppireSheet
   /* The type of entry_widget */
   GtkType entry_type;
 
-  /* expanding selection */
-  PsppireSheetCell selection_cell;
-
   /* global selection button */
   GtkWidget *button;
 
index 8179d29a3721aa27b0b0e7417085a515eb65c591..36300cc806daa17d022c71d49473108f0834b5f2 100644 (file)
 #include <data/sys-file-writer.h>
 #include <data/sys-file-reader.h>
 #include <data/value.h>
+#include <data/vardict.h>
 #include <data/value-labels.h>
 #include <data/format.h>
 #include <data/data-in.h>
+#include <data/data-out.h>
 #include <string.h>
 
 typedef struct fmt_spec input_format ;
@@ -163,6 +165,7 @@ onBoot (ver)
  const char *ver
 CODE:
  assert (0 == strcmp (ver, bare_version));
+ i18n_init ();
  msg_init (NULL, message_handler);
  settings_init (0, 0);
  fh_init ();
@@ -174,12 +177,11 @@ format_value (val, var)
 CODE:
  SV *ret;
  const struct fmt_spec *fmt = var_get_print_format (var);
+ const struct dictionary *dict = var_get_vardict (var)->dict;
  union value uv;
  char *s;
  make_value_from_scalar (&uv, val, var);
- s = malloc (fmt->w);
- memset (s, '\0', fmt->w);
- data_out (&uv, fmt, s);
+ s = data_out (&uv, dict_get_encoding (dict), fmt);
  value_destroy (&uv, var_get_width (var));
  ret = newSVpv (s, fmt->w);
  free (s);
@@ -371,6 +373,37 @@ clear_value_labels (var)
 CODE:
  var_clear_value_labels (var);
 
+SV *
+get_write_format (var)
+ struct variable *var
+CODE:
+ HV *fmthash = (HV *) sv_2mortal ((SV *) newHV());
+ const struct fmt_spec *fmt = var_get_write_format (var);
+
+ hv_store (fmthash, "fmt", 3, newSVnv (fmt->type), 0);
+ hv_store (fmthash, "decimals", 8, newSVnv (fmt->d), 0);
+ hv_store (fmthash, "width", 5, newSVnv (fmt->w), 0);
+
+ RETVAL = newRV ((SV *) fmthash);
+ OUTPUT:
+RETVAL
+
+SV *
+get_print_format (var)
+ struct variable *var
+CODE:
+ HV *fmthash = (HV *) sv_2mortal ((SV *) newHV());
+ const struct fmt_spec *fmt = var_get_print_format (var);
+
+ hv_store (fmthash, "fmt", 3, newSVnv (fmt->type), 0);
+ hv_store (fmthash, "decimals", 8, newSVnv (fmt->d), 0);
+ hv_store (fmthash, "width", 5, newSVnv (fmt->w), 0);
+
+ RETVAL = newRV ((SV *) fmthash);
+ OUTPUT:
+RETVAL
+
+
 void
 pxs_set_write_format (var, fmt)
  struct variable *var
@@ -612,6 +645,7 @@ CODE:
       {
        struct substring ss = ss_cstr (SvPV_nolen (sv));
        if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, 0,
+                       sfi->dict,
                        case_data_rw (c, v),
                        var_get_width (v)) )
          {
index 3cb9f3be48a5f33ecf21591977e1deacb27e09e4..e5599908b683f7b6e6bde716fbfa9f74d3460338 100644 (file)
@@ -249,7 +249,7 @@ An integer denoting the number of decimal places for the format.
 
 =item width
 
-An integer denoting the number of width of the format.
+An integer denoting the width of the format.
 
 =back
 
@@ -282,6 +282,16 @@ sub set_print_format
 
 =pod
 
+
+=head3 get_write_format ()
+
+Returns a reference to a hash containing the write format for the variable.
+
+
+=head3 get_print_format ()
+
+Returns a reference to a hash containing the print format for the variable.
+
 =head3 set_output_format (%fmt)
 
 Sets the write and print formats to C<fmt>.  This is the same as
@@ -510,7 +520,7 @@ values retrieved from a reader.
 
 =head3 PSPP::format_value ($value, $variable)
 
-Returns a scalar containing a string representing C<value> formatted accoring 
+Returns a scalar containing a string representing C<value> formatted according 
 to the print format of C<variable>.
 In the most common ussage,  C<value> should be a value of C<variable>.
 
index 54f873f44f6773d81d37270656e5d114088869a7..fa1dd9d91e430d963de0d4df8e013dc805aee220 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.7.0\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2009-05-16 07:00+0800\n"
+"POT-Creation-Date: 2009-07-26 09:59+0200\n"
 "PO-Revision-Date: 2008-11-05 08:17+0900\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
@@ -49,81 +49,56 @@ msgid ""
 "system-missing, zero, or negative.  These case(s) were ignored."
 msgstr ""
 
-#: src/data/case-tmpfile.c:57
-#, c-format
-msgid "failed to create temporary file"
-msgstr ""
-
-#: src/data/case-tmpfile.c:131
-#, c-format
-msgid "seeking in temporary file"
-msgstr ""
-
-#: src/data/case-tmpfile.c:153
-#, c-format
-msgid "reading temporary file"
-msgstr ""
-
-#: src/data/case-tmpfile.c:155
-#, c-format
-msgid "unexpected end of file reading temporary file"
-msgstr ""
-
-#: src/data/case-tmpfile.c:175
-#, c-format
-msgid "writing to temporary file"
-msgstr ""
-
-#: src/data/data-in.c:262 src/data/data-in.c:452
+#: src/data/data-in.c:274 src/data/data-in.c:464
 msgid "Field contents are not numeric."
 msgstr ""
 
-#: src/data/data-in.c:264 src/data/data-in.c:454
+#: src/data/data-in.c:276 src/data/data-in.c:466
 msgid "Number followed by garbage."
 msgstr ""
 
-#: src/data/data-in.c:275
+#: src/data/data-in.c:287
 msgid "Invalid numeric syntax."
 msgstr ""
 
-#: src/data/data-in.c:284 src/data/data-in.c:467
+#: src/data/data-in.c:296 src/data/data-in.c:479
 msgid "Too-large number set to system-missing."
 msgstr ""
 
-#: src/data/data-in.c:289 src/data/data-in.c:472
+#: src/data/data-in.c:301 src/data/data-in.c:484
 msgid "Too-small number set to zero."
 msgstr ""
 
-#: src/data/data-in.c:315
+#: src/data/data-in.c:327
 msgid "All characters in field must be digits."
 msgstr ""
 
-#: src/data/data-in.c:338
+#: src/data/data-in.c:350
 msgid "Unrecognized character in field."
 msgstr "Unrecognised character in field."
 
-#: src/data/data-in.c:362 src/data/data-in.c:636
+#: src/data/data-in.c:374 src/data/data-in.c:650
 msgid "Field must have even length."
 msgstr ""
 
-#: src/data/data-in.c:367 src/data/data-in.c:647
+#: src/data/data-in.c:379 src/data/data-in.c:661
 msgid "Field must contain only hex digits."
 msgstr ""
 
-#: src/data/data-in.c:686 src/data/data-in.c:733
+#: src/data/data-in.c:700 src/data/data-in.c:747
 msgid "Syntax error in date field."
 msgstr ""
 
-#: src/data/data-in.c:702
+#: src/data/data-in.c:716
 #, c-format
 msgid "Day (%ld) must be between 1 and 31."
 msgstr ""
 
-#: src/data/data-in.c:749
+#: src/data/data-in.c:763
 msgid "Delimiter expected between fields in date."
 msgstr ""
 
-#: src/data/data-in.c:823
+#: src/data/data-in.c:837
 msgid ""
 "Unrecognized month format.  Months may be specified as Arabic or Roman "
 "numerals or as at least 3 letters of their English names."
@@ -131,45 +106,45 @@ msgstr ""
 "Unrecognised month format.  Months may be specified as Arabic or Roman \n"
 "numerals or as at least 3 letters of their English names."
 
-#: src/data/data-in.c:850
+#: src/data/data-in.c:864
 #, c-format
 msgid "Year (%ld) must be between 1582 and 19999."
 msgstr ""
 
-#: src/data/data-in.c:862
+#: src/data/data-in.c:876
 #, c-format
 msgid "Trailing garbage \"%.*s\" following date."
 msgstr ""
 
-#: src/data/data-in.c:878
+#: src/data/data-in.c:892
 msgid "Julian day must have exactly three digits."
 msgstr ""
 
-#: src/data/data-in.c:883
+#: src/data/data-in.c:897
 #, c-format
 msgid "Julian day (%ld) must be between 1 and 366."
 msgstr ""
 
-#: src/data/data-in.c:907
+#: src/data/data-in.c:921
 #, c-format
 msgid "Quarter (%ld) must be between 1 and 4."
 msgstr ""
 
-#: src/data/data-in.c:927
+#: src/data/data-in.c:941
 #, c-format
 msgid "Week (%ld) must be between 1 and 53."
 msgstr ""
 
-#: src/data/data-in.c:940
+#: src/data/data-in.c:954
 msgid "Delimiter expected between fields in time."
 msgstr ""
 
-#: src/data/data-in.c:960
+#: src/data/data-in.c:974
 #, c-format
 msgid "Minute (%ld) must be between 0 and 59."
 msgstr ""
 
-#: src/data/data-in.c:1000
+#: src/data/data-in.c:1014
 msgid ""
 "Unrecognized weekday name.  At least the first two letters of an English "
 "weekday name must be specified."
@@ -177,32 +152,32 @@ msgstr ""
 "Unrecognised weekday name.  At least the first two letters of an English "
 "weekday name must be specified."
 
-#: src/data/data-in.c:1138
+#: src/data/data-in.c:1152
 #, c-format
 msgid "`%c' expected in date field."
 msgstr ""
 
-#: src/data/data-in.c:1179
+#: src/data/data-in.c:1193
 #, c-format
 msgid "column %d"
 msgstr ""
 
-#: src/data/data-in.c:1181
+#: src/data/data-in.c:1195
 #, c-format
 msgid "columns %d-%d"
 msgstr ""
 
-#: src/data/data-in.c:1185
+#: src/data/data-in.c:1199
 #, c-format
 msgid "%s field) "
 msgstr ""
 
-#: src/data/data-out.c:446
+#: src/data/data-out.c:481
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr ""
 
-#: src/data/data-out.c:467
+#: src/data/data-out.c:502
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr ""
@@ -219,13 +194,13 @@ msgstr ""
 msgid "scratch"
 msgstr ""
 
-#: src/data/dictionary.c:926
+#: src/data/dictionary.c:940
 msgid ""
 "At least one case in the data file had a weight value that was user-missing, "
 "system-missing, zero, or negative.  These case(s) were ignored."
 msgstr ""
 
-#: src/data/dictionary.c:1228
+#: src/data/dictionary.c:1263
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr ""
@@ -322,33 +297,33 @@ msgstr[1] ""
 msgid "%s variables are not compatible with %s format %s."
 msgstr ""
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:657
-#: src/ui/gui/psppire.glade:2034 src/ui/gui/psppire-var-store.c:575
+#: src/data/format.c:327 src/data/sys-file-reader.c:734
+#: src/ui/gui/psppire.glade:2009 src/ui/gui/psppire-var-store.c:628
 #: src/ui/gui/var-sheet-dialogs.glade:139
 msgid "String"
 msgstr ""
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:657
-#: src/ui/gui/psppire.glade:2109 src/ui/gui/psppire-var-store.c:568
+#: src/data/format.c:327 src/data/sys-file-reader.c:734
+#: src/ui/gui/psppire.glade:2084 src/ui/gui/psppire-var-store.c:621
 #: src/ui/gui/var-sheet-dialogs.glade:28
 msgid "Numeric"
 msgstr ""
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1214
-#: src/data/sys-file-reader.c:1216
+#: src/data/format.c:328 src/data/sys-file-reader.c:1299
+#: src/data/sys-file-reader.c:1301
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:489 src/language/xforms/recode.c:490
-#: src/language/xforms/recode.c:502 src/language/xforms/recode.c:503
+#: src/language/xforms/recode.c:493 src/language/xforms/recode.c:494
+#: src/language/xforms/recode.c:506 src/language/xforms/recode.c:507
 msgid "numeric"
 msgstr ""
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1214
-#: src/data/sys-file-reader.c:1216
+#: src/data/format.c:328 src/data/sys-file-reader.c:1299
+#: src/data/sys-file-reader.c:1301
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:489 src/language/xforms/recode.c:490
-#: src/language/xforms/recode.c:502 src/language/xforms/recode.c:503
+#: src/language/xforms/recode.c:493 src/language/xforms/recode.c:494
+#: src/language/xforms/recode.c:506 src/language/xforms/recode.c:507
 msgid "string"
 msgstr ""
 
@@ -357,27 +332,27 @@ msgstr ""
 msgid "String variable with width %d is not compatible with format %s."
 msgstr ""
 
-#: src/data/gnumeric-reader.c:33
+#: src/data/gnumeric-reader.c:36
 msgid ""
 "Support for Gnumeric files was not compiled into this installation of PSPP"
 msgstr ""
 
-#: src/data/gnumeric-reader.c:362
+#: src/data/gnumeric-reader.c:368
 #, c-format
-msgid "Error opening \"%s\" for reading as a gnumeric file: %s."
+msgid "Error opening \"%s\" for reading as a Gnumeric file: %s."
 msgstr ""
 
-#: src/data/gnumeric-reader.c:382
+#: src/data/gnumeric-reader.c:388
 #, c-format
 msgid "Invalid cell range \"%s\""
 msgstr ""
 
-#: src/data/gnumeric-reader.c:518 src/data/psql-reader.c:182
+#: src/data/gnumeric-reader.c:520 src/data/psql-reader.c:187
 #, c-format
 msgid "Cannot create variable name from %s"
 msgstr ""
 
-#: src/data/gnumeric-reader.c:530
+#: src/data/gnumeric-reader.c:532
 #, c-format
 msgid "Selected sheet or range of spreadsheet \"%s\" is empty."
 msgstr ""
@@ -448,183 +423,183 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/por-file-reader.c:268 src/data/por-file-writer.c:148
+#: src/data/por-file-reader.c:267 src/data/por-file-writer.c:149
 msgid "portable file"
 msgstr ""
 
-#: src/data/por-file-reader.c:276
+#: src/data/por-file-reader.c:275
 #, c-format
 msgid ""
 "An error occurred while opening \"%s\" for reading as a portable file: %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:297
+#: src/data/por-file-reader.c:296
 msgid "Data record expected."
 msgstr ""
 
-#: src/data/por-file-reader.c:379
+#: src/data/por-file-reader.c:378
 msgid "Number expected."
 msgstr ""
 
-#: src/data/por-file-reader.c:407
+#: src/data/por-file-reader.c:406
 msgid "Missing numeric terminator."
 msgstr ""
 
-#: src/data/por-file-reader.c:430
+#: src/data/por-file-reader.c:429
 msgid "Invalid integer."
 msgstr ""
 
-#: src/data/por-file-reader.c:441
+#: src/data/por-file-reader.c:440 src/data/por-file-reader.c:460
 #, c-format
 msgid "Bad string length %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:502
+#: src/data/por-file-reader.c:523
 #, c-format
 msgid "%s: Not a portable file."
 msgstr ""
 
-#: src/data/por-file-reader.c:519
+#: src/data/por-file-reader.c:540
 #, c-format
 msgid "Unrecognized version code `%c'."
 msgstr "Unrecognised version code `%c'."
 
-#: src/data/por-file-reader.c:528
+#: src/data/por-file-reader.c:549
 #, c-format
 msgid "Bad date string length %zu."
 msgstr ""
 
-#: src/data/por-file-reader.c:530
+#: src/data/por-file-reader.c:551
 #, c-format
 msgid "Bad time string length %zu."
 msgstr ""
 
-#: src/data/por-file-reader.c:572
+#: src/data/por-file-reader.c:593
 #, c-format
 msgid ""
 "%s: Bad format specifier byte (%d).  Variable will be assigned a default "
 "format."
 msgstr ""
 
-#: src/data/por-file-reader.c:593
+#: src/data/por-file-reader.c:614
 #, c-format
 msgid "Numeric variable %s has invalid format specifier %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:597
+#: src/data/por-file-reader.c:618
 #, c-format
 msgid "String variable %s with width %d has invalid format specifier %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:621
+#: src/data/por-file-reader.c:642
 msgid "Expected variable count record."
 msgstr ""
 
-#: src/data/por-file-reader.c:625
+#: src/data/por-file-reader.c:646
 #, c-format
 msgid "Invalid number of variables %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:635
+#: src/data/por-file-reader.c:655
 #, c-format
 msgid "Weight variable name (%s) truncated."
 msgstr ""
 
-#: src/data/por-file-reader.c:650
+#: src/data/por-file-reader.c:670
 msgid "Expected variable record."
 msgstr ""
 
-#: src/data/por-file-reader.c:654
+#: src/data/por-file-reader.c:674
 #, c-format
 msgid "Invalid variable width %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:662
+#: src/data/por-file-reader.c:681
 #, c-format
 msgid "Invalid variable name `%s' in position %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:666
+#: src/data/por-file-reader.c:685 src/data/sys-file-reader.c:592
 #, c-format
 msgid "Bad width %d for variable %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:681
+#: src/data/por-file-reader.c:700
 #, c-format
 msgid "Duplicate variable name %s in position %d."
 msgstr ""
 
-#: src/data/por-file-reader.c:682
+#: src/data/por-file-reader.c:701
 #, c-format
 msgid "Duplicate variable name %s in position %d renamed to %s."
 msgstr ""
 
-#: src/data/por-file-reader.c:725
+#: src/data/por-file-reader.c:750
 #, c-format
 msgid "Weighting variable %s not present in dictionary."
 msgstr ""
 
-#: src/data/por-file-reader.c:772
+#: src/data/por-file-reader.c:794
 #, c-format
 msgid "Unknown variable %s while parsing value labels."
 msgstr ""
 
-#: src/data/por-file-reader.c:775
+#: src/data/por-file-reader.c:797
 #, c-format
 msgid ""
 "Cannot assign value labels to %s and %s, which have different variable types."
 msgstr ""
 
-#: src/data/por-file-writer.c:140
+#: src/data/por-file-writer.c:141
 #, c-format
 msgid "Invalid decimal digits count %d.  Treating as %d."
 msgstr ""
 
-#: src/data/por-file-writer.c:160
+#: src/data/por-file-writer.c:161
 #, c-format
 msgid "Error opening \"%s\" for writing as a portable file: %s."
 msgstr ""
 
-#: src/data/por-file-writer.c:500
+#: src/data/por-file-writer.c:506
 #, c-format
 msgid "An I/O error occurred writing portable file \"%s\"."
 msgstr ""
 
-#: src/data/psql-reader.c:42
+#: src/data/psql-reader.c:46
 msgid ""
 "Support for reading postgres databases was not compiled into this "
 "installation of PSPP"
 msgstr ""
 
-#: src/data/psql-reader.c:237
+#: src/data/psql-reader.c:242
 msgid "Memory error whilst opening psql source"
 msgstr ""
 
-#: src/data/psql-reader.c:243
+#: src/data/psql-reader.c:248
 #, c-format
 msgid "Error opening psql source: %s."
 msgstr ""
 
-#: src/data/psql-reader.c:258
+#: src/data/psql-reader.c:263
 #, c-format
 msgid ""
 "Postgres server is version %s. Reading from versions earlier than 8.0 is not "
 "supported."
 msgstr ""
 
-#: src/data/psql-reader.c:278
+#: src/data/psql-reader.c:283
 msgid ""
 "Connection is unencrypted, but unencrypted connections have not been "
 "permitted."
 msgstr ""
 
-#: src/data/psql-reader.c:317 src/data/psql-reader.c:342
-#: src/data/psql-reader.c:352
+#: src/data/psql-reader.c:322 src/data/psql-reader.c:347
+#: src/data/psql-reader.c:357
 #, c-format
 msgid "Error from psql source: %s."
 msgstr ""
 
-#: src/data/psql-reader.c:447
+#: src/data/psql-reader.c:452
 #, c-format
 msgid "Unsupported OID %d.  SYSMIS values will be inserted."
 msgstr ""
@@ -638,11 +613,11 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/scratch-writer.c:67 src/language/data-io/file-handle.q:181
+#: src/data/scratch-writer.c:66 src/language/data-io/file-handle.q:181
 msgid "scratch file"
 msgstr ""
 
-#: src/data/settings.c:685
+#: src/data/settings.c:686
 #, c-format
 msgid ""
 "%s: Custom currency string `%s' does not contain exactly three periods or "
@@ -653,41 +628,46 @@ msgstr ""
 msgid "Variable suffix too large."
 msgstr ""
 
+#: src/data/sys-file-reader.c:213
+#, c-format
+msgid "Recoded variable name duplicates an existing `%s' within system file."
+msgstr ""
+
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:216 src/data/sys-file-writer.c:200
+#: src/data/sys-file-reader.c:276 src/data/sys-file-writer.c:203
 msgid "system file"
 msgstr ""
 
-#: src/data/sys-file-reader.c:223
+#: src/data/sys-file-reader.c:283
 #, c-format
 msgid "Error opening \"%s\" for reading as a system file: %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:262
+#: src/data/sys-file-reader.c:322
 msgid "Misplaced type 4 record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:273
+#: src/data/sys-file-reader.c:333
 #, c-format
 msgid "Unrecognized record type %d."
 msgstr "Unrecognised record type %d."
 
-#: src/data/sys-file-reader.c:312
+#: src/data/sys-file-reader.c:374
 #, c-format
 msgid "File header claims %d variable positions but %d were read from file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:352
+#: src/data/sys-file-reader.c:414
 #, c-format
 msgid "Error closing system file \"%s\": %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:417 src/data/sys-file-reader.c:427
+#: src/data/sys-file-reader.c:479 src/data/sys-file-reader.c:489
 msgid "This is not an SPSS system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:446
+#: src/data/sys-file-reader.c:511
 msgid ""
 "Compression bias is not the usual value of 100, or system file uses "
 "unrecognized floating-point format."
@@ -695,333 +675,339 @@ msgstr ""
 "Compression bias is not the usual value of 100, or system file uses \n"
 "unrecognised floating-point format."
 
-#: src/data/sys-file-reader.c:514
+#: src/data/sys-file-reader.c:588
 #, c-format
 msgid "Invalid variable name `%s'."
 msgstr ""
 
-#: src/data/sys-file-reader.c:518
-#, c-format
-msgid "Bad variable width %d."
-msgstr ""
-
-#: src/data/sys-file-reader.c:522
+#: src/data/sys-file-reader.c:596
 #, c-format
 msgid "Duplicate variable name `%s' within system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:530
+#: src/data/sys-file-reader.c:604
 msgid "Variable label indicator field is not 0 or 1."
 msgstr ""
 
-#: src/data/sys-file-reader.c:538
+#: src/data/sys-file-reader.c:612
 #, c-format
 msgid "Variable %s has label of invalid length %zu."
 msgstr ""
 
-#: src/data/sys-file-reader.c:557
+#: src/data/sys-file-reader.c:631
 msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:572
+#: src/data/sys-file-reader.c:649
 msgid "String missing value indicator field is not 0, 1, 2, or 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:575
-#, c-format
-msgid ""
-"Ignoring missing values on long string variable %s, which PSPP does not yet "
-"support."
-msgstr ""
-
-#: src/data/sys-file-reader.c:604
+#: src/data/sys-file-reader.c:681
 msgid "Missing string continuation record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:638
+#: src/data/sys-file-reader.c:715
 #, c-format
 msgid "Unknown variable format %<PRIu8>."
 msgstr ""
 
-#: src/data/sys-file-reader.c:656
+#: src/data/sys-file-reader.c:733
 #, c-format
 msgid "%s variable %s has invalid %s format %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:659
+#: src/data/sys-file-reader.c:736
 msgid "print"
 msgstr ""
 
-#: src/data/sys-file-reader.c:659
+#: src/data/sys-file-reader.c:736
 msgid "write"
 msgstr ""
 
-#: src/data/sys-file-reader.c:663
+#: src/data/sys-file-reader.c:740
 msgid "Suppressing further invalid format warnings."
 msgstr ""
 
-#: src/data/sys-file-reader.c:681
+#: src/data/sys-file-reader.c:758
 msgid "Weighting variable must be numeric."
 msgstr ""
 
-#: src/data/sys-file-reader.c:695
+#: src/data/sys-file-reader.c:772
 msgid "Multiple type 6 (document) records."
 msgstr ""
 
-#: src/data/sys-file-reader.c:699
+#: src/data/sys-file-reader.c:776
 #, c-format
 msgid "Number of document lines (%d) must be greater than 0."
 msgstr ""
 
-#: src/data/sys-file-reader.c:707
+#: src/data/sys-file-reader.c:784
 msgid "Document line contains null byte."
 msgstr ""
 
-#: src/data/sys-file-reader.c:793
-msgid ""
-"Ignoring value labels for long string variables, which PSPP does not yet "
-"support."
-msgstr ""
-
-#: src/data/sys-file-reader.c:798
+#: src/data/sys-file-reader.c:874
 #, c-format
 msgid ""
 "Unrecognized record type 7, subtype %d.  Please send a copy of this file, "
 "and the syntax which created it to %s"
 msgstr ""
 
-#: src/data/sys-file-reader.c:825
+#: src/data/sys-file-reader.c:901
 #, c-format
 msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
 msgstr ""
 
-#: src/data/sys-file-reader.c:845
+#: src/data/sys-file-reader.c:921
 #, c-format
 msgid ""
 "Floating-point representation indicated by system file (%d) differs from "
 "expected (%d)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:858
+#: src/data/sys-file-reader.c:934
 msgid "little-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:858
+#: src/data/sys-file-reader.c:934
 msgid "big-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:859
+#: src/data/sys-file-reader.c:935
 #, c-format
 msgid ""
 "Integer format indicated by system file (%s) differs from expected (%s)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:916
+#: src/data/sys-file-reader.c:992
 #, c-format
 msgid "Bad size (%zu) or count (%zu) on extension 4."
 msgstr ""
 
-#: src/data/sys-file-reader.c:920
+#: src/data/sys-file-reader.c:996 src/data/sys-file-reader.c:1000
+#: src/data/sys-file-reader.c:1004
 #, c-format
-msgid "File specifies unexpected value %g as SYSMIS."
+msgid "File specifies unexpected value %g as %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:922
-#, c-format
-msgid "File specifies unexpected value %g as HIGHEST."
-msgstr ""
-
-#: src/data/sys-file-reader.c:924
-#, c-format
-msgid "File specifies unexpected value %g as LOWEST."
-msgstr ""
-
-#: src/data/sys-file-reader.c:940
+#: src/data/sys-file-reader.c:1021
 #, c-format
 msgid "Bad size %zu on extension 11."
 msgstr ""
 
-#: src/data/sys-file-reader.c:952
+#: src/data/sys-file-reader.c:1033
 #, c-format
 msgid "Extension 11 has bad count %zu (for %zu variables)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:973
+#: src/data/sys-file-reader.c:1054
 #, c-format
 msgid ""
 "Invalid variable display parameters for variable %zu (%s).  Default "
 "parameters substituted."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1017
+#: src/data/sys-file-reader.c:1098
 #, c-format
 msgid "Long variable mapping from %s to invalid variable name `%s'."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1027
+#: src/data/sys-file-reader.c:1108
 #, c-format
 msgid "Duplicate long variable name `%s' within system file."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1080
+#: src/data/sys-file-reader.c:1161
 #, c-format
 msgid "%s listed as string of invalid length %s in very length string record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1090
+#: src/data/sys-file-reader.c:1171
 #, c-format
 msgid ""
 "%s listed in very long string record with width %s, which requires only one "
 "segment."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1096
+#: src/data/sys-file-reader.c:1177
 #, c-format
 msgid "Very long string %s overflows dictionary."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1110
+#: src/data/sys-file-reader.c:1191
 #, c-format
 msgid ""
 "Very long string with width %ld has segment %d of width %d (expected %d)"
 msgstr ""
 
-#: src/data/sys-file-reader.c:1155
+#: src/data/sys-file-reader.c:1237
 #, c-format
 msgid "Invalid number of labels: %d.  Ignoring labels."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1186
+#: src/data/sys-file-reader.c:1268
 msgid ""
 "Variable index record (type 4) does not immediately follow value label "
 "record (type 3) as it should."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1193
+#: src/data/sys-file-reader.c:1275
 #, c-format
 msgid ""
 "Number of variables associated with a value label (%d) is not between 1 and "
 "the number of variables (%zu)."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1203
+#: src/data/sys-file-reader.c:1286
 #, c-format
-msgid "Value labels are not allowed on long string variables (%s)."
+msgid ""
+"Value labels may not be added to long string variables (e.g. %s) using "
+"records types 3 and 4."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1210
+#: src/data/sys-file-reader.c:1295
 #, c-format
 msgid ""
 "Variables associated with value label are not all of identical type.  "
 "Variable %s is %s, but variable %s is %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1243
+#: src/data/sys-file-reader.c:1329
 #, c-format
 msgid "Duplicate value label for %g on %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1246
+#: src/data/sys-file-reader.c:1332 src/data/sys-file-reader.c:1513
 #, c-format
 msgid "Duplicate value label for \"%.*s\" on %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1284
+#: src/data/sys-file-reader.c:1370
 #, c-format
 msgid "Error parsing attribute value %s[%d]"
 msgstr ""
 
-#: src/data/sys-file-reader.c:1298
+#: src/data/sys-file-reader.c:1384
 #, c-format
 msgid "Attribute value %s[%d] is not quoted: %s"
 msgstr ""
 
-#: src/data/sys-file-reader.c:1414
+#: src/data/sys-file-reader.c:1447
+#, c-format
+msgid ""
+"Variable name length in long string value label record (%d) exceeds %d-byte "
+"limit."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1457
+#, c-format
+msgid "Ignoring long string value record for unknown variable %s."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1464
+#, c-format
+msgid "Ignoring long string value record for numeric variable %s."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1471
+#, c-format
+msgid ""
+"Ignoring long string value record for variable %s because the record's width "
+"(%d) does not match the variable's width (%d)"
+msgstr ""
+
+#: src/data/sys-file-reader.c:1493
+#, c-format
+msgid ""
+"Ignoring long string value %zu for variable %s, with width %d, that has bad "
+"value width %zu."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1608
 msgid "File ends in partial case."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1422
+#: src/data/sys-file-reader.c:1616
 #, c-format
 msgid "Error reading case from file %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1519 src/data/sys-file-reader.c:1555
+#: src/data/sys-file-reader.c:1713 src/data/sys-file-reader.c:1749
 msgid "Compressed data is corrupt."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1642
+#: src/data/sys-file-reader.c:1836
 #, c-format
 msgid "Variable index %d not in valid range 1...%d."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1647
+#: src/data/sys-file-reader.c:1841
 #, c-format
 msgid "Variable index %d refers to long string continuation."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1715
+#: src/data/sys-file-reader.c:1909
 #, c-format
 msgid "Suppressed %d additional related warnings."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1756
+#: src/data/sys-file-reader.c:1950
 #, c-format
 msgid "Variable map refers to unknown variable %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1864
+#: src/data/sys-file-reader.c:2058
 #, c-format
 msgid "System error: %s."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1866
+#: src/data/sys-file-reader.c:2060
 msgid "Unexpected end of file."
 msgstr ""
 
-#: src/data/sys-file-writer.c:173
+#: src/data/sys-file-writer.c:176
 #, c-format
 msgid "Unknown system file version %d. Treating as version %d."
 msgstr ""
 
-#: src/data/sys-file-writer.c:212
+#: src/data/sys-file-writer.c:215
 #, c-format
 msgid "Error opening \"%s\" for writing as a system file: %s."
 msgstr ""
 
-#: src/data/sys-file-writer.c:837
+#: src/data/sys-file-writer.c:923
 #, c-format
 msgid "An I/O error occurred writing system file \"%s\"."
 msgstr ""
 
-#: src/data/variable.c:240
+#: src/data/variable.c:242
 #, c-format
 msgid ""
 "Character `%c' (in %s) may not appear as the first character in a variable "
 "name."
 msgstr ""
 
-#: src/data/variable.c:252
+#: src/data/variable.c:254
 #, c-format
 msgid "Character `%c' (in %s) may not appear in a variable name."
 msgstr ""
 
-#: src/data/variable.c:280
+#: src/data/variable.c:282
 msgid "Variable name cannot be empty string."
 msgstr ""
 
-#: src/data/variable.c:286
+#: src/data/variable.c:288
 #, c-format
 msgid "Variable name %s exceeds %d-character limit."
 msgstr ""
 
-#: src/data/variable.c:294
+#: src/data/variable.c:296
 #, c-format
 msgid "`%s' may not be used as a variable name because it is a reserved word."
 msgstr ""
 
-#: src/language/command.c:208
+#: src/language/command.c:208 src/language/expressions/parse.c:1267
 #, c-format
-msgid "%s is unimplemented."
+msgid "%s is not yet implemented."
 msgstr ""
 
 #: src/language/command.c:214
@@ -1295,7 +1281,7 @@ msgid ""
 "name."
 msgstr ""
 
-#: src/language/data-io/combine-files.c:757
+#: src/language/data-io/combine-files.c:762
 #, c-format
 msgid "Encountered %zu sets of duplicate cases in the master file."
 msgstr ""
@@ -1345,65 +1331,65 @@ msgstr ""
 msgid "Cannot place variable %s on record %d when RECORDS=%d is specified."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:458
-#: src/language/data-io/data-parser.c:467
+#: src/language/data-io/data-parser.c:460
+#: src/language/data-io/data-parser.c:469
 msgid "Quoted string extends beyond end of line."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:522
+#: src/language/data-io/data-parser.c:525
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:568
+#: src/language/data-io/data-parser.c:572
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:605
+#: src/language/data-io/data-parser.c:610
 #, c-format
 msgid ""
 "Missing value(s) for all variables from %s onward.  These will be filled "
 "with the system-missing value or blanks, as appropriate."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:624
+#: src/language/data-io/data-parser.c:630
 msgid "Record ends in data not part of any field."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:644
-#: src/language/data-io/data-parser.c:685 src/language/data-io/print.c:403
+#: src/language/data-io/data-parser.c:650
+#: src/language/data-io/data-parser.c:691 src/language/data-io/print.c:404
 #: src/language/dictionary/split-file.c:84
 #: src/language/dictionary/sys-file-info.c:169
 #: src/language/dictionary/sys-file-info.c:393
-#: src/language/dictionary/sys-file-info.c:716
-#: src/language/stats/descriptives.c:885 src/ui/gui/psppire-dictview.c:502
+#: src/language/dictionary/sys-file-info.c:725
+#: src/language/stats/descriptives.c:885 src/ui/gui/psppire-dictview.c:491
 msgid "Variable"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:645 src/language/data-io/print.c:404
+#: src/language/data-io/data-parser.c:651 src/language/data-io/print.c:405
 msgid "Record"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:646 src/language/data-io/print.c:405
-#: src/ui/gui/crosstabs.glade:92 src/ui/gui/psppire-var-sheet.c:545
-#: src/ui/gui/psppire-var-store.c:791
+#: src/language/data-io/data-parser.c:652 src/language/data-io/print.c:406
+#: src/ui/gui/crosstabs.glade:92 src/ui/gui/psppire-var-sheet.c:537
+#: src/ui/gui/psppire-var-store.c:839
 msgid "Columns"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:647
-#: src/language/data-io/data-parser.c:686 src/language/data-io/print.c:406
+#: src/language/data-io/data-parser.c:653
+#: src/language/data-io/data-parser.c:692 src/language/data-io/print.c:407
 msgid "Format"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:666
+#: src/language/data-io/data-parser.c:672
 #, c-format
 msgid "Reading %d record from %s."
 msgid_plural "Reading %d records from %s."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/data-parser.c:702
+#: src/language/data-io/data-parser.c:708
 #, c-format
 msgid "Reading free-form data from %s."
 msgstr ""
@@ -1591,19 +1577,19 @@ msgid ""
 "specified on FIXCASE, %d."
 msgstr ""
 
-#: src/language/data-io/inpt-pgm.c:129
+#: src/language/data-io/inpt-pgm.c:130
 msgid "Unexpected end-of-file within INPUT PROGRAM."
 msgstr ""
 
-#: src/language/data-io/inpt-pgm.c:142
+#: src/language/data-io/inpt-pgm.c:143
 msgid "Input program did not create any variables."
 msgstr ""
 
-#: src/language/data-io/inpt-pgm.c:286
+#: src/language/data-io/inpt-pgm.c:288
 msgid "COLUMN subcommand multiply specified."
 msgstr ""
 
-#: src/language/data-io/inpt-pgm.c:336
+#: src/language/data-io/inpt-pgm.c:338
 msgid ""
 "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr ""
@@ -1680,30 +1666,30 @@ msgstr ""
 msgid "The ending column for a field must be greater than the starting column."
 msgstr ""
 
-#: src/language/data-io/print.c:178 src/language/data-io/trim.c:54
+#: src/language/data-io/print.c:179 src/language/data-io/trim.c:54
 msgid "expecting a valid subcommand"
 msgstr ""
 
-#: src/language/data-io/print.c:266
+#: src/language/data-io/print.c:267
 #, c-format
 msgid "Output calls for %d records but %zu specified on RECORDS subcommand."
 msgstr ""
 
-#: src/language/data-io/print.c:436
+#: src/language/data-io/print.c:438
 #, c-format
 msgid "Writing %d record to %s."
 msgid_plural "Writing %d records to %s."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print.c:440
+#: src/language/data-io/print.c:442
 #, c-format
 msgid "Writing %d record."
 msgid_plural "Writing %d records."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:479
+#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:478
 #: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:60
 msgid "expecting end of command"
 msgstr ""
@@ -1760,18 +1746,7 @@ msgstr ""
 msgid "Variable %s is %s in target file, but %s in source file."
 msgstr ""
 
-#: src/language/dictionary/apply-dictionary.c:99
-#, c-format
-msgid "Cannot add value labels from source file to long string variable %s."
-msgstr ""
-
-#: src/language/dictionary/apply-dictionary.c:113
-#, c-format
-msgid ""
-"Cannot apply missing values from source file to long string variable %s."
-msgstr ""
-
-#: src/language/dictionary/apply-dictionary.c:129
+#: src/language/dictionary/apply-dictionary.c:115
 msgid "No matching variables found between the source and target files."
 msgstr ""
 
@@ -1815,12 +1790,12 @@ msgid ""
 "a single list."
 msgstr ""
 
-#: src/language/dictionary/missing-values.c:117
+#: src/language/dictionary/missing-values.c:116
 #, c-format
-msgid "Truncating missing value to short string length (%d characters)."
+msgid "Truncating missing value to maximum acceptable length (%d bytes)."
 msgstr ""
 
-#: src/language/dictionary/missing-values.c:139
+#: src/language/dictionary/missing-values.c:138
 #, c-format
 msgid "Missing values provided are too long to assign to variable of width %d."
 msgstr ""
@@ -1937,21 +1912,21 @@ msgid "Renaming would duplicate variable name %s."
 msgstr ""
 
 #: src/language/dictionary/split-file.c:85
-#: src/language/dictionary/sys-file-info.c:487
-#: src/language/dictionary/sys-file-info.c:636
-#: src/language/stats/crosstabs.q:1167 src/language/stats/crosstabs.q:1194
-#: src/language/stats/crosstabs.q:1214 src/language/stats/crosstabs.q:1236
-#: src/language/stats/examine.q:1958 src/language/stats/frequencies.q:1059
-#: src/language/stats/frequencies.q:1184 src/language/stats/reliability.q:581
-#: src/language/stats/reliability.q:592
+#: src/language/dictionary/sys-file-info.c:486
+#: src/language/dictionary/sys-file-info.c:641
+#: src/language/stats/crosstabs.q:1235 src/language/stats/crosstabs.q:1262
+#: src/language/stats/crosstabs.q:1286 src/language/stats/crosstabs.q:1311
+#: src/language/stats/examine.q:1959 src/language/stats/frequencies.q:1051
+#: src/language/stats/frequencies.q:1176 src/language/stats/reliability.q:582
+#: src/language/stats/reliability.q:593
 msgid "Value"
 msgstr ""
 
 #: src/language/dictionary/split-file.c:86
 #: src/language/dictionary/sys-file-info.c:397
-#: src/language/dictionary/sys-file-info.c:637 src/ui/gui/crosstabs.glade:275
-#: src/ui/gui/psppire.glade:1999 src/ui/gui/psppire-var-sheet.c:542
-#: src/ui/gui/psppire-var-store.c:788
+#: src/language/dictionary/sys-file-info.c:642 src/ui/gui/crosstabs.glade:275
+#: src/ui/gui/psppire.glade:1974 src/ui/gui/psppire-var-sheet.c:534
+#: src/ui/gui/psppire-var-store.c:836
 msgid "Label"
 msgstr ""
 
@@ -1959,7 +1934,7 @@ msgstr ""
 msgid "File:"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:115 src/ui/gui/psppire.glade:1938
+#: src/language/dictionary/sys-file-info.c:115 src/ui/gui/psppire.glade:1913
 #: src/ui/gui/recode.glade:841
 msgid "Label:"
 msgstr ""
@@ -2071,7 +2046,7 @@ msgstr ""
 
 #: src/language/dictionary/sys-file-info.c:171
 #: src/language/dictionary/sys-file-info.c:399
-#: src/language/dictionary/sys-file-info.c:715
+#: src/language/dictionary/sys-file-info.c:724
 msgid "Position"
 msgstr ""
 
@@ -2099,16 +2074,16 @@ msgstr ""
 msgid "Documents in the active file:"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:486
+#: src/language/dictionary/sys-file-info.c:485
 msgid "Attribute"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:544
+#: src/language/dictionary/sys-file-info.c:543
 #, c-format
 msgid "Format: %s"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:551
+#: src/language/dictionary/sys-file-info.c:550
 #, c-format
 msgid "Print Format: %s"
 msgstr ""
@@ -2118,87 +2093,72 @@ msgstr ""
 msgid "Write Format: %s"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:566
+#: src/language/dictionary/sys-file-info.c:567
 #, c-format
 msgid "Measure: %s"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:567
+#: src/language/dictionary/sys-file-info.c:568
 #: src/ui/gui/psppire-var-sheet.c:111
 msgid "Nominal"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:568
+#: src/language/dictionary/sys-file-info.c:569
 #: src/ui/gui/psppire-var-sheet.c:112
 msgid "Ordinal"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:569
+#: src/language/dictionary/sys-file-info.c:570
 #: src/ui/gui/psppire-var-sheet.c:113
 msgid "Scale"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:572
+#: src/language/dictionary/sys-file-info.c:573
 #, c-format
 msgid "Display Alignment: %s"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:573
+#: src/language/dictionary/sys-file-info.c:574
 #: src/ui/gui/psppire-var-sheet.c:104
 msgid "Left"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:574
+#: src/language/dictionary/sys-file-info.c:575
 #: src/ui/gui/psppire-var-sheet.c:106
 msgid "Center"
 msgstr "Centre"
 
-#: src/language/dictionary/sys-file-info.c:575
+#: src/language/dictionary/sys-file-info.c:576
 #: src/ui/gui/psppire-var-sheet.c:105
 msgid "Right"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:578
+#: src/language/dictionary/sys-file-info.c:579
 #, c-format
 msgid "Display Width: %d"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:590
+#: src/language/dictionary/sys-file-info.c:593
 msgid "Missing Values: "
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:693
+#: src/language/dictionary/sys-file-info.c:702
 msgid "No vectors defined."
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:714
+#: src/language/dictionary/sys-file-info.c:723
 msgid "Vector"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:717
+#: src/language/dictionary/sys-file-info.c:726
 msgid "Print Format"
 msgstr ""
 
-#: src/language/dictionary/value-labels.c:121
-#, c-format
-msgid ""
-"It is not possible to assign value labels to long string variables such as %"
-"s."
-msgstr ""
-
-#: src/language/dictionary/value-labels.c:157 src/language/lexer/lexer.c:632
-msgid "expecting string"
-msgstr ""
-
-#: src/language/dictionary/value-labels.c:166 src/language/lexer/lexer.c:659
-msgid "expecting number"
-msgstr ""
-
-#: src/language/dictionary/value-labels.c:182
+#: src/language/dictionary/value-labels.c:150
 msgid "Truncating value label to 60 characters."
 msgstr ""
 
-#: src/language/dictionary/variable-display.c:119
+#: src/language/dictionary/variable-display.c:120
 msgid "Variable display width must be a positive integer."
 msgstr ""
 
@@ -2250,11 +2210,11 @@ msgstr ""
 msgid "The weighting variable may not be scratch."
 msgstr ""
 
-#: src/language/expressions/evaluate.c:154
+#: src/language/expressions/evaluate.c:155
 msgid "expecting number or string"
 msgstr ""
 
-#: src/language/expressions/evaluate.c:168
+#: src/language/expressions/evaluate.c:169
 #, c-format
 msgid "Duplicate variable name %s."
 msgstr ""
@@ -2421,11 +2381,6 @@ msgstr ""
 msgid "%s is a PSPP extension."
 msgstr ""
 
-#: src/language/expressions/parse.c:1267
-#, c-format
-msgid "%s is not yet implemented."
-msgstr ""
-
 #: src/language/expressions/parse.c:1273
 #, c-format
 msgid "%s may not appear after TEMPORARY."
@@ -2446,107 +2401,110 @@ msgstr ""
 
 #: src/language/lexer/lexer.c:389
 #, c-format
-msgid "Bad character in input: `%c'."
+msgid "Bad character in input: `%s'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:391
-#, c-format
-msgid "Bad character in input: `\\%o'."
-msgstr ""
-
-#: src/language/lexer/lexer.c:427
+#: src/language/lexer/lexer.c:426
 #, c-format
 msgid "Subcommand %s may only be specified once."
 msgstr ""
 
-#: src/language/lexer/lexer.c:435
+#: src/language/lexer/lexer.c:434
 #, c-format
 msgid "missing required subcommand %s"
 msgstr ""
 
-#: src/language/lexer/lexer.c:464
+#: src/language/lexer/lexer.c:463
 #, c-format
 msgid "Syntax error %s at %s."
 msgstr ""
 
-#: src/language/lexer/lexer.c:467
+#: src/language/lexer/lexer.c:466
 #, c-format
 msgid "Syntax error at %s."
 msgstr ""
 
-#: src/language/lexer/lexer.c:601 src/language/lexer/lexer.c:618
+#: src/language/lexer/lexer.c:600 src/language/lexer/lexer.c:617
 #, c-format
 msgid "expecting `%s'"
 msgstr ""
 
-#: src/language/lexer/lexer.c:646
+#: src/language/lexer/lexer.c:631
+msgid "expecting string"
+msgstr ""
+
+#: src/language/lexer/lexer.c:645
 msgid "expecting integer"
 msgstr ""
 
-#: src/language/lexer/lexer.c:671
+#: src/language/lexer/lexer.c:658
+msgid "expecting number"
+msgstr ""
+
+#: src/language/lexer/lexer.c:670
 msgid "expecting identifier"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1065
+#: src/language/lexer/lexer.c:1064
 msgid "binary"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1070
+#: src/language/lexer/lexer.c:1069
 msgid "octal"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1075
+#: src/language/lexer/lexer.c:1074
 msgid "hex"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1085
+#: src/language/lexer/lexer.c:1084
 #, c-format
 msgid "String of %s digits has %zu characters, which is not a multiple of %d."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1114
+#: src/language/lexer/lexer.c:1113
 #, c-format
 msgid "`%c' is not a valid %s digit."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1148
+#: src/language/lexer/lexer.c:1147
 msgid "Unterminated string constant."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1202
+#: src/language/lexer/lexer.c:1201
 msgid "Unexpected end of file in string concatenation."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1210
+#: src/language/lexer/lexer.c:1209
 msgid "String expected following `+'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1223
+#: src/language/lexer/lexer.c:1222
 #, c-format
 msgid "String exceeds 255 characters in length (%zu characters)."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:60
+#: src/language/lexer/value-parser.c:60
 #, c-format
 msgid ""
 "Low end of range (%g) is below high end (%g).  The range will be treated as "
 "reversed."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:68
+#: src/language/lexer/value-parser.c:68
 #, c-format
 msgid "Ends of range are equal (%g)."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:76
+#: src/language/lexer/value-parser.c:76
 msgid "LO or LOWEST must be part of a range."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:108
+#: src/language/lexer/value-parser.c:109
 msgid "System-missing value is not valid here."
 msgstr ""
 
-#: src/language/lexer/range-parser.c:116
+#: src/language/lexer/value-parser.c:117
 msgid "expecting number or data string"
 msgstr ""
 
@@ -2693,392 +2651,388 @@ msgstr ""
 msgid "Duplicate variable name %s among target variables."
 msgstr ""
 
-#: src/language/stats/binomial.c:142
+#: src/language/stats/binomial.c:141
 #, c-format
 msgid "Variable %s is not dichotomous"
 msgstr ""
 
-#: src/language/stats/binomial.c:207
+#: src/language/stats/binomial.c:194
 msgid "Binomial Test"
 msgstr ""
 
-#: src/language/stats/binomial.c:238
+#: src/language/stats/binomial.c:224
 msgid "Group1"
 msgstr ""
 
-#: src/language/stats/binomial.c:239
+#: src/language/stats/binomial.c:225
 msgid "Group2"
 msgstr ""
 
-#: src/language/stats/binomial.c:240 src/language/stats/chisquare.c:224
-#: src/language/stats/chisquare.c:284 src/language/stats/crosstabs.q:868
-#: src/language/stats/crosstabs.q:1074 src/language/stats/crosstabs.q:1797
-#: src/language/stats/examine.q:1214 src/language/stats/frequencies.q:1136
-#: src/language/stats/oneway.q:305 src/language/stats/oneway.q:475
-#: src/language/stats/regression.q:309 src/language/stats/reliability.q:717
-#: src/language/stats/sign.c:93 src/language/stats/wilcoxon.c:246
+#: src/language/stats/binomial.c:226 src/language/stats/chisquare.c:202
+#: src/language/stats/chisquare.c:262 src/language/stats/crosstabs.q:845
+#: src/language/stats/crosstabs.q:1172 src/language/stats/crosstabs.q:1596
+#: src/language/stats/examine.q:1216 src/language/stats/frequencies.q:1128
+#: src/language/stats/oneway.q:305 src/language/stats/oneway.q:476
+#: src/language/stats/regression.q:309 src/language/stats/reliability.q:718
+#: src/language/stats/sign.c:94 src/language/stats/wilcoxon.c:262
 #: src/ui/gui/crosstabs-dialog.c:59
 msgid "Total"
 msgstr ""
 
-#: src/language/stats/binomial.c:273 src/language/stats/chisquare.c:247
-#: src/language/stats/crosstabs.q:1192 src/language/stats/crosstabs.q:1233
+#: src/language/stats/binomial.c:259 src/language/stats/chisquare.c:225
+#: src/language/stats/crosstabs.q:1260 src/language/stats/crosstabs.q:1308
 msgid "Category"
 msgstr ""
 
-#: src/language/stats/binomial.c:274 src/language/stats/crosstabs.q:878
-#: src/language/stats/examine.q:1287 src/language/stats/frequencies.q:1407
+#: src/language/stats/binomial.c:260 src/language/stats/crosstabs.q:852
+#: src/language/stats/examine.q:1289 src/language/stats/frequencies.q:1399
 #: src/language/stats/npar-summary.c:123 src/language/stats/oneway.q:389
-#: src/language/stats/reliability.q:720 src/language/stats/sign.c:73
-#: src/language/stats/t-test.q:700 src/language/stats/t-test.q:724
-#: src/language/stats/t-test.q:863 src/language/stats/t-test.q:1425
-#: src/language/stats/wilcoxon.c:229
+#: src/language/stats/reliability.q:721 src/language/stats/sign.c:74
+#: src/language/stats/t-test.q:506 src/language/stats/t-test.q:526
+#: src/language/stats/t-test.q:626 src/language/stats/t-test.q:1105
+#: src/language/stats/wilcoxon.c:245
 msgid "N"
 msgstr ""
 
-#: src/language/stats/binomial.c:275
+#: src/language/stats/binomial.c:261
 msgid "Observed Prop."
 msgstr ""
 
-#: src/language/stats/binomial.c:276
+#: src/language/stats/binomial.c:262
 msgid "Test Prop."
 msgstr ""
 
-#: src/language/stats/binomial.c:279
+#: src/language/stats/binomial.c:265
 #, c-format
 msgid "Exact Sig. (%d-tailed)"
 msgstr ""
 
-#: src/language/stats/chisquare.c:194
+#: src/language/stats/chisquare.c:172
 #, c-format
 msgid ""
 "CHISQUARE test specified %d expected values, but %d distinct values were "
 "encountered in variable %s."
 msgstr ""
 
-#: src/language/stats/chisquare.c:208 src/language/stats/chisquare.c:248
+#: src/language/stats/chisquare.c:186 src/language/stats/chisquare.c:226
 msgid "Observed N"
 msgstr ""
 
-#: src/language/stats/chisquare.c:209 src/language/stats/chisquare.c:249
+#: src/language/stats/chisquare.c:187 src/language/stats/chisquare.c:227
 msgid "Expected N"
 msgstr ""
 
-#: src/language/stats/chisquare.c:210 src/language/stats/chisquare.c:250
+#: src/language/stats/chisquare.c:188 src/language/stats/chisquare.c:228
 #: src/language/stats/regression.q:308 src/ui/gui/crosstabs-dialog.c:61
 msgid "Residual"
 msgstr ""
 
-#: src/language/stats/chisquare.c:243 src/language/stats/sign.c:61
+#: src/language/stats/chisquare.c:221 src/language/stats/sign.c:62
 msgid "Frequencies"
 msgstr ""
 
-#: src/language/stats/chisquare.c:298 src/language/stats/sign.c:114
-#: src/language/stats/wilcoxon.c:297
+#: src/language/stats/chisquare.c:276 src/language/stats/sign.c:115
+#: src/language/stats/wilcoxon.c:313
 msgid "Test Statistics"
 msgstr ""
 
-#: src/language/stats/chisquare.c:312
+#: src/language/stats/chisquare.c:290
 msgid "Chi-Square"
 msgstr ""
 
-#: src/language/stats/chisquare.c:313 src/language/stats/crosstabs.q:1168
-#: src/language/stats/oneway.q:278 src/language/stats/oneway.q:689
-#: src/language/stats/regression.q:302 src/language/stats/t-test.q:1026
-#: src/language/stats/t-test.q:1219 src/language/stats/t-test.q:1316
+#: src/language/stats/chisquare.c:291 src/language/stats/crosstabs.q:1236
+#: src/language/stats/oneway.q:278 src/language/stats/oneway.q:691
+#: src/language/stats/regression.q:302 src/language/stats/t-test.q:753
+#: src/language/stats/t-test.q:924 src/language/stats/t-test.q:1011
 msgid "df"
 msgstr ""
 
-#: src/language/stats/chisquare.c:314
+#: src/language/stats/chisquare.c:292
 msgid "Asymp. Sig."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:278
+#: src/language/stats/crosstabs.q:327
 msgid ""
 "Missing mode REPORT not allowed in general mode.  Assuming MISSING=TABLE."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:288
-msgid "Write mode ALL not allowed in general mode.  Assuming WRITE=CELLS."
-msgstr ""
-
-#: src/language/stats/crosstabs.q:364
+#: src/language/stats/crosstabs.q:416
 msgid "Too many cross-tabulation variables or dimensions."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:374
+#: src/language/stats/crosstabs.q:426
 msgid "expecting BY"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:441
+#: src/language/stats/crosstabs.q:486
 msgid "VARIABLES must be specified before TABLES."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:479
+#: src/language/stats/crosstabs.q:524
 #, c-format
 msgid "Maximum value (%ld) less than minimum value (%ld)."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:863
+#: src/language/stats/crosstabs.q:840
 msgid "Summary."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:865 src/language/stats/examine.q:1275
-#: src/language/stats/reliability.q:708
+#: src/language/stats/crosstabs.q:842 src/language/stats/examine.q:1277
+#: src/language/stats/reliability.q:709
 msgid "Cases"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:866 src/language/stats/examine.q:1212
-#: src/language/stats/frequencies.q:1057 src/language/stats/frequencies.q:1408
-#: src/language/stats/reliability.q:711
+#: src/language/stats/crosstabs.q:843 src/language/stats/examine.q:1214
+#: src/language/stats/frequencies.q:1049 src/language/stats/frequencies.q:1400
+#: src/language/stats/reliability.q:712
 msgid "Valid"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:867 src/language/stats/examine.q:1213
-#: src/language/stats/frequencies.q:1127 src/language/stats/frequencies.q:1409
-#: src/ui/gui/psppire-var-sheet.c:544 src/ui/gui/psppire-var-store.c:790
+#: src/language/stats/crosstabs.q:844 src/language/stats/examine.q:1215
+#: src/language/stats/frequencies.q:1119 src/language/stats/frequencies.q:1401
+#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:838
 msgid "Missing"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:879 src/language/stats/examine.q:1290
-#: src/language/stats/frequencies.q:1061 src/language/stats/frequencies.q:1062
-#: src/language/stats/frequencies.q:1063
+#: src/language/stats/crosstabs.q:853 src/language/stats/examine.q:1292
+#: src/language/stats/frequencies.q:1053 src/language/stats/frequencies.q:1054
+#: src/language/stats/frequencies.q:1055
 msgid "Percent"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1126
+#: src/language/stats/crosstabs.q:1133
 msgid "count"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1127
+#: src/language/stats/crosstabs.q:1134
 msgid "row %"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1128
+#: src/language/stats/crosstabs.q:1135
 msgid "column %"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1129
+#: src/language/stats/crosstabs.q:1136
 msgid "total %"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1130
+#: src/language/stats/crosstabs.q:1137
 msgid "expected"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1131
+#: src/language/stats/crosstabs.q:1138
 msgid "residual"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1132
+#: src/language/stats/crosstabs.q:1139
 msgid "std. resid."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1133
+#: src/language/stats/crosstabs.q:1140
 msgid "adj. resid."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1163
+#: src/language/stats/crosstabs.q:1231
 msgid "Chi-square tests."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1166 src/language/stats/crosstabs.q:1193
-#: src/language/stats/crosstabs.q:1213 src/language/stats/crosstabs.q:1234
-#: src/language/stats/examine.q:1752 src/ui/gui/checkbox-treeview.c:92
+#: src/language/stats/crosstabs.q:1234 src/language/stats/crosstabs.q:1261
+#: src/language/stats/crosstabs.q:1285 src/language/stats/crosstabs.q:1309
+#: src/language/stats/examine.q:1753 src/ui/gui/checkbox-treeview.c:92
 msgid "Statistic"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1170
+#: src/language/stats/crosstabs.q:1238
 msgid "Asymp. Sig. (2-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1172
-msgid "Exact. Sig. (2-sided)"
+#: src/language/stats/crosstabs.q:1240
+msgid "Exact Sig. (2-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1174
-msgid "Exact. Sig. (1-sided)"
+#: src/language/stats/crosstabs.q:1242
+msgid "Exact Sig. (1-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1189
+#: src/language/stats/crosstabs.q:1257
 msgid "Symmetric measures."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1195 src/language/stats/crosstabs.q:1237
+#: src/language/stats/crosstabs.q:1263 src/language/stats/crosstabs.q:1312
 msgid "Asymp. Std. Error"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1196 src/language/stats/crosstabs.q:1238
+#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1313
 msgid "Approx. T"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1197 src/language/stats/crosstabs.q:1239
+#: src/language/stats/crosstabs.q:1265 src/language/stats/crosstabs.q:1314
 msgid "Approx. Sig."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1208
+#: src/language/stats/crosstabs.q:1280
 msgid "Risk estimate."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1212
+#: src/language/stats/crosstabs.q:1284
 #, c-format
 msgid "95%% Confidence Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1215 src/language/stats/t-test.q:1030
-#: src/language/stats/t-test.q:1216 src/language/stats/t-test.q:1319
+#: src/language/stats/crosstabs.q:1287 src/language/stats/t-test.q:757
+#: src/language/stats/t-test.q:921 src/language/stats/t-test.q:1014
 msgid "Lower"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1216 src/language/stats/t-test.q:1031
-#: src/language/stats/t-test.q:1217 src/language/stats/t-test.q:1320
+#: src/language/stats/crosstabs.q:1288 src/language/stats/t-test.q:758
+#: src/language/stats/t-test.q:922 src/language/stats/t-test.q:1015
 msgid "Upper"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1230
+#: src/language/stats/crosstabs.q:1305
 msgid "Directional measures."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1235 src/ui/gui/psppire.glade:2124
-#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:785
+#: src/language/stats/crosstabs.q:1310 src/ui/gui/psppire.glade:2099
+#: src/ui/gui/psppire-var-sheet.c:531 src/ui/gui/psppire-var-store.c:833
 msgid "Type"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1991
+#: src/language/stats/crosstabs.q:1776
 msgid "Pearson Chi-Square"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1992
+#: src/language/stats/crosstabs.q:1777
 msgid "Likelihood Ratio"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1993
+#: src/language/stats/crosstabs.q:1778
 msgid "Fisher's Exact Test"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1994
+#: src/language/stats/crosstabs.q:1779
 msgid "Continuity Correction"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1995
+#: src/language/stats/crosstabs.q:1780
 msgid "Linear-by-Linear Association"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2032 src/language/stats/crosstabs.q:2105
-#: src/language/stats/crosstabs.q:2167
+#: src/language/stats/crosstabs.q:1815 src/language/stats/crosstabs.q:1890
+#: src/language/stats/crosstabs.q:1955
 msgid "N of Valid Cases"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2051 src/language/stats/crosstabs.q:2183
+#: src/language/stats/crosstabs.q:1834 src/language/stats/crosstabs.q:1973
 msgid "Nominal by Nominal"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2052 src/language/stats/crosstabs.q:2184
+#: src/language/stats/crosstabs.q:1835 src/language/stats/crosstabs.q:1974
 msgid "Ordinal by Ordinal"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2053
+#: src/language/stats/crosstabs.q:1836
 msgid "Interval by Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2054
+#: src/language/stats/crosstabs.q:1837
 msgid "Measure of Agreement"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2059 src/ui/gui/crosstabs-dialog.c:41
+#: src/language/stats/crosstabs.q:1842 src/ui/gui/crosstabs-dialog.c:41
 msgid "Phi"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2060
+#: src/language/stats/crosstabs.q:1843
 msgid "Cramer's V"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2061
+#: src/language/stats/crosstabs.q:1844
 msgid "Contingency Coefficient"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2062
+#: src/language/stats/crosstabs.q:1845
 msgid "Kendall's tau-b"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2063
+#: src/language/stats/crosstabs.q:1846
 msgid "Kendall's tau-c"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2064 src/ui/gui/crosstabs-dialog.c:48
+#: src/language/stats/crosstabs.q:1847 src/ui/gui/crosstabs-dialog.c:48
 msgid "Gamma"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2065
+#: src/language/stats/crosstabs.q:1848
 msgid "Spearman Correlation"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2066
+#: src/language/stats/crosstabs.q:1849
 msgid "Pearson's R"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2067 src/ui/gui/crosstabs-dialog.c:50
+#: src/language/stats/crosstabs.q:1850 src/ui/gui/crosstabs-dialog.c:50
 msgid "Kappa"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2140
+#: src/language/stats/crosstabs.q:1928
 #, c-format
 msgid "Odds Ratio for %s (%g / %g)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2143
+#: src/language/stats/crosstabs.q:1931
 #, c-format
 msgid "Odds Ratio for %s (%.*s / %.*s)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2151
+#: src/language/stats/crosstabs.q:1939
 #, c-format
 msgid "For cohort %s = %g"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2154
+#: src/language/stats/crosstabs.q:1942
 #, c-format
 msgid "For cohort %s = %.*s"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2185
+#: src/language/stats/crosstabs.q:1975
 msgid "Nominal by Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2190 src/ui/gui/crosstabs-dialog.c:43
+#: src/language/stats/crosstabs.q:1980 src/ui/gui/crosstabs-dialog.c:43
 msgid "Lambda"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2191
+#: src/language/stats/crosstabs.q:1981
 msgid "Goodman and Kruskal tau"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2192
+#: src/language/stats/crosstabs.q:1982
 msgid "Uncertainty Coefficient"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2193
+#: src/language/stats/crosstabs.q:1983
 msgid "Somers' d"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2194 src/ui/gui/crosstabs-dialog.c:51
+#: src/language/stats/crosstabs.q:1984 src/ui/gui/crosstabs-dialog.c:51
 msgid "Eta"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2199
+#: src/language/stats/crosstabs.q:1989
 msgid "Symmetric"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2200 src/language/stats/crosstabs.q:2201
+#: src/language/stats/crosstabs.q:1990 src/language/stats/crosstabs.q:1991
 #, c-format
 msgid "%s Dependent"
 msgstr ""
 
-#: src/language/stats/descriptives.c:102 src/language/stats/examine.q:1557
+#: src/language/stats/descriptives.c:102 src/language/stats/examine.q:1559
 #: src/language/stats/frequencies.q:123 src/language/stats/npar-summary.c:126
-#: src/language/stats/oneway.q:390 src/language/stats/t-test.q:701
-#: src/language/stats/t-test.q:725 src/language/stats/t-test.q:862
-#: src/language/stats/t-test.q:1213 src/ui/gui/descriptives-dialog.c:39
+#: src/language/stats/oneway.q:390 src/language/stats/t-test.q:507
+#: src/language/stats/t-test.q:527 src/language/stats/t-test.q:625
+#: src/language/stats/t-test.q:918 src/ui/gui/descriptives-dialog.c:39
 #: src/ui/gui/frequencies-dialog.c:40
 msgid "Mean"
 msgstr ""
@@ -3091,13 +3045,13 @@ msgstr ""
 msgid "Std Dev"
 msgstr ""
 
-#: src/language/stats/descriptives.c:105 src/language/stats/examine.q:1588
+#: src/language/stats/descriptives.c:105 src/language/stats/examine.q:1589
 #: src/language/stats/frequencies.q:128 src/ui/gui/descriptives-dialog.c:46
 #: src/ui/gui/frequencies-dialog.c:45
 msgid "Variance"
 msgstr ""
 
-#: src/language/stats/descriptives.c:106 src/language/stats/examine.q:1624
+#: src/language/stats/descriptives.c:106 src/language/stats/examine.q:1625
 #: src/language/stats/frequencies.q:129 src/ui/gui/descriptives-dialog.c:47
 #: src/ui/gui/frequencies-dialog.c:50
 msgid "Kurtosis"
@@ -3107,7 +3061,7 @@ msgstr ""
 msgid "S E Kurt"
 msgstr ""
 
-#: src/language/stats/descriptives.c:108 src/language/stats/examine.q:1619
+#: src/language/stats/descriptives.c:108 src/language/stats/examine.q:1620
 #: src/language/stats/frequencies.q:131 src/ui/gui/descriptives-dialog.c:48
 #: src/ui/gui/frequencies-dialog.c:46
 msgid "Skewness"
@@ -3117,22 +3071,22 @@ msgstr ""
 msgid "S E Skew"
 msgstr ""
 
-#: src/language/stats/descriptives.c:110 src/language/stats/examine.q:1608
+#: src/language/stats/descriptives.c:110 src/language/stats/examine.q:1609
 #: src/language/stats/frequencies.q:133 src/ui/gui/descriptives-dialog.c:43
 #: src/ui/gui/frequencies-dialog.c:48
 msgid "Range"
 msgstr ""
 
-#: src/language/stats/descriptives.c:111 src/language/stats/examine.q:1598
+#: src/language/stats/descriptives.c:111 src/language/stats/examine.q:1599
 #: src/language/stats/frequencies.q:134 src/language/stats/npar-summary.c:132
-#: src/language/stats/oneway.q:403 src/ui/gui/descriptives-dialog.c:41
+#: src/language/stats/oneway.q:404 src/ui/gui/descriptives-dialog.c:41
 #: src/ui/gui/frequencies-dialog.c:42
 msgid "Minimum"
 msgstr ""
 
-#: src/language/stats/descriptives.c:112 src/language/stats/examine.q:1603
+#: src/language/stats/descriptives.c:112 src/language/stats/examine.q:1604
 #: src/language/stats/frequencies.q:135 src/language/stats/npar-summary.c:135
-#: src/language/stats/oneway.q:404 src/ui/gui/descriptives-dialog.c:42
+#: src/language/stats/oneway.q:405 src/ui/gui/descriptives-dialog.c:42
 #: src/ui/gui/frequencies-dialog.c:43
 msgid "Maximum"
 msgstr ""
@@ -3187,202 +3141,182 @@ msgstr ""
 msgid "Valid cases = %g; cases with missing value(s) = %g."
 msgstr ""
 
-#: src/language/stats/examine.q:343 src/language/stats/examine.q:496
-#: src/language/stats/examine.q:1058
+#: src/language/stats/examine.q:346 src/language/stats/examine.q:499
+#: src/language/stats/examine.q:1060
 msgid "Not creating plot because data set is empty."
 msgstr ""
 
-#: src/language/stats/examine.q:353
+#: src/language/stats/examine.q:356
 #, c-format
 msgid "Normal Q-Q Plot of %s"
 msgstr ""
 
-#: src/language/stats/examine.q:354 src/language/stats/examine.q:359
+#: src/language/stats/examine.q:357 src/language/stats/examine.q:362
 msgid "Observed Value"
 msgstr ""
 
-#: src/language/stats/examine.q:355
+#: src/language/stats/examine.q:358
 msgid "Expected Normal"
 msgstr ""
 
-#: src/language/stats/examine.q:357
+#: src/language/stats/examine.q:360
 #, c-format
 msgid "Detrended Normal Q-Q Plot of %s"
 msgstr ""
 
-#: src/language/stats/examine.q:360
+#: src/language/stats/examine.q:363
 msgid "Dev from Normal"
 msgstr ""
 
-#: src/language/stats/examine.q:513
+#: src/language/stats/examine.q:516
 #, c-format
 msgid "Boxplot of %s vs. %s"
 msgstr ""
 
-#: src/language/stats/examine.q:517
+#: src/language/stats/examine.q:520
 #, c-format
 msgid "Boxplot of %s"
 msgstr ""
 
-#: src/language/stats/examine.q:753 src/language/stats/examine.q:766
+#: src/language/stats/examine.q:756 src/language/stats/examine.q:769
 #, c-format
 msgid "%s and %s are mutually exclusive"
 msgstr ""
 
-#: src/language/stats/examine.q:1270 src/language/stats/reliability.q:685
+#: src/language/stats/examine.q:1272 src/language/stats/reliability.q:686
 msgid "Case Processing Summary"
 msgstr ""
 
-#: src/language/stats/examine.q:1562 src/language/stats/oneway.q:398
+#: src/language/stats/examine.q:1564 src/language/stats/oneway.q:398
 #, c-format
 msgid "%g%% Confidence Interval for Mean"
 msgstr ""
 
-#: src/language/stats/examine.q:1568 src/language/stats/oneway.q:400
+#: src/language/stats/examine.q:1570 src/language/stats/oneway.q:401
+#: src/language/stats/roc.c:962
 msgid "Lower Bound"
 msgstr ""
 
-#: src/language/stats/examine.q:1573 src/language/stats/oneway.q:401
+#: src/language/stats/examine.q:1575 src/language/stats/oneway.q:402
+#: src/language/stats/roc.c:963
 msgid "Upper Bound"
 msgstr ""
 
-#: src/language/stats/examine.q:1578
-#, c-format
-msgid "5%% Trimmed Mean"
+#: src/language/stats/examine.q:1579
+msgid "5% Trimmed Mean"
 msgstr ""
 
-#: src/language/stats/examine.q:1583 src/language/stats/frequencies.q:125
+#: src/language/stats/examine.q:1584 src/language/stats/frequencies.q:125
 #: src/ui/gui/frequencies-dialog.c:52
 msgid "Median"
 msgstr ""
 
-#: src/language/stats/examine.q:1593 src/language/stats/npar-summary.c:129
-#: src/language/stats/oneway.q:391 src/language/stats/t-test.q:702
-#: src/language/stats/t-test.q:726 src/language/stats/t-test.q:864
-#: src/language/stats/t-test.q:1214
+#: src/language/stats/examine.q:1594 src/language/stats/npar-summary.c:129
+#: src/language/stats/oneway.q:391 src/language/stats/t-test.q:508
+#: src/language/stats/t-test.q:528 src/language/stats/t-test.q:627
+#: src/language/stats/t-test.q:919
 msgid "Std. Deviation"
 msgstr ""
 
-#: src/language/stats/examine.q:1613
+#: src/language/stats/examine.q:1614
 msgid "Interquartile Range"
 msgstr ""
 
-#: src/language/stats/examine.q:1749 src/language/stats/oneway.q:407
+#: src/language/stats/examine.q:1750 src/language/stats/oneway.q:408
 #: src/ui/gui/examine.glade:310
 msgid "Descriptives"
 msgstr ""
 
-#: src/language/stats/examine.q:1755 src/language/stats/oneway.q:392
-#: src/language/stats/oneway.q:687 src/language/stats/regression.q:203
+#: src/language/stats/examine.q:1756 src/language/stats/oneway.q:392
+#: src/language/stats/oneway.q:689 src/language/stats/regression.q:203
+#: src/language/stats/roc.c:959
 msgid "Std. Error"
 msgstr ""
 
-#: src/language/stats/examine.q:1852 src/language/stats/examine.q:1857
-#: src/ui/gui/psppire-data-store.c:756 src/ui/gui/psppire-var-store.c:646
-#: src/ui/gui/psppire-var-store.c:656 src/ui/gui/psppire-var-store.c:666
-#: src/ui/gui/psppire-var-store.c:777
-#, c-format
-msgid "%d"
-msgstr ""
-
-#: src/language/stats/examine.q:1938
+#: src/language/stats/examine.q:1939
 msgid "Highest"
 msgstr ""
 
-#: src/language/stats/examine.q:1943
+#: src/language/stats/examine.q:1944
 msgid "Lowest"
 msgstr ""
 
-#: src/language/stats/examine.q:1950
+#: src/language/stats/examine.q:1951
 msgid "Extreme Values"
 msgstr ""
 
-#: src/language/stats/examine.q:1954
+#: src/language/stats/examine.q:1955
 msgid "Case Number"
 msgstr ""
 
-#: src/language/stats/examine.q:2076
+#: src/language/stats/examine.q:2077
 msgid "Tukey's Hinges"
 msgstr ""
 
-#: src/language/stats/examine.q:2116 src/language/stats/examine.q:2134
-#: src/language/stats/frequencies.q:1418 src/language/stats/npar-summary.c:142
+#: src/language/stats/examine.q:2117 src/language/stats/examine.q:2134
+#: src/language/stats/frequencies.q:1410 src/language/stats/npar-summary.c:142
 #: src/ui/gui/examine.glade:333
 msgid "Percentiles"
 msgstr ""
 
-#: src/language/stats/examine.q:2123
+#: src/language/stats/examine.q:2124
 #, c-format
 msgid "%g"
 msgstr ""
 
-#: src/language/stats/flip.c:96
+#: src/language/stats/flip.c:98
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 msgstr ""
 
-#: src/language/stats/flip.c:151
+#: src/language/stats/flip.c:150
 msgid "Could not create temporary file for FLIP."
 msgstr ""
 
-#: src/language/stats/flip.c:162
-#, c-format
-msgid "Error writing FLIP file: %s."
-msgstr ""
-
-#: src/language/stats/flip.c:262
-#, c-format
-msgid "Could not create acceptable variant for variable %s."
-msgstr ""
-
-#: src/language/stats/flip.c:278
-msgid "Cannot create more than 99999 variable names."
-msgstr ""
-
-#: src/language/stats/flip.c:394
+#: src/language/stats/flip.c:327
 #, c-format
 msgid "Error rewinding FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:401
+#: src/language/stats/flip.c:334
 msgid "Error creating FLIP source file."
 msgstr ""
 
-#: src/language/stats/flip.c:414
+#: src/language/stats/flip.c:347
 #, c-format
 msgid "Error reading FLIP file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:416
+#: src/language/stats/flip.c:349
 msgid "Unexpected end of file reading FLIP file."
 msgstr ""
 
-#: src/language/stats/flip.c:432
+#: src/language/stats/flip.c:365
 #, c-format
 msgid "Error seeking FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:440
+#: src/language/stats/flip.c:373
 #, c-format
 msgid "Error writing FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:451
+#: src/language/stats/flip.c:384
 #, c-format
 msgid "Error closing FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:459
+#: src/language/stats/flip.c:392
 #, c-format
 msgid "Error rewinding FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:487
+#: src/language/stats/flip.c:426
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:490
+#: src/language/stats/flip.c:429
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr ""
 
@@ -3402,66 +3336,66 @@ msgstr ""
 msgid "S.E. Skew"
 msgstr ""
 
-#: src/language/stats/frequencies.q:409
+#: src/language/stats/frequencies.q:407
 msgid ""
 "At most one of BARCHART, HISTOGRAM, or HBAR should be given.  HBAR will be "
 "assumed.  Argument values will be given precedence increasing along the "
 "order given."
 msgstr ""
 
-#: src/language/stats/frequencies.q:492
+#: src/language/stats/frequencies.q:490
 #, c-format
 msgid ""
 "MAX must be greater than or equal to MIN, if both are specified.  However, "
 "MIN was specified as %g and MAX as %g.  MIN and MAX will be ignored."
 msgstr ""
 
-#: src/language/stats/frequencies.q:757
+#: src/language/stats/frequencies.q:754
 #, c-format
 msgid "Variable %s specified multiple times on VARIABLES subcommand."
 msgstr ""
 
-#: src/language/stats/frequencies.q:820
+#: src/language/stats/frequencies.q:812
 msgid "`)' expected after GROUPED interval list."
 msgstr ""
 
-#: src/language/stats/frequencies.q:832
+#: src/language/stats/frequencies.q:824
 #, c-format
 msgid "Variables %s specified on GROUPED but not on VARIABLES."
 msgstr ""
 
-#: src/language/stats/frequencies.q:839
+#: src/language/stats/frequencies.q:831
 #, c-format
 msgid "Variables %s specified multiple times on GROUPED subcommand."
 msgstr ""
 
-#: src/language/stats/frequencies.q:1058 src/language/stats/frequencies.q:1151
-#: src/language/stats/frequencies.q:1152 src/language/stats/frequencies.q:1187
+#: src/language/stats/frequencies.q:1050 src/language/stats/frequencies.q:1143
+#: src/language/stats/frequencies.q:1144 src/language/stats/frequencies.q:1179
 msgid "Cum"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1060 src/output/charts/plot-hist.c:140
+#: src/language/stats/frequencies.q:1052 src/output/charts/plot-hist.c:140
 msgid "Frequency"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1081
+#: src/language/stats/frequencies.q:1073
 msgid "Value Label"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1185
+#: src/language/stats/frequencies.q:1177
 msgid "Freq"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1186 src/language/stats/frequencies.q:1188
+#: src/language/stats/frequencies.q:1178 src/language/stats/frequencies.q:1180
 msgid "Pct"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1381
+#: src/language/stats/frequencies.q:1373
 #, c-format
 msgid "No valid data for variable %s; statistics not displayed."
 msgstr ""
 
-#: src/language/stats/frequencies.q:1422
+#: src/language/stats/frequencies.q:1414
 msgid "50 (Median)"
 msgstr ""
 
@@ -3498,7 +3432,7 @@ msgid ""
 "exactly %d values."
 msgstr ""
 
-#: src/language/stats/npar.q:441 src/language/stats/t-test.q:501
+#: src/language/stats/npar.q:441 src/language/stats/t-test.q:379
 #, c-format
 msgid ""
 "PAIRED was specified but the number of variables preceding WITH (%zu) did "
@@ -3544,11 +3478,11 @@ msgid "Mean Square"
 msgstr ""
 
 #: src/language/stats/oneway.q:280 src/language/stats/regression.q:304
-#: src/language/stats/t-test.q:1023
+#: src/language/stats/t-test.q:750
 msgid "F"
 msgstr ""
 
-#: src/language/stats/oneway.q:281 src/language/stats/oneway.q:538
+#: src/language/stats/oneway.q:281 src/language/stats/oneway.q:539
 #: src/language/stats/regression.q:206 src/language/stats/regression.q:305
 msgid "Significance"
 msgstr ""
@@ -3565,19 +3499,19 @@ msgstr ""
 msgid "ANOVA"
 msgstr ""
 
-#: src/language/stats/oneway.q:535
+#: src/language/stats/oneway.q:536
 msgid "Levene Statistic"
 msgstr ""
 
-#: src/language/stats/oneway.q:536
+#: src/language/stats/oneway.q:537
 msgid "df1"
 msgstr ""
 
-#: src/language/stats/oneway.q:537
+#: src/language/stats/oneway.q:538
 msgid "df2"
 msgstr ""
 
-#: src/language/stats/oneway.q:540
+#: src/language/stats/oneway.q:541
 msgid "Test of Homogeneity of Variances"
 msgstr ""
 
@@ -3585,34 +3519,34 @@ msgstr ""
 msgid "Contrast Coefficients"
 msgstr ""
 
-#: src/language/stats/oneway.q:610 src/language/stats/oneway.q:685
+#: src/language/stats/oneway.q:610 src/language/stats/oneway.q:687
 msgid "Contrast"
 msgstr ""
 
-#: src/language/stats/oneway.q:683
+#: src/language/stats/oneway.q:685
 msgid "Contrast Tests"
 msgstr ""
 
-#: src/language/stats/oneway.q:686
+#: src/language/stats/oneway.q:688
 msgid "Value of Contrast"
 msgstr ""
 
-#: src/language/stats/oneway.q:688 src/language/stats/regression.q:205
-#: src/language/stats/t-test.q:1025 src/language/stats/t-test.q:1218
-#: src/language/stats/t-test.q:1315
+#: src/language/stats/oneway.q:690 src/language/stats/regression.q:205
+#: src/language/stats/t-test.q:752 src/language/stats/t-test.q:923
+#: src/language/stats/t-test.q:1010
 msgid "t"
 msgstr ""
 
-#: src/language/stats/oneway.q:690 src/language/stats/t-test.q:1027
-#: src/language/stats/t-test.q:1220 src/language/stats/t-test.q:1317
+#: src/language/stats/oneway.q:692 src/language/stats/t-test.q:754
+#: src/language/stats/t-test.q:925 src/language/stats/t-test.q:1012
 msgid "Sig. (2-tailed)"
 msgstr ""
 
-#: src/language/stats/oneway.q:734
+#: src/language/stats/oneway.q:736
 msgid "Assume equal variances"
 msgstr ""
 
-#: src/language/stats/oneway.q:738
+#: src/language/stats/oneway.q:740
 msgid "Does not assume equal"
 msgstr ""
 
@@ -3639,33 +3573,33 @@ msgstr ""
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:729
+#: src/language/stats/rank.q:728
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:743
+#: src/language/stats/rank.q:741
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:753
+#: src/language/stats/rank.q:750
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:766
+#: src/language/stats/rank.q:762
 msgid ""
 "FRACTION has been specified, but NORMAL and PROPORTION rank functions have "
 "not been requested.  The FRACTION subcommand will be ignored."
 msgstr ""
 
-#: src/language/stats/rank.q:857
+#: src/language/stats/rank.q:853
 #, c-format
 msgid "Variable %s already exists."
 msgstr ""
 
-#: src/language/stats/rank.q:862
+#: src/language/stats/rank.q:858
 msgid "Too many variables in INTO clause."
 msgstr ""
 
@@ -3732,104 +3666,182 @@ msgstr ""
 msgid "Dependent variable must be numeric."
 msgstr ""
 
-#: src/language/stats/reliability.q:432
+#: src/language/stats/reliability.q:433
 msgid "Reliability Statistics"
 msgstr ""
 
-#: src/language/stats/reliability.q:475
+#: src/language/stats/reliability.q:476
 msgid "Item-Total Statistics"
 msgstr ""
 
-#: src/language/stats/reliability.q:497
+#: src/language/stats/reliability.q:498
 msgid "Scale Mean if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.q:500
+#: src/language/stats/reliability.q:501
 msgid "Scale Variance if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.q:503
+#: src/language/stats/reliability.q:504
 msgid "Corrected Item-Total Correlation"
 msgstr ""
 
-#: src/language/stats/reliability.q:506
+#: src/language/stats/reliability.q:507
 msgid "Cronbach's Alpha if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.q:556 src/language/stats/reliability.q:575
+#: src/language/stats/reliability.q:557 src/language/stats/reliability.q:576
 msgid "Cronbach's Alpha"
 msgstr ""
 
-#: src/language/stats/reliability.q:559
+#: src/language/stats/reliability.q:560
 msgid "N of items"
 msgstr ""
 
-#: src/language/stats/reliability.q:578
+#: src/language/stats/reliability.q:579
 msgid "Part 1"
 msgstr ""
 
-#: src/language/stats/reliability.q:584 src/language/stats/reliability.q:595
+#: src/language/stats/reliability.q:585 src/language/stats/reliability.q:596
 msgid "N of Items"
 msgstr ""
 
-#: src/language/stats/reliability.q:589
+#: src/language/stats/reliability.q:590
 msgid "Part 2"
 msgstr ""
 
-#: src/language/stats/reliability.q:600
+#: src/language/stats/reliability.q:601
 msgid "Total N of Items"
 msgstr ""
 
-#: src/language/stats/reliability.q:603
+#: src/language/stats/reliability.q:604
 msgid "Correlation Between Forms"
 msgstr ""
 
-#: src/language/stats/reliability.q:607
+#: src/language/stats/reliability.q:608
 msgid "Spearman-Brown Coefficient"
 msgstr ""
 
-#: src/language/stats/reliability.q:610
+#: src/language/stats/reliability.q:611
 msgid "Equal Length"
 msgstr ""
 
-#: src/language/stats/reliability.q:613
+#: src/language/stats/reliability.q:614
 msgid "Unequal Length"
 msgstr ""
 
-#: src/language/stats/reliability.q:617
+#: src/language/stats/reliability.q:618
 msgid "Guttman Split-Half Coefficient"
 msgstr ""
 
-#: src/language/stats/reliability.q:714
+#: src/language/stats/reliability.q:715
 msgid "Excluded"
 msgstr ""
 
 #: src/language/stats/reliability.q:723
+msgid "%"
+msgstr ""
+
+#: src/language/stats/roc.c:938
+msgid "Area Under the Curve"
+msgstr ""
+
+#: src/language/stats/roc.c:940
 #, c-format
-msgid "%%"
+msgid "Area Under the Curve (%s)"
 msgstr ""
 
-#: src/language/stats/sign.c:90
-msgid "Negative Differences"
+#: src/language/stats/roc.c:946
+msgid "Area"
+msgstr ""
+
+#: src/language/stats/roc.c:960
+msgid "Asymptotic Sig."
+msgstr ""
+
+#: src/language/stats/roc.c:967
+#, c-format
+msgid "Asymp. %g%% Confidence Interval"
+msgstr ""
+
+#: src/language/stats/roc.c:973
+msgid "Variable under test"
+msgstr ""
+
+#: src/language/stats/roc.c:1032
+msgid "Case Summary"
+msgstr ""
+
+#: src/language/stats/roc.c:1054
+msgid "Unweighted"
+msgstr ""
+
+#: src/language/stats/roc.c:1055
+msgid "Weighted"
+msgstr ""
+
+#: src/language/stats/roc.c:1059
+msgid "Valid N (listwise)"
+msgstr ""
+
+#: src/language/stats/roc.c:1062
+msgid "Positive"
+msgstr ""
+
+#: src/language/stats/roc.c:1063
+msgid "Negative"
+msgstr ""
+
+#: src/language/stats/roc.c:1091
+msgid "Coordinates of the Curve"
+msgstr ""
+
+#: src/language/stats/roc.c:1093
+#, c-format
+msgid "Coordinates of the Curve (%s)"
+msgstr ""
+
+#: src/language/stats/roc.c:1103
+msgid "Test variable"
+msgstr ""
+
+#: src/language/stats/roc.c:1105
+msgid "Positive if greater than or equal to"
+msgstr ""
+
+#: src/language/stats/roc.c:1106 src/language/stats/roc.c:1171
+msgid "Sensitivity"
+msgstr ""
+
+#: src/language/stats/roc.c:1107 src/language/stats/roc.c:1170
+msgid "1 - Specificity"
+msgstr ""
+
+#: src/language/stats/roc.c:1169
+msgid "ROC Curve"
 msgstr ""
 
 #: src/language/stats/sign.c:91
+msgid "Negative Differences"
+msgstr ""
+
+#: src/language/stats/sign.c:92
 msgid "Positive Differences"
 msgstr ""
 
-#: src/language/stats/sign.c:92 src/language/stats/wilcoxon.c:245
+#: src/language/stats/sign.c:93 src/language/stats/wilcoxon.c:261
 msgid "Ties"
 msgstr ""
 
-#: src/language/stats/sign.c:133
+#: src/language/stats/sign.c:134 src/language/stats/wilcoxon.c:331
 msgid "Exact Sig. (2-tailed)"
 msgstr ""
 
-#: src/language/stats/sign.c:136
+#: src/language/stats/sign.c:137 src/language/stats/wilcoxon.c:332
 msgid "Exact Sig. (1-tailed)"
 msgstr ""
 
-#: src/language/stats/sign.c:139 src/language/stats/wilcoxon.c:319
+#: src/language/stats/sign.c:140 src/language/stats/wilcoxon.c:335
 msgid "Point Probability"
 msgstr ""
 
@@ -3850,161 +3862,148 @@ msgstr ""
 msgid "Variable %s specified twice in sort criteria."
 msgstr ""
 
-#: src/language/stats/t-test.q:280
-msgid "TESTVAL, GROUPS and PAIRS subcommands are mutually exclusive."
+#: src/language/stats/t-test.q:189
+msgid "Exactly one of TESTVAL, GROUPS and PAIRS subcommands must be specified."
 msgstr ""
 
-#: src/language/stats/t-test.q:298
-msgid "VARIABLES subcommand is not appropriate with PAIRS"
+#: src/language/stats/t-test.q:210
+msgid "VARIABLES subcommand may not be used with PAIRS."
 msgstr ""
 
-#: src/language/stats/t-test.q:336
+#: src/language/stats/t-test.q:229
 msgid "One or more VARIABLES must be specified."
 msgstr ""
 
-#: src/language/stats/t-test.q:386
-#, c-format
-msgid "Long string variable %s is not valid here."
-msgstr ""
-
-#: src/language/stats/t-test.q:406 src/language/stats/t-test.q:420
+#: src/language/stats/t-test.q:323
 msgid ""
 "When applying GROUPS to a string variable, two values must be specified."
 msgstr ""
 
-#: src/language/stats/t-test.q:518
+#: src/language/stats/t-test.q:394
 msgid "At least two variables must be specified on PAIRS."
 msgstr ""
 
-#: src/language/stats/t-test.q:698
+#: src/language/stats/t-test.q:504
 msgid "One-Sample Statistics"
 msgstr ""
 
-#: src/language/stats/t-test.q:703 src/language/stats/t-test.q:727
-#: src/language/stats/t-test.q:865
+#: src/language/stats/t-test.q:509 src/language/stats/t-test.q:529
+#: src/language/stats/t-test.q:628
 msgid "SE. Mean"
 msgstr ""
 
-#: src/language/stats/t-test.q:722
+#: src/language/stats/t-test.q:523
 msgid "Group Statistics"
 msgstr ""
 
-#: src/language/stats/t-test.q:859
+#: src/language/stats/t-test.q:622
 msgid "Paired Sample Statistics"
 msgstr ""
 
-#: src/language/stats/t-test.q:885 src/language/stats/t-test.q:1243
-#: src/language/stats/t-test.q:1442
+#: src/language/stats/t-test.q:642 src/language/stats/t-test.q:945
+#: src/language/stats/t-test.q:1119
 #, c-format
 msgid "Pair %d"
 msgstr ""
 
-#: src/language/stats/t-test.q:1011
+#: src/language/stats/t-test.q:738
 msgid "Independent Samples Test"
 msgstr ""
 
-#: src/language/stats/t-test.q:1019
+#: src/language/stats/t-test.q:746
 msgid "Levene's Test for Equality of Variances"
 msgstr ""
 
-#: src/language/stats/t-test.q:1021
+#: src/language/stats/t-test.q:748
 msgid "t-test for Equality of Means"
 msgstr ""
 
-#: src/language/stats/t-test.q:1024 src/language/stats/t-test.q:1427
+#: src/language/stats/t-test.q:751 src/language/stats/t-test.q:1107
 msgid "Sig."
 msgstr ""
 
-#: src/language/stats/t-test.q:1028 src/language/stats/t-test.q:1318
+#: src/language/stats/t-test.q:755 src/language/stats/t-test.q:1013
 msgid "Mean Difference"
 msgstr ""
 
-#: src/language/stats/t-test.q:1029
+#: src/language/stats/t-test.q:756
 msgid "Std. Error Difference"
 msgstr ""
 
-#: src/language/stats/t-test.q:1034 src/language/stats/t-test.q:1210
-#: src/language/stats/t-test.q:1310
+#: src/language/stats/t-test.q:761 src/language/stats/t-test.q:915
+#: src/language/stats/t-test.q:1005
 #, c-format
 msgid "%g%% Confidence Interval of the Difference"
 msgstr ""
 
-#: src/language/stats/t-test.q:1090
+#: src/language/stats/t-test.q:815
 msgid "Equal variances assumed"
 msgstr ""
 
-#: src/language/stats/t-test.q:1142
+#: src/language/stats/t-test.q:861
 msgid "Equal variances not assumed"
 msgstr ""
 
-#: src/language/stats/t-test.q:1200
+#: src/language/stats/t-test.q:905
 msgid "Paired Samples Test"
 msgstr ""
 
-#: src/language/stats/t-test.q:1203
+#: src/language/stats/t-test.q:908
 msgid "Paired Differences"
 msgstr ""
 
-#: src/language/stats/t-test.q:1215
+#: src/language/stats/t-test.q:920
 msgid "Std. Error Mean"
 msgstr ""
 
-#: src/language/stats/t-test.q:1299
+#: src/language/stats/t-test.q:994
 msgid "One-Sample Test"
 msgstr ""
 
-#: src/language/stats/t-test.q:1304
+#: src/language/stats/t-test.q:999
 #, c-format
 msgid "Test Value = %f"
 msgstr ""
 
-#: src/language/stats/t-test.q:1422
+#: src/language/stats/t-test.q:1102
 msgid "Paired Samples Correlations"
 msgstr ""
 
-#: src/language/stats/t-test.q:1426
+#: src/language/stats/t-test.q:1106
 msgid "Correlation"
 msgstr ""
 
-#: src/language/stats/t-test.q:1445
+#: src/language/stats/t-test.q:1121
 #, c-format
 msgid "%s & %s"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:216
+#: src/language/stats/wilcoxon.c:232
 msgid "Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:230
+#: src/language/stats/wilcoxon.c:246
 msgid "Mean Rank"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:231
+#: src/language/stats/wilcoxon.c:247
 msgid "Sum of Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:243
+#: src/language/stats/wilcoxon.c:259
 msgid "Negative Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:244
+#: src/language/stats/wilcoxon.c:260
 msgid "Positive Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:310
+#: src/language/stats/wilcoxon.c:326
 msgid "Z"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:311
-msgid "Asymp. Sig (2-tailed)"
-msgstr ""
-
-#: src/language/stats/wilcoxon.c:315
-msgid "Exact Sig (2-tailed)"
-msgstr ""
-
-#: src/language/stats/wilcoxon.c:316
-msgid "Exact Sig (1-tailed)"
+#: src/language/stats/wilcoxon.c:327
+msgid "Asymp. Sig. (2-tailed)"
 msgstr ""
 
 #: src/language/syntax-file.c:88
@@ -4017,34 +4016,16 @@ msgstr ""
 msgid "Opening `%s': %s."
 msgstr ""
 
-#: src/language/syntax-file.c:106
+#: src/language/syntax-file.c:107
 #, c-format
 msgid "Reading `%s': %s."
 msgstr ""
 
-#: src/language/syntax-file.c:126
+#: src/language/syntax-file.c:127
 #, c-format
 msgid "Closing `%s': %s."
 msgstr ""
 
-#: src/language/tests/check-model.q:138
-msgid "PATH and SEARCH subcommands are mutually exclusive.  Ignoring PATH."
-msgstr ""
-
-#: src/language/tests/check-model.q:156
-msgid "At least one value must be specified on PATH."
-msgstr ""
-
-#: src/language/tests/check-model.q:167
-#, c-format
-msgid "Hash bits adjusted to %d."
-msgstr ""
-
-#: src/language/tests/check-model.q:208
-#, c-format
-msgid "error opening \"%s\" for writing"
-msgstr ""
-
 #: src/language/tests/float-format.c:124
 #, c-format
 msgid "%zu-byte string needed but %zu-byte string supplied."
@@ -4174,98 +4155,45 @@ msgid ""
 "is of type string."
 msgstr ""
 
-#: src/language/utilities/set.q:522
-msgid "BLANKS is SYSMIS."
-msgstr ""
-
-#: src/language/utilities/set.q:524
-#, c-format
-msgid "BLANKS is %g."
-msgstr ""
-
-#: src/language/utilities/set.q:559
-#, c-format
-msgid "%s is \"%s\"."
+#: src/language/utilities/set.q:668
+msgid "ISL (32-bit IEEE 754 single, little-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:595
-#, c-format
-msgid "DECIMAL is \"%c\"."
+#: src/language/utilities/set.q:671
+msgid "ISB (32-bit IEEE 754 single, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:601
-#, c-format
-msgid "ENDCMD is \"%c\"."
+#: src/language/utilities/set.q:674
+msgid "IDL (64-bit IEEE 754 double, little-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:609
-#, c-format
-msgid "ERRORS is \"%s\"."
+#: src/language/utilities/set.q:677
+msgid "IDB (64-bit IEEE 754 double, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:620
-#, c-format
-msgid "FORMAT is %s."
+#: src/language/utilities/set.q:681
+msgid "VF (32-bit VAX F, VAX-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:626
-#, c-format
-msgid "LENGTH is %d."
+#: src/language/utilities/set.q:684
+msgid "VD (64-bit VAX D, VAX-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:632
-#, c-format
-msgid "LOCALE is %s"
+#: src/language/utilities/set.q:687
+msgid "VG (64-bit VAX G, VAX-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:638
-#, c-format
-msgid "MXERRS is %d."
+#: src/language/utilities/set.q:691
+msgid "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:644
-#, c-format
-msgid "MXLOOPS is %d."
+#: src/language/utilities/set.q:694
+msgid "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:650
+#: src/language/utilities/set.q:793
 #, c-format
-msgid "MXWARNS is %d."
-msgstr ""
-
-#: src/language/utilities/set.q:657 src/language/utilities/set.q:708
-#, c-format
-msgid "%s is %s (%s)."
-msgstr ""
-
-#: src/language/utilities/set.q:729
-msgid "SCOMPRESSION is ON."
-msgstr ""
-
-#: src/language/utilities/set.q:731
-msgid "SCOMPRESSION is OFF."
-msgstr ""
-
-#: src/language/utilities/set.q:738
-msgid "UNDEFINED is WARN."
-msgstr ""
-
-#: src/language/utilities/set.q:740
-msgid "UNDEFINED is NOWARN."
-msgstr ""
-
-#: src/language/utilities/set.q:748
-msgid "WEIGHT is off."
-msgstr ""
-
-#: src/language/utilities/set.q:750
-#, c-format
-msgid "WEIGHT is variable %s."
-msgstr ""
-
-#: src/language/utilities/set.q:768
-#, c-format
-msgid "WIDTH is %d."
+msgid "%s is %s."
 msgstr ""
 
 #: src/language/utilities/title.c:68
@@ -4291,7 +4219,7 @@ msgid ""
 "When executing COMPUTE: %g is not a valid value as an index into vector %s."
 msgstr ""
 
-#: src/language/xforms/compute.c:354
+#: src/language/xforms/compute.c:353
 #, c-format
 msgid "There is no vector named %s."
 msgstr ""
@@ -4300,44 +4228,44 @@ msgstr ""
 msgid "Destination cannot be a string variable."
 msgstr ""
 
-#: src/language/xforms/recode.c:251
+#: src/language/xforms/recode.c:248
 msgid ""
 "Inconsistent target variable types.  Target variables must be all numeric or "
 "all string."
 msgstr ""
 
-#: src/language/xforms/recode.c:272
+#: src/language/xforms/recode.c:269
 msgid "CONVERT requires string input values and numeric output values."
 msgstr ""
 
-#: src/language/xforms/recode.c:329
+#: src/language/xforms/recode.c:324
 msgid "THRU is not allowed with string variables."
 msgstr ""
 
-#: src/language/xforms/recode.c:407
+#: src/language/xforms/recode.c:403
 msgid "expecting output value"
 msgstr ""
 
-#: src/language/xforms/recode.c:456
+#: src/language/xforms/recode.c:460
 #, c-format
 msgid ""
 "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same "
 "number of variables as source and target variables."
 msgstr ""
 
-#: src/language/xforms/recode.c:471
+#: src/language/xforms/recode.c:475
 #, c-format
 msgid ""
 "There is no variable named %s.  (All string variables specified on INTO must "
 "already exist.  Use the STRING command to create a string variable.)"
 msgstr ""
 
-#: src/language/xforms/recode.c:487
+#: src/language/xforms/recode.c:491
 #, c-format
 msgid "INTO is required with %s input values and %s output values."
 msgstr ""
 
-#: src/language/xforms/recode.c:500
+#: src/language/xforms/recode.c:504
 #, c-format
 msgid "Type mismatch.  Cannot store %s data in %s variable %s."
 msgstr ""
@@ -4368,6 +4296,31 @@ msgstr ""
 msgid "hash table:"
 msgstr ""
 
+#: src/libpspp/tmpfile.c:55
+#, c-format
+msgid "failed to create temporary file"
+msgstr ""
+
+#: src/libpspp/tmpfile.c:96
+#, c-format
+msgid "seeking in temporary file"
+msgstr ""
+
+#: src/libpspp/tmpfile.c:115
+#, c-format
+msgid "reading temporary file"
+msgstr ""
+
+#: src/libpspp/tmpfile.c:117
+#, c-format
+msgid "unexpected end of file reading temporary file"
+msgstr ""
+
+#: src/libpspp/tmpfile.c:136
+#, c-format
+msgid "writing to temporary file"
+msgstr ""
+
 #: src/math/percentiles.c:35
 msgid "HAverage"
 msgstr ""
@@ -4529,7 +4482,7 @@ msgstr ""
 msgid "ascii: closing output file \"%s\""
 msgstr ""
 
-#: src/output/chart.c:145
+#: src/output/chart.c:154
 #, c-format
 msgid "creating \"%s\""
 msgstr ""
@@ -4779,17 +4732,27 @@ msgstr ""
 msgid "closing Postscript encoding \"%s\""
 msgstr ""
 
-#: src/output/table.c:236
+#: src/output/table.c:237
 #, c-format
 msgid "bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr ""
 
-#: src/output/table.c:307
+#: src/output/table.c:308
 #, c-format
 msgid ""
 "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr ""
 
+#: src/ui/gui/about.c:64
+msgid "A program for the analysis of sampled data"
+msgstr ""
+
+#. TRANSLATORS: Use this string to list the people who have helped with
+#. translation to your language.
+#: src/ui/gui/about.c:74
+msgid "translator-credits"
+msgstr "John Darrington"
+
 #: src/ui/gui/comments-dialog.c:58
 #, c-format
 msgid "Column Number: %d"
@@ -4829,7 +4792,7 @@ msgstr ""
 
 #: src/ui/gui/crosstabs-dialog.c:53 src/ui/gui/crosstabs-dialog.c:64
 #: src/ui/gui/crosstabs-dialog.c:99 src/ui/gui/crosstabs-dialog.c:107
-#: src/ui/gui/psppire-var-store.c:559 src/ui/gui/var-display.c:16
+#: src/ui/gui/psppire-var-store.c:612 src/ui/gui/var-display.c:16
 #: src/ui/gui/variable-info-dialog.c:40
 msgid "None"
 msgstr ""
@@ -4883,7 +4846,7 @@ msgstr ""
 msgid "Pivot"
 msgstr ""
 
-#: src/ui/gui/crosstabs.glade:253 src/ui/gui/psppire.glade:781
+#: src/ui/gui/crosstabs.glade:253 src/ui/gui/psppire.glade:756
 msgid "Ascending"
 msgstr ""
 
@@ -4958,7 +4921,7 @@ msgid "_Edit"
 msgstr ""
 
 #: src/ui/gui/data-editor.glade:174 src/ui/gui/data-editor.glade:843
-#: src/ui/gui/psppire-data-window.c:844 src/ui/gui/psppire-data-window.c:934
+#: src/ui/gui/psppire-data-window.c:847 src/ui/gui/psppire-data-window.c:937
 msgid "Insert Variable"
 msgstr ""
 
@@ -5151,11 +5114,11 @@ msgstr ""
 msgid "_About"
 msgstr ""
 
-#: src/ui/gui/data-editor.glade:702 src/ui/gui/psppire-data-window.c:379
+#: src/ui/gui/data-editor.glade:702 src/ui/gui/psppire-data-window.c:383
 msgid "Open"
 msgstr ""
 
-#: src/ui/gui/data-editor.glade:712 src/ui/gui/psppire-data-window.c:582
+#: src/ui/gui/data-editor.glade:712 src/ui/gui/psppire-data-window.c:585
 msgid "Save"
 msgstr ""
 
@@ -5183,7 +5146,7 @@ msgstr ""
 msgid "Find"
 msgstr ""
 
-#: src/ui/gui/data-editor.glade:831 src/ui/gui/psppire-data-window.c:898
+#: src/ui/gui/data-editor.glade:831 src/ui/gui/psppire-data-window.c:901
 msgid "Insert Case"
 msgstr ""
 
@@ -5298,7 +5261,7 @@ msgstr ""
 msgid "Missing Values"
 msgstr ""
 
-#: src/ui/gui/find-dialog.c:657
+#: src/ui/gui/find-dialog.c:652
 #, c-format
 msgid "Bad regular expression: %s"
 msgstr ""
@@ -5344,7 +5307,7 @@ msgstr ""
 msgid "Standard error of the kurtosis"
 msgstr ""
 
-#: src/ui/gui/frequencies.glade:98 src/ui/gui/psppire.glade:277
+#: src/ui/gui/frequencies.glade:98 src/ui/gui/psppire.glade:252
 #: src/ui/gui/rank.glade:103
 msgid "Variable(s):"
 msgstr ""
@@ -5381,11 +5344,11 @@ msgstr ""
 msgid "Maximum no of categories"
 msgstr ""
 
-#: src/ui/gui/helper.c:186
+#: src/ui/gui/helper.c:197
 msgid "Sorry. The help system hasn't yet been implemented."
 msgstr ""
 
-#: src/ui/gui/helper.c:231
+#: src/ui/gui/helper.c:242
 #, c-format
 msgid "Cannot open reference manual: %s"
 msgstr ""
@@ -5472,11 +5435,11 @@ msgstr ""
 msgid "gtk-close"
 msgstr ""
 
-#: src/ui/gui/missing-val-dialog.c:114 src/ui/gui/missing-val-dialog.c:159
+#: src/ui/gui/missing-val-dialog.c:113 src/ui/gui/missing-val-dialog.c:167
 msgid "Incorrect value for variable type"
 msgstr ""
 
-#: src/ui/gui/missing-val-dialog.c:135 src/ui/gui/missing-val-dialog.c:142
+#: src/ui/gui/missing-val-dialog.c:134 src/ui/gui/missing-val-dialog.c:143
 msgid "Incorrect range specification"
 msgstr ""
 
@@ -5577,18 +5540,25 @@ msgstr ""
 msgid "_Select"
 msgstr ""
 
-#: src/ui/gui/psppire-data-editor.c:956
+#: src/ui/gui/psppire-data-editor.c:951
 msgid "Data View"
 msgstr ""
 
-#: src/ui/gui/psppire-data-editor.c:959
+#: src/ui/gui/psppire-data-editor.c:954
 msgid "Variable View"
 msgstr ""
 
-#: src/ui/gui/psppire-data-store.c:746
+#: src/ui/gui/psppire-data-store.c:744
 msgid "var"
 msgstr ""
 
+#: src/ui/gui/psppire-data-store.c:755 src/ui/gui/psppire-var-store.c:699
+#: src/ui/gui/psppire-var-store.c:709 src/ui/gui/psppire-var-store.c:719
+#: src/ui/gui/psppire-var-store.c:825
+#, c-format
+msgid "%d"
+msgstr ""
+
 #: src/ui/gui/psppire-data-window.c:213
 msgid "Transformations Pending"
 msgstr ""
@@ -5597,201 +5567,201 @@ msgstr ""
 msgid "Filter off"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:241
+#: src/ui/gui/psppire-data-window.c:243
 #, c-format
 msgid "Filter by %s"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:262
+#: src/ui/gui/psppire-data-window.c:264
 msgid "No Split"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:271
+#: src/ui/gui/psppire-data-window.c:273
 msgid "Split by "
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:299
+#: src/ui/gui/psppire-data-window.c:301
 msgid "Weights off"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:311
+#: src/ui/gui/psppire-data-window.c:315
 #, c-format
 msgid "Weight by %s"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:387 src/ui/gui/psppire-data-window.c:590
+#: src/ui/gui/psppire-data-window.c:391 src/ui/gui/psppire-data-window.c:593
 msgid "System Files (*.sav)"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:393 src/ui/gui/psppire-data-window.c:596
+#: src/ui/gui/psppire-data-window.c:397 src/ui/gui/psppire-data-window.c:599
 msgid "Portable Files (*.por) "
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:399 src/ui/gui/psppire-data-window.c:602
+#: src/ui/gui/psppire-data-window.c:403 src/ui/gui/psppire-data-window.c:605
 #: src/ui/gui/psppire-syntax-window.c:298
 #: src/ui/gui/psppire-syntax-window.c:385
 msgid "All Files"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:610
+#: src/ui/gui/psppire-data-window.c:613
 msgid "System File"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:615
+#: src/ui/gui/psppire-data-window.c:618
 msgid "Portable File"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:765
+#: src/ui/gui/psppire-data-window.c:768
 msgid "Font Selection"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:833
+#: src/ui/gui/psppire-data-window.c:836
 msgid "Sort Ascending"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:839
+#: src/ui/gui/psppire-data-window.c:842
 msgid "Sort Descending"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:847 src/ui/gui/psppire-data-window.c:901
-#: src/ui/gui/psppire-data-window.c:937 src/ui/gui/psppire-data-window.c:1302
-#: src/ui/gui/psppire-data-window.c:1320
+#: src/ui/gui/psppire-data-window.c:850 src/ui/gui/psppire-data-window.c:904
+#: src/ui/gui/psppire-data-window.c:940 src/ui/gui/psppire-data-window.c:1308
+#: src/ui/gui/psppire-data-window.c:1326
 msgid "Clear"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1179
+#: src/ui/gui/psppire-data-window.c:1185
 msgid "Open a data file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1197
+#: src/ui/gui/psppire-data-window.c:1203
 msgid "New data file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1212
+#: src/ui/gui/psppire-data-window.c:1218
 msgid "Import text data file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1228 src/ui/gui/psppire-data-window.c:1245
+#: src/ui/gui/psppire-data-window.c:1234 src/ui/gui/psppire-data-window.c:1251
 msgid "Save data to file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1244
+#: src/ui/gui/psppire-data-window.c:1250
 msgid "Save As"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1283
+#: src/ui/gui/psppire-data-window.c:1289
 msgid "Show/hide value labels"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1303
+#: src/ui/gui/psppire-data-window.c:1309
 msgid "Delete the cases at the selected position(s)"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1321
+#: src/ui/gui/psppire-data-window.c:1327
 msgid "Delete the variables at the selected position(s)"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1339
+#: src/ui/gui/psppire-data-window.c:1345
 msgid "Create a new variable at the current position"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1354
+#: src/ui/gui/psppire-data-window.c:1360
 msgid "Create a new case at the current position"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1370
+#: src/ui/gui/psppire-data-window.c:1376
 msgid "Jump to a Case in the Data Sheet"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1386
+#: src/ui/gui/psppire-data-window.c:1392
 msgid "Weight cases by variable"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1400
+#: src/ui/gui/psppire-data-window.c:1406
 msgid "Transpose the cases with the variables"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1414
+#: src/ui/gui/psppire-data-window.c:1420
 msgid "Split the active file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1429
+#: src/ui/gui/psppire-data-window.c:1435
 msgid "Sort cases in the active file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1443
+#: src/ui/gui/psppire-data-window.c:1449
 msgid "Select cases from the active file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1457
+#: src/ui/gui/psppire-data-window.c:1463
 msgid "Compute new values for a variable"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1471
+#: src/ui/gui/psppire-data-window.c:1477
 msgid "Perform one way analysis of variance"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1486
+#: src/ui/gui/psppire-data-window.c:1492
 msgid "Calculate T Test for samples from independent groups"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1500
+#: src/ui/gui/psppire-data-window.c:1506
 msgid "Calculate T Test for paired samples"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1514
+#: src/ui/gui/psppire-data-window.c:1520
 msgid "Calculate T Test for sample from a single distribution"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1529
+#: src/ui/gui/psppire-data-window.c:1535
 msgid "Commentary text for the data file"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1555
+#: src/ui/gui/psppire-data-window.c:1561
 msgid "Rank Cases"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1569
+#: src/ui/gui/psppire-data-window.c:1575
 msgid "Recode values into the same variables"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1583
+#: src/ui/gui/psppire-data-window.c:1589
 msgid "Recode values into different variables"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1597
+#: src/ui/gui/psppire-data-window.c:1603
 msgid "Jump to variable"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1610
+#: src/ui/gui/psppire-data-window.c:1616
 msgid "Calculate descriptive statistics (mean, variance, ...)"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1624
+#: src/ui/gui/psppire-data-window.c:1630
 msgid "Generate frequency statistics"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1638
+#: src/ui/gui/psppire-data-window.c:1644
 msgid "Generate crosstabulations"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1653
+#: src/ui/gui/psppire-data-window.c:1659
 msgid "Examine Data by Factors"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1667
+#: src/ui/gui/psppire-data-window.c:1673
 msgid "Estimate parameters of the linear model"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1681 src/ui/gui/reliability.glade:7
+#: src/ui/gui/psppire-data-window.c:1687 src/ui/gui/reliability.glade:7
 msgid "Reliability Analysis"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1844
+#: src/ui/gui/psppire-data-window.c:1850
 msgid "Split the window vertically and horizontally"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1886
+#: src/ui/gui/psppire-data-window.c:1892
 msgid "Data Editor"
 msgstr ""
 
@@ -5807,187 +5777,182 @@ msgstr ""
 msgid "How many things can be selected"
 msgstr ""
 
-#: src/ui/gui/psppire-dictview.c:539
+#: src/ui/gui/psppire-dictview.c:528
 msgid "Prefer variable labels"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:10
-msgid ""
-"This is beta status software.  Please report bugs to bug-gnu-pspp@gnu.org"
-msgstr ""
-
-#: src/ui/gui/psppire.glade:72 src/ui/gui/psppire.glade:155
+#: src/ui/gui/psppire.glade:47 src/ui/gui/psppire.glade:130
 #: src/ui/gui/weight-cases-dialog.c:79
 msgid "Do not weight cases"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:83
+#: src/ui/gui/psppire.glade:58
 msgid "Weight cases by"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:108
+#: src/ui/gui/psppire.glade:83
 msgid "Frequency Variable"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:148
+#: src/ui/gui/psppire.glade:123
 msgid "Current Status: "
 msgstr ""
 
-#: src/ui/gui/psppire.glade:244
+#: src/ui/gui/psppire.glade:219
 msgid "Name Variable:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:429
+#: src/ui/gui/psppire.glade:404
 msgid "Analyze all cases.  Do not create groups."
 msgstr "Analyse all cases.  Do not create groups."
 
-#: src/ui/gui/psppire.glade:440
+#: src/ui/gui/psppire.glade:415
 msgid "Compare groups."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:454
+#: src/ui/gui/psppire.glade:429
 msgid "Organize output by groups."
 msgstr "Organise output by groups."
 
-#: src/ui/gui/psppire.glade:502
+#: src/ui/gui/psppire.glade:477
 msgid "Groups based on:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:565
+#: src/ui/gui/psppire.glade:540
 msgid "Sort the file by grouping variables."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:577
+#: src/ui/gui/psppire.glade:552
 msgid "File is already sorted."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:622
+#: src/ui/gui/psppire.glade:597
 msgid "Current Status : "
 msgstr ""
 
-#: src/ui/gui/psppire.glade:630
+#: src/ui/gui/psppire.glade:605
 msgid "Analysis by groups is off"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:729
+#: src/ui/gui/psppire.glade:704
 msgid "Sort by:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:792
+#: src/ui/gui/psppire.glade:767
 msgid "Descending"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:809
+#: src/ui/gui/psppire.glade:784
 msgid "Sort Order"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:878
+#: src/ui/gui/psppire.glade:853
 msgid "Target Variable:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:909
+#: src/ui/gui/psppire.glade:884
 msgid "Type & Label"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:949
+#: src/ui/gui/psppire.glade:924
 msgid "="
 msgstr ""
 
-#: src/ui/gui/psppire.glade:995
+#: src/ui/gui/psppire.glade:970
 msgid "Numeric Expressions:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1049
+#: src/ui/gui/psppire.glade:1024
 msgid "Functions:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1112 src/ui/gui/psppire.glade:1516
+#: src/ui/gui/psppire.glade:1087 src/ui/gui/psppire.glade:1491
 #: src/ui/gui/recode.glade:731
 msgid "If..."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1345
+#: src/ui/gui/psppire.glade:1320
 msgid "Use filter variable"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1398
+#: src/ui/gui/psppire.glade:1373
 msgid "Based on time or case range"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1411
+#: src/ui/gui/psppire.glade:1386
 msgid "Range..."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1450
+#: src/ui/gui/psppire.glade:1425
 msgid "Random sample of cases"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1464
+#: src/ui/gui/psppire.glade:1439
 msgid "Sample..."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1502
+#: src/ui/gui/psppire.glade:1477
 msgid "If condition is satisfied"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1551
+#: src/ui/gui/psppire.glade:1526
 msgid "All Cases"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1566
+#: src/ui/gui/psppire.glade:1541
 msgid "Select"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1595
+#: src/ui/gui/psppire.glade:1570
 msgid "Filtered"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1606
+#: src/ui/gui/psppire.glade:1581
 msgid "Deleted"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1624
+#: src/ui/gui/psppire.glade:1599
 msgid "Unselected Cases Are"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1689
+#: src/ui/gui/psppire.glade:1664
 msgid "Comments:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1731
+#: src/ui/gui/psppire.glade:1706
 msgid "Display comments in output"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1746
+#: src/ui/gui/psppire.glade:1721
 msgid "Column Number: 0"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1829
+#: src/ui/gui/psppire.glade:1804
 msgid "First case"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1842
+#: src/ui/gui/psppire.glade:1817
 msgid "Last case"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1855
+#: src/ui/gui/psppire.glade:1830
 msgid "Observation"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1919
+#: src/ui/gui/psppire.glade:1894
 msgid "Use expression as label"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2045 src/ui/gui/psppire-var-sheet.c:540
-#: src/ui/gui/psppire-var-store.c:786
+#: src/ui/gui/psppire.glade:2020 src/ui/gui/psppire-var-sheet.c:532
+#: src/ui/gui/psppire-var-store.c:834
 msgid "Width"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2175
+#: src/ui/gui/psppire.glade:2150
 msgid "Goto Case Number:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2312
+#: src/ui/gui/psppire.glade:2287
 msgid "Sample Size"
 msgstr ""
 
@@ -6022,47 +5987,47 @@ msgstr ""
 msgid "Cannot load syntax file '%s'"
 msgstr ""
 
-#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:784
+#: src/ui/gui/psppire-var-sheet.c:530 src/ui/gui/psppire-var-store.c:832
 msgid "Name"
 msgstr ""
 
-#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:787
+#: src/ui/gui/psppire-var-sheet.c:533 src/ui/gui/psppire-var-store.c:835
 msgid "Decimals"
 msgstr ""
 
-#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:789
+#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:837
 msgid "Values"
 msgstr ""
 
-#: src/ui/gui/psppire-var-sheet.c:546 src/ui/gui/psppire-var-store.c:792
+#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:840
 msgid "Align"
 msgstr ""
 
-#: src/ui/gui/psppire-var-sheet.c:547 src/ui/gui/psppire-var-store.c:793
+#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:841
 msgid "Measure"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:569 src/ui/gui/var-sheet-dialogs.glade:43
+#: src/ui/gui/psppire-var-store.c:622 src/ui/gui/var-sheet-dialogs.glade:43
 msgid "Comma"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:570 src/ui/gui/var-sheet-dialogs.glade:59
+#: src/ui/gui/psppire-var-store.c:623 src/ui/gui/var-sheet-dialogs.glade:59
 msgid "Dot"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:571
+#: src/ui/gui/psppire-var-store.c:624
 msgid "Scientific"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:572 src/ui/gui/var-sheet-dialogs.glade:91
+#: src/ui/gui/psppire-var-store.c:625 src/ui/gui/var-sheet-dialogs.glade:91
 msgid "Date"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:573 src/ui/gui/var-sheet-dialogs.glade:107
+#: src/ui/gui/psppire-var-store.c:626 src/ui/gui/var-sheet-dialogs.glade:107
 msgid "Dollar"
 msgstr ""
 
-#: src/ui/gui/psppire-var-store.c:574
+#: src/ui/gui/psppire-var-store.c:627
 msgid "Custom"
 msgstr ""
 
@@ -6444,11 +6409,11 @@ msgid "You may choose below how much of the file should actually be imported."
 msgstr ""
 
 #: src/ui/gui/text-data-import-dialog.c:1523
-#: src/ui/gui/text-data-import-dialog.c:1765
+#: src/ui/gui/text-data-import-dialog.c:1768
 msgid "This input line has too few separators to fill in this field."
 msgstr ""
 
-#: src/ui/gui/text-data-import-dialog.c:1756
+#: src/ui/gui/text-data-import-dialog.c:1759
 #, c-format
 msgid "Field content \"%.*s\" cannot be parsed in format %s."
 msgstr ""
@@ -6624,39 +6589,39 @@ msgstr ""
 msgid "Confidence Interval: %2d %%"
 msgstr ""
 
-#: src/ui/gui/t-test-paired-samples.c:227
+#: src/ui/gui/t-test-paired-samples.c:226
 msgid "Var 1"
 msgstr ""
 
-#: src/ui/gui/t-test-paired-samples.c:228
+#: src/ui/gui/t-test-paired-samples.c:227
 msgid "Var 2"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:92
+#: src/ui/gui/variable-info-dialog.c:76
 #, c-format
 msgid "Label: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:101
+#: src/ui/gui/variable-info-dialog.c:83
 #, c-format
 msgid "Type: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:105
+#: src/ui/gui/variable-info-dialog.c:87
 #, c-format
 msgid "Missing Values: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:110
+#: src/ui/gui/variable-info-dialog.c:92
 #, c-format
 msgid "Measurement Level: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:124
+#: src/ui/gui/variable-info-dialog.c:107
 msgid "Value Labels:\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:137
+#: src/ui/gui/variable-info-dialog.c:117
 #, c-format
 msgid "%s %s\n"
 msgstr ""
index 1c3163be3dfe315a8dbd12dee5b90322bd9e9ebd..34eedc88a67c7965c92472d7facbc349aa27542d 100644 (file)
--- a/po/nl.po
+++ b/po/nl.po
@@ -33,7 +33,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: nl\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2009-05-16 07:00+0800\n"
+"POT-Creation-Date: 2009-07-26 09:59+0200\n"
 "PO-Revision-Date: 2009-05-15 18:24+0200\n"
 "Last-Translator:  <pspp@sjpaes.nl>\n"
 "Language-Team: Dutch\n"
@@ -80,81 +80,56 @@ msgstr ""
 "Ten minste een case in de gelezen data heeft een gewicht waarde 'user-"
 "missing, system-missing, zero, of negatief.  Deze case(s) zijn genegeerd."
 
-#: src/data/case-tmpfile.c:57
-#, c-format
-msgid "failed to create temporary file"
-msgstr "aanmaken van een tijdelijk bestand is mislukt"
-
-#: src/data/case-tmpfile.c:131
-#, c-format
-msgid "seeking in temporary file"
-msgstr "zoeken in tijdelijk bestand"
-
-#: src/data/case-tmpfile.c:153
-#, c-format
-msgid "reading temporary file"
-msgstr "lezen tijdelijk bestand"
-
-#: src/data/case-tmpfile.c:155
-#, c-format
-msgid "unexpected end of file reading temporary file"
-msgstr "onverwacht einde bestand bij het lezen van tijdelijk bestand"
-
-#: src/data/case-tmpfile.c:175
-#, c-format
-msgid "writing to temporary file"
-msgstr "schrijven naar tijdelijk bestand"
-
-#: src/data/data-in.c:262 src/data/data-in.c:452
+#: src/data/data-in.c:274 src/data/data-in.c:464
 msgid "Field contents are not numeric."
 msgstr "Veld inhoud is niet numeriek."
 
-#: src/data/data-in.c:264 src/data/data-in.c:454
+#: src/data/data-in.c:276 src/data/data-in.c:466
 msgid "Number followed by garbage."
 msgstr "Nummer gevolgd door rommel."
 
-#: src/data/data-in.c:275
+#: src/data/data-in.c:287
 msgid "Invalid numeric syntax."
 msgstr "Ongeldige numerieke syntax."
 
-#: src/data/data-in.c:284 src/data/data-in.c:467
+#: src/data/data-in.c:296 src/data/data-in.c:479
 msgid "Too-large number set to system-missing."
 msgstr "Te groot getal, is op system-missing gezet."
 
-#: src/data/data-in.c:289 src/data/data-in.c:472
+#: src/data/data-in.c:301 src/data/data-in.c:484
 msgid "Too-small number set to zero."
 msgstr "Te klein getal, is op nul gezet."
 
-#: src/data/data-in.c:315
+#: src/data/data-in.c:327
 msgid "All characters in field must be digits."
 msgstr "Alle karakters in veld moeten cijfers zijn."
 
-#: src/data/data-in.c:338
+#: src/data/data-in.c:350
 msgid "Unrecognized character in field."
 msgstr "Onherkenbaar karakter in veld."
 
-#: src/data/data-in.c:362 src/data/data-in.c:636
+#: src/data/data-in.c:374 src/data/data-in.c:650
 msgid "Field must have even length."
 msgstr "Veld moet een even lengte hebben."
 
-#: src/data/data-in.c:367 src/data/data-in.c:647
+#: src/data/data-in.c:379 src/data/data-in.c:661
 msgid "Field must contain only hex digits."
 msgstr "Veld mag alleen hex cijfers bevatten."
 
-#: src/data/data-in.c:686 src/data/data-in.c:733
+#: src/data/data-in.c:700 src/data/data-in.c:747
 msgid "Syntax error in date field."
 msgstr "Syntax fout in datum veld."
 
-#: src/data/data-in.c:702
+#: src/data/data-in.c:716
 #, c-format
 msgid "Day (%ld) must be between 1 and 31."
 msgstr "Dag (%ld) moet tussen 1 en 31 zijn."
 
-#: src/data/data-in.c:749
+#: src/data/data-in.c:763
 msgid "Delimiter expected between fields in date."
 msgstr "Veldscheider verwacht tussen velden in datum."
 
-#: src/data/data-in.c:823
+#: src/data/data-in.c:837
 msgid ""
 "Unrecognized month format.  Months may be specified as Arabic or Roman "
 "numerals or as at least 3 letters of their English names."
@@ -163,45 +138,45 @@ msgstr ""
 "of Romeins numeriek of als tenminste de eerste 3 letters van hun Engelse "
 "naam."
 
-#: src/data/data-in.c:850
+#: src/data/data-in.c:864
 #, c-format
 msgid "Year (%ld) must be between 1582 and 19999."
 msgstr "Jaar (%ld) moet tussen 1582 en 19999 zijn."
 
-#: src/data/data-in.c:862
+#: src/data/data-in.c:876
 #, c-format
 msgid "Trailing garbage \"%.*s\" following date."
 msgstr "Afsluitende rommel \"%.*s\" achter datum."
 
-#: src/data/data-in.c:878
+#: src/data/data-in.c:892
 msgid "Julian day must have exactly three digits."
 msgstr "Juliaanse datum moet bestaan uit precies 3 cijfers."
 
-#: src/data/data-in.c:883
+#: src/data/data-in.c:897
 #, c-format
 msgid "Julian day (%ld) must be between 1 and 366."
 msgstr "Juliaanse dag (%ld) moet tussen 1 en 366 zijn."
 
-#: src/data/data-in.c:907
+#: src/data/data-in.c:921
 #, c-format
 msgid "Quarter (%ld) must be between 1 and 4."
 msgstr "Kwartaal (%ld) moet tussen 1 en 4 zijn."
 
-#: src/data/data-in.c:927
+#: src/data/data-in.c:941
 #, c-format
 msgid "Week (%ld) must be between 1 and 53."
 msgstr "Week (%ld) moet tussen 1 en 53 zijn."
 
-#: src/data/data-in.c:940
+#: src/data/data-in.c:954
 msgid "Delimiter expected between fields in time."
 msgstr "Veldscheider verwacht tussen velden in tijd."
 
-#: src/data/data-in.c:960
+#: src/data/data-in.c:974
 #, c-format
 msgid "Minute (%ld) must be between 0 and 59."
 msgstr "Minuut (%ld) moet tussen 0 en 59 zijn."
 
-#: src/data/data-in.c:1000
+#: src/data/data-in.c:1014
 msgid ""
 "Unrecognized weekday name.  At least the first two letters of an English "
 "weekday name must be specified."
@@ -209,32 +184,32 @@ msgstr ""
 "Niet herkende weekdag naam.  Tenminste de eerste 2 letters van een Engelse "
 "weekdag naam moeten opgegeven worden."
 
-#: src/data/data-in.c:1138
+#: src/data/data-in.c:1152
 #, c-format
 msgid "`%c' expected in date field."
 msgstr "`%c' verwacht in datum veld."
 
-#: src/data/data-in.c:1179
+#: src/data/data-in.c:1193
 #, c-format
 msgid "column %d"
 msgstr "kolom %d"
 
-#: src/data/data-in.c:1181
+#: src/data/data-in.c:1195
 #, c-format
 msgid "columns %d-%d"
 msgstr "kolommen %d-%d"
 
-#: src/data/data-in.c:1185
+#: src/data/data-in.c:1199
 #, c-format
 msgid "%s field) "
 msgstr "%s veld) "
 
-#: src/data/data-out.c:446
+#: src/data/data-out.c:481
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr "Weekdag nummer %f is niet tussen 1 en 7."
 
-#: src/data/data-out.c:467
+#: src/data/data-out.c:502
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr "Maand nummer %f is niet tussen 1 en 12."
@@ -251,7 +226,7 @@ msgstr "systeem"
 msgid "scratch"
 msgstr ""
 
-#: src/data/dictionary.c:926
+#: src/data/dictionary.c:940
 msgid ""
 "At least one case in the data file had a weight value that was user-missing, "
 "system-missing, zero, or negative.  These case(s) were ignored."
@@ -259,7 +234,7 @@ msgstr ""
 "Op zijn minst een case in het data bestand heeft een gewicht waarde user-"
 "missing, system-missing, nul, of negatief.  Deze case(s) zijn genegeerd."
 
-#: src/data/dictionary.c:1228
+#: src/data/dictionary.c:1263
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr "Document regel afgekapt tot %d bytes."
@@ -369,33 +344,33 @@ msgstr[1] ""
 msgid "%s variables are not compatible with %s format %s."
 msgstr "%s variabelen zijn niet compatibel met %s formaat %s."
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:657
-#: src/ui/gui/psppire.glade:2034 src/ui/gui/psppire-var-store.c:575
+#: src/data/format.c:327 src/data/sys-file-reader.c:734
+#: src/ui/gui/psppire.glade:2009 src/ui/gui/psppire-var-store.c:628
 #: src/ui/gui/var-sheet-dialogs.glade:139
 msgid "String"
 msgstr ""
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:657
-#: src/ui/gui/psppire.glade:2109 src/ui/gui/psppire-var-store.c:568
+#: src/data/format.c:327 src/data/sys-file-reader.c:734
+#: src/ui/gui/psppire.glade:2084 src/ui/gui/psppire-var-store.c:621
 #: src/ui/gui/var-sheet-dialogs.glade:28
 msgid "Numeric"
 msgstr "Numeriek"
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1214
-#: src/data/sys-file-reader.c:1216
+#: src/data/format.c:328 src/data/sys-file-reader.c:1299
+#: src/data/sys-file-reader.c:1301
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:489 src/language/xforms/recode.c:490
-#: src/language/xforms/recode.c:502 src/language/xforms/recode.c:503
+#: src/language/xforms/recode.c:493 src/language/xforms/recode.c:494
+#: src/language/xforms/recode.c:506 src/language/xforms/recode.c:507
 msgid "numeric"
 msgstr "numeriek"
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1214
-#: src/data/sys-file-reader.c:1216
+#: src/data/format.c:328 src/data/sys-file-reader.c:1299
+#: src/data/sys-file-reader.c:1301
 #: src/language/dictionary/apply-dictionary.c:78
 #: src/language/dictionary/apply-dictionary.c:79
-#: src/language/xforms/recode.c:489 src/language/xforms/recode.c:490
-#: src/language/xforms/recode.c:502 src/language/xforms/recode.c:503
+#: src/language/xforms/recode.c:493 src/language/xforms/recode.c:494
+#: src/language/xforms/recode.c:506 src/language/xforms/recode.c:507
 msgid "string"
 msgstr ""
 
@@ -404,30 +379,30 @@ msgstr ""
 msgid "String variable with width %d is not compatible with format %s."
 msgstr "String variabele met breedte %d is niet compatibel met formaat %s."
 
-#: src/data/gnumeric-reader.c:33
+#: src/data/gnumeric-reader.c:36
 msgid ""
 "Support for Gnumeric files was not compiled into this installation of PSPP"
 msgstr ""
 "Ondersteuning voor Gnumeric bestanden is niet gecompileerd in deze "
 "installatie van PSPP"
 
-#: src/data/gnumeric-reader.c:362
-#, c-format
-msgid "Error opening \"%s\" for reading as a gnumeric file: %s."
+#: src/data/gnumeric-reader.c:368
+#, fuzzy, c-format
+msgid "Error opening \"%s\" for reading as a Gnumeric file: %s."
 msgstr ""
 "Fout bij het openen van \"%s\" voor het lezen als een gnumeric bestand: %s."
 
-#: src/data/gnumeric-reader.c:382
+#: src/data/gnumeric-reader.c:388
 #, c-format
 msgid "Invalid cell range \"%s\""
 msgstr "Ongeldige cel range \"%s\""
 
-#: src/data/gnumeric-reader.c:518 src/data/psql-reader.c:182
+#: src/data/gnumeric-reader.c:520 src/data/psql-reader.c:187
 #, c-format
 msgid "Cannot create variable name from %s"
 msgstr "Kan geen variabele naam creëren van %s"
 
-#: src/data/gnumeric-reader.c:530
+#: src/data/gnumeric-reader.c:532
 #, c-format
 msgid "Selected sheet or range of spreadsheet \"%s\" is empty."
 msgstr "Geselecteerd blad of range van werkblad \"%s\" is leeg."
@@ -499,11 +474,11 @@ msgstr "onverwacht einde bestand"
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/por-file-reader.c:268 src/data/por-file-writer.c:148
+#: src/data/por-file-reader.c:267 src/data/por-file-writer.c:149
 msgid "portable file"
 msgstr "overdraagbaar (portable) bestand"
 
-#: src/data/por-file-reader.c:276
+#: src/data/por-file-reader.c:275
 #, c-format
 msgid ""
 "An error occurred while opening \"%s\" for reading as a portable file: %s."
@@ -511,48 +486,48 @@ msgstr ""
 "Er is een fout opgetreden tijdens het openen van \"%s\" voor het lezen als "
 "overdraagbaar (portable) bestand: %s."
 
-#: src/data/por-file-reader.c:297
+#: src/data/por-file-reader.c:296
 msgid "Data record expected."
 msgstr "Data record verwacht."
 
-#: src/data/por-file-reader.c:379
+#: src/data/por-file-reader.c:378
 msgid "Number expected."
 msgstr "Nummer verwacht."
 
-#: src/data/por-file-reader.c:407
+#: src/data/por-file-reader.c:406
 msgid "Missing numeric terminator."
 msgstr "Ontbrekende numerieke afsluiter."
 
-#: src/data/por-file-reader.c:430
+#: src/data/por-file-reader.c:429
 msgid "Invalid integer."
 msgstr "Ongeldige integer."
 
-#: src/data/por-file-reader.c:441
+#: src/data/por-file-reader.c:440 src/data/por-file-reader.c:460
 #, c-format
 msgid "Bad string length %d."
 msgstr "Foutieve string lengte %d."
 
-#: src/data/por-file-reader.c:502
+#: src/data/por-file-reader.c:523
 #, c-format
 msgid "%s: Not a portable file."
 msgstr "%s: Geen overdraagbaar (portable) bestand."
 
-#: src/data/por-file-reader.c:519
+#: src/data/por-file-reader.c:540
 #, c-format
 msgid "Unrecognized version code `%c'."
 msgstr "Niet herkende versie code `%c'."
 
-#: src/data/por-file-reader.c:528
+#: src/data/por-file-reader.c:549
 #, c-format
 msgid "Bad date string length %zu."
 msgstr "Foutieve datum string lengte %zu."
 
-#: src/data/por-file-reader.c:530
+#: src/data/por-file-reader.c:551
 #, c-format
 msgid "Bad time string length %zu."
 msgstr "Foutieve tijd string lengte %zu."
 
-#: src/data/por-file-reader.c:572
+#: src/data/por-file-reader.c:593
 #, c-format
 msgid ""
 "%s: Bad format specifier byte (%d).  Variable will be assigned a default "
@@ -561,71 +536,71 @@ msgstr ""
 "%s: Foutief formaat specificatie byte (%d). Variabele krijgt een default "
 "formaat."
 
-#: src/data/por-file-reader.c:593
+#: src/data/por-file-reader.c:614
 #, c-format
 msgid "Numeric variable %s has invalid format specifier %s."
 msgstr "Numerieke variabele %s heeft een ongeldige formaat specificatie %s."
 
-#: src/data/por-file-reader.c:597
+#: src/data/por-file-reader.c:618
 #, c-format
 msgid "String variable %s with width %d has invalid format specifier %s."
 msgstr ""
 "String variabele %s met breedte %d heeft ongeldige formaat specificatie %s."
 
-#: src/data/por-file-reader.c:621
+#: src/data/por-file-reader.c:642
 msgid "Expected variable count record."
 msgstr "Variabele teller record verwacht."
 
-#: src/data/por-file-reader.c:625
+#: src/data/por-file-reader.c:646
 #, c-format
 msgid "Invalid number of variables %d."
 msgstr "Ongeldig aantal variabelen %d."
 
-#: src/data/por-file-reader.c:635
+#: src/data/por-file-reader.c:655
 #, c-format
 msgid "Weight variable name (%s) truncated."
 msgstr "Weging variabele naam (%s) afgekapt."
 
-#: src/data/por-file-reader.c:650
+#: src/data/por-file-reader.c:670
 msgid "Expected variable record."
 msgstr "Variabel record verwacht."
 
-#: src/data/por-file-reader.c:654
+#: src/data/por-file-reader.c:674
 #, c-format
 msgid "Invalid variable width %d."
 msgstr "Ongeldige variabele breedte %d."
 
-#: src/data/por-file-reader.c:662
+#: src/data/por-file-reader.c:681
 #, c-format
 msgid "Invalid variable name `%s' in position %d."
 msgstr "Ongeldige variabele naam '%s' in positie %d."
 
-#: src/data/por-file-reader.c:666
+#: src/data/por-file-reader.c:685 src/data/sys-file-reader.c:592
 #, c-format
 msgid "Bad width %d for variable %s."
 msgstr "Foutieve breedte %d voor variabele %s."
 
-#: src/data/por-file-reader.c:681
+#: src/data/por-file-reader.c:700
 #, c-format
 msgid "Duplicate variable name %s in position %d."
 msgstr "Dubbele variabele naam %s in positie %d."
 
-#: src/data/por-file-reader.c:682
+#: src/data/por-file-reader.c:701
 #, c-format
 msgid "Duplicate variable name %s in position %d renamed to %s."
 msgstr "Dubbele variabele naam %s in positie %d hernoemd naar %s."
 
-#: src/data/por-file-reader.c:725
+#: src/data/por-file-reader.c:750
 #, c-format
 msgid "Weighting variable %s not present in dictionary."
 msgstr "Weging variabele %s niet aanwezig in woordenboek."
 
-#: src/data/por-file-reader.c:772
+#: src/data/por-file-reader.c:794
 #, c-format
 msgid "Unknown variable %s while parsing value labels."
 msgstr "Onbekende variabele %s tijdens het ontleden van waarde labels."
 
-#: src/data/por-file-reader.c:775
+#: src/data/por-file-reader.c:797
 #, c-format
 msgid ""
 "Cannot assign value labels to %s and %s, which have different variable types."
@@ -633,26 +608,26 @@ msgstr ""
 "Kan geen waarde labels toekennen aan %s en %s, die verschillende variabele "
 "types hebben."
 
-#: src/data/por-file-writer.c:140
+#: src/data/por-file-writer.c:141
 #, c-format
 msgid "Invalid decimal digits count %d.  Treating as %d."
 msgstr "Ongeldige decimaal cijfers teller %d. Behandeld als %d."
 
-#: src/data/por-file-writer.c:160
+#: src/data/por-file-writer.c:161
 #, c-format
 msgid "Error opening \"%s\" for writing as a portable file: %s."
 msgstr ""
 "Fout tijdens openen \"%s\" voor het schrijven als een overdraagbaar "
 "(portable) bestand: %s."
 
-#: src/data/por-file-writer.c:500
+#: src/data/por-file-writer.c:506
 #, c-format
 msgid "An I/O error occurred writing portable file \"%s\"."
 msgstr ""
 "Een I/O fout opgetreden tijdens het schrijven van overdraagbaar (portable) "
 "bestand \"%s\"."
 
-#: src/data/psql-reader.c:42
+#: src/data/psql-reader.c:46
 msgid ""
 "Support for reading postgres databases was not compiled into this "
 "installation of PSPP"
@@ -660,16 +635,16 @@ msgstr ""
 "Ondersteuning voor het lezen van postgres databases was niet gecompileerd in "
 "deze installatie van PSPP"
 
-#: src/data/psql-reader.c:237
+#: src/data/psql-reader.c:242
 msgid "Memory error whilst opening psql source"
 msgstr "Geheugen fout tijdens het openen van psql source"
 
-#: src/data/psql-reader.c:243
+#: src/data/psql-reader.c:248
 #, c-format
 msgid "Error opening psql source: %s."
 msgstr "Fout tijdens openen psql source: %s."
 
-#: src/data/psql-reader.c:258
+#: src/data/psql-reader.c:263
 #, c-format
 msgid ""
 "Postgres server is version %s. Reading from versions earlier than 8.0 is not "
@@ -678,7 +653,7 @@ msgstr ""
 "Postgres server is versie %s. Lezen van versies ouder dan 8.0 wordt niet "
 "ondersteund."
 
-#: src/data/psql-reader.c:278
+#: src/data/psql-reader.c:283
 msgid ""
 "Connection is unencrypted, but unencrypted connections have not been "
 "permitted."
@@ -686,13 +661,13 @@ msgstr ""
 "Connectie is niet geëncrypt, maar niet geëncrypte connecties zijn niet "
 "toegestaan."
 
-#: src/data/psql-reader.c:317 src/data/psql-reader.c:342
-#: src/data/psql-reader.c:352
+#: src/data/psql-reader.c:322 src/data/psql-reader.c:347
+#: src/data/psql-reader.c:357
 #, c-format
 msgid "Error from psql source: %s."
 msgstr "Fout van psql source: %s."
 
-#: src/data/psql-reader.c:447
+#: src/data/psql-reader.c:452
 #, c-format
 msgid "Unsupported OID %d.  SYSMIS values will be inserted."
 msgstr "Niet ondersteunde OID %d. SYSMIS waarde wordt ingevoegd."
@@ -706,11 +681,11 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/scratch-writer.c:67 src/language/data-io/file-handle.q:181
+#: src/data/scratch-writer.c:66 src/language/data-io/file-handle.q:181
 msgid "scratch file"
 msgstr "scratch bestand"
 
-#: src/data/settings.c:685
+#: src/data/settings.c:686
 #, c-format
 msgid ""
 "%s: Custom currency string `%s' does not contain exactly three periods or "
@@ -723,143 +698,126 @@ msgstr ""
 msgid "Variable suffix too large."
 msgstr "Variabele achtervoegsel te lang."
 
+#: src/data/sys-file-reader.c:213
+#, fuzzy, c-format
+msgid "Recoded variable name duplicates an existing `%s' within system file."
+msgstr "Dubbele variabele naam '%s' binnen system file."
+
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:216 src/data/sys-file-writer.c:200
+#: src/data/sys-file-reader.c:276 src/data/sys-file-writer.c:203
 msgid "system file"
 msgstr "systeem bestand"
 
-#: src/data/sys-file-reader.c:223
+#: src/data/sys-file-reader.c:283
 #, c-format
 msgid "Error opening \"%s\" for reading as a system file: %s."
 msgstr ""
 "Fout bij het openen van \"%s\" voor het lezen als een systeem file: %s."
 
-#: src/data/sys-file-reader.c:262
+#: src/data/sys-file-reader.c:322
 msgid "Misplaced type 4 record."
 msgstr "Verkeerd geplaatst type 4 record. "
 
-#: src/data/sys-file-reader.c:273
+#: src/data/sys-file-reader.c:333
 #, c-format
 msgid "Unrecognized record type %d."
 msgstr "Niet herkend record type %d."
 
-#: src/data/sys-file-reader.c:312
+#: src/data/sys-file-reader.c:374
 #, c-format
 msgid "File header claims %d variable positions but %d were read from file."
 msgstr ""
 "Bestand kop claimt %d variabele posities maar er zijn er %d gelezen van het "
 "bestand."
 
-#: src/data/sys-file-reader.c:352
+#: src/data/sys-file-reader.c:414
 #, c-format
 msgid "Error closing system file \"%s\": %s."
 msgstr "Fout bij het sluiten van system file \"%s\": %s."
 
-#: src/data/sys-file-reader.c:417 src/data/sys-file-reader.c:427
+#: src/data/sys-file-reader.c:479 src/data/sys-file-reader.c:489
 msgid "This is not an SPSS system file."
 msgstr "Dit is geen SPSS systeem bestand."
 
-#: src/data/sys-file-reader.c:446
+#: src/data/sys-file-reader.c:511
 msgid ""
 "Compression bias is not the usual value of 100, or system file uses "
 "unrecognized floating-point format."
 msgstr ""
 
-#: src/data/sys-file-reader.c:514
+#: src/data/sys-file-reader.c:588
 #, c-format
 msgid "Invalid variable name `%s'."
 msgstr "Ongeldige variabele naam '%s'."
 
-#: src/data/sys-file-reader.c:518
-#, c-format
-msgid "Bad variable width %d."
-msgstr "Foutieve variabele breedte %d."
-
-#: src/data/sys-file-reader.c:522
+#: src/data/sys-file-reader.c:596
 #, c-format
 msgid "Duplicate variable name `%s' within system file."
 msgstr "Dubbele variabele naam '%s' binnen system file."
 
-#: src/data/sys-file-reader.c:530
+#: src/data/sys-file-reader.c:604
 msgid "Variable label indicator field is not 0 or 1."
 msgstr "Variabel label indicator veld is niet 0 of 1."
 
-#: src/data/sys-file-reader.c:538
+#: src/data/sys-file-reader.c:612
 #, c-format
 msgid "Variable %s has label of invalid length %zu."
 msgstr "Variabele %s heeft label van ongeldige lengte %zu."
 
-#: src/data/sys-file-reader.c:557
+#: src/data/sys-file-reader.c:631
 msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
 msgstr ""
 "Numeriek ontbrekende waarde indicator veld is niet -3, -2, 0, 1, 2, of 3."
 
-#: src/data/sys-file-reader.c:572
+#: src/data/sys-file-reader.c:649
 msgid "String missing value indicator field is not 0, 1, 2, or 3."
 msgstr "String missing waarde indicator veld is niet 0, 1, 2, of 3."
 
-#: src/data/sys-file-reader.c:575
-#, c-format
-msgid ""
-"Ignoring missing values on long string variable %s, which PSPP does not yet "
-"support."
-msgstr ""
-"Negeren van missing values voor lange string variabele %s, wat PSPP nog niet "
-"ondersteunt."
-
-#: src/data/sys-file-reader.c:604
+#: src/data/sys-file-reader.c:681
 msgid "Missing string continuation record."
 msgstr "Mis string continuering record."
 
-#: src/data/sys-file-reader.c:638
+#: src/data/sys-file-reader.c:715
 #, c-format
 msgid "Unknown variable format %<PRIu8>."
 msgstr "Onbekend variabele formaat %<PRIu8>."
 
-#: src/data/sys-file-reader.c:656
+#: src/data/sys-file-reader.c:733
 #, c-format
 msgid "%s variable %s has invalid %s format %s."
 msgstr "%s variabele %s heeft ongeldig %s formaat %s."
 
-#: src/data/sys-file-reader.c:659
+#: src/data/sys-file-reader.c:736
 msgid "print"
 msgstr "afdrukken"
 
-#: src/data/sys-file-reader.c:659
+#: src/data/sys-file-reader.c:736
 msgid "write"
 msgstr "schrijf"
 
-#: src/data/sys-file-reader.c:663
+#: src/data/sys-file-reader.c:740
 msgid "Suppressing further invalid format warnings."
 msgstr "Onderdrukt verdere ongeldige formaat waarschuwingen."
 
-#: src/data/sys-file-reader.c:681
+#: src/data/sys-file-reader.c:758
 msgid "Weighting variable must be numeric."
 msgstr "Weging variabele moet numeriek zijn."
 
-#: src/data/sys-file-reader.c:695
+#: src/data/sys-file-reader.c:772
 msgid "Multiple type 6 (document) records."
 msgstr "Meerdere type 6 (document) records."
 
-#: src/data/sys-file-reader.c:699
+#: src/data/sys-file-reader.c:776
 #, c-format
 msgid "Number of document lines (%d) must be greater than 0."
 msgstr "Aantal document regels (%d) moet groter dan 0 zijn."
 
-#: src/data/sys-file-reader.c:707
+#: src/data/sys-file-reader.c:784
 msgid "Document line contains null byte."
 msgstr "Document regel bevat null byte."
 
-#: src/data/sys-file-reader.c:793
-msgid ""
-"Ignoring value labels for long string variables, which PSPP does not yet "
-"support."
-msgstr ""
-"Negeer waarde labels voor lange string variabelen, die door PSPP nog niet "
-"ondersteund worden."
-
-#: src/data/sys-file-reader.c:798
+#: src/data/sys-file-reader.c:874
 #, c-format
 msgid ""
 "Unrecognized record type 7, subtype %d.  Please send a copy of this file, "
@@ -868,13 +826,13 @@ msgstr ""
 "Niet herkend type 7, subtype %d.  Stuur s.v.p. een kopie van dit bestand en "
 "de syntax waarmee het is aangemaakt naar %s "
 
-#: src/data/sys-file-reader.c:825
+#: src/data/sys-file-reader.c:901
 #, c-format
 msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
 msgstr ""
 "Foutieve lengte (%zu) of aantal (%zu) veld in record type 7, subtype 3."
 
-#: src/data/sys-file-reader.c:845
+#: src/data/sys-file-reader.c:921
 #, c-format
 msgid ""
 "Floating-point representation indicated by system file (%d) differs from "
@@ -883,15 +841,15 @@ msgstr ""
 "Drijvende komma representatie aangegeven door systeem bestand %d verschilt "
 "van verwachting (%d)."
 
-#: src/data/sys-file-reader.c:858
+#: src/data/sys-file-reader.c:934
 msgid "little-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:858
+#: src/data/sys-file-reader.c:934
 msgid "big-endian"
 msgstr ""
 
-#: src/data/sys-file-reader.c:859
+#: src/data/sys-file-reader.c:935
 #, c-format
 msgid ""
 "Integer format indicated by system file (%s) differs from expected (%s)."
@@ -899,37 +857,28 @@ msgstr ""
 "Integer formaat aangegeven door systeem bestand (%s) verschilt van verwacht "
 "(%s). "
 
-#: src/data/sys-file-reader.c:916
+#: src/data/sys-file-reader.c:992
 #, c-format
 msgid "Bad size (%zu) or count (%zu) on extension 4."
 msgstr "Foutieve lengte (%zu) of aantal (%zu) bij extensie 4."
 
-#: src/data/sys-file-reader.c:920
-#, c-format
-msgid "File specifies unexpected value %g as SYSMIS."
+#: src/data/sys-file-reader.c:996 src/data/sys-file-reader.c:1000
+#: src/data/sys-file-reader.c:1004
+#, fuzzy, c-format
+msgid "File specifies unexpected value %g as %s."
 msgstr "Bestand specificeert onverwachte waarde %g als SYSMIS."
 
-#: src/data/sys-file-reader.c:922
-#, c-format
-msgid "File specifies unexpected value %g as HIGHEST."
-msgstr "Bestand specificeert onverwachte waarde %g als HIGHEST."
-
-#: src/data/sys-file-reader.c:924
-#, c-format
-msgid "File specifies unexpected value %g as LOWEST."
-msgstr "Bestand specificeert onverwachte waarde %g als LOWEST."
-
-#: src/data/sys-file-reader.c:940
+#: src/data/sys-file-reader.c:1021
 #, c-format
 msgid "Bad size %zu on extension 11."
 msgstr "Foutieve lengte %zu voor extensie 11."
 
-#: src/data/sys-file-reader.c:952
+#: src/data/sys-file-reader.c:1033
 #, c-format
 msgid "Extension 11 has bad count %zu (for %zu variables)."
 msgstr "Extensie 11 heeft een foutief aantal %zu (voor %zu variabelen)."
 
-#: src/data/sys-file-reader.c:973
+#: src/data/sys-file-reader.c:1054
 #, c-format
 msgid ""
 "Invalid variable display parameters for variable %zu (%s).  Default "
@@ -938,22 +887,22 @@ msgstr ""
 "Ongeldige variabele toon parameters voor variabele %zu (%s).  Default "
 "parameters ingevuld."
 
-#: src/data/sys-file-reader.c:1017
+#: src/data/sys-file-reader.c:1098
 #, c-format
 msgid "Long variable mapping from %s to invalid variable name `%s'."
 msgstr "Lange variabele afbeelding van %s tot ongeldige naam '%s'. "
 
-#: src/data/sys-file-reader.c:1027
+#: src/data/sys-file-reader.c:1108
 #, c-format
 msgid "Duplicate long variable name `%s' within system file."
 msgstr "Dubbele lange variabele naam `%s' binnen systeem bestand."
 
-#: src/data/sys-file-reader.c:1080
+#: src/data/sys-file-reader.c:1161
 #, c-format
 msgid "%s listed as string of invalid length %s in very length string record."
 msgstr ""
 
-#: src/data/sys-file-reader.c:1090
+#: src/data/sys-file-reader.c:1171
 #, c-format
 msgid ""
 "%s listed in very long string record with width %s, which requires only one "
@@ -962,12 +911,12 @@ msgstr ""
 "%s vermeld in erg lang string record met breedte %s, dat slechts een segment "
 "vereist."
 
-#: src/data/sys-file-reader.c:1096
+#: src/data/sys-file-reader.c:1177
 #, c-format
 msgid "Very long string %s overflows dictionary."
 msgstr "Erg lange string %s is te groot voor woordenboek."
 
-#: src/data/sys-file-reader.c:1110
+#: src/data/sys-file-reader.c:1191
 #, c-format
 msgid ""
 "Very long string with width %ld has segment %d of width %d (expected %d)"
@@ -975,12 +924,12 @@ msgstr ""
 "Erg lange string met breedte %ld heeft segment %d van breedte %d (verwacht %"
 "d)"
 
-#: src/data/sys-file-reader.c:1155
+#: src/data/sys-file-reader.c:1237
 #, c-format
 msgid "Invalid number of labels: %d.  Ignoring labels."
 msgstr "Ongeldig aantal labels: %d. Labels worden genegeerd."
 
-#: src/data/sys-file-reader.c:1186
+#: src/data/sys-file-reader.c:1268
 msgid ""
 "Variable index record (type 4) does not immediately follow value label "
 "record (type 3) as it should."
@@ -988,7 +937,7 @@ msgstr ""
 "Variabele index record (type 4) volgt niet onmiddellijk waarde label record "
 "(type 3) zoals het moet."
 
-#: src/data/sys-file-reader.c:1193
+#: src/data/sys-file-reader.c:1275
 #, c-format
 msgid ""
 "Number of variables associated with a value label (%d) is not between 1 and "
@@ -997,12 +946,14 @@ msgstr ""
 "Aantal variabelen geassocieerd aan waarde label (%d) is niet tussen 1 en het "
 "aantal variabelen (%zu)."
 
-#: src/data/sys-file-reader.c:1203
-#, c-format
-msgid "Value labels are not allowed on long string variables (%s)."
+#: src/data/sys-file-reader.c:1286
+#, fuzzy, c-format
+msgid ""
+"Value labels may not be added to long string variables (e.g. %s) using "
+"records types 3 and 4."
 msgstr "Waarde labels zijn niet toegestaan bij lange string variabelen (%s)."
 
-#: src/data/sys-file-reader.c:1210
+#: src/data/sys-file-reader.c:1295
 #, c-format
 msgid ""
 "Variables associated with value label are not all of identical type.  "
@@ -1011,87 +962,120 @@ msgstr ""
 "Variabelen geassocieerd met waarde label zijn niet allemaal van het "
 "identieke type.  Variabele %s is %s, maar variabele %s is %s."
 
-#: src/data/sys-file-reader.c:1243
+#: src/data/sys-file-reader.c:1329
 #, c-format
 msgid "Duplicate value label for %g on %s."
 msgstr "Dubbel waarde label voor %g op %s."
 
-#: src/data/sys-file-reader.c:1246
+#: src/data/sys-file-reader.c:1332 src/data/sys-file-reader.c:1513
 #, c-format
 msgid "Duplicate value label for \"%.*s\" on %s."
 msgstr "Dubbel waarde label voor \"%.*s\" on %s."
 
-#: src/data/sys-file-reader.c:1284
+#: src/data/sys-file-reader.c:1370
 #, c-format
 msgid "Error parsing attribute value %s[%d]"
 msgstr "Fout bij het ontleden van attribuut waarde %s[%d]"
 
-#: src/data/sys-file-reader.c:1298
+#: src/data/sys-file-reader.c:1384
 #, c-format
 msgid "Attribute value %s[%d] is not quoted: %s"
 msgstr "Attribuut waarde %s[%d] is niet geciteerd: %s"
 
-#: src/data/sys-file-reader.c:1414
+#: src/data/sys-file-reader.c:1447
+#, c-format
+msgid ""
+"Variable name length in long string value label record (%d) exceeds %d-byte "
+"limit."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1457
+#, fuzzy, c-format
+msgid "Ignoring long string value record for unknown variable %s."
+msgstr "Variabele afbeelding refereert aan onbekende variabele %s."
+
+#: src/data/sys-file-reader.c:1464
+#, fuzzy, c-format
+msgid "Ignoring long string value record for numeric variable %s."
+msgstr ""
+"Kan missing values uit bron bestand niet toepassen op lange string variabele "
+"%s."
+
+#: src/data/sys-file-reader.c:1471
+#, c-format
+msgid ""
+"Ignoring long string value record for variable %s because the record's width "
+"(%d) does not match the variable's width (%d)"
+msgstr ""
+
+#: src/data/sys-file-reader.c:1493
+#, c-format
+msgid ""
+"Ignoring long string value %zu for variable %s, with width %d, that has bad "
+"value width %zu."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1608
 msgid "File ends in partial case."
 msgstr "Bestand eindigt in gedeeltelijke case."
 
-#: src/data/sys-file-reader.c:1422
+#: src/data/sys-file-reader.c:1616
 #, c-format
 msgid "Error reading case from file %s."
 msgstr "Fout tijdens lezen case van bestand %s."
 
-#: src/data/sys-file-reader.c:1519 src/data/sys-file-reader.c:1555
+#: src/data/sys-file-reader.c:1713 src/data/sys-file-reader.c:1749
 msgid "Compressed data is corrupt."
 msgstr "Gecomprimeerde data is corrupt."
 
-#: src/data/sys-file-reader.c:1642
+#: src/data/sys-file-reader.c:1836
 #, c-format
 msgid "Variable index %d not in valid range 1...%d."
 msgstr "Variabele index %d niet in geldige range 1...%d."
 
-#: src/data/sys-file-reader.c:1647
+#: src/data/sys-file-reader.c:1841
 #, c-format
 msgid "Variable index %d refers to long string continuation."
 msgstr "Variabele index %d verwijst naar lange string voortzetting."
 
-#: src/data/sys-file-reader.c:1715
+#: src/data/sys-file-reader.c:1909
 #, c-format
 msgid "Suppressed %d additional related warnings."
 msgstr "Onderdrukt %d extra gerelateerde waarschuwingen."
 
-#: src/data/sys-file-reader.c:1756
+#: src/data/sys-file-reader.c:1950
 #, c-format
 msgid "Variable map refers to unknown variable %s."
 msgstr "Variabele afbeelding refereert aan onbekende variabele %s."
 
-#: src/data/sys-file-reader.c:1864
+#: src/data/sys-file-reader.c:2058
 #, c-format
 msgid "System error: %s."
 msgstr "Systeem fout: %s."
 
-#: src/data/sys-file-reader.c:1866
+#: src/data/sys-file-reader.c:2060
 msgid "Unexpected end of file."
 msgstr "Onverwacht bestand einde."
 
-#: src/data/sys-file-writer.c:173
+#: src/data/sys-file-writer.c:176
 #, c-format
 msgid "Unknown system file version %d. Treating as version %d."
 msgstr "Onbekende systeem bestand versie %d. Behandeld als versie %d."
 
-#: src/data/sys-file-writer.c:212
+#: src/data/sys-file-writer.c:215
 #, c-format
 msgid "Error opening \"%s\" for writing as a system file: %s."
 msgstr ""
 "Fout bij het openen van \"%s\" voor het schrijven als een systeem bestand: %"
 "s."
 
-#: src/data/sys-file-writer.c:837
+#: src/data/sys-file-writer.c:923
 #, c-format
 msgid "An I/O error occurred writing system file \"%s\"."
 msgstr ""
 "Een I/O fout is opgetreden tijdens het schrijven van systeem bestand \"%s\"."
 
-#: src/data/variable.c:240
+#: src/data/variable.c:242
 #, c-format
 msgid ""
 "Character `%c' (in %s) may not appear as the first character in a variable "
@@ -1100,31 +1084,31 @@ msgstr ""
 "Karakter '%c' (in %s) mag niet als eerste karakter in een variabele naam "
 "voorkomen. "
 
-#: src/data/variable.c:252
+#: src/data/variable.c:254
 #, c-format
 msgid "Character `%c' (in %s) may not appear in a variable name."
 msgstr "Karakter '%c' (in %s) mag niet in een variabele naam voorkomen."
 
-#: src/data/variable.c:280
+#: src/data/variable.c:282
 msgid "Variable name cannot be empty string."
 msgstr "Variabele naam kan geen lege string zijn."
 
-#: src/data/variable.c:286
+#: src/data/variable.c:288
 #, c-format
 msgid "Variable name %s exceeds %d-character limit."
 msgstr "Variabele naam %s overschrijdt de limiet van %d-karakters."
 
-#: src/data/variable.c:294
+#: src/data/variable.c:296
 #, c-format
 msgid "`%s' may not be used as a variable name because it is a reserved word."
 msgstr ""
 "'%s' mag niet gebruikt worden als variabele naam omdat het een gereserveerd "
 "woord is."
 
-#: src/language/command.c:208
+#: src/language/command.c:208 src/language/expressions/parse.c:1267
 #, c-format
-msgid "%s is unimplemented."
-msgstr "%s is niet geïmplementeerd."
+msgid "%s is not yet implemented."
+msgstr "%s is nog niet geïmplementeerd."
 
 #: src/language/command.c:214
 #, c-format
@@ -1424,7 +1408,7 @@ msgstr ""
 "Variabele naam %s gespecificeerd op %s subopdracht dupliceert een bestaande "
 "variabele naam."
 
-#: src/language/data-io/combine-files.c:757
+#: src/language/data-io/combine-files.c:762
 #, c-format
 msgid "Encountered %zu sets of duplicate cases in the master file."
 msgstr "Ontmoet %zu sets van dubbele cases in het master bestand. "
@@ -1476,22 +1460,22 @@ msgid "Cannot place variable %s on record %d when RECORDS=%d is specified."
 msgstr ""
 "Kan variabele %s niet plaatsen in record %d als RECORDS=%d is gespecificeerd."
 
-#: src/language/data-io/data-parser.c:458
-#: src/language/data-io/data-parser.c:467
+#: src/language/data-io/data-parser.c:460
+#: src/language/data-io/data-parser.c:469
 msgid "Quoted string extends beyond end of line."
 msgstr "Geciteerde string loopt door na regeleinde."
 
-#: src/language/data-io/data-parser.c:522
+#: src/language/data-io/data-parser.c:525
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr "Gedeeltelijke case van %d van %d records genegeerd."
 
-#: src/language/data-io/data-parser.c:568
+#: src/language/data-io/data-parser.c:572
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr "Gedeeltelijke case overgeslagen. De eerste gemiste variabele was %s."
 
-#: src/language/data-io/data-parser.c:605
+#: src/language/data-io/data-parser.c:610
 #, c-format
 msgid ""
 "Missing value(s) for all variables from %s onward.  These will be filled "
@@ -1500,43 +1484,43 @@ msgstr ""
 "Missing value(s) voor alle variabelen vanaf %s. Deze worden gevuld met de "
 "geschikte system-missing waarde of spatie."
 
-#: src/language/data-io/data-parser.c:624
+#: src/language/data-io/data-parser.c:630
 msgid "Record ends in data not part of any field."
 msgstr "Record eindigd in data die geen onderdeel is van een veld."
 
-#: src/language/data-io/data-parser.c:644
-#: src/language/data-io/data-parser.c:685 src/language/data-io/print.c:403
+#: src/language/data-io/data-parser.c:650
+#: src/language/data-io/data-parser.c:691 src/language/data-io/print.c:404
 #: src/language/dictionary/split-file.c:84
 #: src/language/dictionary/sys-file-info.c:169
 #: src/language/dictionary/sys-file-info.c:393
-#: src/language/dictionary/sys-file-info.c:716
-#: src/language/stats/descriptives.c:885 src/ui/gui/psppire-dictview.c:502
+#: src/language/dictionary/sys-file-info.c:725
+#: src/language/stats/descriptives.c:885 src/ui/gui/psppire-dictview.c:491
 msgid "Variable"
 msgstr "Variabele"
 
-#: src/language/data-io/data-parser.c:645 src/language/data-io/print.c:404
+#: src/language/data-io/data-parser.c:651 src/language/data-io/print.c:405
 msgid "Record"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:646 src/language/data-io/print.c:405
-#: src/ui/gui/crosstabs.glade:92 src/ui/gui/psppire-var-sheet.c:545
-#: src/ui/gui/psppire-var-store.c:791
+#: src/language/data-io/data-parser.c:652 src/language/data-io/print.c:406
+#: src/ui/gui/crosstabs.glade:92 src/ui/gui/psppire-var-sheet.c:537
+#: src/ui/gui/psppire-var-store.c:839
 msgid "Columns"
 msgstr "Kolommen"
 
-#: src/language/data-io/data-parser.c:647
-#: src/language/data-io/data-parser.c:686 src/language/data-io/print.c:406
+#: src/language/data-io/data-parser.c:653
+#: src/language/data-io/data-parser.c:692 src/language/data-io/print.c:407
 msgid "Format"
 msgstr "Formaat"
 
-#: src/language/data-io/data-parser.c:666
+#: src/language/data-io/data-parser.c:672
 #, c-format
 msgid "Reading %d record from %s."
 msgid_plural "Reading %d records from %s."
 msgstr[0] "Lezen %d record van %s."
 msgstr[1] "Lezen %d records van %s."
 
-#: src/language/data-io/data-parser.c:702
+#: src/language/data-io/data-parser.c:708
 #, c-format
 msgid "Reading free-form data from %s."
 msgstr "Lezen vrij-formaat data van %s."
@@ -1746,19 +1730,19 @@ msgstr ""
 "Het gespecificeerde record nummer, %ld, overschrijdt het aantal records per "
 "case zoals gespecificeerd in FIXCASE, %d."
 
-#: src/language/data-io/inpt-pgm.c:129
+#: src/language/data-io/inpt-pgm.c:130
 msgid "Unexpected end-of-file within INPUT PROGRAM."
 msgstr "Onverwacht einde-bestand binnen INPUT PROGRAM."
 
-#: src/language/data-io/inpt-pgm.c:142
+#: src/language/data-io/inpt-pgm.c:143
 msgid "Input program did not create any variables."
 msgstr "Input program heeft geen variabelen gecreëerd."
 
-#: src/language/data-io/inpt-pgm.c:286
+#: src/language/data-io/inpt-pgm.c:288
 msgid "COLUMN subcommand multiply specified."
 msgstr "COLUMN subopdracht meerdere keren gespecificeerd."
 
-#: src/language/data-io/inpt-pgm.c:336
+#: src/language/data-io/inpt-pgm.c:338
 msgid ""
 "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr ""
@@ -1847,31 +1831,31 @@ msgstr "Kolom posities voor velden mogen niet negatief zijn."
 msgid "The ending column for a field must be greater than the starting column."
 msgstr "De eind kolom van een veld moet groter zijn dan de start kolom."
 
-#: src/language/data-io/print.c:178 src/language/data-io/trim.c:54
+#: src/language/data-io/print.c:179 src/language/data-io/trim.c:54
 msgid "expecting a valid subcommand"
 msgstr "een geldig subopdracht verwacht"
 
-#: src/language/data-io/print.c:266
+#: src/language/data-io/print.c:267
 #, c-format
 msgid "Output calls for %d records but %zu specified on RECORDS subcommand."
 msgstr ""
 "De output vraagt %d records maar %zu gespecificeerd bij RECORDS subopdracht. "
 
-#: src/language/data-io/print.c:436
+#: src/language/data-io/print.c:438
 #, c-format
 msgid "Writing %d record to %s."
 msgid_plural "Writing %d records to %s."
 msgstr[0] "Schrijven van %d record naar %s."
 msgstr[1] "Schrijven van %d records naar %s."
 
-#: src/language/data-io/print.c:440
+#: src/language/data-io/print.c:442
 #, c-format
 msgid "Writing %d record."
 msgid_plural "Writing %d records."
 msgstr[0] "Schrijven van %d record."
 msgstr[1] "Schrijven van %d records."
 
-#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:479
+#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:478
 #: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:60
 msgid "expecting end of command"
 msgstr "verwacht einde van opdracht "
@@ -1932,22 +1916,7 @@ msgstr "Kan niet alle variabelen DROP-en uit woordenboek."
 msgid "Variable %s is %s in target file, but %s in source file."
 msgstr "Variabele %s is %s in doel bestand, maar %s in bron bestand."
 
-#: src/language/dictionary/apply-dictionary.c:99
-#, c-format
-msgid "Cannot add value labels from source file to long string variable %s."
-msgstr ""
-"Kan geen value labels van bron bestand toevoegen aan lange string variabele %"
-"s."
-
-#: src/language/dictionary/apply-dictionary.c:113
-#, c-format
-msgid ""
-"Cannot apply missing values from source file to long string variable %s."
-msgstr ""
-"Kan missing values uit bron bestand niet toepassen op lange string variabele "
-"%s."
-
-#: src/language/dictionary/apply-dictionary.c:129
+#: src/language/dictionary/apply-dictionary.c:115
 msgid "No matching variables found between the source and target files."
 msgstr ""
 "Geen overeenkomende variabelen gevonden tussen het bron en het doel bestand."
@@ -1998,12 +1967,12 @@ msgstr ""
 "Kan numerieke variabelen (b.v. %s) en string variabelen (b.v. %s) niet mixen "
 "binnen een enkele lijst."
 
-#: src/language/dictionary/missing-values.c:117
-#, c-format
-msgid "Truncating missing value to short string length (%d characters)."
+#: src/language/dictionary/missing-values.c:116
+#, fuzzy, c-format
+msgid "Truncating missing value to maximum acceptable length (%d bytes)."
 msgstr "Afkappen missing value naar short string lengte (%d karakters)."
 
-#: src/language/dictionary/missing-values.c:139
+#: src/language/dictionary/missing-values.c:138
 #, c-format
 msgid "Missing values provided are too long to assign to variable of width %d."
 msgstr ""
@@ -2134,21 +2103,21 @@ msgid "Renaming would duplicate variable name %s."
 msgstr "Hernoemen zou variabele naam %s dupliceren."
 
 #: src/language/dictionary/split-file.c:85
-#: src/language/dictionary/sys-file-info.c:487
-#: src/language/dictionary/sys-file-info.c:636
-#: src/language/stats/crosstabs.q:1167 src/language/stats/crosstabs.q:1194
-#: src/language/stats/crosstabs.q:1214 src/language/stats/crosstabs.q:1236
-#: src/language/stats/examine.q:1958 src/language/stats/frequencies.q:1059
-#: src/language/stats/frequencies.q:1184 src/language/stats/reliability.q:581
-#: src/language/stats/reliability.q:592
+#: src/language/dictionary/sys-file-info.c:486
+#: src/language/dictionary/sys-file-info.c:641
+#: src/language/stats/crosstabs.q:1235 src/language/stats/crosstabs.q:1262
+#: src/language/stats/crosstabs.q:1286 src/language/stats/crosstabs.q:1311
+#: src/language/stats/examine.q:1959 src/language/stats/frequencies.q:1051
+#: src/language/stats/frequencies.q:1176 src/language/stats/reliability.q:582
+#: src/language/stats/reliability.q:593
 msgid "Value"
 msgstr "Waarde"
 
 #: src/language/dictionary/split-file.c:86
 #: src/language/dictionary/sys-file-info.c:397
-#: src/language/dictionary/sys-file-info.c:637 src/ui/gui/crosstabs.glade:275
-#: src/ui/gui/psppire.glade:1999 src/ui/gui/psppire-var-sheet.c:542
-#: src/ui/gui/psppire-var-store.c:788
+#: src/language/dictionary/sys-file-info.c:642 src/ui/gui/crosstabs.glade:275
+#: src/ui/gui/psppire.glade:1974 src/ui/gui/psppire-var-sheet.c:534
+#: src/ui/gui/psppire-var-store.c:836
 msgid "Label"
 msgstr ""
 
@@ -2156,7 +2125,7 @@ msgstr ""
 msgid "File:"
 msgstr "Bestand:"
 
-#: src/language/dictionary/sys-file-info.c:115 src/ui/gui/psppire.glade:1938
+#: src/language/dictionary/sys-file-info.c:115 src/ui/gui/psppire.glade:1913
 #: src/ui/gui/recode.glade:841
 msgid "Label:"
 msgstr ""
@@ -2268,7 +2237,7 @@ msgstr "Omschrijving"
 
 #: src/language/dictionary/sys-file-info.c:171
 #: src/language/dictionary/sys-file-info.c:399
-#: src/language/dictionary/sys-file-info.c:715
+#: src/language/dictionary/sys-file-info.c:724
 msgid "Position"
 msgstr "Positie"
 
@@ -2296,16 +2265,16 @@ msgstr "Het actieve bestand woordenboek bevat geen documenten."
 msgid "Documents in the active file:"
 msgstr "Documenten in het actieve bestand:"
 
-#: src/language/dictionary/sys-file-info.c:486
+#: src/language/dictionary/sys-file-info.c:485
 msgid "Attribute"
 msgstr "Attribuut"
 
-#: src/language/dictionary/sys-file-info.c:544
+#: src/language/dictionary/sys-file-info.c:543
 #, c-format
 msgid "Format: %s"
 msgstr "Formaat: %s"
 
-#: src/language/dictionary/sys-file-info.c:551
+#: src/language/dictionary/sys-file-info.c:550
 #, c-format
 msgid "Print Format: %s"
 msgstr "Print Formaat: %s"
@@ -2315,89 +2284,72 @@ msgstr "Print Formaat: %s"
 msgid "Write Format: %s"
 msgstr "Schrijf Formaat: %s"
 
-#: src/language/dictionary/sys-file-info.c:566
+#: src/language/dictionary/sys-file-info.c:567
 #, c-format
 msgid "Measure: %s"
 msgstr "Meting: %s"
 
-#: src/language/dictionary/sys-file-info.c:567
+#: src/language/dictionary/sys-file-info.c:568
 #: src/ui/gui/psppire-var-sheet.c:111
 msgid "Nominal"
 msgstr "Nominaal"
 
-#: src/language/dictionary/sys-file-info.c:568
+#: src/language/dictionary/sys-file-info.c:569
 #: src/ui/gui/psppire-var-sheet.c:112
 msgid "Ordinal"
 msgstr "Ordinaal"
 
-#: src/language/dictionary/sys-file-info.c:569
+#: src/language/dictionary/sys-file-info.c:570
 #: src/ui/gui/psppire-var-sheet.c:113
 msgid "Scale"
 msgstr "Schaal"
 
-#: src/language/dictionary/sys-file-info.c:572
+#: src/language/dictionary/sys-file-info.c:573
 #, c-format
 msgid "Display Alignment: %s"
 msgstr "Toon Groepering: %s"
 
-#: src/language/dictionary/sys-file-info.c:573
+#: src/language/dictionary/sys-file-info.c:574
 #: src/ui/gui/psppire-var-sheet.c:104
 msgid "Left"
 msgstr "Links"
 
-#: src/language/dictionary/sys-file-info.c:574
+#: src/language/dictionary/sys-file-info.c:575
 #: src/ui/gui/psppire-var-sheet.c:106
 msgid "Center"
 msgstr "Centreer"
 
-#: src/language/dictionary/sys-file-info.c:575
+#: src/language/dictionary/sys-file-info.c:576
 #: src/ui/gui/psppire-var-sheet.c:105
 msgid "Right"
 msgstr "Rechts"
 
-#: src/language/dictionary/sys-file-info.c:578
+#: src/language/dictionary/sys-file-info.c:579
 #, c-format
 msgid "Display Width: %d"
 msgstr "Toonbreedte: %d"
 
-#: src/language/dictionary/sys-file-info.c:590
+#: src/language/dictionary/sys-file-info.c:593
 msgid "Missing Values: "
 msgstr "Ontbrekende Waardes:"
 
-#: src/language/dictionary/sys-file-info.c:693
+#: src/language/dictionary/sys-file-info.c:702
 msgid "No vectors defined."
 msgstr "Geen vectoren gedefinieerd."
 
-#: src/language/dictionary/sys-file-info.c:714
+#: src/language/dictionary/sys-file-info.c:723
 msgid "Vector"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:717
+#: src/language/dictionary/sys-file-info.c:726
 msgid "Print Format"
 msgstr "Print Formaat"
 
-#: src/language/dictionary/value-labels.c:121
-#, c-format
-msgid ""
-"It is not possible to assign value labels to long string variables such as %"
-"s."
-msgstr ""
-"Het is niet mogelijk om waarde labels aan lange string variabelen als %s toe "
-"te kennen."
-
-#: src/language/dictionary/value-labels.c:157 src/language/lexer/lexer.c:632
-msgid "expecting string"
-msgstr "string verwacht"
-
-#: src/language/dictionary/value-labels.c:166 src/language/lexer/lexer.c:659
-msgid "expecting number"
-msgstr "nummer verwacht"
-
-#: src/language/dictionary/value-labels.c:182
+#: src/language/dictionary/value-labels.c:150
 msgid "Truncating value label to 60 characters."
 msgstr "Afkappen waarde label tot 60 karakters."
 
-#: src/language/dictionary/variable-display.c:119
+#: src/language/dictionary/variable-display.c:120
 msgid "Variable display width must be a positive integer."
 msgstr "Variabele toonbreedte moet een positieve integer zijn."
 
@@ -2449,11 +2401,11 @@ msgstr "De weging variabele moet numeriek zijn."
 msgid "The weighting variable may not be scratch."
 msgstr "De weging variabele mag geen scratch zijn."
 
-#: src/language/expressions/evaluate.c:154
+#: src/language/expressions/evaluate.c:155
 msgid "expecting number or string"
 msgstr "verwacht nummer of string"
 
-#: src/language/expressions/evaluate.c:168
+#: src/language/expressions/evaluate.c:169
 #, c-format
 msgid "Duplicate variable name %s."
 msgstr "Dubbele variabele naam %s."
@@ -2640,11 +2592,6 @@ msgstr "verwacht ',' of ')' bij aanroep %s functie"
 msgid "%s is a PSPP extension."
 msgstr "%s is een PSPP extensie."
 
-#: src/language/expressions/parse.c:1267
-#, c-format
-msgid "%s is not yet implemented."
-msgstr "%s is nog niet geïmplementeerd."
-
 #: src/language/expressions/parse.c:1273
 #, c-format
 msgid "%s may not appear after TEMPORARY."
@@ -2664,89 +2611,92 @@ msgid "%s does not form a valid number."
 msgstr "%s vormt geen geldig nummer."
 
 #: src/language/lexer/lexer.c:389
-#, c-format
-msgid "Bad character in input: `%c'."
+#, fuzzy, c-format
+msgid "Bad character in input: `%s'."
 msgstr "Fout karakter in input: '%c'."
 
-#: src/language/lexer/lexer.c:391
-#, c-format
-msgid "Bad character in input: `\\%o'."
-msgstr "Fout karakter in input: '\\%o'."
-
-#: src/language/lexer/lexer.c:427
+#: src/language/lexer/lexer.c:426
 #, c-format
 msgid "Subcommand %s may only be specified once."
 msgstr "Subopdracht %s mag slechts een keer gespecificeerd worden."
 
-#: src/language/lexer/lexer.c:435
+#: src/language/lexer/lexer.c:434
 #, c-format
 msgid "missing required subcommand %s"
 msgstr "mis verplichte subopdracht %s"
 
-#: src/language/lexer/lexer.c:464
+#: src/language/lexer/lexer.c:463
 #, c-format
 msgid "Syntax error %s at %s."
 msgstr "Syntax fout %s op %s."
 
-#: src/language/lexer/lexer.c:467
+#: src/language/lexer/lexer.c:466
 #, c-format
 msgid "Syntax error at %s."
 msgstr "Syntax fout op %s."
 
-#: src/language/lexer/lexer.c:601 src/language/lexer/lexer.c:618
+#: src/language/lexer/lexer.c:600 src/language/lexer/lexer.c:617
 #, c-format
 msgid "expecting `%s'"
 msgstr "verwacht '%s'"
 
-#: src/language/lexer/lexer.c:646
+#: src/language/lexer/lexer.c:631
+msgid "expecting string"
+msgstr "string verwacht"
+
+#: src/language/lexer/lexer.c:645
 msgid "expecting integer"
 msgstr "verwacht integer"
 
-#: src/language/lexer/lexer.c:671
+#: src/language/lexer/lexer.c:658
+msgid "expecting number"
+msgstr "nummer verwacht"
+
+#: src/language/lexer/lexer.c:670
 msgid "expecting identifier"
 msgstr "verwacht herkenningsteken"
 
-#: src/language/lexer/lexer.c:1065
+#: src/language/lexer/lexer.c:1064
 msgid "binary"
 msgstr "binair"
 
-#: src/language/lexer/lexer.c:1070
+#: src/language/lexer/lexer.c:1069
 msgid "octal"
 msgstr "octaal"
 
-#: src/language/lexer/lexer.c:1075
+#: src/language/lexer/lexer.c:1074
 msgid "hex"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1085
+#: src/language/lexer/lexer.c:1084
 #, c-format
 msgid "String of %s digits has %zu characters, which is not a multiple of %d."
 msgstr ""
 "String van %s cijfers heeft %zu karakters, wat geen meervoud van %d is."
 
-#: src/language/lexer/lexer.c:1114
+#: src/language/lexer/lexer.c:1113
 #, c-format
 msgid "`%c' is not a valid %s digit."
 msgstr "'%c' is geen geldig %s cijfer."
 
-#: src/language/lexer/lexer.c:1148
+#: src/language/lexer/lexer.c:1147
 msgid "Unterminated string constant."
 msgstr "Geen einde aan string constante."
 
-#: src/language/lexer/lexer.c:1202
+#: src/language/lexer/lexer.c:1201
 msgid "Unexpected end of file in string concatenation."
 msgstr "Onverwacht bestandseinde in string samenvoeging."
 
-#: src/language/lexer/lexer.c:1210
+#: src/language/lexer/lexer.c:1209
 msgid "String expected following `+'."
 msgstr "String verwacht achter '+'."
 
-#: src/language/lexer/lexer.c:1223
+#: src/language/lexer/lexer.c:1222
 #, c-format
 msgid "String exceeds 255 characters in length (%zu characters)."
 msgstr "String overschrijdt de lengte van 255 karakters (%zu karakters)."
 
-#: src/language/lexer/range-parser.c:60
+#: src/language/lexer/value-parser.c:60
 #, c-format
 msgid ""
 "Low end of range (%g) is below high end (%g).  The range will be treated as "
@@ -2755,20 +2705,20 @@ msgstr ""
 "Ondergrens van range (%g) is lager dan bovengrens (%g). De range wordt "
 "behandeld als omgekeerd."
 
-#: src/language/lexer/range-parser.c:68
+#: src/language/lexer/value-parser.c:68
 #, c-format
 msgid "Ends of range are equal (%g)."
 msgstr "Eindes van range zijn gelijk (%g)."
 
-#: src/language/lexer/range-parser.c:76
+#: src/language/lexer/value-parser.c:76
 msgid "LO or LOWEST must be part of a range."
 msgstr "LO of LOWEST moet een onderdeel van een range zijn."
 
-#: src/language/lexer/range-parser.c:108
+#: src/language/lexer/value-parser.c:109
 msgid "System-missing value is not valid here."
 msgstr "System-missing waarde is hier niet geldig."
 
-#: src/language/lexer/range-parser.c:116
+#: src/language/lexer/value-parser.c:117
 msgid "expecting number or data string"
 msgstr "nummer of data string verwacht"
 
@@ -2940,63 +2890,63 @@ msgstr "Doel variabele %s dupliceert bestaande variabele %s."
 msgid "Duplicate variable name %s among target variables."
 msgstr "Dubbele variabele naam %s tussen doel variabelen."
 
-#: src/language/stats/binomial.c:142
+#: src/language/stats/binomial.c:141
 #, c-format
 msgid "Variable %s is not dichotomous"
 msgstr "Variabele %s is niet dichotomisch "
 
-#: src/language/stats/binomial.c:207
+#: src/language/stats/binomial.c:194
 msgid "Binomial Test"
 msgstr ""
 
-#: src/language/stats/binomial.c:238
+#: src/language/stats/binomial.c:224
 msgid "Group1"
 msgstr "Groep1 "
 
-#: src/language/stats/binomial.c:239
+#: src/language/stats/binomial.c:225
 msgid "Group2"
 msgstr "Groep2"
 
-#: src/language/stats/binomial.c:240 src/language/stats/chisquare.c:224
-#: src/language/stats/chisquare.c:284 src/language/stats/crosstabs.q:868
-#: src/language/stats/crosstabs.q:1074 src/language/stats/crosstabs.q:1797
-#: src/language/stats/examine.q:1214 src/language/stats/frequencies.q:1136
-#: src/language/stats/oneway.q:305 src/language/stats/oneway.q:475
-#: src/language/stats/regression.q:309 src/language/stats/reliability.q:717
-#: src/language/stats/sign.c:93 src/language/stats/wilcoxon.c:246
+#: src/language/stats/binomial.c:226 src/language/stats/chisquare.c:202
+#: src/language/stats/chisquare.c:262 src/language/stats/crosstabs.q:845
+#: src/language/stats/crosstabs.q:1172 src/language/stats/crosstabs.q:1596
+#: src/language/stats/examine.q:1216 src/language/stats/frequencies.q:1128
+#: src/language/stats/oneway.q:305 src/language/stats/oneway.q:476
+#: src/language/stats/regression.q:309 src/language/stats/reliability.q:718
+#: src/language/stats/sign.c:94 src/language/stats/wilcoxon.c:262
 #: src/ui/gui/crosstabs-dialog.c:59
 msgid "Total"
 msgstr "Totaal"
 
-#: src/language/stats/binomial.c:273 src/language/stats/chisquare.c:247
-#: src/language/stats/crosstabs.q:1192 src/language/stats/crosstabs.q:1233
+#: src/language/stats/binomial.c:259 src/language/stats/chisquare.c:225
+#: src/language/stats/crosstabs.q:1260 src/language/stats/crosstabs.q:1308
 msgid "Category"
 msgstr "Categorie"
 
-#: src/language/stats/binomial.c:274 src/language/stats/crosstabs.q:878
-#: src/language/stats/examine.q:1287 src/language/stats/frequencies.q:1407
+#: src/language/stats/binomial.c:260 src/language/stats/crosstabs.q:852
+#: src/language/stats/examine.q:1289 src/language/stats/frequencies.q:1399
 #: src/language/stats/npar-summary.c:123 src/language/stats/oneway.q:389
-#: src/language/stats/reliability.q:720 src/language/stats/sign.c:73
-#: src/language/stats/t-test.q:700 src/language/stats/t-test.q:724
-#: src/language/stats/t-test.q:863 src/language/stats/t-test.q:1425
-#: src/language/stats/wilcoxon.c:229
+#: src/language/stats/reliability.q:721 src/language/stats/sign.c:74
+#: src/language/stats/t-test.q:506 src/language/stats/t-test.q:526
+#: src/language/stats/t-test.q:626 src/language/stats/t-test.q:1105
+#: src/language/stats/wilcoxon.c:245
 msgid "N"
 msgstr ""
 
-#: src/language/stats/binomial.c:275
+#: src/language/stats/binomial.c:261
 msgid "Observed Prop."
 msgstr ""
 
-#: src/language/stats/binomial.c:276
+#: src/language/stats/binomial.c:262
 msgid "Test Prop."
 msgstr ""
 
-#: src/language/stats/binomial.c:279
+#: src/language/stats/binomial.c:265
 #, c-format
 msgid "Exact Sig. (%d-tailed)"
 msgstr ""
 
-#: src/language/stats/chisquare.c:194
+#: src/language/stats/chisquare.c:172
 #, c-format
 msgid ""
 "CHISQUARE test specified %d expected values, but %d distinct values were "
@@ -3005,332 +2955,327 @@ msgstr ""
 "CHISQUARE test specificeert %d verwachte waardes, maar %d verschillende "
 "waardes werden gevonden in variabele %s."
 
-#: src/language/stats/chisquare.c:208 src/language/stats/chisquare.c:248
+#: src/language/stats/chisquare.c:186 src/language/stats/chisquare.c:226
 msgid "Observed N"
 msgstr "Waargenomen N"
 
-#: src/language/stats/chisquare.c:209 src/language/stats/chisquare.c:249
+#: src/language/stats/chisquare.c:187 src/language/stats/chisquare.c:227
 msgid "Expected N"
 msgstr "Verwacht N"
 
-#: src/language/stats/chisquare.c:210 src/language/stats/chisquare.c:250
+#: src/language/stats/chisquare.c:188 src/language/stats/chisquare.c:228
 #: src/language/stats/regression.q:308 src/ui/gui/crosstabs-dialog.c:61
 msgid "Residual"
 msgstr "Overblijvend"
 
-#: src/language/stats/chisquare.c:243 src/language/stats/sign.c:61
+#: src/language/stats/chisquare.c:221 src/language/stats/sign.c:62
 msgid "Frequencies"
 msgstr "Frequenties"
 
-#: src/language/stats/chisquare.c:298 src/language/stats/sign.c:114
-#: src/language/stats/wilcoxon.c:297
+#: src/language/stats/chisquare.c:276 src/language/stats/sign.c:115
+#: src/language/stats/wilcoxon.c:313
 msgid "Test Statistics"
 msgstr ""
 
-#: src/language/stats/chisquare.c:312
+#: src/language/stats/chisquare.c:290
 msgid "Chi-Square"
 msgstr ""
 
-#: src/language/stats/chisquare.c:313 src/language/stats/crosstabs.q:1168
-#: src/language/stats/oneway.q:278 src/language/stats/oneway.q:689
-#: src/language/stats/regression.q:302 src/language/stats/t-test.q:1026
-#: src/language/stats/t-test.q:1219 src/language/stats/t-test.q:1316
+#: src/language/stats/chisquare.c:291 src/language/stats/crosstabs.q:1236
+#: src/language/stats/oneway.q:278 src/language/stats/oneway.q:691
+#: src/language/stats/regression.q:302 src/language/stats/t-test.q:753
+#: src/language/stats/t-test.q:924 src/language/stats/t-test.q:1011
 msgid "df"
 msgstr ""
 
-#: src/language/stats/chisquare.c:314
+#: src/language/stats/chisquare.c:292
 msgid "Asymp. Sig."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:278
+#: src/language/stats/crosstabs.q:327
 msgid ""
 "Missing mode REPORT not allowed in general mode.  Assuming MISSING=TABLE."
 msgstr ""
 "Missing modus REPORT niet toegestaan in algemene modus.  MISSING=TABLE "
 "aangenomen."
 
-#: src/language/stats/crosstabs.q:288
-msgid "Write mode ALL not allowed in general mode.  Assuming WRITE=CELLS."
-msgstr ""
-"Write modus ALL niet toegestaan in algemen modus.  WRITE=CELLS aangenomen."
-
-#: src/language/stats/crosstabs.q:364
+#: src/language/stats/crosstabs.q:416
 msgid "Too many cross-tabulation variables or dimensions."
 msgstr "Te veel cross-tabulation variabelen of dimensies."
 
-#: src/language/stats/crosstabs.q:374
+#: src/language/stats/crosstabs.q:426
 msgid "expecting BY"
 msgstr "BY verwacht"
 
-#: src/language/stats/crosstabs.q:441
+#: src/language/stats/crosstabs.q:486
 msgid "VARIABLES must be specified before TABLES."
 msgstr "VARIABLES dient voor TABLES gespecificeerd te worden."
 
-#: src/language/stats/crosstabs.q:479
+#: src/language/stats/crosstabs.q:524
 #, c-format
 msgid "Maximum value (%ld) less than minimum value (%ld)."
 msgstr "Maximum waarde (%ld) is kleiner dan minimum waarde (%ld)."
 
-#: src/language/stats/crosstabs.q:863
+#: src/language/stats/crosstabs.q:840
 msgid "Summary."
 msgstr "Overzicht."
 
-#: src/language/stats/crosstabs.q:865 src/language/stats/examine.q:1275
-#: src/language/stats/reliability.q:708
+#: src/language/stats/crosstabs.q:842 src/language/stats/examine.q:1277
+#: src/language/stats/reliability.q:709
 msgid "Cases"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:866 src/language/stats/examine.q:1212
-#: src/language/stats/frequencies.q:1057 src/language/stats/frequencies.q:1408
-#: src/language/stats/reliability.q:711
+#: src/language/stats/crosstabs.q:843 src/language/stats/examine.q:1214
+#: src/language/stats/frequencies.q:1049 src/language/stats/frequencies.q:1400
+#: src/language/stats/reliability.q:712
 msgid "Valid"
 msgstr "Geldig"
 
-#: src/language/stats/crosstabs.q:867 src/language/stats/examine.q:1213
-#: src/language/stats/frequencies.q:1127 src/language/stats/frequencies.q:1409
-#: src/ui/gui/psppire-var-sheet.c:544 src/ui/gui/psppire-var-store.c:790
+#: src/language/stats/crosstabs.q:844 src/language/stats/examine.q:1215
+#: src/language/stats/frequencies.q:1119 src/language/stats/frequencies.q:1401
+#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:838
 msgid "Missing"
 msgstr "Ontbrekend"
 
-#: src/language/stats/crosstabs.q:879 src/language/stats/examine.q:1290
-#: src/language/stats/frequencies.q:1061 src/language/stats/frequencies.q:1062
-#: src/language/stats/frequencies.q:1063
+#: src/language/stats/crosstabs.q:853 src/language/stats/examine.q:1292
+#: src/language/stats/frequencies.q:1053 src/language/stats/frequencies.q:1054
+#: src/language/stats/frequencies.q:1055
 msgid "Percent"
 msgstr "Procent"
 
-#: src/language/stats/crosstabs.q:1126
+#: src/language/stats/crosstabs.q:1133
 msgid "count"
 msgstr "aantal"
 
-#: src/language/stats/crosstabs.q:1127
+#: src/language/stats/crosstabs.q:1134
 msgid "row %"
 msgstr "rij %"
 
-#: src/language/stats/crosstabs.q:1128
+#: src/language/stats/crosstabs.q:1135
 msgid "column %"
 msgstr "kolom %"
 
-#: src/language/stats/crosstabs.q:1129
+#: src/language/stats/crosstabs.q:1136
 msgid "total %"
 msgstr "totaal %"
 
-#: src/language/stats/crosstabs.q:1130
+#: src/language/stats/crosstabs.q:1137
 msgid "expected"
 msgstr "verwacht"
 
-#: src/language/stats/crosstabs.q:1131
+#: src/language/stats/crosstabs.q:1138
 msgid "residual"
 msgstr "overblijvend"
 
-#: src/language/stats/crosstabs.q:1132
+#: src/language/stats/crosstabs.q:1139
 msgid "std. resid."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1133
+#: src/language/stats/crosstabs.q:1140
 msgid "adj. resid."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1163
+#: src/language/stats/crosstabs.q:1231
 msgid "Chi-square tests."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1166 src/language/stats/crosstabs.q:1193
-#: src/language/stats/crosstabs.q:1213 src/language/stats/crosstabs.q:1234
-#: src/language/stats/examine.q:1752 src/ui/gui/checkbox-treeview.c:92
+#: src/language/stats/crosstabs.q:1234 src/language/stats/crosstabs.q:1261
+#: src/language/stats/crosstabs.q:1285 src/language/stats/crosstabs.q:1309
+#: src/language/stats/examine.q:1753 src/ui/gui/checkbox-treeview.c:92
 msgid "Statistic"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1170
+#: src/language/stats/crosstabs.q:1238
 msgid "Asymp. Sig. (2-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1172
-msgid "Exact. Sig. (2-sided)"
+#: src/language/stats/crosstabs.q:1240
+msgid "Exact Sig. (2-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1174
-msgid "Exact. Sig. (1-sided)"
+#: src/language/stats/crosstabs.q:1242
+msgid "Exact Sig. (1-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1189
+#: src/language/stats/crosstabs.q:1257
 msgid "Symmetric measures."
 msgstr "Symmetrische metingen."
 
-#: src/language/stats/crosstabs.q:1195 src/language/stats/crosstabs.q:1237
+#: src/language/stats/crosstabs.q:1263 src/language/stats/crosstabs.q:1312
 msgid "Asymp. Std. Error"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1196 src/language/stats/crosstabs.q:1238
+#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1313
 msgid "Approx. T"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1197 src/language/stats/crosstabs.q:1239
+#: src/language/stats/crosstabs.q:1265 src/language/stats/crosstabs.q:1314
 msgid "Approx. Sig."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1208
+#: src/language/stats/crosstabs.q:1280
 msgid "Risk estimate."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1212
+#: src/language/stats/crosstabs.q:1284
 #, c-format
 msgid "95%% Confidence Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1215 src/language/stats/t-test.q:1030
-#: src/language/stats/t-test.q:1216 src/language/stats/t-test.q:1319
+#: src/language/stats/crosstabs.q:1287 src/language/stats/t-test.q:757
+#: src/language/stats/t-test.q:921 src/language/stats/t-test.q:1014
 msgid "Lower"
 msgstr "Lager"
 
-#: src/language/stats/crosstabs.q:1216 src/language/stats/t-test.q:1031
-#: src/language/stats/t-test.q:1217 src/language/stats/t-test.q:1320
+#: src/language/stats/crosstabs.q:1288 src/language/stats/t-test.q:758
+#: src/language/stats/t-test.q:922 src/language/stats/t-test.q:1015
 msgid "Upper"
 msgstr "Hoger"
 
-#: src/language/stats/crosstabs.q:1230
+#: src/language/stats/crosstabs.q:1305
 msgid "Directional measures."
 msgstr "Directioneel metingen."
 
-#: src/language/stats/crosstabs.q:1235 src/ui/gui/psppire.glade:2124
-#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:785
+#: src/language/stats/crosstabs.q:1310 src/ui/gui/psppire.glade:2099
+#: src/ui/gui/psppire-var-sheet.c:531 src/ui/gui/psppire-var-store.c:833
 msgid "Type"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1991
+#: src/language/stats/crosstabs.q:1776
 msgid "Pearson Chi-Square"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1992
+#: src/language/stats/crosstabs.q:1777
 msgid "Likelihood Ratio"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1993
+#: src/language/stats/crosstabs.q:1778
 msgid "Fisher's Exact Test"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1994
+#: src/language/stats/crosstabs.q:1779
 msgid "Continuity Correction"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1995
+#: src/language/stats/crosstabs.q:1780
 msgid "Linear-by-Linear Association"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2032 src/language/stats/crosstabs.q:2105
-#: src/language/stats/crosstabs.q:2167
+#: src/language/stats/crosstabs.q:1815 src/language/stats/crosstabs.q:1890
+#: src/language/stats/crosstabs.q:1955
 msgid "N of Valid Cases"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2051 src/language/stats/crosstabs.q:2183
+#: src/language/stats/crosstabs.q:1834 src/language/stats/crosstabs.q:1973
 msgid "Nominal by Nominal"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2052 src/language/stats/crosstabs.q:2184
+#: src/language/stats/crosstabs.q:1835 src/language/stats/crosstabs.q:1974
 msgid "Ordinal by Ordinal"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2053
+#: src/language/stats/crosstabs.q:1836
 msgid "Interval by Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2054
+#: src/language/stats/crosstabs.q:1837
 msgid "Measure of Agreement"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2059 src/ui/gui/crosstabs-dialog.c:41
+#: src/language/stats/crosstabs.q:1842 src/ui/gui/crosstabs-dialog.c:41
 msgid "Phi"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2060
+#: src/language/stats/crosstabs.q:1843
 msgid "Cramer's V"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2061
+#: src/language/stats/crosstabs.q:1844
 msgid "Contingency Coefficient"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2062
+#: src/language/stats/crosstabs.q:1845
 msgid "Kendall's tau-b"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2063
+#: src/language/stats/crosstabs.q:1846
 msgid "Kendall's tau-c"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2064 src/ui/gui/crosstabs-dialog.c:48
+#: src/language/stats/crosstabs.q:1847 src/ui/gui/crosstabs-dialog.c:48
 msgid "Gamma"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2065
+#: src/language/stats/crosstabs.q:1848
 msgid "Spearman Correlation"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2066
+#: src/language/stats/crosstabs.q:1849
 msgid "Pearson's R"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2067 src/ui/gui/crosstabs-dialog.c:50
+#: src/language/stats/crosstabs.q:1850 src/ui/gui/crosstabs-dialog.c:50
 msgid "Kappa"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2140
+#: src/language/stats/crosstabs.q:1928
 #, c-format
 msgid "Odds Ratio for %s (%g / %g)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2143
+#: src/language/stats/crosstabs.q:1931
 #, c-format
 msgid "Odds Ratio for %s (%.*s / %.*s)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2151
+#: src/language/stats/crosstabs.q:1939
 #, c-format
 msgid "For cohort %s = %g"
 msgstr "Voor cohort %s = %g"
 
-#: src/language/stats/crosstabs.q:2154
+#: src/language/stats/crosstabs.q:1942
 #, c-format
 msgid "For cohort %s = %.*s"
 msgstr "Voor cohort %s = %.*s"
 
-#: src/language/stats/crosstabs.q:2185
+#: src/language/stats/crosstabs.q:1975
 msgid "Nominal by Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2190 src/ui/gui/crosstabs-dialog.c:43
+#: src/language/stats/crosstabs.q:1980 src/ui/gui/crosstabs-dialog.c:43
 msgid "Lambda"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2191
+#: src/language/stats/crosstabs.q:1981
 msgid "Goodman and Kruskal tau"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2192
+#: src/language/stats/crosstabs.q:1982
 msgid "Uncertainty Coefficient"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2193
+#: src/language/stats/crosstabs.q:1983
 msgid "Somers' d"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2194 src/ui/gui/crosstabs-dialog.c:51
+#: src/language/stats/crosstabs.q:1984 src/ui/gui/crosstabs-dialog.c:51
 msgid "Eta"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2199
+#: src/language/stats/crosstabs.q:1989
 msgid "Symmetric"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2200 src/language/stats/crosstabs.q:2201
+#: src/language/stats/crosstabs.q:1990 src/language/stats/crosstabs.q:1991
 #, c-format
 msgid "%s Dependent"
 msgstr ""
 
-#: src/language/stats/descriptives.c:102 src/language/stats/examine.q:1557
+#: src/language/stats/descriptives.c:102 src/language/stats/examine.q:1559
 #: src/language/stats/frequencies.q:123 src/language/stats/npar-summary.c:126
-#: src/language/stats/oneway.q:390 src/language/stats/t-test.q:701
-#: src/language/stats/t-test.q:725 src/language/stats/t-test.q:862
-#: src/language/stats/t-test.q:1213 src/ui/gui/descriptives-dialog.c:39
+#: src/language/stats/oneway.q:390 src/language/stats/t-test.q:507
+#: src/language/stats/t-test.q:527 src/language/stats/t-test.q:625
+#: src/language/stats/t-test.q:918 src/ui/gui/descriptives-dialog.c:39
 #: src/ui/gui/frequencies-dialog.c:40
 msgid "Mean"
 msgstr "Gemiddeld"
@@ -3343,13 +3288,13 @@ msgstr ""
 msgid "Std Dev"
 msgstr ""
 
-#: src/language/stats/descriptives.c:105 src/language/stats/examine.q:1588
+#: src/language/stats/descriptives.c:105 src/language/stats/examine.q:1589
 #: src/language/stats/frequencies.q:128 src/ui/gui/descriptives-dialog.c:46
 #: src/ui/gui/frequencies-dialog.c:45
 msgid "Variance"
 msgstr ""
 
-#: src/language/stats/descriptives.c:106 src/language/stats/examine.q:1624
+#: src/language/stats/descriptives.c:106 src/language/stats/examine.q:1625
 #: src/language/stats/frequencies.q:129 src/ui/gui/descriptives-dialog.c:47
 #: src/ui/gui/frequencies-dialog.c:50
 msgid "Kurtosis"
@@ -3359,7 +3304,7 @@ msgstr ""
 msgid "S E Kurt"
 msgstr ""
 
-#: src/language/stats/descriptives.c:108 src/language/stats/examine.q:1619
+#: src/language/stats/descriptives.c:108 src/language/stats/examine.q:1620
 #: src/language/stats/frequencies.q:131 src/ui/gui/descriptives-dialog.c:48
 #: src/ui/gui/frequencies-dialog.c:46
 msgid "Skewness"
@@ -3369,22 +3314,22 @@ msgstr ""
 msgid "S E Skew"
 msgstr ""
 
-#: src/language/stats/descriptives.c:110 src/language/stats/examine.q:1608
+#: src/language/stats/descriptives.c:110 src/language/stats/examine.q:1609
 #: src/language/stats/frequencies.q:133 src/ui/gui/descriptives-dialog.c:43
 #: src/ui/gui/frequencies-dialog.c:48
 msgid "Range"
 msgstr ""
 
-#: src/language/stats/descriptives.c:111 src/language/stats/examine.q:1598
+#: src/language/stats/descriptives.c:111 src/language/stats/examine.q:1599
 #: src/language/stats/frequencies.q:134 src/language/stats/npar-summary.c:132
-#: src/language/stats/oneway.q:403 src/ui/gui/descriptives-dialog.c:41
+#: src/language/stats/oneway.q:404 src/ui/gui/descriptives-dialog.c:41
 #: src/ui/gui/frequencies-dialog.c:42
 msgid "Minimum"
 msgstr ""
 
-#: src/language/stats/descriptives.c:112 src/language/stats/examine.q:1603
+#: src/language/stats/descriptives.c:112 src/language/stats/examine.q:1604
 #: src/language/stats/frequencies.q:135 src/language/stats/npar-summary.c:135
-#: src/language/stats/oneway.q:404 src/ui/gui/descriptives-dialog.c:42
+#: src/language/stats/oneway.q:405 src/ui/gui/descriptives-dialog.c:42
 #: src/ui/gui/frequencies-dialog.c:43
 msgid "Maximum"
 msgstr ""
@@ -3441,203 +3386,183 @@ msgstr ""
 msgid "Valid cases = %g; cases with missing value(s) = %g."
 msgstr "Geldige cases = %g; cases met missing value(s) = %g."
 
-#: src/language/stats/examine.q:343 src/language/stats/examine.q:496
-#: src/language/stats/examine.q:1058
+#: src/language/stats/examine.q:346 src/language/stats/examine.q:499
+#: src/language/stats/examine.q:1060
 msgid "Not creating plot because data set is empty."
 msgstr "Er wordt geen plot aangemaakt omdat de data set leeg is."
 
-#: src/language/stats/examine.q:353
+#: src/language/stats/examine.q:356
 #, c-format
 msgid "Normal Q-Q Plot of %s"
 msgstr "Normal Q-Q Plot van %s"
 
-#: src/language/stats/examine.q:354 src/language/stats/examine.q:359
+#: src/language/stats/examine.q:357 src/language/stats/examine.q:362
 msgid "Observed Value"
 msgstr "Waargenomen Waarde"
 
-#: src/language/stats/examine.q:355
+#: src/language/stats/examine.q:358
 msgid "Expected Normal"
 msgstr ""
 
-#: src/language/stats/examine.q:357
+#: src/language/stats/examine.q:360
 #, c-format
 msgid "Detrended Normal Q-Q Plot of %s"
 msgstr "Detrended Normal Q-Q Plot van %s"
 
-#: src/language/stats/examine.q:360
+#: src/language/stats/examine.q:363
 msgid "Dev from Normal"
 msgstr ""
 
-#: src/language/stats/examine.q:513
+#: src/language/stats/examine.q:516
 #, c-format
 msgid "Boxplot of %s vs. %s"
 msgstr ""
 
-#: src/language/stats/examine.q:517
+#: src/language/stats/examine.q:520
 #, c-format
 msgid "Boxplot of %s"
 msgstr ""
 
-#: src/language/stats/examine.q:753 src/language/stats/examine.q:766
+#: src/language/stats/examine.q:756 src/language/stats/examine.q:769
 #, c-format
 msgid "%s and %s are mutually exclusive"
 msgstr "%s en %s zijn wederzijds exclusief"
 
-#: src/language/stats/examine.q:1270 src/language/stats/reliability.q:685
+#: src/language/stats/examine.q:1272 src/language/stats/reliability.q:686
 msgid "Case Processing Summary"
 msgstr "Case Bewerkings Overzicht"
 
-#: src/language/stats/examine.q:1562 src/language/stats/oneway.q:398
+#: src/language/stats/examine.q:1564 src/language/stats/oneway.q:398
 #, c-format
 msgid "%g%% Confidence Interval for Mean"
 msgstr ""
 
-#: src/language/stats/examine.q:1568 src/language/stats/oneway.q:400
+#: src/language/stats/examine.q:1570 src/language/stats/oneway.q:401
+#: src/language/stats/roc.c:962
 msgid "Lower Bound"
 msgstr "Beneden Grens"
 
-#: src/language/stats/examine.q:1573 src/language/stats/oneway.q:401
+#: src/language/stats/examine.q:1575 src/language/stats/oneway.q:402
+#: src/language/stats/roc.c:963
 msgid "Upper Bound"
 msgstr "Boven Grens"
 
-#: src/language/stats/examine.q:1578
-#, c-format
-msgid "5%% Trimmed Mean"
+#: src/language/stats/examine.q:1579
+msgid "5% Trimmed Mean"
 msgstr ""
 
-#: src/language/stats/examine.q:1583 src/language/stats/frequencies.q:125
+#: src/language/stats/examine.q:1584 src/language/stats/frequencies.q:125
 #: src/ui/gui/frequencies-dialog.c:52
 msgid "Median"
 msgstr ""
 
-#: src/language/stats/examine.q:1593 src/language/stats/npar-summary.c:129
-#: src/language/stats/oneway.q:391 src/language/stats/t-test.q:702
-#: src/language/stats/t-test.q:726 src/language/stats/t-test.q:864
-#: src/language/stats/t-test.q:1214
+#: src/language/stats/examine.q:1594 src/language/stats/npar-summary.c:129
+#: src/language/stats/oneway.q:391 src/language/stats/t-test.q:508
+#: src/language/stats/t-test.q:528 src/language/stats/t-test.q:627
+#: src/language/stats/t-test.q:919
 msgid "Std. Deviation"
 msgstr ""
 
-#: src/language/stats/examine.q:1613
+#: src/language/stats/examine.q:1614
 msgid "Interquartile Range"
 msgstr ""
 
-#: src/language/stats/examine.q:1749 src/language/stats/oneway.q:407
+#: src/language/stats/examine.q:1750 src/language/stats/oneway.q:408
 #: src/ui/gui/examine.glade:310
 msgid "Descriptives"
 msgstr ""
 
-#: src/language/stats/examine.q:1755 src/language/stats/oneway.q:392
-#: src/language/stats/oneway.q:687 src/language/stats/regression.q:203
+#: src/language/stats/examine.q:1756 src/language/stats/oneway.q:392
+#: src/language/stats/oneway.q:689 src/language/stats/regression.q:203
+#: src/language/stats/roc.c:959
 msgid "Std. Error"
 msgstr ""
 
-#: src/language/stats/examine.q:1852 src/language/stats/examine.q:1857
-#: src/ui/gui/psppire-data-store.c:756 src/ui/gui/psppire-var-store.c:646
-#: src/ui/gui/psppire-var-store.c:656 src/ui/gui/psppire-var-store.c:666
-#: src/ui/gui/psppire-var-store.c:777
-#, c-format
-msgid "%d"
-msgstr ""
-
-#: src/language/stats/examine.q:1938
+#: src/language/stats/examine.q:1939
 msgid "Highest"
 msgstr "Hoogste"
 
-#: src/language/stats/examine.q:1943
+#: src/language/stats/examine.q:1944
 msgid "Lowest"
 msgstr "Laagste"
 
-#: src/language/stats/examine.q:1950
+#: src/language/stats/examine.q:1951
 msgid "Extreme Values"
 msgstr "Extreme Waardes"
 
-#: src/language/stats/examine.q:1954
+#: src/language/stats/examine.q:1955
 msgid "Case Number"
 msgstr "Case Nummer"
 
-#: src/language/stats/examine.q:2076
+#: src/language/stats/examine.q:2077
 msgid "Tukey's Hinges"
 msgstr ""
 
-#: src/language/stats/examine.q:2116 src/language/stats/examine.q:2134
-#: src/language/stats/frequencies.q:1418 src/language/stats/npar-summary.c:142
+#: src/language/stats/examine.q:2117 src/language/stats/examine.q:2134
+#: src/language/stats/frequencies.q:1410 src/language/stats/npar-summary.c:142
 #: src/ui/gui/examine.glade:333
 msgid "Percentiles"
 msgstr ""
 
-#: src/language/stats/examine.q:2123
+#: src/language/stats/examine.q:2124
 #, c-format
 msgid "%g"
 msgstr ""
 
-#: src/language/stats/flip.c:96
+#: src/language/stats/flip.c:98
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 msgstr ""
 "FLIP negeert TEMPORARY. Tijdelijke transformaties worden permanent gemaakt."
 
-#: src/language/stats/flip.c:151
+#: src/language/stats/flip.c:150
 msgid "Could not create temporary file for FLIP."
 msgstr "Kon geen tijdelijk bestand voor FLIP aanmaken."
 
-#: src/language/stats/flip.c:162
-#, c-format
-msgid "Error writing FLIP file: %s."
-msgstr "Fout tijdens het schrijven van FLIP bestand: %s."
-
-#: src/language/stats/flip.c:262
-#, c-format
-msgid "Could not create acceptable variant for variable %s."
-msgstr "Kon geen acceptabele variant voor variabele %s creëren."
-
-#: src/language/stats/flip.c:278
-msgid "Cannot create more than 99999 variable names."
-msgstr "Kan niet meer dan 99999 variabele namen creëren."
-
-#: src/language/stats/flip.c:394
+#: src/language/stats/flip.c:327
 #, c-format
 msgid "Error rewinding FLIP file: %s."
 msgstr "Fout tijdens terugdraaien FLIP bestand: %s."
 
-#: src/language/stats/flip.c:401
+#: src/language/stats/flip.c:334
 msgid "Error creating FLIP source file."
 msgstr "Fout tijdens het creëren van FLIP bron bestand."
 
-#: src/language/stats/flip.c:414
+#: src/language/stats/flip.c:347
 #, c-format
 msgid "Error reading FLIP file: %s."
 msgstr "Fout tijdens lezen FLIP bestand: %s."
 
-#: src/language/stats/flip.c:416
+#: src/language/stats/flip.c:349
 msgid "Unexpected end of file reading FLIP file."
 msgstr "Onverwacht einde bestand tijdens lezen FLIP bestand."
 
-#: src/language/stats/flip.c:432
+#: src/language/stats/flip.c:365
 #, c-format
 msgid "Error seeking FLIP source file: %s."
 msgstr "Fout tijdens zoeken FLIP bron bestand: %s."
 
-#: src/language/stats/flip.c:440
+#: src/language/stats/flip.c:373
 #, c-format
 msgid "Error writing FLIP source file: %s."
 msgstr "Fout tijdens schrijven FLIP bron bestand: %s."
 
-#: src/language/stats/flip.c:451
+#: src/language/stats/flip.c:384
 #, c-format
 msgid "Error closing FLIP source file: %s."
 msgstr "Fout tijdens sluiten FLIP bron bestand: %s."
 
-#: src/language/stats/flip.c:459
+#: src/language/stats/flip.c:392
 #, c-format
 msgid "Error rewinding FLIP source file: %s."
 msgstr "Fout tijdens terugdraaien FLIP bron bestand: %s."
 
-#: src/language/stats/flip.c:487
+#: src/language/stats/flip.c:426
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr "Fout tijdens lezen FLIP tijdelijk bestand: %s."
 
-#: src/language/stats/flip.c:490
+#: src/language/stats/flip.c:429
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr "Onverwacht einde bestand tijdens lezen FLIP tijdelijk bestand."
 
@@ -3657,7 +3582,7 @@ msgstr ""
 msgid "S.E. Skew"
 msgstr ""
 
-#: src/language/stats/frequencies.q:409
+#: src/language/stats/frequencies.q:407
 msgid ""
 "At most one of BARCHART, HISTOGRAM, or HBAR should be given.  HBAR will be "
 "assumed.  Argument values will be given precedence increasing along the "
@@ -3667,7 +3592,7 @@ msgstr ""
 "HBAR wordt aangenomen.  Argument waardes zullen gebruikt worden in opgegeven "
 "volgorde."
 
-#: src/language/stats/frequencies.q:492
+#: src/language/stats/frequencies.q:490
 #, c-format
 msgid ""
 "MAX must be greater than or equal to MIN, if both are specified.  However, "
@@ -3676,52 +3601,52 @@ msgstr ""
 "MAX moet groter of gelijk zijn aan MIN, als beiden zijn opgegeven. Maar, MIN "
 "was opgegeven als %g en MAX als %g. MIN en MAX worden genegeerd."
 
-#: src/language/stats/frequencies.q:757
+#: src/language/stats/frequencies.q:754
 #, c-format
 msgid "Variable %s specified multiple times on VARIABLES subcommand."
 msgstr "Variabele %s is meerdere keren opgegeven bij VARIABLES subopdracht."
 
-#: src/language/stats/frequencies.q:820
+#: src/language/stats/frequencies.q:812
 msgid "`)' expected after GROUPED interval list."
 msgstr "')' verwacht na GROUPED interval lijst."
 
-#: src/language/stats/frequencies.q:832
+#: src/language/stats/frequencies.q:824
 #, c-format
 msgid "Variables %s specified on GROUPED but not on VARIABLES."
 msgstr "Variabele %s gespecificeerd bij GROUPED maar niet bij VARIABLES."
 
-#: src/language/stats/frequencies.q:839
+#: src/language/stats/frequencies.q:831
 #, c-format
 msgid "Variables %s specified multiple times on GROUPED subcommand."
 msgstr "Variabele %s is meerdere keren gespecificeerd bij GROUPED subopdracht."
 
-#: src/language/stats/frequencies.q:1058 src/language/stats/frequencies.q:1151
-#: src/language/stats/frequencies.q:1152 src/language/stats/frequencies.q:1187
+#: src/language/stats/frequencies.q:1050 src/language/stats/frequencies.q:1143
+#: src/language/stats/frequencies.q:1144 src/language/stats/frequencies.q:1179
 msgid "Cum"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1060 src/output/charts/plot-hist.c:140
+#: src/language/stats/frequencies.q:1052 src/output/charts/plot-hist.c:140
 msgid "Frequency"
 msgstr "Frequenties"
 
-#: src/language/stats/frequencies.q:1081
+#: src/language/stats/frequencies.q:1073
 msgid "Value Label"
 msgstr "Waarde Label"
 
-#: src/language/stats/frequencies.q:1185
+#: src/language/stats/frequencies.q:1177
 msgid "Freq"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1186 src/language/stats/frequencies.q:1188
+#: src/language/stats/frequencies.q:1178 src/language/stats/frequencies.q:1180
 msgid "Pct"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1381
+#: src/language/stats/frequencies.q:1373
 #, c-format
 msgid "No valid data for variable %s; statistics not displayed."
 msgstr "Geen geldige data voor variabele %s; statistieken worden niet getoond."
 
-#: src/language/stats/frequencies.q:1422
+#: src/language/stats/frequencies.q:1414
 msgid "50 (Median)"
 msgstr ""
 
@@ -3761,7 +3686,7 @@ msgstr ""
 "%d verwachte waardes waren opgegeven, maar de opgegeven range (%d-%d) "
 "vereist precies %d waardes."
 
-#: src/language/stats/npar.q:441 src/language/stats/t-test.q:501
+#: src/language/stats/npar.q:441 src/language/stats/t-test.q:379
 #, c-format
 msgid ""
 "PAIRED was specified but the number of variables preceding WITH (%zu) did "
@@ -3809,11 +3734,11 @@ msgid "Mean Square"
 msgstr ""
 
 #: src/language/stats/oneway.q:280 src/language/stats/regression.q:304
-#: src/language/stats/t-test.q:1023
+#: src/language/stats/t-test.q:750
 msgid "F"
 msgstr ""
 
-#: src/language/stats/oneway.q:281 src/language/stats/oneway.q:538
+#: src/language/stats/oneway.q:281 src/language/stats/oneway.q:539
 #: src/language/stats/regression.q:206 src/language/stats/regression.q:305
 msgid "Significance"
 msgstr "Significantie "
@@ -3830,19 +3755,19 @@ msgstr "Binnen Groepen"
 msgid "ANOVA"
 msgstr ""
 
-#: src/language/stats/oneway.q:535
+#: src/language/stats/oneway.q:536
 msgid "Levene Statistic"
 msgstr ""
 
-#: src/language/stats/oneway.q:536
+#: src/language/stats/oneway.q:537
 msgid "df1"
 msgstr ""
 
-#: src/language/stats/oneway.q:537
+#: src/language/stats/oneway.q:538
 msgid "df2"
 msgstr ""
 
-#: src/language/stats/oneway.q:540
+#: src/language/stats/oneway.q:541
 msgid "Test of Homogeneity of Variances"
 msgstr ""
 
@@ -3850,34 +3775,34 @@ msgstr ""
 msgid "Contrast Coefficients"
 msgstr ""
 
-#: src/language/stats/oneway.q:610 src/language/stats/oneway.q:685
+#: src/language/stats/oneway.q:610 src/language/stats/oneway.q:687
 msgid "Contrast"
 msgstr ""
 
-#: src/language/stats/oneway.q:683
+#: src/language/stats/oneway.q:685
 msgid "Contrast Tests"
 msgstr ""
 
-#: src/language/stats/oneway.q:686
+#: src/language/stats/oneway.q:688
 msgid "Value of Contrast"
 msgstr ""
 
-#: src/language/stats/oneway.q:688 src/language/stats/regression.q:205
-#: src/language/stats/t-test.q:1025 src/language/stats/t-test.q:1218
-#: src/language/stats/t-test.q:1315
+#: src/language/stats/oneway.q:690 src/language/stats/regression.q:205
+#: src/language/stats/t-test.q:752 src/language/stats/t-test.q:923
+#: src/language/stats/t-test.q:1010
 msgid "t"
 msgstr ""
 
-#: src/language/stats/oneway.q:690 src/language/stats/t-test.q:1027
-#: src/language/stats/t-test.q:1220 src/language/stats/t-test.q:1317
+#: src/language/stats/oneway.q:692 src/language/stats/t-test.q:754
+#: src/language/stats/t-test.q:925 src/language/stats/t-test.q:1012
 msgid "Sig. (2-tailed)"
 msgstr ""
 
-#: src/language/stats/oneway.q:734
+#: src/language/stats/oneway.q:736
 msgid "Assume equal variances"
 msgstr "Veronderstelt gelijke variantie"
 
-#: src/language/stats/oneway.q:738
+#: src/language/stats/oneway.q:740
 msgid "Does not assume equal"
 msgstr "Veronderstelt niet gelijk"
 
@@ -3904,22 +3829,22 @@ msgstr "Variabelen gecreëerd door RANK"
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr "%s in %s(%s van %s gebruikt %s PER %s)"
 
-#: src/language/stats/rank.q:729
+#: src/language/stats/rank.q:728
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr "%s in %s(%s van %s PER %s)"
 
-#: src/language/stats/rank.q:743
+#: src/language/stats/rank.q:741
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr "%s in %s(%s van %s gebruikt %s"
 
-#: src/language/stats/rank.q:753
+#: src/language/stats/rank.q:750
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr "%s in %s(%s van %s)"
 
-#: src/language/stats/rank.q:766
+#: src/language/stats/rank.q:762
 msgid ""
 "FRACTION has been specified, but NORMAL and PROPORTION rank functions have "
 "not been requested.  The FRACTION subcommand will be ignored."
@@ -3927,12 +3852,12 @@ msgstr ""
 "FRACTION is gespecificeerd maar NORMAL en PROPORTION rangschik functies ziin "
 "niet gevraagd. De FRACTION subopdracht wordt genegeerd."
 
-#: src/language/stats/rank.q:857
+#: src/language/stats/rank.q:853
 #, c-format
 msgid "Variable %s already exists."
 msgstr "Variabele %s bestaat al."
 
-#: src/language/stats/rank.q:862
+#: src/language/stats/rank.q:858
 msgid "Too many variables in INTO clause."
 msgstr "Te veel variabelen in INTO clause."
 
@@ -3999,104 +3924,189 @@ msgstr ""
 msgid "Dependent variable must be numeric."
 msgstr "Afhankelijke variabele moet numeriek zijn."
 
-#: src/language/stats/reliability.q:432
+#: src/language/stats/reliability.q:433
 msgid "Reliability Statistics"
 msgstr ""
 
-#: src/language/stats/reliability.q:475
+#: src/language/stats/reliability.q:476
 msgid "Item-Total Statistics"
 msgstr ""
 
-#: src/language/stats/reliability.q:497
+#: src/language/stats/reliability.q:498
 msgid "Scale Mean if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.q:500
+#: src/language/stats/reliability.q:501
 msgid "Scale Variance if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.q:503
+#: src/language/stats/reliability.q:504
 msgid "Corrected Item-Total Correlation"
 msgstr ""
 
-#: src/language/stats/reliability.q:506
+#: src/language/stats/reliability.q:507
 msgid "Cronbach's Alpha if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.q:556 src/language/stats/reliability.q:575
+#: src/language/stats/reliability.q:557 src/language/stats/reliability.q:576
 msgid "Cronbach's Alpha"
 msgstr ""
 
-#: src/language/stats/reliability.q:559
+#: src/language/stats/reliability.q:560
 msgid "N of items"
 msgstr ""
 
-#: src/language/stats/reliability.q:578
+#: src/language/stats/reliability.q:579
 msgid "Part 1"
 msgstr "Deel 1"
 
-#: src/language/stats/reliability.q:584 src/language/stats/reliability.q:595
+#: src/language/stats/reliability.q:585 src/language/stats/reliability.q:596
 msgid "N of Items"
 msgstr ""
 
-#: src/language/stats/reliability.q:589
+#: src/language/stats/reliability.q:590
 msgid "Part 2"
 msgstr "Deel 2"
 
-#: src/language/stats/reliability.q:600
+#: src/language/stats/reliability.q:601
 msgid "Total N of Items"
 msgstr ""
 
-#: src/language/stats/reliability.q:603
+#: src/language/stats/reliability.q:604
 msgid "Correlation Between Forms"
 msgstr ""
 
-#: src/language/stats/reliability.q:607
+#: src/language/stats/reliability.q:608
 msgid "Spearman-Brown Coefficient"
 msgstr ""
 
-#: src/language/stats/reliability.q:610
+#: src/language/stats/reliability.q:611
 msgid "Equal Length"
 msgstr "Gelijke Lengte"
 
-#: src/language/stats/reliability.q:613
+#: src/language/stats/reliability.q:614
 msgid "Unequal Length"
 msgstr "Ongelijke Lengte"
 
-#: src/language/stats/reliability.q:617
+#: src/language/stats/reliability.q:618
 msgid "Guttman Split-Half Coefficient"
 msgstr ""
 
-#: src/language/stats/reliability.q:714
+#: src/language/stats/reliability.q:715
 msgid "Excluded"
 msgstr "Uitgesloten"
 
 #: src/language/stats/reliability.q:723
+msgid "%"
+msgstr ""
+
+#: src/language/stats/roc.c:938
+msgid "Area Under the Curve"
+msgstr ""
+
+#: src/language/stats/roc.c:940
+#, c-format
+msgid "Area Under the Curve (%s)"
+msgstr ""
+
+#: src/language/stats/roc.c:946
+msgid "Area"
+msgstr ""
+
+#: src/language/stats/roc.c:960
+msgid "Asymptotic Sig."
+msgstr ""
+
+#: src/language/stats/roc.c:967
+#, c-format
+msgid "Asymp. %g%% Confidence Interval"
+msgstr ""
+
+#: src/language/stats/roc.c:973
+#, fuzzy
+msgid "Variable under test"
+msgstr "Variabelen"
+
+#: src/language/stats/roc.c:1032
+#, fuzzy
+msgid "Case Summary"
+msgstr "Overzicht."
+
+#: src/language/stats/roc.c:1054
+#, fuzzy
+msgid "Unweighted"
+msgstr "Niet gewogen."
+
+#: src/language/stats/roc.c:1055
+#, fuzzy
+msgid "Weighted"
+msgstr "Gewicht:"
+
+#: src/language/stats/roc.c:1059
+msgid "Valid N (listwise)"
+msgstr ""
+
+#: src/language/stats/roc.c:1062
+#, fuzzy
+msgid "Positive"
+msgstr "positief"
+
+#: src/language/stats/roc.c:1063
+#, fuzzy
+msgid "Negative"
+msgstr "negatief"
+
+#: src/language/stats/roc.c:1091
+msgid "Coordinates of the Curve"
+msgstr ""
+
+#: src/language/stats/roc.c:1093
 #, c-format
-msgid "%%"
+msgid "Coordinates of the Curve (%s)"
+msgstr ""
+
+#: src/language/stats/roc.c:1103
+#, fuzzy
+msgid "Test variable"
+msgstr "Test Variabel(en):"
+
+#: src/language/stats/roc.c:1105
+msgid "Positive if greater than or equal to"
+msgstr ""
+
+#: src/language/stats/roc.c:1106 src/language/stats/roc.c:1171
+msgid "Sensitivity"
+msgstr ""
+
+#: src/language/stats/roc.c:1107 src/language/stats/roc.c:1170
+msgid "1 - Specificity"
 msgstr ""
 
-#: src/language/stats/sign.c:90
+#: src/language/stats/roc.c:1169
+msgid "ROC Curve"
+msgstr ""
+
+#: src/language/stats/sign.c:91
 msgid "Negative Differences"
 msgstr "Negatieve Verschillen"
 
-#: src/language/stats/sign.c:91
+#: src/language/stats/sign.c:92
 msgid "Positive Differences"
 msgstr "Positieve Verschillen"
 
-#: src/language/stats/sign.c:92 src/language/stats/wilcoxon.c:245
+#: src/language/stats/sign.c:93 src/language/stats/wilcoxon.c:261
 msgid "Ties"
 msgstr ""
 
-#: src/language/stats/sign.c:133
+#: src/language/stats/sign.c:134 src/language/stats/wilcoxon.c:331
 msgid "Exact Sig. (2-tailed)"
 msgstr ""
 
-#: src/language/stats/sign.c:136
+#: src/language/stats/sign.c:137 src/language/stats/wilcoxon.c:332
 msgid "Exact Sig. (1-tailed)"
 msgstr ""
 
-#: src/language/stats/sign.c:139 src/language/stats/wilcoxon.c:319
+#: src/language/stats/sign.c:140 src/language/stats/wilcoxon.c:335
 msgid "Point Probability"
 msgstr ""
 
@@ -4117,163 +4127,152 @@ msgstr "')' verwacht."
 msgid "Variable %s specified twice in sort criteria."
 msgstr "Variabele %s 2 keer opgegeven in sort criteria."
 
-#: src/language/stats/t-test.q:280
-msgid "TESTVAL, GROUPS and PAIRS subcommands are mutually exclusive."
+#: src/language/stats/t-test.q:189
+#, fuzzy
+msgid "Exactly one of TESTVAL, GROUPS and PAIRS subcommands must be specified."
 msgstr "TESTVAL, GROUPS en PAIRS subopdracht zijn wederzijds uitsluitend."
 
-#: src/language/stats/t-test.q:298
-msgid "VARIABLES subcommand is not appropriate with PAIRS"
+#: src/language/stats/t-test.q:210
+#, fuzzy
+msgid "VARIABLES subcommand may not be used with PAIRS."
 msgstr "VARIABLES subprogramma is niet het juiste met PAIRS"
 
-#: src/language/stats/t-test.q:336
+#: src/language/stats/t-test.q:229
 msgid "One or more VARIABLES must be specified."
 msgstr "Een of meer VARIABLES moeten gespecificeerd zijn."
 
-#: src/language/stats/t-test.q:386
-#, c-format
-msgid "Long string variable %s is not valid here."
-msgstr "Lange string variabele %s is niet geldig hier."
-
-#: src/language/stats/t-test.q:406 src/language/stats/t-test.q:420
+#: src/language/stats/t-test.q:323
 msgid ""
 "When applying GROUPS to a string variable, two values must be specified."
 msgstr ""
 "By het toepassen van GROUPS op een string variabele moeten twee waardes "
 "opgegeven zijn."
 
-#: src/language/stats/t-test.q:518
+#: src/language/stats/t-test.q:394
 msgid "At least two variables must be specified on PAIRS."
 msgstr "Ten minste 2 variabelen moeten opgegeven worden bij PAIRS."
 
-#: src/language/stats/t-test.q:698
+#: src/language/stats/t-test.q:504
 msgid "One-Sample Statistics"
 msgstr ""
 
-#: src/language/stats/t-test.q:703 src/language/stats/t-test.q:727
-#: src/language/stats/t-test.q:865
+#: src/language/stats/t-test.q:509 src/language/stats/t-test.q:529
+#: src/language/stats/t-test.q:628
 msgid "SE. Mean"
 msgstr ""
 
-#: src/language/stats/t-test.q:722
+#: src/language/stats/t-test.q:523
 msgid "Group Statistics"
 msgstr ""
 
-#: src/language/stats/t-test.q:859
+#: src/language/stats/t-test.q:622
 msgid "Paired Sample Statistics"
 msgstr ""
 
-#: src/language/stats/t-test.q:885 src/language/stats/t-test.q:1243
-#: src/language/stats/t-test.q:1442
+#: src/language/stats/t-test.q:642 src/language/stats/t-test.q:945
+#: src/language/stats/t-test.q:1119
 #, c-format
 msgid "Pair %d"
 msgstr ""
 
-#: src/language/stats/t-test.q:1011
+#: src/language/stats/t-test.q:738
 msgid "Independent Samples Test"
 msgstr ""
 
-#: src/language/stats/t-test.q:1019
+#: src/language/stats/t-test.q:746
 msgid "Levene's Test for Equality of Variances"
 msgstr ""
 
-#: src/language/stats/t-test.q:1021
+#: src/language/stats/t-test.q:748
 msgid "t-test for Equality of Means"
 msgstr ""
 
-#: src/language/stats/t-test.q:1024 src/language/stats/t-test.q:1427
+#: src/language/stats/t-test.q:751 src/language/stats/t-test.q:1107
 msgid "Sig."
 msgstr ""
 
-#: src/language/stats/t-test.q:1028 src/language/stats/t-test.q:1318
+#: src/language/stats/t-test.q:755 src/language/stats/t-test.q:1013
 msgid "Mean Difference"
 msgstr "Gemiddelde Verschil"
 
-#: src/language/stats/t-test.q:1029
+#: src/language/stats/t-test.q:756
 msgid "Std. Error Difference"
 msgstr ""
 
-#: src/language/stats/t-test.q:1034 src/language/stats/t-test.q:1210
-#: src/language/stats/t-test.q:1310
+#: src/language/stats/t-test.q:761 src/language/stats/t-test.q:915
+#: src/language/stats/t-test.q:1005
 #, c-format
 msgid "%g%% Confidence Interval of the Difference"
 msgstr ""
 
-#: src/language/stats/t-test.q:1090
+#: src/language/stats/t-test.q:815
 msgid "Equal variances assumed"
 msgstr ""
 
-#: src/language/stats/t-test.q:1142
+#: src/language/stats/t-test.q:861
 msgid "Equal variances not assumed"
 msgstr ""
 
-#: src/language/stats/t-test.q:1200
+#: src/language/stats/t-test.q:905
 msgid "Paired Samples Test"
 msgstr ""
 
-#: src/language/stats/t-test.q:1203
+#: src/language/stats/t-test.q:908
 msgid "Paired Differences"
 msgstr ""
 
-#: src/language/stats/t-test.q:1215
+#: src/language/stats/t-test.q:920
 msgid "Std. Error Mean"
 msgstr ""
 
-#: src/language/stats/t-test.q:1299
+#: src/language/stats/t-test.q:994
 msgid "One-Sample Test"
 msgstr ""
 
-#: src/language/stats/t-test.q:1304
+#: src/language/stats/t-test.q:999
 #, c-format
 msgid "Test Value = %f"
 msgstr ""
 
-#: src/language/stats/t-test.q:1422
+#: src/language/stats/t-test.q:1102
 msgid "Paired Samples Correlations"
 msgstr ""
 
-#: src/language/stats/t-test.q:1426
+#: src/language/stats/t-test.q:1106
 msgid "Correlation"
 msgstr "Correlatie"
 
-#: src/language/stats/t-test.q:1445
+#: src/language/stats/t-test.q:1121
 #, c-format
 msgid "%s & %s"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:216
+#: src/language/stats/wilcoxon.c:232
 msgid "Ranks"
 msgstr "Rangen"
 
-#: src/language/stats/wilcoxon.c:230
+#: src/language/stats/wilcoxon.c:246
 msgid "Mean Rank"
 msgstr "Gemiddelde Rang"
 
-#: src/language/stats/wilcoxon.c:231
+#: src/language/stats/wilcoxon.c:247
 msgid "Sum of Ranks"
 msgstr "Totaal van de Rangen"
 
-#: src/language/stats/wilcoxon.c:243
+#: src/language/stats/wilcoxon.c:259
 msgid "Negative Ranks"
 msgstr "Negatieve Rangen"
 
-#: src/language/stats/wilcoxon.c:244
+#: src/language/stats/wilcoxon.c:260
 msgid "Positive Ranks"
 msgstr "Positieve Rangen"
 
-#: src/language/stats/wilcoxon.c:310
+#: src/language/stats/wilcoxon.c:326
 msgid "Z"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:311
-msgid "Asymp. Sig (2-tailed)"
-msgstr ""
-
-#: src/language/stats/wilcoxon.c:315
-msgid "Exact Sig (2-tailed)"
-msgstr ""
-
-#: src/language/stats/wilcoxon.c:316
-msgid "Exact Sig (1-tailed)"
+#: src/language/stats/wilcoxon.c:327
+msgid "Asymp. Sig. (2-tailed)"
 msgstr ""
 
 #: src/language/syntax-file.c:88
@@ -4286,35 +4285,16 @@ msgstr "openen \"%s\" als syntax bestand"
 msgid "Opening `%s': %s."
 msgstr "Openen '%s': %s."
 
-#: src/language/syntax-file.c:106
+#: src/language/syntax-file.c:107
 #, c-format
 msgid "Reading `%s': %s."
 msgstr "Lezen '%s': %s."
 
-#: src/language/syntax-file.c:126
+#: src/language/syntax-file.c:127
 #, c-format
 msgid "Closing `%s': %s."
 msgstr "Sluiten '%s': %s."
 
-#: src/language/tests/check-model.q:138
-msgid "PATH and SEARCH subcommands are mutually exclusive.  Ignoring PATH."
-msgstr ""
-"PATH en SEARCH subopdrachten zijn wederzijds uitsluitend. PATH genegeerd. "
-
-#: src/language/tests/check-model.q:156
-msgid "At least one value must be specified on PATH."
-msgstr "Tenminste 1 waarde dient bij PATH opgegeven te zijn."
-
-#: src/language/tests/check-model.q:167
-#, c-format
-msgid "Hash bits adjusted to %d."
-msgstr "Hash bits aangepast naar %d."
-
-#: src/language/tests/check-model.q:208
-#, c-format
-msgid "error opening \"%s\" for writing"
-msgstr "fout bij openen \"%s\" voor schrijven"
-
 #: src/language/tests/float-format.c:124
 #, c-format
 msgid "%zu-byte string needed but %zu-byte string supplied."
@@ -4448,99 +4428,46 @@ msgstr ""
 "FORMAT vereist numeriek uitvoer formaat als een argument. Opgegeven formaat %"
 "s is van het type string."
 
-#: src/language/utilities/set.q:522
-msgid "BLANKS is SYSMIS."
-msgstr ""
-
-#: src/language/utilities/set.q:524
-#, c-format
-msgid "BLANKS is %g."
-msgstr ""
-
-#: src/language/utilities/set.q:559
-#, c-format
-msgid "%s is \"%s\"."
-msgstr ""
-
-#: src/language/utilities/set.q:595
-#, c-format
-msgid "DECIMAL is \"%c\"."
-msgstr ""
-
-#: src/language/utilities/set.q:601
-#, c-format
-msgid "ENDCMD is \"%c\"."
-msgstr ""
-
-#: src/language/utilities/set.q:609
-#, c-format
-msgid "ERRORS is \"%s\"."
+#: src/language/utilities/set.q:668
+msgid "ISL (32-bit IEEE 754 single, little-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:620
-#, c-format
-msgid "FORMAT is %s."
+#: src/language/utilities/set.q:671
+msgid "ISB (32-bit IEEE 754 single, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:626
-#, c-format
-msgid "LENGTH is %d."
+#: src/language/utilities/set.q:674
+msgid "IDL (64-bit IEEE 754 double, little-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:632
-#, c-format
-msgid "LOCALE is %s"
+#: src/language/utilities/set.q:677
+msgid "IDB (64-bit IEEE 754 double, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:638
-#, c-format
-msgid "MXERRS is %d."
+#: src/language/utilities/set.q:681
+msgid "VF (32-bit VAX F, VAX-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:644
-#, c-format
-msgid "MXLOOPS is %d."
+#: src/language/utilities/set.q:684
+msgid "VD (64-bit VAX D, VAX-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:650
-#, c-format
-msgid "MXWARNS is %d."
+#: src/language/utilities/set.q:687
+msgid "VG (64-bit VAX G, VAX-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:657 src/language/utilities/set.q:708
-#, c-format
-msgid "%s is %s (%s)."
+#: src/language/utilities/set.q:691
+msgid "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:729
-msgid "SCOMPRESSION is ON."
+#: src/language/utilities/set.q:694
+msgid "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 msgstr ""
 
-#: src/language/utilities/set.q:731
-msgid "SCOMPRESSION is OFF."
-msgstr ""
-
-#: src/language/utilities/set.q:738
-msgid "UNDEFINED is WARN."
-msgstr ""
-
-#: src/language/utilities/set.q:740
-msgid "UNDEFINED is NOWARN."
-msgstr ""
-
-#: src/language/utilities/set.q:748
-msgid "WEIGHT is off."
-msgstr "WEGING is uit."
-
-#: src/language/utilities/set.q:750
-#, c-format
-msgid "WEIGHT is variable %s."
-msgstr "WEGING is variabele %s."
-
-#: src/language/utilities/set.q:768
-#, c-format
-msgid "WIDTH is %d."
-msgstr "BREEDTE is %d."
+#: src/language/utilities/set.q:793
+#, fuzzy, c-format
+msgid "%s is %s."
+msgstr "%s van %s"
 
 #: src/language/utilities/title.c:68
 #, c-format
@@ -4569,7 +4496,7 @@ msgstr ""
 "Tijdens uitvoeren van COMPUTE: %g is geen geldige waarde als een index in "
 "vector %s."
 
-#: src/language/xforms/compute.c:354
+#: src/language/xforms/compute.c:353
 #, c-format
 msgid "There is no vector named %s."
 msgstr "Er is geen vector genaamd %s."
@@ -4578,7 +4505,7 @@ msgstr "Er is geen vector genaamd %s."
 msgid "Destination cannot be a string variable."
 msgstr "Bestemming kan geen string variabele zijn."
 
-#: src/language/xforms/recode.c:251
+#: src/language/xforms/recode.c:248
 msgid ""
 "Inconsistent target variable types.  Target variables must be all numeric or "
 "all string."
@@ -4586,19 +4513,19 @@ msgstr ""
 "Inconsistent doel variabele types.  Doel variabelen moeten allemaal numeriek "
 "of allemaal string zijn. "
 
-#: src/language/xforms/recode.c:272
+#: src/language/xforms/recode.c:269
 msgid "CONVERT requires string input values and numeric output values."
 msgstr "CONVERT vereist string invoer waardes en numerieke uitvoer waardes."
 
-#: src/language/xforms/recode.c:329
+#: src/language/xforms/recode.c:324
 msgid "THRU is not allowed with string variables."
 msgstr "THRU is niet toegestaan met string variabelen."
 
-#: src/language/xforms/recode.c:407
+#: src/language/xforms/recode.c:403
 msgid "expecting output value"
 msgstr "verwacht uitvoer waarde"
 
-#: src/language/xforms/recode.c:456
+#: src/language/xforms/recode.c:460
 #, c-format
 msgid ""
 "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same "
@@ -4607,7 +4534,7 @@ msgstr ""
 "%zu variabel(en) kunnen niet gehercodeerd worden in %zu variabel(en).  "
 "Specificeer hetzelfde aantal variabelen als bron en als doel variabelen."
 
-#: src/language/xforms/recode.c:471
+#: src/language/xforms/recode.c:475
 #, c-format
 msgid ""
 "There is no variable named %s.  (All string variables specified on INTO must "
@@ -4617,12 +4544,12 @@ msgstr ""
 "INTO dienen al te bestaan.  Gebruik de STRING opdracht om een string "
 "variabele aan te maken.)"
 
-#: src/language/xforms/recode.c:487
+#: src/language/xforms/recode.c:491
 #, c-format
 msgid "INTO is required with %s input values and %s output values."
 msgstr "INTO is vereist met %s invoer waardes en %s uitvoer waardes."
 
-#: src/language/xforms/recode.c:500
+#: src/language/xforms/recode.c:504
 #, c-format
 msgid "Type mismatch.  Cannot store %s data in %s variable %s."
 msgstr "Type fout. Kan %s data niet in %s variabele %s opslaan. "
@@ -4653,6 +4580,31 @@ msgstr "De filter variabele mag niet scratch zijn."
 msgid "hash table:"
 msgstr "hash tabel:"
 
+#: src/libpspp/tmpfile.c:55
+#, c-format
+msgid "failed to create temporary file"
+msgstr "aanmaken van een tijdelijk bestand is mislukt"
+
+#: src/libpspp/tmpfile.c:96
+#, c-format
+msgid "seeking in temporary file"
+msgstr "zoeken in tijdelijk bestand"
+
+#: src/libpspp/tmpfile.c:115
+#, c-format
+msgid "reading temporary file"
+msgstr "lezen tijdelijk bestand"
+
+#: src/libpspp/tmpfile.c:117
+#, c-format
+msgid "unexpected end of file reading temporary file"
+msgstr "onverwacht einde bestand bij het lezen van tijdelijk bestand"
+
+#: src/libpspp/tmpfile.c:136
+#, c-format
+msgid "writing to temporary file"
+msgstr "schrijven naar tijdelijk bestand"
+
 #: src/math/percentiles.c:35
 msgid "HAverage"
 msgstr ""
@@ -4817,7 +4769,7 @@ msgstr "%s - Pagina %d"
 msgid "ascii: closing output file \"%s\""
 msgstr "ascii: sluiten uitvoer bestand \"%s\""
 
-#: src/output/chart.c:145
+#: src/output/chart.c:154
 #, c-format
 msgid "creating \"%s\""
 msgstr "aanmaken \"%s\""
@@ -5079,17 +5031,27 @@ msgstr "ongeldig numeriek formaat"
 msgid "closing Postscript encoding \"%s\""
 msgstr "sluiten Postscript codering \"%s\""
 
-#: src/output/table.c:236
+#: src/output/table.c:237
 #, c-format
 msgid "bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr ""
 
-#: src/output/table.c:307
+#: src/output/table.c:308
 #, c-format
 msgid ""
 "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr ""
 
+#: src/ui/gui/about.c:64
+msgid "A program for the analysis of sampled data"
+msgstr ""
+
+#. TRANSLATORS: Use this string to list the people who have helped with
+#. translation to your language.
+#: src/ui/gui/about.c:74
+msgid "translator-credits"
+msgstr ""
+
 #: src/ui/gui/comments-dialog.c:58
 #, c-format
 msgid "Column Number: %d"
@@ -5129,7 +5091,7 @@ msgstr ""
 
 #: src/ui/gui/crosstabs-dialog.c:53 src/ui/gui/crosstabs-dialog.c:64
 #: src/ui/gui/crosstabs-dialog.c:99 src/ui/gui/crosstabs-dialog.c:107
-#: src/ui/gui/psppire-var-store.c:559 src/ui/gui/var-display.c:16
+#: src/ui/gui/psppire-var-store.c:612 src/ui/gui/var-display.c:16
 #: src/ui/gui/variable-info-dialog.c:40
 msgid "None"
 msgstr "Geen"
@@ -5183,7 +5145,7 @@ msgstr "Print tabellen"
 msgid "Pivot"
 msgstr ""
 
-#: src/ui/gui/crosstabs.glade:253 src/ui/gui/psppire.glade:781
+#: src/ui/gui/crosstabs.glade:253 src/ui/gui/psppire.glade:756
 msgid "Ascending"
 msgstr "Oplopend"
 
@@ -5258,7 +5220,7 @@ msgid "_Edit"
 msgstr ""
 
 #: src/ui/gui/data-editor.glade:174 src/ui/gui/data-editor.glade:843
-#: src/ui/gui/psppire-data-window.c:844 src/ui/gui/psppire-data-window.c:934
+#: src/ui/gui/psppire-data-window.c:847 src/ui/gui/psppire-data-window.c:937
 msgid "Insert Variable"
 msgstr "Invoegen Variabele"
 
@@ -5451,11 +5413,11 @@ msgstr "_Handboek"
 msgid "_About"
 msgstr "_Over"
 
-#: src/ui/gui/data-editor.glade:702 src/ui/gui/psppire-data-window.c:379
+#: src/ui/gui/data-editor.glade:702 src/ui/gui/psppire-data-window.c:383
 msgid "Open"
 msgstr ""
 
-#: src/ui/gui/data-editor.glade:712 src/ui/gui/psppire-data-window.c:582
+#: src/ui/gui/data-editor.glade:712 src/ui/gui/psppire-data-window.c:585
 msgid "Save"
 msgstr "Opslaan"
 
@@ -5483,7 +5445,7 @@ msgstr "Variabelen"
 msgid "Find"
 msgstr "Vind"
 
-#: src/ui/gui/data-editor.glade:831 src/ui/gui/psppire-data-window.c:898
+#: src/ui/gui/data-editor.glade:831 src/ui/gui/psppire-data-window.c:901
 msgid "Insert Case"
 msgstr "Invoegen Case"
 
@@ -5598,7 +5560,7 @@ msgstr "Herhaal waardes"
 msgid "Missing Values"
 msgstr "Ontbrekende Waardes"
 
-#: src/ui/gui/find-dialog.c:657
+#: src/ui/gui/find-dialog.c:652
 #, c-format
 msgid "Bad regular expression: %s"
 msgstr "Foutieve regulaire expressie: %s"
@@ -5644,7 +5606,7 @@ msgstr ""
 msgid "Standard error of the kurtosis"
 msgstr ""
 
-#: src/ui/gui/frequencies.glade:98 src/ui/gui/psppire.glade:277
+#: src/ui/gui/frequencies.glade:98 src/ui/gui/psppire.glade:252
 #: src/ui/gui/rank.glade:103
 msgid "Variable(s):"
 msgstr "Variabele(n):"
@@ -5681,11 +5643,11 @@ msgstr "Onderdruk tabellen met meer dan N categorieën"
 msgid "Maximum no of categories"
 msgstr "Maximaal aantal categorieën"
 
-#: src/ui/gui/helper.c:186
+#: src/ui/gui/helper.c:197
 msgid "Sorry. The help system hasn't yet been implemented."
 msgstr "Sorry. Het help systeem is nog niet geïmplementeerd."
 
-#: src/ui/gui/helper.c:231
+#: src/ui/gui/helper.c:242
 #, c-format
 msgid "Cannot open reference manual: %s"
 msgstr "Kan de handleiding niet openen: %s"
@@ -5774,11 +5736,11 @@ msgstr ""
 msgid "gtk-close"
 msgstr ""
 
-#: src/ui/gui/missing-val-dialog.c:114 src/ui/gui/missing-val-dialog.c:159
+#: src/ui/gui/missing-val-dialog.c:113 src/ui/gui/missing-val-dialog.c:167
 msgid "Incorrect value for variable type"
 msgstr "Foutieve waarde voor variabele type"
 
-#: src/ui/gui/missing-val-dialog.c:135 src/ui/gui/missing-val-dialog.c:142
+#: src/ui/gui/missing-val-dialog.c:134 src/ui/gui/missing-val-dialog.c:143
 msgid "Incorrect range specification"
 msgstr "Foutieve range specificatie"
 
@@ -5879,18 +5841,25 @@ msgstr "_Standaard"
 msgid "_Select"
 msgstr "_Selecteer"
 
-#: src/ui/gui/psppire-data-editor.c:956
+#: src/ui/gui/psppire-data-editor.c:951
 msgid "Data View"
 msgstr "Data Weergave"
 
-#: src/ui/gui/psppire-data-editor.c:959
+#: src/ui/gui/psppire-data-editor.c:954
 msgid "Variable View"
 msgstr "Variabele Weergave"
 
-#: src/ui/gui/psppire-data-store.c:746
+#: src/ui/gui/psppire-data-store.c:744
 msgid "var"
 msgstr ""
 
+#: src/ui/gui/psppire-data-store.c:755 src/ui/gui/psppire-var-store.c:699
+#: src/ui/gui/psppire-var-store.c:709 src/ui/gui/psppire-var-store.c:719
+#: src/ui/gui/psppire-var-store.c:825
+#, c-format
+msgid "%d"
+msgstr ""
+
 #: src/ui/gui/psppire-data-window.c:213
 msgid "Transformations Pending"
 msgstr "Transformaties Uitstaand"
@@ -5899,201 +5868,201 @@ msgstr "Transformaties Uitstaand"
 msgid "Filter off"
 msgstr "Filter uit"
 
-#: src/ui/gui/psppire-data-window.c:241
+#: src/ui/gui/psppire-data-window.c:243
 #, c-format
 msgid "Filter by %s"
 msgstr "Filter op %s"
 
-#: src/ui/gui/psppire-data-window.c:262
+#: src/ui/gui/psppire-data-window.c:264
 msgid "No Split"
 msgstr "Geen Splits"
 
-#: src/ui/gui/psppire-data-window.c:271
+#: src/ui/gui/psppire-data-window.c:273
 msgid "Split by "
 msgstr "Splits op "
 
-#: src/ui/gui/psppire-data-window.c:299
+#: src/ui/gui/psppire-data-window.c:301
 msgid "Weights off"
 msgstr "Weging uit"
 
-#: src/ui/gui/psppire-data-window.c:311
+#: src/ui/gui/psppire-data-window.c:315
 #, c-format
 msgid "Weight by %s"
 msgstr "Weeg op %s"
 
-#: src/ui/gui/psppire-data-window.c:387 src/ui/gui/psppire-data-window.c:590
+#: src/ui/gui/psppire-data-window.c:391 src/ui/gui/psppire-data-window.c:593
 msgid "System Files (*.sav)"
 msgstr "Systeem Bestand (*.sav)"
 
-#: src/ui/gui/psppire-data-window.c:393 src/ui/gui/psppire-data-window.c:596
+#: src/ui/gui/psppire-data-window.c:397 src/ui/gui/psppire-data-window.c:599
 msgid "Portable Files (*.por) "
 msgstr "Overdraagbaar (Portable) Bestand (*.por)"
 
-#: src/ui/gui/psppire-data-window.c:399 src/ui/gui/psppire-data-window.c:602
+#: src/ui/gui/psppire-data-window.c:403 src/ui/gui/psppire-data-window.c:605
 #: src/ui/gui/psppire-syntax-window.c:298
 #: src/ui/gui/psppire-syntax-window.c:385
 msgid "All Files"
 msgstr "Alle bestanden"
 
-#: src/ui/gui/psppire-data-window.c:610
+#: src/ui/gui/psppire-data-window.c:613
 msgid "System File"
 msgstr "Systeem Bestand"
 
-#: src/ui/gui/psppire-data-window.c:615
+#: src/ui/gui/psppire-data-window.c:618
 msgid "Portable File"
 msgstr "Overdraagbaar (Portable) Bestand"
 
-#: src/ui/gui/psppire-data-window.c:765
+#: src/ui/gui/psppire-data-window.c:768
 msgid "Font Selection"
 msgstr "Font Selectie"
 
-#: src/ui/gui/psppire-data-window.c:833
+#: src/ui/gui/psppire-data-window.c:836
 msgid "Sort Ascending"
 msgstr "Sorteer oplopend"
 
-#: src/ui/gui/psppire-data-window.c:839
+#: src/ui/gui/psppire-data-window.c:842
 msgid "Sort Descending"
 msgstr "Sorteer aflopend"
 
-#: src/ui/gui/psppire-data-window.c:847 src/ui/gui/psppire-data-window.c:901
-#: src/ui/gui/psppire-data-window.c:937 src/ui/gui/psppire-data-window.c:1302
-#: src/ui/gui/psppire-data-window.c:1320
+#: src/ui/gui/psppire-data-window.c:850 src/ui/gui/psppire-data-window.c:904
+#: src/ui/gui/psppire-data-window.c:940 src/ui/gui/psppire-data-window.c:1308
+#: src/ui/gui/psppire-data-window.c:1326
 msgid "Clear"
 msgstr "Ruimop"
 
-#: src/ui/gui/psppire-data-window.c:1179
+#: src/ui/gui/psppire-data-window.c:1185
 msgid "Open a data file"
 msgstr "Open een data bestand"
 
-#: src/ui/gui/psppire-data-window.c:1197
+#: src/ui/gui/psppire-data-window.c:1203
 msgid "New data file"
 msgstr "Nieuw data bestand"
 
-#: src/ui/gui/psppire-data-window.c:1212
+#: src/ui/gui/psppire-data-window.c:1218
 msgid "Import text data file"
 msgstr "Importeer text data bestand"
 
-#: src/ui/gui/psppire-data-window.c:1228 src/ui/gui/psppire-data-window.c:1245
+#: src/ui/gui/psppire-data-window.c:1234 src/ui/gui/psppire-data-window.c:1251
 msgid "Save data to file"
 msgstr "Data opslaan als bestand"
 
-#: src/ui/gui/psppire-data-window.c:1244
+#: src/ui/gui/psppire-data-window.c:1250
 msgid "Save As"
 msgstr "Opslaan Als"
 
-#: src/ui/gui/psppire-data-window.c:1283
+#: src/ui/gui/psppire-data-window.c:1289
 msgid "Show/hide value labels"
 msgstr "Show/verberg waarde labels"
 
-#: src/ui/gui/psppire-data-window.c:1303
+#: src/ui/gui/psppire-data-window.c:1309
 msgid "Delete the cases at the selected position(s)"
 msgstr "Verwijder de cases op de geselecteerde positie(s)"
 
-#: src/ui/gui/psppire-data-window.c:1321
+#: src/ui/gui/psppire-data-window.c:1327
 msgid "Delete the variables at the selected position(s)"
 msgstr "Verwijder de variabele op de geselecteerde positie(s)"
 
-#: src/ui/gui/psppire-data-window.c:1339
+#: src/ui/gui/psppire-data-window.c:1345
 msgid "Create a new variable at the current position"
 msgstr "Creëer een nieuwe variabele op de huidige positie"
 
-#: src/ui/gui/psppire-data-window.c:1354
+#: src/ui/gui/psppire-data-window.c:1360
 msgid "Create a new case at the current position"
 msgstr "Creëer een nieuwe case op de huidige positie"
 
-#: src/ui/gui/psppire-data-window.c:1370
+#: src/ui/gui/psppire-data-window.c:1376
 msgid "Jump to a Case in the Data Sheet"
 msgstr "Spring naar een Case in het Data Blad"
 
-#: src/ui/gui/psppire-data-window.c:1386
+#: src/ui/gui/psppire-data-window.c:1392
 msgid "Weight cases by variable"
 msgstr "Weeg cases per variabele"
 
-#: src/ui/gui/psppire-data-window.c:1400
+#: src/ui/gui/psppire-data-window.c:1406
 msgid "Transpose the cases with the variables"
 msgstr "Herschik de cases met de variabelen"
 
-#: src/ui/gui/psppire-data-window.c:1414
+#: src/ui/gui/psppire-data-window.c:1420
 msgid "Split the active file"
 msgstr "Splits het actieve bestand"
 
-#: src/ui/gui/psppire-data-window.c:1429
+#: src/ui/gui/psppire-data-window.c:1435
 msgid "Sort cases in the active file"
 msgstr "Sorteer cases in het actieve bestand"
 
-#: src/ui/gui/psppire-data-window.c:1443
+#: src/ui/gui/psppire-data-window.c:1449
 msgid "Select cases from the active file"
 msgstr "Selecteer cases van het actieve bestand"
 
-#: src/ui/gui/psppire-data-window.c:1457
+#: src/ui/gui/psppire-data-window.c:1463
 msgid "Compute new values for a variable"
 msgstr "Bereken nieuwe waardes voor een variabele"
 
-#: src/ui/gui/psppire-data-window.c:1471
+#: src/ui/gui/psppire-data-window.c:1477
 msgid "Perform one way analysis of variance"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1486
+#: src/ui/gui/psppire-data-window.c:1492
 msgid "Calculate T Test for samples from independent groups"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1500
+#: src/ui/gui/psppire-data-window.c:1506
 msgid "Calculate T Test for paired samples"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1514
+#: src/ui/gui/psppire-data-window.c:1520
 msgid "Calculate T Test for sample from a single distribution"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1529
+#: src/ui/gui/psppire-data-window.c:1535
 msgid "Commentary text for the data file"
 msgstr "Commentaar tekst voor het data bestand"
 
-#: src/ui/gui/psppire-data-window.c:1555
+#: src/ui/gui/psppire-data-window.c:1561
 msgid "Rank Cases"
 msgstr "Rangschik Cases"
 
-#: src/ui/gui/psppire-data-window.c:1569
+#: src/ui/gui/psppire-data-window.c:1575
 msgid "Recode values into the same variables"
 msgstr "Hercodeer waardes in dezelfde Variabelen"
 
-#: src/ui/gui/psppire-data-window.c:1583
+#: src/ui/gui/psppire-data-window.c:1589
 msgid "Recode values into different variables"
 msgstr "Hercodeer waardes in andere Variabelen"
 
-#: src/ui/gui/psppire-data-window.c:1597
+#: src/ui/gui/psppire-data-window.c:1603
 msgid "Jump to variable"
 msgstr "Spring naar Variabele"
 
-#: src/ui/gui/psppire-data-window.c:1610
+#: src/ui/gui/psppire-data-window.c:1616
 msgid "Calculate descriptive statistics (mean, variance, ...)"
 msgstr "Bereken descriptive statistieken (mean, variance, ...)"
 
-#: src/ui/gui/psppire-data-window.c:1624
+#: src/ui/gui/psppire-data-window.c:1630
 msgid "Generate frequency statistics"
 msgstr "Genereer frequentie statistieken"
 
-#: src/ui/gui/psppire-data-window.c:1638
+#: src/ui/gui/psppire-data-window.c:1644
 msgid "Generate crosstabulations"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1653
+#: src/ui/gui/psppire-data-window.c:1659
 msgid "Examine Data by Factors"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1667
+#: src/ui/gui/psppire-data-window.c:1673
 msgid "Estimate parameters of the linear model"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1681 src/ui/gui/reliability.glade:7
+#: src/ui/gui/psppire-data-window.c:1687 src/ui/gui/reliability.glade:7
 msgid "Reliability Analysis"
 msgstr ""
 
-#: src/ui/gui/psppire-data-window.c:1844
+#: src/ui/gui/psppire-data-window.c:1850
 msgid "Split the window vertically and horizontally"
 msgstr "Splits het venster verticaal en horizontaal"
 
-#: src/ui/gui/psppire-data-window.c:1886
+#: src/ui/gui/psppire-data-window.c:1892
 msgid "Data Editor"
 msgstr ""
 
@@ -6109,188 +6078,182 @@ msgstr ""
 msgid "How many things can be selected"
 msgstr "Hoeveel dingen kunnen worden geselecteerd"
 
-#: src/ui/gui/psppire-dictview.c:539
+#: src/ui/gui/psppire-dictview.c:528
 msgid "Prefer variable labels"
 msgstr "Prefereer variabele labels"
 
-#: src/ui/gui/psppire.glade:10
-msgid ""
-"This is beta status software.  Please report bugs to bug-gnu-pspp@gnu.org"
-msgstr ""
-"Dit is beta status software. Rapporteer bugs s.v.p. bij bug-gnu-pspp@gnu.org"
-
-#: src/ui/gui/psppire.glade:72 src/ui/gui/psppire.glade:155
+#: src/ui/gui/psppire.glade:47 src/ui/gui/psppire.glade:130
 #: src/ui/gui/weight-cases-dialog.c:79
 msgid "Do not weight cases"
 msgstr "Weeg cases niet"
 
-#: src/ui/gui/psppire.glade:83
+#: src/ui/gui/psppire.glade:58
 msgid "Weight cases by"
 msgstr "Weeg cases op"
 
-#: src/ui/gui/psppire.glade:108
+#: src/ui/gui/psppire.glade:83
 msgid "Frequency Variable"
 msgstr "Frequencie Variabele"
 
-#: src/ui/gui/psppire.glade:148
+#: src/ui/gui/psppire.glade:123
 msgid "Current Status: "
 msgstr "Huidige Status:"
 
-#: src/ui/gui/psppire.glade:244
+#: src/ui/gui/psppire.glade:219
 msgid "Name Variable:"
 msgstr "Naam Variabele:"
 
-#: src/ui/gui/psppire.glade:429
+#: src/ui/gui/psppire.glade:404
 msgid "Analyze all cases.  Do not create groups."
 msgstr "Analyseer alle cases.  Creëer geen groepen."
 
-#: src/ui/gui/psppire.glade:440
+#: src/ui/gui/psppire.glade:415
 msgid "Compare groups."
 msgstr "Vergelijk groepen."
 
-#: src/ui/gui/psppire.glade:454
+#: src/ui/gui/psppire.glade:429
 msgid "Organize output by groups."
 msgstr "Organiseer uitvoer per groepen."
 
-#: src/ui/gui/psppire.glade:502
+#: src/ui/gui/psppire.glade:477
 msgid "Groups based on:"
 msgstr "Groepen gebaseerd op:"
 
-#: src/ui/gui/psppire.glade:565
+#: src/ui/gui/psppire.glade:540
 msgid "Sort the file by grouping variables."
 msgstr "Sorteer bestand op groepering variabelen."
 
-#: src/ui/gui/psppire.glade:577
+#: src/ui/gui/psppire.glade:552
 msgid "File is already sorted."
 msgstr "Bestand is al gesorteerd."
 
-#: src/ui/gui/psppire.glade:622
+#: src/ui/gui/psppire.glade:597
 msgid "Current Status : "
 msgstr "Huidige Status : "
 
-#: src/ui/gui/psppire.glade:630
+#: src/ui/gui/psppire.glade:605
 msgid "Analysis by groups is off"
 msgstr "Analyseer per groep is uit"
 
-#: src/ui/gui/psppire.glade:729
+#: src/ui/gui/psppire.glade:704
 msgid "Sort by:"
 msgstr "Sorteer op:"
 
-#: src/ui/gui/psppire.glade:792
+#: src/ui/gui/psppire.glade:767
 msgid "Descending"
 msgstr "Aflopend"
 
-#: src/ui/gui/psppire.glade:809
+#: src/ui/gui/psppire.glade:784
 msgid "Sort Order"
 msgstr "Sorteer Volgorde"
 
-#: src/ui/gui/psppire.glade:878
+#: src/ui/gui/psppire.glade:853
 msgid "Target Variable:"
 msgstr "Doel Variabele:"
 
-#: src/ui/gui/psppire.glade:909
+#: src/ui/gui/psppire.glade:884
 msgid "Type & Label"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:949
+#: src/ui/gui/psppire.glade:924
 msgid "="
 msgstr ""
 
-#: src/ui/gui/psppire.glade:995
+#: src/ui/gui/psppire.glade:970
 msgid "Numeric Expressions:"
 msgstr "Numerieke Expressies:"
 
-#: src/ui/gui/psppire.glade:1049
+#: src/ui/gui/psppire.glade:1024
 msgid "Functions:"
 msgstr "Functies:"
 
-#: src/ui/gui/psppire.glade:1112 src/ui/gui/psppire.glade:1516
+#: src/ui/gui/psppire.glade:1087 src/ui/gui/psppire.glade:1491
 #: src/ui/gui/recode.glade:731
 msgid "If..."
 msgstr "Als..."
 
-#: src/ui/gui/psppire.glade:1345
+#: src/ui/gui/psppire.glade:1320
 msgid "Use filter variable"
 msgstr "Gebruik filter variabele"
 
-#: src/ui/gui/psppire.glade:1398
+#: src/ui/gui/psppire.glade:1373
 msgid "Based on time or case range"
 msgstr "Gebaseerd op tijd of case volgorde"
 
-#: src/ui/gui/psppire.glade:1411
+#: src/ui/gui/psppire.glade:1386
 msgid "Range..."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1450
+#: src/ui/gui/psppire.glade:1425
 msgid "Random sample of cases"
 msgstr "Random steekproef van cases"
 
-#: src/ui/gui/psppire.glade:1464
+#: src/ui/gui/psppire.glade:1439
 msgid "Sample..."
 msgstr "Steekproef..."
 
-#: src/ui/gui/psppire.glade:1502
+#: src/ui/gui/psppire.glade:1477
 msgid "If condition is satisfied"
 msgstr "Aan If conditie is voldaan"
 
-#: src/ui/gui/psppire.glade:1551
+#: src/ui/gui/psppire.glade:1526
 msgid "All Cases"
 msgstr "Alle Cases"
 
-#: src/ui/gui/psppire.glade:1566
+#: src/ui/gui/psppire.glade:1541
 msgid "Select"
 msgstr "Selecteer"
 
-#: src/ui/gui/psppire.glade:1595
+#: src/ui/gui/psppire.glade:1570
 msgid "Filtered"
 msgstr "Gefilterd"
 
-#: src/ui/gui/psppire.glade:1606
+#: src/ui/gui/psppire.glade:1581
 msgid "Deleted"
 msgstr "Verwijderd"
 
-#: src/ui/gui/psppire.glade:1624
+#: src/ui/gui/psppire.glade:1599
 msgid "Unselected Cases Are"
 msgstr "Niet geselecteerde Cases zijn"
 
-#: src/ui/gui/psppire.glade:1689
+#: src/ui/gui/psppire.glade:1664
 msgid "Comments:"
 msgstr "Commentaren:"
 
-#: src/ui/gui/psppire.glade:1731
+#: src/ui/gui/psppire.glade:1706
 msgid "Display comments in output"
 msgstr "Toon commentaren in uitvoer"
 
-#: src/ui/gui/psppire.glade:1746
+#: src/ui/gui/psppire.glade:1721
 msgid "Column Number: 0"
 msgstr "Kolom Nummer: 0"
 
-#: src/ui/gui/psppire.glade:1829
+#: src/ui/gui/psppire.glade:1804
 msgid "First case"
 msgstr "Eerste case"
 
-#: src/ui/gui/psppire.glade:1842
+#: src/ui/gui/psppire.glade:1817
 msgid "Last case"
 msgstr "Laatste case"
 
-#: src/ui/gui/psppire.glade:1855
+#: src/ui/gui/psppire.glade:1830
 msgid "Observation"
 msgstr "Observatie"
 
-#: src/ui/gui/psppire.glade:1919
+#: src/ui/gui/psppire.glade:1894
 msgid "Use expression as label"
 msgstr "Gebruik expressie als label"
 
-#: src/ui/gui/psppire.glade:2045 src/ui/gui/psppire-var-sheet.c:540
-#: src/ui/gui/psppire-var-store.c:786
+#: src/ui/gui/psppire.glade:2020 src/ui/gui/psppire-var-sheet.c:532
+#: src/ui/gui/psppire-var-store.c:834
 msgid "Width"
 msgstr "Breedte"
 
-#: src/ui/gui/psppire.glade:2175
+#: src/ui/gui/psppire.glade:2150
 msgid "Goto Case Number:"
 msgstr "Ga naar Case Nummer:"
 
-#: src/ui/gui/psppire.glade:2312
+#: src/ui/gui/psppire.glade:2287
 msgid "Sample Size"
 msgstr "Steekproef Grootte"
 
@@ -6325,47 +6288,47 @@ msgstr ""
 msgid "Cannot load syntax file '%s'"
 msgstr "Kan syntax bestand \"%s\" niet laden"
 
-#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:784
+#: src/ui/gui/psppire-var-sheet.c:530 src/ui/gui/psppire-var-store.c:832
 msgid "Name"
 msgstr "Naam"
 
-#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:787
+#: src/ui/gui/psppire-var-sheet.c:533 src/ui/gui/psppire-var-store.c:835
 msgid "Decimals"
 msgstr "Decimalen"
 
-#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:789
+#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:837
 msgid "Values"
 msgstr "Waardes"
 
-#: src/ui/gui/psppire-var-sheet.c:546 src/ui/gui/psppire-var-store.c:792
+#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:840
 msgid "Align"
 msgstr "Uitlijnen"
 
-#: src/ui/gui/psppire-var-sheet.c:547 src/ui/gui/psppire-var-store.c:793
+#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:841
 msgid "Measure"
 msgstr "Meting"
 
-#: src/ui/gui/psppire-var-store.c:569 src/ui/gui/var-sheet-dialogs.glade:43
+#: src/ui/gui/psppire-var-store.c:622 src/ui/gui/var-sheet-dialogs.glade:43
 msgid "Comma"
 msgstr "Komma"
 
-#: src/ui/gui/psppire-var-store.c:570 src/ui/gui/var-sheet-dialogs.glade:59
+#: src/ui/gui/psppire-var-store.c:623 src/ui/gui/var-sheet-dialogs.glade:59
 msgid "Dot"
 msgstr "Punt"
 
-#: src/ui/gui/psppire-var-store.c:571
+#: src/ui/gui/psppire-var-store.c:624
 msgid "Scientific"
 msgstr "Wetenschappelijk"
 
-#: src/ui/gui/psppire-var-store.c:572 src/ui/gui/var-sheet-dialogs.glade:91
+#: src/ui/gui/psppire-var-store.c:625 src/ui/gui/var-sheet-dialogs.glade:91
 msgid "Date"
 msgstr "Datum"
 
-#: src/ui/gui/psppire-var-store.c:573 src/ui/gui/var-sheet-dialogs.glade:107
+#: src/ui/gui/psppire-var-store.c:626 src/ui/gui/var-sheet-dialogs.glade:107
 msgid "Dollar"
 msgstr "Euro"
 
-#: src/ui/gui/psppire-var-store.c:574
+#: src/ui/gui/psppire-var-store.c:627
 msgid "Custom"
 msgstr "Aangepast"
 
@@ -6762,12 +6725,12 @@ msgstr ""
 "moet worden."
 
 #: src/ui/gui/text-data-import-dialog.c:1523
-#: src/ui/gui/text-data-import-dialog.c:1765
+#: src/ui/gui/text-data-import-dialog.c:1768
 msgid "This input line has too few separators to fill in this field."
 msgstr ""
 "Deze invoer regel heeft te weinig scheidingstekens om dit veld te vullen."
 
-#: src/ui/gui/text-data-import-dialog.c:1756
+#: src/ui/gui/text-data-import-dialog.c:1759
 #, c-format
 msgid "Field content \"%.*s\" cannot be parsed in format %s."
 msgstr "Veld inhoud \"%.*s\" kan niet ontleed worden in formaat %s."
@@ -6953,39 +6916,39 @@ msgstr "Test Waarde:"
 msgid "Confidence Interval: %2d %%"
 msgstr ""
 
-#: src/ui/gui/t-test-paired-samples.c:227
+#: src/ui/gui/t-test-paired-samples.c:226
 msgid "Var 1"
 msgstr ""
 
-#: src/ui/gui/t-test-paired-samples.c:228
+#: src/ui/gui/t-test-paired-samples.c:227
 msgid "Var 2"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:92
+#: src/ui/gui/variable-info-dialog.c:76
 #, c-format
 msgid "Label: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:101
+#: src/ui/gui/variable-info-dialog.c:83
 #, c-format
 msgid "Type: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:105
+#: src/ui/gui/variable-info-dialog.c:87
 #, c-format
 msgid "Missing Values: %s\n"
 msgstr "Ontbrekende Waardes: %s\n"
 
-#: src/ui/gui/variable-info-dialog.c:110
+#: src/ui/gui/variable-info-dialog.c:92
 #, c-format
 msgid "Measurement Level: %s\n"
 msgstr "Meetniveau: %s\n"
 
-#: src/ui/gui/variable-info-dialog.c:124
+#: src/ui/gui/variable-info-dialog.c:107
 msgid "Value Labels:\n"
 msgstr "Waarde Labels:\n"
 
-#: src/ui/gui/variable-info-dialog.c:137
+#: src/ui/gui/variable-info-dialog.c:117
 #, c-format
 msgid "%s %s\n"
 msgstr ""
@@ -7177,5 +7140,90 @@ msgstr "Print een lijst van bekende driver classes en eindig daarna"
 msgid "Start an interactive session"
 msgstr "Start een interactieve sessie"
 
+#~ msgid "Bad variable width %d."
+#~ msgstr "Foutieve variabele breedte %d."
+
+#~ msgid "File specifies unexpected value %g as HIGHEST."
+#~ msgstr "Bestand specificeert onverwachte waarde %g als HIGHEST."
+
+#~ msgid "File specifies unexpected value %g as LOWEST."
+#~ msgstr "Bestand specificeert onverwachte waarde %g als LOWEST."
+
+#~ msgid "%s is unimplemented."
+#~ msgstr "%s is niet geïmplementeerd."
+
+#~ msgid "Bad character in input: `\\%o'."
+#~ msgstr "Fout karakter in input: '\\%o'."
+
+#~ msgid "WEIGHT is off."
+#~ msgstr "WEGING is uit."
+
+#~ msgid "WEIGHT is variable %s."
+#~ msgstr "WEGING is variabele %s."
+
+#~ msgid "WIDTH is %d."
+#~ msgstr "BREEDTE is %d."
+
+#~ msgid ""
+#~ "Ignoring missing values on long string variable %s, which PSPP does not "
+#~ "yet support."
+#~ msgstr ""
+#~ "Negeren van missing values voor lange string variabele %s, wat PSPP nog "
+#~ "niet ondersteunt."
+
+#~ msgid ""
+#~ "Ignoring value labels for long string variables, which PSPP does not yet "
+#~ "support."
+#~ msgstr ""
+#~ "Negeer waarde labels voor lange string variabelen, die door PSPP nog niet "
+#~ "ondersteund worden."
+
+#~ msgid "Cannot add value labels from source file to long string variable %s."
+#~ msgstr ""
+#~ "Kan geen value labels van bron bestand toevoegen aan lange string "
+#~ "variabele %s."
+
+#~ msgid ""
+#~ "It is not possible to assign value labels to long string variables such "
+#~ "as %s."
+#~ msgstr ""
+#~ "Het is niet mogelijk om waarde labels aan lange string variabelen als %s "
+#~ "toe te kennen."
+
+#~ msgid "Write mode ALL not allowed in general mode.  Assuming WRITE=CELLS."
+#~ msgstr ""
+#~ "Write modus ALL niet toegestaan in algemen modus.  WRITE=CELLS aangenomen."
+
+#~ msgid "Error writing FLIP file: %s."
+#~ msgstr "Fout tijdens het schrijven van FLIP bestand: %s."
+
+#~ msgid "Could not create acceptable variant for variable %s."
+#~ msgstr "Kon geen acceptabele variant voor variabele %s creëren."
+
+#~ msgid "Cannot create more than 99999 variable names."
+#~ msgstr "Kan niet meer dan 99999 variabele namen creëren."
+
+#~ msgid "Long string variable %s is not valid here."
+#~ msgstr "Lange string variabele %s is niet geldig hier."
+
+#~ msgid "PATH and SEARCH subcommands are mutually exclusive.  Ignoring PATH."
+#~ msgstr ""
+#~ "PATH en SEARCH subopdrachten zijn wederzijds uitsluitend. PATH genegeerd. "
+
+#~ msgid "At least one value must be specified on PATH."
+#~ msgstr "Tenminste 1 waarde dient bij PATH opgegeven te zijn."
+
+#~ msgid "Hash bits adjusted to %d."
+#~ msgstr "Hash bits aangepast naar %d."
+
+#~ msgid "error opening \"%s\" for writing"
+#~ msgstr "fout bij openen \"%s\" voor schrijven"
+
+#~ msgid ""
+#~ "This is beta status software.  Please report bugs to bug-gnu-pspp@gnu.org"
+#~ msgstr ""
+#~ "Dit is beta status software. Rapporteer bugs s.v.p. bij bug-gnu-pspp@gnu."
+#~ "org"
+
 #~ msgid "Diagnositic options:"
 #~ msgstr "Diagnostische opties:"
index 411b9f0d49904cc118f3052c35c096c70c0e8376..49297d1349f5c50661e904408f6135684786e710 100644 (file)
@@ -100,7 +100,7 @@ case_map_execute (const struct case_map *map, struct ccase *src)
         {
           int src_idx = map->map[dst_idx];
           if (src_idx != -1)
-            *case_data_rw_idx (dst, dst_idx) = *case_data_idx (src, src_idx);
+           value_copy (case_data_rw_idx (dst, dst_idx), case_data_idx (src, src_idx), caseproto_get_width (map->proto, dst_idx));
         }
       case_unref (src);
       return dst;
index a4a78dd0efcf9750d26c169e4db63a46e2093a25..dc4029268ebf981bc10d96ecccf7c88eb53dd71a 100644 (file)
@@ -308,7 +308,7 @@ case_num_idx (const struct ccase *c, size_t idx)
 
    Like the strings embedded in all "union value"s, the return
    value is not null-terminated. */
-const char *
+const uint8_t *
 case_str (const struct ccase *c, const struct variable *v)
 {
   size_t idx = var_get_case_index (v);
@@ -321,7 +321,7 @@ case_str (const struct ccase *c, const struct variable *v)
 
    Like the strings embedded in all "union value"s, the return
    value is not null-terminated. */
-const char *
+const uint8_t *
 case_str_idx (const struct ccase *c, size_t idx)
 {
   assert (idx < c->proto->n_widths);
@@ -336,7 +336,7 @@ case_str_idx (const struct ccase *c, size_t idx)
 
    Like the strings embedded in all "union value"s, the return
    value is not null-terminated. */
-char *
+uint8_t *
 case_str_rw (struct ccase *c, const struct variable *v)
 {
   size_t idx = var_get_case_index (v);
@@ -352,7 +352,7 @@ case_str_rw (struct ccase *c, const struct variable *v)
 
    Like the strings embedded in all "union value"s, the return
    value is not null-terminated. */
-char *
+uint8_t *
 case_str_rw_idx (struct ccase *c, size_t idx)
 {
   assert (idx < c->proto->n_widths);
index 36feb15f6b073a82533bc71161f3b8f7a00f4a76..0bfc62cdce96054fe461043ac2cb44bf39436c03 100644 (file)
@@ -94,10 +94,10 @@ union value *case_data_rw_idx (struct ccase *, size_t idx);
 double case_num (const struct ccase *, const struct variable *);
 double case_num_idx (const struct ccase *, size_t idx);
 
-const char *case_str (const struct ccase *, const struct variable *);
-const char *case_str_idx (const struct ccase *, size_t idx);
-char *case_str_rw (struct ccase *, const struct variable *);
-char *case_str_rw_idx (struct ccase *, size_t idx);
+const uint8_t *case_str (const struct ccase *, const struct variable *);
+const uint8_t *case_str_idx (const struct ccase *, size_t idx);
+uint8_t *case_str_rw (struct ccase *, const struct variable *);
+uint8_t *case_str_rw_idx (struct ccase *, size_t idx);
 
 int case_compare (const struct ccase *, const struct ccase *,
                   const struct variable *const *, size_t n_vars);
index 548c22fb2ddd646653debaeb50e22fae70dd9c81..feffa15c4510ba97e57cd95705cd9afd290c1e04 100644 (file)
@@ -19,6 +19,7 @@
 #include <data/casereader.h>
 #include <stdlib.h>
 
+#include <data/variable.h>
 #include <data/casereader-provider.h>
 #include <libpspp/taint.h>
 
@@ -359,3 +360,132 @@ car_translate (struct ccase *input, void *car_)
 }
 
 
+\f
+
+struct consolidator
+{
+  const struct variable *key;
+  const struct variable *weight;
+  double cc;
+  double prev_cc;
+
+  casenumber n;
+  struct casereader *clone;
+  struct caseproto *proto;
+  int direction;
+};
+
+static bool
+uniquify (const struct ccase *c, void *aux)
+{
+  struct consolidator *cdr = aux;
+  const union value *current_value = case_data (c, cdr->key);
+  const int key_width = var_get_width (cdr->key);
+  const double weight = cdr->weight ? case_data (c, cdr->weight)->f : 1.0;
+  const struct ccase *next_case = casereader_peek (cdr->clone, cdr->n + 1);
+  int dir = 0;
+
+  cdr->n ++;
+  cdr->cc += weight;
+
+  if ( NULL == next_case)
+      goto end;
+  
+  dir = value_compare_3way (case_data (next_case, cdr->key),
+                           current_value, key_width);
+  if ( dir != 0 )
+    {
+      /* Insist that the data are sorted */
+      assert (cdr->direction == 0 || dir == cdr->direction);
+      cdr->direction = dir;
+      goto end;
+    }
+  
+  return false;
+
+ end:
+  cdr->prev_cc = cdr->cc;
+  cdr->cc = 0;
+  return true;
+}
+
+
+
+static struct ccase *
+consolodate_weight (struct ccase *input, void *aux)
+{
+  struct consolidator *cdr = aux;
+  struct ccase *c;
+
+  if (cdr->weight)
+    {
+      c = case_unshare (input);
+      case_data_rw (c, cdr->weight)->f = cdr->prev_cc;
+    }
+  else
+    {
+      c = case_unshare_and_resize (input, cdr->proto);
+      case_data_rw_idx (c, caseproto_get_n_widths (cdr->proto) - 1)->f = cdr->prev_cc;    
+    }
+
+  return c;
+}
+
+
+static bool
+uniquify_destroy (void *aux)
+{
+  struct consolidator *cdr = aux;
+
+  casereader_destroy (cdr->clone);
+  caseproto_unref (cdr->proto);
+  free (cdr);
+
+  return true;
+}
+
+
+
+/* Returns a new casereader which is based upon INPUT, but which contains a maximum 
+   of one case for each distinct value of KEY.
+   If WEIGHT is non-null, then the new casereader's values for this variable
+   will be the sum of all values matching KEY.
+   IF WEIGHT is null, then the new casereader will have an additional numeric
+   value appended, which will contain the total number of cases containing
+   KEY.
+   INPUT must be sorted on KEY
+*/
+struct casereader *
+casereader_create_distinct (struct casereader *input,
+                                              const struct variable *key,
+                                              const struct variable *weight)
+{
+  struct casereader *u ;
+  struct casereader *ud ;
+  struct caseproto *output_proto = caseproto_ref (casereader_get_proto (input));
+
+  struct consolidator *cdr = xmalloc (sizeof (*cdr));
+  cdr->n = 0;
+  cdr->key = key;
+  cdr->weight = weight;
+  cdr->cc = 0;
+  cdr->clone = casereader_clone (input);
+  cdr->direction = 0;
+
+  if ( NULL == cdr->weight )
+    output_proto = caseproto_add_width (output_proto, 0);
+
+  cdr->proto = output_proto;
+
+  u = casereader_create_filter_func (input, uniquify,
+                                    NULL, cdr, NULL);
+
+  ud = casereader_create_translator (u,
+                                    output_proto,
+                                    consolodate_weight,
+                                    uniquify_destroy,
+                                    cdr);
+
+  return ud;
+}
+
index d4f2966a5e7a18be9395f253445fa4fa82ff2beb..3b903bbfd52d66cdba8ffe0e960fa7f0d1ef2474 100644 (file)
@@ -140,5 +140,10 @@ casereader_create_append_rank (struct casereader *,
                               enum rank_error *err,
                               distinct_func *distinct_callback, void *aux);
 
+struct casereader *
+casereader_create_distinct (struct casereader *input,
+                           const struct variable *key,
+                           const struct variable *weight);
+
 
 #endif /* data/casereader.h */
index eda6d1258f729b8d05352fb71fe1a24a0cdb1ef6..33e369f971da8751f78e29e76f23d230e6e0227d 100644 (file)
 #include "settings.h"
 #include "value.h"
 #include "format.h"
+#include "dictionary.h"
 
 #include <libpspp/assertion.h>
 #include <libpspp/legacy-encoding.h>
+#include <libpspp/i18n.h>
 #include <libpspp/compiler.h>
 #include <libpspp/integer-format.h>
 #include <libpspp/message.h>
@@ -53,7 +55,7 @@
 /* Information about parsing one data field. */
 struct data_in
   {
-    enum legacy_encoding encoding;/* Encoding of source. */
+    const char *src_enc;        /* Encoding of source. */
     struct substring input;     /* Source. */
     enum fmt_type format;       /* Input format. */
     int implied_decimals;       /* Number of implied decimal places. */
@@ -88,6 +90,9 @@ static int hexit_value (int c);
    representation in OUTPUT, which the caller must have
    initialized with the given WIDTH (0 for a numeric field,
    otherwise the string width).
+   Iff FORMAT is a string format, then DICT must be a pointer
+   to the dictionary associated with OUTPUT.  Otherwise, DICT
+   may be null.
 
    If no decimal point is included in a numeric format, then
    IMPLIED_DECIMALS decimal places are implied.  Specify 0 if no
@@ -100,9 +105,11 @@ static int hexit_value (int c);
    FIRST_COLUMN plus the length of the input because of the
    possibility of escaped quotes in strings, etc.) */
 bool
-data_in (struct substring input, enum legacy_encoding encoding,
+data_in (struct substring input, const char *encoding,
          enum fmt_type format, int implied_decimals,
-         int first_column, int last_column, union value *output, int width)
+         int first_column, int last_column,
+        const struct dictionary *dict,
+        union value *output, int width)
 {
   static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
     {
@@ -111,25 +118,11 @@ data_in (struct substring input, enum legacy_encoding encoding,
     };
 
   struct data_in i;
-  void *copy = NULL;
+
   bool ok;
 
   assert ((width != 0) == fmt_is_string (format));
 
-  if (encoding == LEGACY_NATIVE
-      || fmt_get_category (format) & (FMT_CAT_BINARY | FMT_CAT_STRING))
-    {
-      i.input = input;
-      i.encoding = encoding;
-    }
-  else
-    {
-      ss_alloc_uninit (&i.input, ss_length (input));
-      legacy_recode (encoding, ss_data (input), LEGACY_NATIVE,
-                     ss_data (i.input), ss_length (input));
-      i.encoding = LEGACY_NATIVE;
-      copy = ss_data (i.input);
-    }
   i.format = format;
   i.implied_decimals = implied_decimals;
 
@@ -138,21 +131,39 @@ data_in (struct substring input, enum legacy_encoding encoding,
 
   i.first_column = first_column;
   i.last_column = last_column;
+  i.src_enc = encoding;
 
-  if (!ss_is_empty (i.input))
+  if (ss_is_empty (input))
     {
-      ok = handlers[i.format] (&i);
-      if (!ok)
-        default_result (&i);
+      default_result (&i);
+      return true;
+    }
+
+  if (fmt_get_category (format) & ( FMT_CAT_BINARY | FMT_CAT_HEXADECIMAL | FMT_CAT_LEGACY))
+    {
+      i.input = input;
     }
   else
     {
-      default_result (&i);
-      ok = true;
+      const char *dest_encoding;
+      char *s = NULL;
+      if ( dict == NULL)
+       {
+         assert (0 == (fmt_get_category (format) & (FMT_CAT_BINARY | FMT_CAT_STRING)));
+         dest_encoding = LEGACY_NATIVE;
+       }
+      else
+       dest_encoding = dict_get_encoding (dict);
+
+      s = recode_string (dest_encoding, i.src_enc, ss_data (input), ss_length (input));
+      ss_alloc_uninit (&i.input, strlen (s));
+      memcpy (ss_data (i.input), s, ss_length (input));
+      free (s);
     }
 
-  if (copy)
-    free (copy);
+  ok = handlers[i.format] (&i);
+  if (!ok)
+    default_result (&i);
 
   return ok;
 }
@@ -608,12 +619,13 @@ parse_A (struct data_in *i)
 {
   /* This is equivalent to buf_copy_rpad, except that we posibly
      do a character set recoding in the middle. */
-  char *dst = value_str_rw (i->output, i->width);
+  uint8_t *dst = value_str_rw (i->output, i->width);
   size_t dst_size = i->width;
   const char *src = ss_data (i->input);
   size_t src_size = ss_length (i->input);
 
-  legacy_recode (i->encoding, src, LEGACY_NATIVE, dst, MIN (src_size, dst_size));
+  memcpy (dst, src, MIN (src_size, dst_size));
+
   if (dst_size > src_size)
     memset (&dst[src_size], ' ', dst_size - src_size);
 
@@ -624,7 +636,7 @@ parse_A (struct data_in *i)
 static bool
 parse_AHEX (struct data_in *i)
 {
-  char *s = value_str_rw (i->output, i->width);
+  uint8_t *s = value_str_rw (i->output, i->width);
   size_t j;
 
   for (j = 0; ; j++)
@@ -639,10 +651,10 @@ parse_AHEX (struct data_in *i)
           return false;
         }
 
-      if (i->encoding != LEGACY_NATIVE)
+      if (0 != strcmp (i->src_enc, LEGACY_NATIVE))
         {
-          hi = legacy_to_native (i->encoding, hi);
-          lo = legacy_to_native (i->encoding, lo);
+          hi = legacy_to_native (i->src_enc, hi);
+          lo = legacy_to_native (i->src_enc, lo);
         }
       if (!c_isxdigit (hi) || !c_isxdigit (lo))
        {
index 3a8d67cc22f66b28eb0bed54126e5a3255449064..3ebd5933c43b0370e29cfd279cd3b22fcdbb0b4d 100644 (file)
 
 enum fmt_type;
 union value;
-bool data_in (struct substring input, enum legacy_encoding,
+struct dictionary;
+bool data_in (struct substring input, const char *encoding,
               enum fmt_type, int implied_decimals,
               int first_column, int last_column,
+             const struct dictionary *dict,
               union value *output, int width);
 
 #endif /* data/data-in.h */
index e7800a8ff2de3a64c58d77b1aee3688a76c90b5d..94a6130adb154bd06b61901414e4209498cbf106 100644 (file)
@@ -36,6 +36,8 @@
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
+#include <libpspp/pool.h>
+#include <libpspp/i18n.h>
 
 #include "minmax.h"
 
@@ -83,38 +85,68 @@ static void output_binary_integer (uint64_t, int bytes, enum integer_format,
                                    char *);
 static void output_hex (const void *, size_t bytes, char *);
 \f
-/* Same as data_out, and additionally recodes the output from
-   native form into the given legacy character ENCODING. */
-void
-data_out_legacy (const union value *input, enum legacy_encoding encoding,
-                 const struct fmt_spec *format, char *output)
-{
-  static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] =
+
+static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] =
     {
 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) output_##METHOD,
 #include "format.def"
     };
 
+/* Similar to data_out. Additionally recodes the output from
+   native form into the given legacy character ENCODING.
+   OUTPUT must be provided by the caller and must be at least
+   FORMAT->w long. No null terminator is appended to OUTPUT.
+*/
+void
+data_out_legacy (const union value *input, const char *encoding,
+                 const struct fmt_spec *format, char *output)
+{
   assert (fmt_check_output (format));
 
   converters[format->type] (input, format, output);
-  if (encoding != LEGACY_NATIVE
+  if (0 != strcmp (encoding, LEGACY_NATIVE)
       && fmt_get_category (format->type) != FMT_CAT_BINARY)
-    legacy_recode (LEGACY_NATIVE, output, encoding, output, format->w);
+    {
+      char *s  = recode_string (encoding, LEGACY_NATIVE, output, format->w );
+      memcpy (output, s, format->w);
+      free (s);
+    }
 }
 
-/* Converts the INPUT value into printable form in the exactly
-   FORMAT->W characters in OUTPUT according to format
-   specification FORMAT. No null terminator is appended to the
-   buffer.
+/* Converts the INPUT value into a UTF8 encoded string, according
+   to format specification FORMAT. 
 
    VALUE must be the correct width for FORMAT, that is, its
-   width must be fmt_var_width(FORMAT). */
-void
-data_out (const union value *input, const struct fmt_spec *format,
-          char *output)
+   width must be fmt_var_width(FORMAT).
+
+   ENCODING must be the encoding of INPUT.  Normally this can
+   be obtained by calling dict_get_encoding on the dictionary
+   with which INPUT is associated.
+
+   The return value is dynamically allocated, and must be freed
+   by the caller.  If POOL is non-null, then the return value is
+   allocated on that pool.
+*/
+char *
+data_out_pool (const union value *input, const char *encoding,
+              const struct fmt_spec *format, struct pool *pool)
+{
+  char *output = xmalloc (format->w + 1);
+  char *t ;
+  assert (fmt_check_output (format));
+
+  converters[format->type] (input, format, output);
+  output[format->w] = '\0';
+
+  t =  recode_string_pool (UTF8, encoding, output, format->w, pool);
+  free (output);
+  return t;
+}
+
+char *
+data_out (const union value *input, const char *encoding, const struct fmt_spec *format)
 {
-  return data_out_legacy (input, LEGACY_NATIVE, format, output);
+  return data_out_pool (input, encoding, format, NULL);
 }
 
 \f
index f9f70da90d37843d546752b3ad97baf041fdfc51..735679b41257b78d0918ae4c83e29c90eeb62546 100644 (file)
 struct fmt_spec;
 union value;
 
-void data_out (const union value *, const struct fmt_spec *, char *);
+char * data_out (const union value *, const char *encoding, const struct fmt_spec *);
 
-void data_out_legacy (const union value *, enum legacy_encoding,
-                      const struct fmt_spec *, char *);
+char * data_out_pool (const union value *, const char *encoding, const struct fmt_spec *, struct pool *pool);
+
+void data_out_legacy (const union value *input, const char *encoding,
+                     const struct fmt_spec *format, char *output);
 
 #endif /* data-out.h */
index 0652501faa17fa27b19989b07e471b816731360c..6ed3f8f9f95205158cbf2a33227e5dbec6a81529 100644 (file)
@@ -49,7 +49,7 @@ struct file_handle
     /* FH_REF_FILE only. */
     char *file_name;           /* File name as provided by user. */
     enum fh_mode mode;         /* File mode. */
-    enum legacy_encoding encoding;/* File encoding. */
+    const char *encoding;       /* File encoding. */
 
     /* FH_REF_FILE and FH_REF_INLINE only. */
     size_t record_width;        /* Length of fixed-format records. */
@@ -325,7 +325,7 @@ fh_get_tab_width (const struct file_handle *handle)
 }
 
 /* Returns the encoding of characters read from HANDLE. */
-enum legacy_encoding
+const char *
 fh_get_legacy_encoding (const struct file_handle *handle)
 {
   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
index 73e118cdf848f81e1e6405983fec02b45f0a6a9c..b4a6d6100e8ed291ed8705a659d381beb8ec26a6 100644 (file)
@@ -54,7 +54,7 @@ struct fh_properties
     enum fh_mode mode;          /* File mode. */
     size_t record_width;        /* Length of fixed-format records. */
     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
-    enum legacy_encoding encoding;/* ASCII or EBCDIC? */
+    const char *encoding;       /* ASCII or EBCDIC? */
   };
 
 void fh_init (void);
@@ -89,7 +89,7 @@ enum fh_mode fh_get_mode (const struct file_handle *) ;
 /* Properties of FH_REF_FILE and FH_REF_INLINE file handles. */
 size_t fh_get_record_width (const struct file_handle *);
 size_t fh_get_tab_width (const struct file_handle *);
-enum legacy_encoding fh_get_legacy_encoding (const struct file_handle *);
+const char *fh_get_legacy_encoding (const struct file_handle *);
 
 /* Properties of FH_REF_SCRATCH file handles. */
 struct scratch_handle *fh_get_scratch_handle (const struct file_handle *);
index 1a6ddc1bad52c3e99143b19ee2927c6c1f340b67..f166ee6aba86f1a00acefb409c466e253635a574 100644 (file)
@@ -365,7 +365,7 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
 
   if ( NULL == gz)
     {
-      msg (ME, _("Error opening \"%s\" for reading as a gnumeric file: %s."),
+      msg (ME, _("Error opening \"%s\" for reading as a Gnumeric file: %s."),
            gri->file_name, strerror (errno));
 
       goto error;
index c1a7469158ead5204e6da7fa5a4432ad36fc3bbb..61bb9bcb13c4968a4500fc4fc98ee13e2f631c1b 100644 (file)
@@ -160,7 +160,7 @@ mv_add_value (struct missing_values *mv, const union value *v)
    Returns true if successful, false if MV has no more room for
    missing values or if S is not an acceptable missing value. */
 bool
-mv_add_str (struct missing_values *mv, const char s[])
+mv_add_str (struct missing_values *mv, const uint8_t s[])
 {
   union value v;
   bool ok;
@@ -404,7 +404,7 @@ is_num_user_missing (const struct missing_values *mv, double d)
    MV must be a set of string missing values.
    S[] must contain exactly as many characters as MV's width. */
 static bool
-is_str_user_missing (const struct missing_values *mv, const char s[])
+is_str_user_missing (const struct missing_values *mv, const uint8_t s[])
 {
   const union value *v = mv->values;
   assert (mv->width > 0);
@@ -456,7 +456,7 @@ mv_is_num_missing (const struct missing_values *mv, double d,
    MV must be a set of string missing values.
    S[] must contain exactly as many characters as MV's width. */
 bool
-mv_is_str_missing (const struct missing_values *mv, const char s[],
+mv_is_str_missing (const struct missing_values *mv, const uint8_t s[],
                    enum mv_class class)
 {
   assert (mv->width > 0);
index 5576fc6c7c47f98f23db6d997bcca1d593c750d7..4d046faec3a1be411c4b5be5b2f0e93881b0e182 100644 (file)
@@ -64,7 +64,7 @@ enum mv_class
 bool mv_is_value_missing (const struct missing_values *, const union value *,
                           enum mv_class);
 bool mv_is_num_missing (const struct missing_values *, double, enum mv_class);
-bool mv_is_str_missing (const struct missing_values *, const char[],
+bool mv_is_str_missing (const struct missing_values *, const uint8_t[],
                         enum mv_class);
 
 /* Initializing missing value sets. */
@@ -94,7 +94,7 @@ void mv_get_range (const struct missing_values *, double *low, double *high);
 
 /* Adding and modifying discrete values. */
 bool mv_add_value (struct missing_values *, const union value *);
-bool mv_add_str (struct missing_values *, const char[]);
+bool mv_add_str (struct missing_values *, const uint8_t[]);
 bool mv_add_num (struct missing_values *, double);
 void mv_pop_value (struct missing_values *, union value *);
 bool mv_replace_value (struct missing_values *, const union value *, int idx);
index 461796bf66fee167377740cb35a9f636a2b17d52..a463124274a20c6cd62e1071f15c51cd95edcb3a 100644 (file)
@@ -447,6 +447,28 @@ read_string (struct pfm_reader *r, char *buf)
   *buf = '\0';
 }
 
+
+/* Reads a string into BUF, which must have room for 256
+   characters.
+   Returns the number of bytes read.
+*/
+static size_t
+read_bytes (struct pfm_reader *r, uint8_t *buf)
+{
+  int n = read_int (r);
+  if (n < 0 || n > 255)
+    error (r, _("Bad string length %d."), n);
+
+  while (n-- > 0)
+    {
+      *buf++ = r->cc;
+      advance (r);
+    }
+  return n;
+}
+
+
+
 /* Reads a string and returns a copy of it allocated from R's
    pool. */
 static char *
@@ -739,9 +761,9 @@ parse_value (struct pfm_reader *r, int width, union value *v)
   value_init (v, width);
   if (width > 0)
     {
-      char string[256];
-      read_string (r, string);
-      value_copy_str_rpad (v, width, string, ' ');
+      uint8_t buf[256];
+      size_t n_bytes = read_bytes (r, buf);
+      value_copy_buf_rpad (v, width, buf, n_bytes, ' ');
     }
   else
     v->f = read_float (r);
@@ -844,9 +866,9 @@ por_file_casereader_read (struct casereader *reader, void *r_)
         case_data_rw_idx (c, i)->f = read_float (r);
       else
         {
-          char string[256];
-          read_string (r, string);
-          buf_copy_str_rpad (case_str_rw_idx (c, i), width, string, ' ');
+          uint8_t buf[256];
+          size_t n_bytes = read_bytes (r, buf);
+          u8_buf_copy_rpad (case_str_rw_idx (c, i), width, buf, n_bytes, ' ');
         }
     }
 
@@ -860,17 +882,30 @@ pfm_detect (FILE *file)
 {
   unsigned char header[464];
   char trans[256];
-  int cooked_cnt, raw_cnt;
+  int cooked_cnt, raw_cnt, line_len;
   int i;
 
   cooked_cnt = raw_cnt = 0;
+  line_len = 0;
   while (cooked_cnt < sizeof header)
     {
       int c = getc (file);
       if (c == EOF || raw_cnt++ > 512)
         return false;
-      else if (c != '\n' && c != '\r')
-        header[cooked_cnt++] = c;
+      else if (c == '\n')
+        {
+          while (line_len < 80 && cooked_cnt < sizeof header)
+            {
+              header[cooked_cnt++] = ' ';
+              line_len++;
+            }
+          line_len = 0;
+        }
+      else if (c != '\r')
+        {
+          header[cooked_cnt++] = c;
+          line_len++;
+        }
     }
 
   memset (trans, 0, 256);
index 948319468c3c1d7a1c43d36663c10a49c6d168f7..03098685e86d338164ad8963f3f331bc24abb94d 100644 (file)
@@ -64,6 +64,16 @@ subcase_init_var (struct subcase *sc, const struct variable *var,
   subcase_add_var (sc, var, direction);
 }
 
+
+void
+subcase_init (struct subcase *sc, int index, int width,
+                  enum subcase_direction direction)
+{
+  subcase_init_empty (sc);
+  subcase_add (sc, index, width, direction);
+}
+
+
 /* Removes all the fields from SC. */
 void
 subcase_clear (struct subcase *sc)
@@ -89,6 +99,7 @@ subcase_destroy (struct subcase *sc)
   caseproto_unref (sc->proto);
 }
 
+
 /* Add a field for VAR to SC, with DIRECTION as the sort order.
    Returns true if successful, false if VAR already has a field
    in SC. */
@@ -96,7 +107,17 @@ bool
 subcase_add_var (struct subcase *sc, const struct variable *var,
                  enum subcase_direction direction)
 {
-  size_t case_index = var_get_case_index (var);
+  return subcase_add (sc, var_get_case_index (var),
+                     var_get_width (var), direction);
+}
+
+/* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the sort order.
+   Returns true if successful, false if CASE_INDEX already has a field
+   in SC. */
+bool
+subcase_add (struct subcase *sc, int case_index, int width,
+                 enum subcase_direction direction)
+{
   struct subcase_field *field;
   size_t i;
 
@@ -107,7 +128,7 @@ subcase_add_var (struct subcase *sc, const struct variable *var,
   sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
   field = &sc->fields[sc->n_fields++];
   field->case_index = case_index;
-  field->width = var_get_width (var);
+  field->width = width;
   field->direction = direction;
   invalidate_proto (sc);
   return true;
index 050cf17dcd3477f4b236e7af58c1a1ca1595c036..6e59da1d3679ac5b4c89f8a1b6a6ca6bc910627c 100644 (file)
@@ -53,10 +53,16 @@ void subcase_init_vars (struct subcase *,
                         const struct variable *const *, size_t n_vars);
 void subcase_init_var (struct subcase *,
                        const struct variable *, enum subcase_direction);
+void subcase_init (struct subcase *, int index, int width,
+                  enum subcase_direction);
+
 void subcase_clone (struct subcase *, const struct subcase *);
 void subcase_clear (struct subcase *);
 void subcase_destroy (struct subcase *);
 
+bool subcase_add (struct subcase *sc, int index, int width,
+                 enum subcase_direction direction);
+
 bool subcase_add_var (struct subcase *, const struct variable *,
                       enum subcase_direction);
 
index 67767a9f4a32374e4d4bc6d4b835ad76617e8a74..b0a41a83573b0e986fb35bfb3bce46379282662f 100644 (file)
@@ -25,6 +25,7 @@
 #include <setjmp.h>
 #include <stdlib.h>
 
+#include <libpspp/i18n.h>
 #include <libpspp/assertion.h>
 #include <libpspp/message.h>
 #include <libpspp/compiler.h>
@@ -186,6 +187,62 @@ static void read_long_string_value_labels (struct sfm_reader *,
                                           size_t size, size_t count,
                                           struct dictionary *);
 
+/* Convert all the strings in DICT from the dict encoding to UTF8 */
+static void
+recode_strings (struct dictionary *dict)
+{
+  int i;
+
+  const char *enc = dict_get_encoding (dict);
+
+  if ( NULL == enc)
+    enc = get_default_encoding ();
+
+  for (i = 0 ; i < dict_get_var_cnt (dict); ++i)
+    {
+      /* Convert the long variable name */
+      struct variable *var = dict_get_var (dict, i);
+      const char *native_name = var_get_name (var);
+      char *utf8_name = recode_string (UTF8, enc, native_name, -1);
+      if ( 0 != strcmp (utf8_name, native_name))
+       {
+         if ( NULL == dict_lookup_var (dict, utf8_name))
+           dict_rename_var (dict, var, utf8_name);
+         else
+           msg (MW,
+            _("Recoded variable name duplicates an existing `%s' within system file."), utf8_name);
+    }
+
+      free (utf8_name);
+
+      /* Convert the variable label */
+      if (var_has_label (var))
+       {
+         char *utf8_label = recode_string (UTF8, enc, var_get_label (var), -1);
+         var_set_label (var, utf8_label);
+         free (utf8_label);
+       }
+
+      if (var_has_value_labels (var))
+       {
+         const struct val_lab *vl = NULL;
+         const struct val_labs *vlabs = var_get_value_labels (var);
+
+         for (vl = val_labs_first (vlabs); vl != NULL; vl = val_labs_next (vlabs, vl))
+           {
+             const union value *val = val_lab_get_value (vl);
+             const char *label = val_lab_get_label (vl);
+             char *new_label = NULL;
+
+             new_label = recode_string (UTF8, enc, label, -1);
+
+             var_replace_value_label (var, val, new_label);
+             free (new_label);
+           }
+       }
+    }
+}
+
 /* Opens the system file designated by file handle FH for
    reading.  Reads the system file's dictionary into *DICT.
    If INFO is non-null, then it receives additional info about the
@@ -303,6 +360,8 @@ sfm_open_reader (struct file_handle *fh, struct dictionary **dict,
       r->has_long_var_names = true;
     }
 
+  recode_strings (*dict);
+
   /* Read record 999 data, which is just filler. */
   read_int (r);
 
@@ -446,9 +505,21 @@ read_header (struct sfm_reader *r, struct dictionary *dict,
   read_bytes (r, raw_bias, sizeof raw_bias);
   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
     {
-      sys_warn (r, _("Compression bias is not the usual "
-                     "value of 100, or system file uses unrecognized "
-                     "floating-point format."));
+      uint8_t zero_bias[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+      if (memcmp (raw_bias, zero_bias, 8))
+        sys_warn (r, _("Compression bias is not the usual "
+                       "value of 100, or system file uses unrecognized "
+                       "floating-point format."));
+      else
+        {
+          /* Some software is known to write all-zeros to this
+             field.  Such software also writes floating-point
+             numbers in the format that we expect by default
+             (it seems that all software most likely does, in
+             reality), so don't warn in this case. */
+        }
+
       if (r->integer_format == INTEGER_MSB_FIRST)
         r->float_format = FLOAT_IEEE_DOUBLE_BE;
       else
@@ -518,7 +589,7 @@ read_variable_record (struct sfm_reader *r, struct dictionary *dict,
 
   /* Create variable. */
   if (width < 0 || width > 255)
-    sys_error (r, _("Bad variable width %d."), width);
+    sys_error (r, _("Bad width %d for variable %s."), width, name);
   var = dict_create_var (dict, name, width);
   if (var == NULL)
     sys_error (r,
@@ -582,7 +653,7 @@ read_variable_record (struct sfm_reader *r, struct dictionary *dict,
           value_set_missing (&value, mv_width);
           for (i = 0; i < missing_value_code; i++)
             {
-              char *s = value_str_rw (&value, mv_width);
+              uint8_t *s = value_str_rw (&value, mv_width);
               read_bytes (r, s, 8);
               mv_add_str (&mv, s);
             }
@@ -922,11 +993,16 @@ read_machine_float_info (struct sfm_reader *r, size_t size, size_t count)
                size, count);
 
   if (sysmis != SYSMIS)
-    sys_warn (r, _("File specifies unexpected value %g as SYSMIS."), sysmis);
+    sys_warn (r, _("File specifies unexpected value %g as %s."),
+              sysmis, "SYSMIS");
+
   if (highest != HIGHEST)
-    sys_warn (r, _("File specifies unexpected value %g as HIGHEST."), highest);
+    sys_warn (r, _("File specifies unexpected value %g as %s."),
+              highest, "HIGHEST");
+
   if (lowest != LOWEST)
-    sys_warn (r, _("File specifies unexpected value %g as LOWEST."), lowest);
+    sys_warn (r, _("File specifies unexpected value %g as %s."),
+              lowest, "LOWEST");
 }
 
 /* Read record type 7, subtype 11, which specifies how variables
@@ -1133,7 +1209,7 @@ read_value_labels (struct sfm_reader *r,
 
   struct label
     {
-      char raw_value[8];        /* Value as uninterpreted bytes. */
+      uint8_t raw_value[8];        /* Value as uninterpreted bytes. */
       union value value;        /* Value. */
       char *label;              /* Null-terminated label string. */
     };
@@ -1231,7 +1307,7 @@ read_value_labels (struct sfm_reader *r,
 
       value_init_pool (subpool, &label->value, max_width);
       if (var_is_alpha (var[0]))
-        buf_copy_rpad (value_str_rw (&label->value, max_width), max_width,
+        u8_buf_copy_rpad (value_str_rw (&label->value, max_width), max_width,
                        label->raw_value, sizeof label->raw_value, ' ');
       else
         label->value.f = float_get_double (r->float_format, label->raw_value);
@@ -1411,7 +1487,7 @@ read_long_string_value_labels (struct sfm_reader *r,
           /* Read value. */
           value_length = read_int (r);
           if (value_length == width)
-            read_string (r, value_str_rw (&value, width), width + 1);
+            read_bytes (r, value_str_rw (&value, width), width);
           else
             {
               sys_warn (r, _("Ignoring long string value %zu for variable %s, "
@@ -1468,11 +1544,11 @@ static void partial_record (struct sfm_reader *r)
 static void read_error (struct casereader *, const struct sfm_reader *);
 
 static bool read_case_number (struct sfm_reader *, double *);
-static bool read_case_string (struct sfm_reader *, char *, size_t);
+static bool read_case_string (struct sfm_reader *, uint8_t *, size_t);
 static int read_opcode (struct sfm_reader *);
 static bool read_compressed_number (struct sfm_reader *, double *);
-static bool read_compressed_string (struct sfm_reader *, char *);
-static bool read_whole_strings (struct sfm_reader *, char *, size_t);
+static bool read_compressed_string (struct sfm_reader *, uint8_t *);
+static bool read_whole_strings (struct sfm_reader *, uint8_t *, size_t);
 static bool skip_whole_strings (struct sfm_reader *, size_t);
 
 /* Reads and returns one case from READER's file.  Returns a null
@@ -1507,7 +1583,7 @@ sys_file_casereader_read (struct casereader *reader, void *r_)
         }
       else
         {
-          char *s = value_str_rw (v, sv->var_width);
+          uint8_t *s = value_str_rw (v, sv->var_width);
           if (!read_case_string (r, s + sv->offset, sv->segment_width))
             goto eof;
           if (!skip_whole_strings (r, ROUND_DOWN (sv->padding, 8)))
@@ -1569,7 +1645,7 @@ read_case_number (struct sfm_reader *r, double *d)
    Returns true if successful, false if end of file is
    reached immediately. */
 static bool
-read_case_string (struct sfm_reader *r, char *s, size_t length)
+read_case_string (struct sfm_reader *r, uint8_t *s, size_t length)
 {
   size_t whole = ROUND_DOWN (length, 8);
   size_t partial = length % 8;
@@ -1582,7 +1658,7 @@ read_case_string (struct sfm_reader *r, char *s, size_t length)
 
   if (partial)
     {
-      char bounce[8];
+      uint8_t bounce[8];
       if (!read_whole_strings (r, bounce, sizeof bounce))
         {
           if (whole)
@@ -1653,7 +1729,7 @@ read_compressed_number (struct sfm_reader *r, double *d)
    Returns true if successful, false if end of file is
    reached immediately. */
 static bool
-read_compressed_string (struct sfm_reader *r, char *dst)
+read_compressed_string (struct sfm_reader *r, uint8_t *dst)
 {
   switch (read_opcode (r))
     {
@@ -1682,7 +1758,7 @@ read_compressed_string (struct sfm_reader *r, char *dst)
    Returns true if successful, false if end of file is
    reached immediately. */
 static bool
-read_whole_strings (struct sfm_reader *r, char *s, size_t length)
+read_whole_strings (struct sfm_reader *r, uint8_t *s, size_t length)
 {
   assert (length % 8 == 0);
   if (!r->compressed)
@@ -1710,7 +1786,7 @@ read_whole_strings (struct sfm_reader *r, char *s, size_t length)
 static bool
 skip_whole_strings (struct sfm_reader *r, size_t length)
 {
-  char buffer[1024];
+  uint8_t buffer[1024];
   assert (length < sizeof buffer);
   return read_whole_strings (r, buffer, length);
 }
index 13dc2de6a60cf45d9d0d2729675f265ae1c5b185..3fed2e05445135ec2ebcc300ce23c4855d0f41df 100644 (file)
@@ -31,6 +31,7 @@
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
+#include <libpspp/i18n.h>
 #include <libpspp/version.h>
 
 #include <data/attributes.h>
@@ -94,9 +95,9 @@ struct sfm_writer
 static const struct casewriter_class sys_file_casewriter_class;
 
 static void write_header (struct sfm_writer *, const struct dictionary *);
-static void write_variable (struct sfm_writer *, const struct variable *);
+static void write_variable (struct sfm_writer *, const struct variable *, const struct dictionary *);
 static void write_value_labels (struct sfm_writer *,
-                                struct variable *, int idx);
+                                struct variable *, int idx, const struct dictionary *);
 static void write_integer_info_record (struct sfm_writer *);
 static void write_float_info_record (struct sfm_writer *);
 
@@ -222,7 +223,7 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
   /* Write basic variable info. */
   short_names_assign (d);
   for (i = 0; i < dict_get_var_cnt (d); i++)
-    write_variable (w, dict_get_var (d, i));
+    write_variable (w, dict_get_var (d, i), d);
 
   /* Write out value labels. */
   idx = 0;
@@ -230,7 +231,7 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
     {
       struct variable *v = dict_get_var (d, i);
 
-      write_value_labels (w, v, idx);
+      write_value_labels (w, v, idx, d);
       idx += sfm_width_to_octs (var_get_width (v));
     }
 
@@ -420,7 +421,7 @@ write_variable_continuation_records (struct sfm_writer *w, int width)
 /* Write the variable record(s) for variable V to system file
    W. */
 static void
-write_variable (struct sfm_writer *w, const struct variable *v)
+write_variable (struct sfm_writer *w, const struct variable *v, const struct dictionary *dict)
 {
   int width = var_get_width (v);
   int segment_cnt = sfm_width_to_segments (width);
@@ -461,9 +462,11 @@ write_variable (struct sfm_writer *w, const struct variable *v)
   if (var_has_label (v))
     {
       const char *label = var_get_label (v);
-      size_t padded_len = ROUND_UP (MIN (strlen (label), 255), 4);
+      char *l = recode_string (dict_get_encoding (dict), UTF8, label, -1);
+      size_t padded_len = ROUND_UP (MIN (strlen (l), 255), 4);
       write_int (w, padded_len);
-      write_string (w, label, padded_len);
+      write_string (w, l, padded_len);
+      free (l);
     }
 
   /* Write the missing values, if any, range first. */
@@ -505,7 +508,7 @@ write_variable (struct sfm_writer *w, const struct variable *v)
    Value labels for long string variables are written separately,
    by write_long_string_value_labels. */
 static void
-write_value_labels (struct sfm_writer *w, struct variable *v, int idx)
+write_value_labels (struct sfm_writer *w, struct variable *v, int idx, const struct dictionary *dict)
 {
   const struct val_labs *val_labs;
   const struct val_lab **labels;
@@ -524,13 +527,14 @@ write_value_labels (struct sfm_writer *w, struct variable *v, int idx)
   for (i = 0; i < n_labels; i++)
     {
       const struct val_lab *vl = labels[i];
-      const char *label = val_lab_get_label (vl);
+      char *label = recode_string (dict_get_encoding (dict), UTF8, val_lab_get_label (vl), -1);
       uint8_t len = MIN (strlen (label), 255);
 
       write_value (w, val_lab_get_value (vl), var_get_width (v));
       write_bytes (w, &len, 1);
       write_bytes (w, label, len);
       write_zeros (w, REM_RND_UP (len + 1, 8));
+      free (label);
     }
   free (labels);
 
@@ -774,11 +778,13 @@ write_longvar_table (struct sfm_writer *w, const struct dictionary *dict)
   for (i = 0; i < dict_get_var_cnt (dict); i++)
     {
       struct variable *v = dict_get_var (dict, i);
+      char *longname = recode_string (dict_get_encoding (dict), UTF8, var_get_name (v), -1);
 
       if (i)
         ds_put_char (&map, '\t');
       ds_put_format (&map, "%s=%s",
-                     var_get_short_name (v, 0), var_get_name (v));
+                     var_get_short_name (v, 0), longname);
+      free (longname);
     }
 
   write_int (w, 7);             /* Record type. */
index ce050c01668a47652e12bf9746e14deac2e58f9d..6dbecb11abfca8137bc8fdc763ffc1c0a8568bc2 100644 (file)
@@ -22,6 +22,7 @@
 #include <libpspp/hash.h>
 #include <libpspp/pool.h>
 #include <libpspp/str.h>
+#include <gl/unistr.h>
 
 #include "minmax.h"
 #include "xalloc.h"
@@ -44,7 +45,7 @@ value_copy_rpad (union value *dst, int dst_width,
                  const union value *src, int src_width,
                  char pad)
 {
-  buf_copy_rpad (value_str_rw (dst, dst_width), dst_width,
+  u8_buf_copy_rpad (value_str_rw (dst, dst_width), dst_width,
                  value_str (src, src_width), src_width,
                  pad);
 }
@@ -62,10 +63,10 @@ value_copy_rpad (union value *dst, int dst_width,
    DST was initialized.  Passing, e.g., a smaller value in order
    to modify only a prefix of DST will not work in every case. */
 void
-value_copy_str_rpad (union value *dst, int dst_width, const char *src,
+value_copy_str_rpad (union value *dst, int dst_width, const uint8_t *src,
                      char pad)
 {
-  value_copy_buf_rpad (dst, dst_width, src, strlen (src), pad);
+  value_copy_buf_rpad (dst, dst_width, src, u8_strlen (src), pad);
 }
 
 /* Copies the SRC_LEN bytes at SRC to string value DST with width
@@ -81,9 +82,9 @@ value_copy_str_rpad (union value *dst, int dst_width, const char *src,
    to modify only a prefix of DST will not work in every case. */
 void
 value_copy_buf_rpad (union value *dst, int dst_width,
-                     const char *src, size_t src_len, char pad)
+                     const uint8_t *src, size_t src_len, char pad)
 {
-  buf_copy_rpad (value_str_rw (dst, dst_width), dst_width, src, src_len, pad);
+  u8_buf_copy_rpad (value_str_rw (dst, dst_width), dst_width, src, src_len, pad);
 }
 
 /* Sets V to the system-missing value for data of the given
@@ -145,7 +146,7 @@ value_is_resizable (const union value *value, int old_width, int new_width)
     return false;
   else
     {
-      const char *str = value_str (value, old_width);
+      const uint8_t *str = value_str (value, old_width);
       int i;
 
       for (i = new_width; i < old_width; i++)
@@ -225,7 +226,7 @@ value_resize_pool (struct pool *pool, union value *value,
     {
       if (new_width > MAX_SHORT_STRING)
         {
-          char *new_long_string = pool_alloc_unaligned (pool, new_width);
+          uint8_t *new_long_string = pool_alloc_unaligned (pool, new_width);
           memcpy (new_long_string, value_str (value, old_width), old_width);
           value->long_string = new_long_string;
         }
index 905f0823d594e61b5c21c501e04c23a3b050dc5d..f9782e2d867d47028f134c4b406dbfd53313d68c 100644 (file)
@@ -20,6 +20,7 @@
 #include <assert.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include "xalloc.h"
 \f
@@ -45,8 +46,8 @@
 union value
   {
     double f;
-    char short_string[MAX_SHORT_STRING];
-    char *long_string;
+    uint8_t short_string[MAX_SHORT_STRING];
+    uint8_t *long_string;
   };
 
 static inline void value_init (union value *, int width);
@@ -55,20 +56,17 @@ static inline bool value_try_init (union value *, int width);
 static inline void value_destroy (union value *, int width);
 
 static inline double value_num (const union value *);
-static inline const char *value_str (const union value *, int width);
-static inline char *value_str_rw (union value *, int width);
-
-int compare_values (const void *, const void *, const void *var);
-unsigned hash_value (const void *, const void *var);
+static inline const uint8_t *value_str (const union value *, int width);
+static inline uint8_t *value_str_rw (union value *, int width);
 
 static inline void value_copy (union value *, const union value *, int width);
 void value_copy_rpad (union value *, int dst_width,
                       const union value *, int src_width,
                       char pad);
-void value_copy_str_rpad (union value *, int dst_width, const char *,
+void value_copy_str_rpad (union value *, int dst_width, const uint8_t *,
                           char pad);
 void value_copy_buf_rpad (union value *dst, int dst_width,
-                          const char *src, size_t src_len, char pad);
+                          const uint8_t *src, size_t src_len, char pad);
 void value_set_missing (union value *, int width);
 int value_compare_3way (const union value *, const union value *, int width);
 bool value_equal (const union value *, const union value *, int width);
@@ -150,7 +148,7 @@ value_num (const union value *v)
    It is important that WIDTH be the actual value that was passed
    to value_init.  Passing, e.g., a smaller value because only
    that number of bytes will be accessed will not always work. */
-static inline const char *
+static inline const uint8_t *
 value_str (const union value *v, int width)
 {
   assert (width > 0);
@@ -164,7 +162,7 @@ value_str (const union value *v, int width)
    It is important that WIDTH be the actual value that was passed
    to value_init.  Passing, e.g., a smaller value because only
    that number of bytes will be accessed will not always work. */
-static inline char *
+static inline uint8_t *
 value_str_rw (union value *v, int width)
 {
   assert (width > 0);
index bd0e8bf5691782a22ecdd376537fda692b98b95a..05edc57e2db85a3c02df4fbe3a16a6747d92c4bc 100644 (file)
@@ -149,13 +149,13 @@ var_clone (const struct variable *old_var)
   return new_var;
 }
 
-/* Create a variable to be used for internal calculations only.
-   The variable is assigned a unique dictionary index and a case
-   index of CASE_IDX. */
+/* Create a variable of the specified WIDTH to be used for
+   internal calculations only.  The variable is assigned a unique
+   dictionary index and a case index of CASE_IDX. */
 struct variable *
-var_create_internal (int case_idx)
+var_create_internal (int case_idx, int width)
 {
-  struct variable *v = var_create ("$internal", 0);
+  struct variable *v = var_create ("$internal", width);
   struct vardict_info vdi;
   static int counter = INT_MAX / 2;
 
@@ -494,7 +494,7 @@ var_is_num_missing (const struct variable *v, double d, enum mv_class class)
    S[] must contain exactly as many characters as V's width.
    V must be a string variable. */
 bool
-var_is_str_missing (const struct variable *v, const char s[],
+var_is_str_missing (const struct variable *v, const uint8_t s[],
                     enum mv_class class)
 {
   return mv_is_str_missing (&v->miss, s, class);
@@ -590,10 +590,12 @@ var_append_value_name (const struct variable *v, const union value *value,
                       struct string *str)
 {
   const char *name = var_lookup_value_label (v, value);
+  const struct dictionary *dict = var_get_vardict (v)->dict;
   if (name == NULL)
     {
-      char *s = ds_put_uninit (str, v->print.w);
-      data_out (value, &v->print, s);
+      char *s = data_out (value, dict_get_encoding (dict), &v->print);
+      ds_put_cstr (str, s);
+      free (s);
     }
   else
     ds_put_cstr (str, name);
index 2752aeb325faaa03d86e92c3aa0a57a228552962..0b619a497ed1eefa04a1dac97ec4be20afac4b80 100644 (file)
@@ -32,7 +32,7 @@ union value;
 struct variable *var_create (const char *name, int width);
 struct variable *var_clone (const struct variable *);
 void var_destroy (struct variable *);
-struct variable *var_create_internal (int case_idx);
+struct variable *var_create_internal (int case_idx, int width);
 
 
 /* Variable names. */
@@ -69,7 +69,7 @@ bool var_has_missing_values (const struct variable *);
 bool var_is_value_missing (const struct variable *, const union value *,
                            enum mv_class);
 bool var_is_num_missing (const struct variable *, double, enum mv_class);
-bool var_is_str_missing (const struct variable *, const char[], enum mv_class);
+bool var_is_str_missing (const struct variable *, const uint8_t[], enum mv_class);
 
 /* Value labels. */
 const char *var_lookup_value_label (const struct variable *,
index 548d671eb4d307b4af27ddae629a5407e8b87867..74f99a89a682009dfa0fa62452669cf8622a446c 100644 (file)
@@ -204,7 +204,7 @@ do_parse_command (struct lexer *lexer,
     }
   else if (command->function == NULL)
     {
-      msg (SE, _("%s is unimplemented."), command->name);
+      msg (SE, _("%s is not yet implemented."), command->name);
       result = CMD_NOT_IMPLEMENTED;
       goto finish;
     }
index 4c8df335722aa192eb2e38297c6449f5679b19f4..fa1bb1e88c6b2da3f683cbc49cb15449a9d24d07 100644 (file)
@@ -117,6 +117,7 @@ DEF_CMD (S_DATA, 0, "RANK", cmd_rank)
 DEF_CMD (S_DATA, 0, "REGRESSION", cmd_regression)
 DEF_CMD (S_DATA, 0, "RELIABILITY", cmd_reliability)
 DEF_CMD (S_DATA, 0, "RENAME VARIABLES", cmd_rename_variables)
+DEF_CMD (S_DATA, 0, "ROC", cmd_roc)
 DEF_CMD (S_DATA, 0, "SAMPLE", cmd_sample)
 DEF_CMD (S_DATA, 0, "SAVE", cmd_save)
 DEF_CMD (S_DATA, 0, "SORT CASES", cmd_sort_cases)
@@ -237,7 +238,6 @@ UNIMPL_CMD ("REPEATING DATA", "Specify multiple cases per input record")
 UNIMPL_CMD ("REPORT", "Pretty print working file")
 UNIMPL_CMD ("RESTORE", "Restore settings")
 UNIMPL_CMD ("RMV", "Replace missing values")
-UNIMPL_CMD ("ROC", "Receiver operating characteristic")
 UNIMPL_CMD ("SAVE TRANSLATE", "Save to foriegn format")
 UNIMPL_CMD ("SCRIPT", "Run script file")
 UNIMPL_CMD ("SEASON", "Estimate seasonal factors")
index de85748856e003928f67512b17f93e265cead03e..d43af347a701693224980ea18281eaf72d6c0e60 100644 (file)
@@ -86,7 +86,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
   bool ok;
 
   dict = in_input_program () ? dataset_dict (ds) : dict_create ();
-  parser = data_parser_create ();
+  parser = data_parser_create (dict);
   reader = NULL;
 
   table = -1;                /* Print table if nonzero, -1=undecided. */
index 44054267785fb51a874de832ac66e2da51376881..fe78aeb36ed272f309481870d79ea6669d48d735 100644 (file)
@@ -41,6 +41,7 @@
 /* Data parser for textual data like that read by DATA LIST. */
 struct data_parser
   {
+    const struct dictionary *dict; /*Dictionary of destination */
     enum data_parser_type type; /* Type of data to parse. */
     int skip_records;           /* Records to skip before first real data. */
     casenumber max_cases;       /* Max number of cases to read. */
@@ -79,7 +80,7 @@ static void set_any_sep (struct data_parser *parser);
 
 /* Creates and returns a new data parser. */
 struct data_parser *
-data_parser_create (void)
+data_parser_create (const struct dictionary *dict)
 {
   struct data_parser *parser = xmalloc (sizeof *parser);
 
@@ -91,6 +92,7 @@ data_parser_create (void)
   parser->fields = NULL;
   parser->field_cnt = 0;
   parser->field_allocated = 0;
+  parser->dict = dict;
 
   parser->span = true;
   parser->empty_line_has_field = false;
@@ -483,7 +485,8 @@ cut_field (const struct data_parser *parser, struct dfm_reader *reader,
       /* Regular field. */
       ss_get_chars (&p, ss_cspan (p, ds_ss (&parser->any_sep)), field);
       *last_column = dfm_column_start (reader);
-      if (!ss_ltrim (&p, parser->soft_seps) || ss_is_empty (p))
+      if (!ss_ltrim (&p, parser->soft_seps) || ss_is_empty (p)
+          || ss_find_char (parser->hard_seps, p.string[0]) != SIZE_MAX)
         {
           /* Advance past a trailing hard separator,
              regardless of whether one actually existed.  If
@@ -505,7 +508,7 @@ static bool
 parse_fixed (const struct data_parser *parser, struct dfm_reader *reader,
              struct ccase *c)
 {
-  enum legacy_encoding encoding = dfm_reader_get_legacy_encoding (reader);
+  const char *encoding = dfm_reader_get_legacy_encoding (reader);
   struct field *f;
   int row;
 
@@ -531,6 +534,7 @@ parse_fixed (const struct data_parser *parser, struct dfm_reader *reader,
                             f->format.w),
                  encoding, f->format.type, f->format.d,
                  f->first_column, f->first_column + f->format.w,
+                parser->dict,
                  case_data_rw_idx (c, f->case_idx),
                  fmt_var_width (&f->format));
 
@@ -547,7 +551,7 @@ static bool
 parse_delimited_span (const struct data_parser *parser,
                       struct dfm_reader *reader, struct ccase *c)
 {
-  enum legacy_encoding encoding = dfm_reader_get_legacy_encoding (reader);
+  const char *encoding = dfm_reader_get_legacy_encoding (reader);
   struct string tmp = DS_EMPTY_INITIALIZER;
   struct field *f;
 
@@ -574,6 +578,7 @@ parse_delimited_span (const struct data_parser *parser,
 
       data_in (s, encoding, f->format.type, 0,
                first_column, last_column,
+              parser->dict,
                case_data_rw_idx (c, f->case_idx),
                fmt_var_width (&f->format));
     }
@@ -588,7 +593,7 @@ static bool
 parse_delimited_no_span (const struct data_parser *parser,
                          struct dfm_reader *reader, struct ccase *c)
 {
-  enum legacy_encoding encoding = dfm_reader_get_legacy_encoding (reader);
+  const char *encoding = dfm_reader_get_legacy_encoding (reader);
   struct string tmp = DS_EMPTY_INITIALIZER;
   struct substring s;
   struct field *f;
@@ -614,6 +619,7 @@ parse_delimited_no_span (const struct data_parser *parser,
 
       data_in (s, encoding, f->format.type, 0,
                first_column, last_column,
+              parser->dict,
                case_data_rw_idx (c, f->case_idx),
                fmt_var_width (&f->format));
     }
index b250e91bb53d2d7cf7b628fd6f41cb8113f7f30b..5a53a2f64ddcc3ab5c30286f438df15158014e4a 100644 (file)
@@ -38,7 +38,7 @@ enum data_parser_type
   };
 
 /* Creating and configuring any parser. */
-struct data_parser *data_parser_create (void);
+struct data_parser *data_parser_create (const struct dictionary *dict);
 void data_parser_destroy (struct data_parser *);
 
 enum data_parser_type data_parser_get_type (const struct data_parser *);
index 24ddcf13ec61cf6749c64cd63bfd4e03268cbeea..6f620a6a948341a0dfa5db150763d20f51e92284 100644 (file)
@@ -597,7 +597,7 @@ dfm_expand_tabs (struct dfm_reader *r)
 }
 
 /* Returns the legacy character encoding of data read from READER. */
-enum legacy_encoding
+const char *
 dfm_reader_get_legacy_encoding (const struct dfm_reader *reader)
 {
   return fh_get_legacy_encoding (reader->fh);
index c7fee613d01caefe81f5edf5fe10c6f0538dc84f..308701c253147d48863a01bdb159c002e5fbf52a 100644 (file)
@@ -38,8 +38,7 @@ bool dfm_reader_error (const struct dfm_reader *);
 unsigned dfm_eof (struct dfm_reader *);
 struct substring dfm_get_record (struct dfm_reader *);
 void dfm_expand_tabs (struct dfm_reader *);
-enum legacy_encoding dfm_reader_get_legacy_encoding (
-  const struct dfm_reader *);
+const char *dfm_reader_get_legacy_encoding (const struct dfm_reader *);
 int dfm_get_percent_read (const struct dfm_reader *);
 
 /* Line control. */
index b5df59d4605f2535a690aea77e0934eb46ee6a65..85b11d4c1e553054160f8b1a57a3d1cac2704a00 100644 (file)
@@ -200,7 +200,7 @@ dfm_close_writer (struct dfm_writer *w)
 }
 
 /* Returns the legacy character encoding of data written to WRITER. */
-enum legacy_encoding
+const char *
 dfm_writer_get_legacy_encoding (const struct dfm_writer *writer)
 {
   return fh_get_legacy_encoding (writer->fh);
index 2142f2155008a8c934e471a72d837e992faae044..045db3163fd3144f2653e294d5a023e1416dc0f6 100644 (file)
@@ -27,7 +27,6 @@ struct dfm_writer *dfm_open_writer (struct file_handle *);
 bool dfm_close_writer (struct dfm_writer *);
 bool dfm_write_error (const struct dfm_writer *);
 bool dfm_put_record (struct dfm_writer *, const char *rec, size_t len);
-enum legacy_encoding dfm_writer_get_legacy_encoding (
-  const struct dfm_writer *);
+const char *dfm_writer_get_legacy_encoding (const struct dfm_writer *);
 
 #endif /* data-writer.h */
index 827dbab499e9af94a7c55fee5a42764a1ca39f89..3e053ed57262eb5f6e94d404ed5686253e640a16 100644 (file)
@@ -102,7 +102,7 @@ cmd_file_handle (struct lexer *lexer, struct dataset *ds)
           properties.mode = FH_MODE_VARIABLE;
           break;
         case FH_360:
-          properties.encoding = LEGACY_EBCDIC;
+          properties.encoding = "EBCDIC-US";
           if (cmd.recform == FH_FIXED || cmd.recform == FH_F)
             properties.mode = FH_MODE_FIXED;
           else if (cmd.recform == FH_VARIABLE || cmd.recform == FH_V)
index e4ab76a9992739c78a36f6ad2a98c4f6e0b48d83..32202babdea8848f5c3a06b6431b0db3c4b007ff 100644 (file)
@@ -271,7 +271,7 @@ static int
 parse_get_txt (struct lexer *lexer, struct dataset *ds)
 {
   struct data_parser *parser = NULL;
-  struct dictionary *dict = NULL;
+  struct dictionary *dict = dict_create ();
   struct file_handle *fh = NULL;
   struct dfm_reader *reader = NULL;
 
@@ -288,7 +288,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
   if (fh == NULL)
     goto error;
 
-  parser = data_parser_create ();
+  parser = data_parser_create (dict);
   has_type = false;
   data_parser_set_type (parser, DP_DELIMITED);
   data_parser_set_span (parser, false);
@@ -465,7 +465,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
     }
   lex_match (lexer, '=');
 
-  dict = dict_create ();
+
   record = 1;
   type = data_parser_get_type (parser);
   do
index 5f1b3a99e5fe01c66ff45d1a1529639cc70cc78c..614fa1271e71b5ed3180e2f4e98e1b454745b769 100644 (file)
@@ -665,6 +665,7 @@ list_case (const struct ccase *c, casenumber case_idx,
            const struct dataset *ds, struct ll_list *targets)
 {
   struct dictionary *dict = dataset_dict (ds);
+  const char *encoding = dict_get_encoding (dict);
   struct list_target *target;
 
   ll_for_each (target, struct list_target, ll, targets)
@@ -688,6 +689,7 @@ list_case (const struct ccase *c, casenumber case_idx,
               const struct variable *v = cmd.v_variables[column];
               const struct fmt_spec *print = var_get_print_format (v);
               int width;
+              char *s;
 
               if (target->type == 0 && column >= target->n_vertical)
                 {
@@ -716,20 +718,17 @@ list_case (const struct ccase *c, casenumber case_idx,
               if (width > print->w)
                 ds_put_char_multiple(&line_buffer, ' ', width - print->w);
 
-              if (fmt_is_string (print->type)
-                  || dict_contains_var (dict, v))
-                {
-                  data_out (case_data (c, v), print,
-                            ds_put_uninit (&line_buffer, print->w));
-                }
+              if (fmt_is_string (print->type) || dict_contains_var (dict, v))
+                s = data_out (case_data (c, v), encoding, print);
               else
                 {
                   union value case_idx_value;
                   case_idx_value.f = case_idx;
-                  data_out (&case_idx_value, print,
-                            ds_put_uninit (&line_buffer,print->w));
+                  s = data_out (&case_idx_value, encoding, print);
                 }
 
+              ds_put_cstr (&line_buffer, s);
+              free (s);
               ds_put_char(&line_buffer, ' ');
             }
 
@@ -753,21 +752,23 @@ list_case (const struct ccase *c, casenumber case_idx,
             {
               const struct variable *v = cmd.v_variables[column];
               const struct fmt_spec *print = var_get_print_format (v);
-              char buf[256];
+              char *s;
 
               if (fmt_is_string (print->type)
                   || dict_contains_var (dict, v))
-                data_out (case_data (c, v), print, buf);
+                s = data_out (case_data (c, v), encoding, print);
               else
                 {
                   union value case_idx_value;
                   case_idx_value.f = case_idx;
-                  data_out (&case_idx_value, print, buf);
+                  s = data_out (&case_idx_value, encoding, print);
                 }
 
               fputs ("    <TD>", x->file);
-              html_put_cell_contents (d, TAB_FIX, ss_buffer (buf, print->w));
+              html_put_cell_contents (d, TAB_FIX, ss_cstr (s));
               fputs ("</TD>\n", x->file);
+
+              free (s);
             }
 
           fputs ("  </TR>\n", x->file);
index 897c10cc158c8858a6c539bb54275bb53e9c0aec..dd1e26d270dab5d8d13eff9a85146260b68cc053 100644 (file)
@@ -32,6 +32,7 @@
 #include <language/lexer/lexer.h>
 #include <language/lexer/variable-parser.h>
 #include <libpspp/assertion.h>
+#include <libpspp/i18n.h>
 #include <libpspp/compiler.h>
 #include <libpspp/ll.h>
 #include <libpspp/message.h>
@@ -83,7 +84,7 @@ struct print_trns
     struct pool *pool;          /* Stores related data. */
     bool eject;                 /* Eject page before printing? */
     bool include_prefix;        /* Prefix lines with space? */
-    enum legacy_encoding encoding; /* Encoding to use for output. */
+    const char *encoding;       /* Encoding to use for output. */
     struct dfm_writer *writer; /* Output file, NULL=listing file. */
     struct ll_list specs;       /* List of struct prt_out_specs. */
     size_t record_cnt;          /* Number of records to write. */
@@ -480,12 +481,13 @@ print_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
       else
         {
           ds_put_substring (&trns->line, ds_ss (&spec->string));
-          if (trns->encoding != LEGACY_NATIVE)
+          if (0 != strcmp (trns->encoding, LEGACY_NATIVE))
             {
               size_t length = ds_length (&spec->string);
               char *data = ss_data (ds_tail (&trns->line, length));
-              legacy_recode (LEGACY_NATIVE, data,
-                             trns->encoding, data, length);
+             char *s = recode_string (trns->encoding, LEGACY_NATIVE, data, length);
+             memcpy (data, s, length);
+             free (s);
             }
         }
     }
index aa3ce698206ba652cef8a299c6f6926095329881..819b0a9021cfe5821b4060e02b9932830b2a6120 100644 (file)
@@ -101,7 +101,7 @@ cmd_missing_values (struct lexer *lexer, struct dataset *ds)
               mv_init (&mv, MV_MAX_STRING);
               while (!lex_match (lexer, ')'))
                 {
-                  char value[MV_MAX_STRING];
+                  uint8_t value[MV_MAX_STRING];
                   size_t length;
 
                   if (!lex_force_string (lexer))
index 5d3650e3b3de569bd6e3eee5e1ff30d3ffddd267..d2f59ccc813fe8661435bb03bee0cbf1a01caa20 100644 (file)
@@ -88,17 +88,18 @@ output_split_file_values (const struct dataset *ds, const struct ccase *c)
   for (i = 0; i < split_cnt; i++)
     {
       const struct variable *v = split[i];
-      char temp_buf[80];
+      char *s;
       const char *val_lab;
       const struct fmt_spec *print = var_get_print_format (v);
 
       tab_text_format (t, 0, i + 1, TAB_LEFT, "%s", var_get_name (v));
 
-      data_out (case_data (c, v), print, temp_buf);
-      temp_buf[print->w] = 0;
+      s = data_out (case_data (c, v), dict_get_encoding (dict), print);
 
-      tab_text_format (t, 1, i + 1, 0, "%.*s", print->w, temp_buf);
+      tab_text_format (t, 1, i + 1, 0, "%.*s", print->w, s);
 
+      free (s);
+      
       val_lab = var_lookup_value_label (v, case_data (c, v));
       if (val_lab)
        tab_text (t, 2, i + 1, TAB_LEFT, val_lab);
index 2d31bd47182dcb158d9f9c50e644fb03bb7b07bf..d283867214811ea142d83cafd39d9b69faf2a0a0 100644 (file)
@@ -573,7 +573,7 @@ string function RTRIM (string s, string c)
 function NUMBER (string s, ni_format f)
 {
   union value out;
-  data_in (ss_head (s, f->w), LEGACY_NATIVE, f->type, f->d, 0, 0, &out, 0);
+  data_in (ss_head (s, f->w), LEGACY_NATIVE, f->type, f->d, 0, 0, NULL, &out, 0);
   return out.f;
 }
 
@@ -582,11 +582,15 @@ absorb_miss string function STRING (x, no_format f)
 {
   union value v;
   struct substring dst;
+  char *s;
 
   v.f = x;
-  dst = alloc_string (e, f->w);
+
   assert (!fmt_is_string (f->type));
-  data_out (&v, f, dst.string);
+  s = data_out (&v, LEGACY_NATIVE, f);
+  dst = alloc_string (e, strlen (s));
+  strcpy (dst.string, s);
+  free (s);
   return dst;
 }
 
index 265116141eb36f0d8ffa685a326431cd79f7b7ad..8b3f2a48d00474811a09c090f8a82d1b75ed7546 100644 (file)
@@ -385,10 +385,9 @@ lex_get (struct lexer *lexer)
           else
             {
               unsigned char c = *lexer->prog++;
-              if (c_isgraph (c))
-                msg (SE, _("Bad character in input: `%c'."), c);
-              else
-                msg (SE, _("Bad character in input: `\\%o'."), c);
+              char *c_name = xasprintf (c_isgraph (c) ? "%c" : "\\%o", c);
+              msg (SE, _("Bad character in input: `%s'."), c_name);
+              free (c_name);
               continue;
             }
         }
index 2cf9cf2bb9ad71f91d6ad301c4625d6b2a7cd012..c780d86f04e95429bad3ee1004bbf2021ab89884 100644 (file)
@@ -99,8 +99,9 @@ parse_number (struct lexer *lexer, double *x, const enum fmt_type *format)
   else if (lex_token (lexer) == T_STRING && format != NULL)
     {
       union value v;
+      assert (! (fmt_get_category (*format) & ( FMT_CAT_STRING )));
       data_in (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE,
-               *format, 0, 0, 0, &v, 0);
+               *format, 0, 0, 0, NULL, &v, 0);
       lex_get (lexer);
       *x = v.f;
       if (*x == SYSMIS)
index 3af2cd8d749a833a55b1a437b9aede885772c1dd..891e0ccaa3cb8f7c4bb4ba0da73feb1d456a1843 100644 (file)
@@ -1105,10 +1105,10 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
             proto = caseproto_add_width (proto, 0);
 
            if ( ! iter->subject)
-             iter->subject = var_create_internal (0);
+             iter->subject = var_create_internal (0, 0);
 
            if ( ! iter->weight)
-             iter->weight = var_create_internal (1);
+             iter->weight = var_create_internal (1, 0);
 
             subcase_init_var (&ordering, iter->subject, SC_ASCEND);
            iter->writer = sort_create_writer (&ordering, proto);
index 5aee445c4b29818f0995adb991f30ad3e9ea70fc..8eb52cf030de86ab041baca050a9cdb78b3802e8 100644 (file)
@@ -32,10 +32,11 @@ language_stats_sources = \
        src/language/stats/freq.h \
        src/language/stats/npar-summary.c \
        src/language/stats/npar-summary.h \
-       src/language/stats/wilcoxon.c \
-       src/language/stats/wilcoxon.h \
+       src/language/stats/roc.c \
        src/language/stats/sign.c \
-       src/language/stats/sign.h
+       src/language/stats/sign.h \
+       src/language/stats/wilcoxon.c \
+       src/language/stats/wilcoxon.h
 
 all_q_sources += $(src_language_stats_built_sources:.c=.q)
 EXTRA_DIST += $(src_language_stats_built_sources:.c=.q)
index 7db55a2c24b2278072acad0fb26d00482a3db24b..5695ed6478b64490095ea0c8abde83873fb38030 100644 (file)
@@ -177,6 +177,7 @@ get_var_range (const struct variable *v)
 
 struct crosstabs_proc
   {
+    const struct dictionary *dict;
     enum { INTEGER, GENERAL } mode;
     enum mv_class exclude;
     bool pivot;
@@ -210,6 +211,7 @@ static void
 init_proc (struct crosstabs_proc *proc, struct dataset *ds)
 {
   const struct variable *wv = dict_get_weight (dataset_dict (ds));
+  proc->dict = dataset_dict (ds);
   proc->bad_warn = true;
   proc->variables = NULL;
   proc->n_variables = 0;
@@ -1189,14 +1191,16 @@ create_crosstab_table (struct crosstabs_proc *proc, struct pivot_table *pt)
     {
       const struct variable *var = pt->const_vars[i];
       size_t ofs;
+      char *s = NULL;
 
       ds_put_format (&title, ", %s=", var_get_name (var));
 
       /* Insert the formatted value of the variable, then trim
          leading spaces in what was just inserted. */
       ofs = ds_length (&title);
-      data_out (&pt->const_values[i], var_get_print_format (var),
-                ds_put_uninit (&title, var_get_width (var)));
+      s = data_out (&pt->const_values[i], dict_get_encoding (proc->dict), var_get_print_format (var));
+      ds_put_cstr (&title, s);
+      free (s);
       ds_remove (&title, ofs, ss_cspan (ds_substr (&title, ofs, SIZE_MAX),
                                         ss_cstr (" ")));
     }
@@ -1237,9 +1241,9 @@ create_chisq_table (struct pivot_table *pt)
   tab_text (chisq, 3, 0, TAB_RIGHT | TAT_TITLE,
             _("Asymp. Sig. (2-sided)"));
   tab_text (chisq, 4, 0, TAB_RIGHT | TAT_TITLE,
-            _("Exact. Sig. (2-sided)"));
+            _("Exact Sig. (2-sided)"));
   tab_text (chisq, 5, 0, TAB_RIGHT | TAT_TITLE,
-            _("Exact. Sig. (1-sided)"));
+            _("Exact Sig. (1-sided)"));
   tab_offset (chisq, 0, 1);
 
   return chisq;
@@ -1534,13 +1538,12 @@ table_value_missing (struct crosstabs_proc *proc,
       const struct fmt_spec *print = var_get_print_format (var);
       if (proc->exclude == MV_NEVER && var_is_value_missing (var, v, MV_USER))
         {
-          char *s = xmalloc (print->w + 2);
-          strcpy (&s[print->w], "M");
-          tab_text (table, c, r, opt, s + strspn (s, " "));
+          char *s = data_out (v, dict_get_encoding (proc->dict), print);
+          tab_text_format (table, c, r, opt, "%sM", s + strspn (s, " "));
           free (s);
         }
       else
-        tab_value (table, c, r, opt, v, print);
+        tab_value (table, c, r, opt, v, proc->dict, print);
     }
 }
 
@@ -1566,22 +1569,26 @@ display_dimensions (struct crosstabs_proc *proc, struct pivot_table *pt,
    additionally suffixed with a letter `M'. */
 static void
 format_cell_entry (struct tab_table *table, int c, int r, double value,
-                   char suffix, bool mark_missing)
+                   char suffix, bool mark_missing, const struct dictionary *dict)
 {
   const struct fmt_spec f = {FMT_F, 10, 1};
   union value v;
-  int len = 10;
-  char s[16];
+  char suffixes[3];
+  int suffix_len;
+  char *s;
 
   v.f = value;
-  data_out (&v, &f, s);
+  s = data_out (&v, dict_get_encoding (dict), &f);
+
+  suffix_len = 0;
   if (suffix != 0)
-    s[len++] = suffix;
+    suffixes[suffix_len++] = suffix;
   if (mark_missing)
-    s[len++] = 'M';
-  s[len] = '\0';
+    suffixes[suffix_len++] = 'M';
+  suffixes[suffix_len] = '\0';
 
-  tab_text (table, c, r, TAB_RIGHT, s + strspn (s, " "));
+  tab_text_format (table, c, r, TAB_RIGHT, "%s%s",
+                   s + strspn (s, " "), suffixes);
 }
 
 /* Displays the crosstabulation table. */
@@ -1656,7 +1663,7 @@ display_crosstabulation (struct crosstabs_proc *proc, struct pivot_table *pt,
                 default:
                   NOT_REACHED ();
                 }
-              format_cell_entry (table, c, i, v, suffix, mark_missing);
+              format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
             }
 
           mp++;
@@ -1707,7 +1714,7 @@ display_crosstabulation (struct crosstabs_proc *proc, struct pivot_table *pt,
               NOT_REACHED ();
             }
 
-          format_cell_entry (table, pt->n_cols, 0, v, suffix, mark_missing);
+          format_cell_entry (table, pt->n_cols, 0, v, suffix, mark_missing, proc->dict);
           tab_next_row (table);
         }
     }
@@ -1757,7 +1764,7 @@ display_crosstabulation (struct crosstabs_proc *proc, struct pivot_table *pt,
               NOT_REACHED ();
             }
 
-          format_cell_entry (table, c, i, v, suffix, mark_missing);
+          format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
         }
       last_row = i;
     }
index 3ca2413fcf35f2d56bba7b2200cde2934bb92985..3e595968d9c4c3232f719a1b48520a2a71dfdc37 100644 (file)
@@ -40,7 +40,8 @@
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
 #include <libpspp/str.h>
-
+#include <data/data-in.h>
+#include <data/data-out.h>
 #include "intprops.h"
 #include "minmax.h"
 #include "xalloc.h"
@@ -66,6 +67,7 @@ struct flip_pgm
     int n_cases;                /* Pre-flip number of cases. */
 
     struct variable *new_names_var; /* Variable with new variable names. */
+    struct dictionary *dict;     /* Dictionary of the names */
     struct var_names old_names; /* Variable names before FLIP. */
     struct var_names new_names; /* Variable names after FLIP. */
 
@@ -105,6 +107,7 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
   flip->file = NULL;
   flip->cases_read = 0;
   flip->error = false;
+  flip->dict = dict;
 
   lex_match (lexer, '/');
   if (lex_match_id (lexer, "VARIABLES"))
@@ -181,9 +184,9 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
             }
           else
             {
-              int width = var_get_width (flip->new_names_var);
-              name = pool_strdup0 (flip->pool,
-                                   value_str (value, width), width);
+              name = data_out_pool (value, dict_get_encoding (flip->dict), var_get_write_format (flip->new_names_var),
+                flip->pool);
+       
             }
           var_names_add (flip->pool, &flip->new_names, name);
         }
@@ -270,7 +273,7 @@ make_new_var (struct dictionary *dict, const char *name_)
         {
           char n[VAR_NAME_LEN + 1];
           int ofs = MIN (VAR_NAME_LEN - 1 - intlog10 (i), len);
-          memcpy (n, name, ofs);
+          strncpy (n, name, ofs);
           sprintf (&n[ofs], "%d", i);
 
           if (dict_create_var (dict, n, 0))
@@ -407,8 +410,12 @@ flip_casereader_read (struct casereader *reader, void *flip_)
     return false;
 
   c = case_create (casereader_get_proto (reader));
-  value_copy_str_rpad (case_data_rw_idx (c, 0), 8,
-                       flip->old_names.names[flip->cases_read], ' ');
+  data_in (ss_cstr (flip->old_names.names[flip->cases_read]), dict_get_encoding (flip->dict), 
+       FMT_A, 0,
+       0, 0,
+       flip->dict, 
+       case_data_rw_idx (c, 0), 8);
+       
   for (i = 0; i < flip->n_cases; i++)
     {
       double in;
index e670c089b5c69c93a40ba52427a254d34c3b6732..76ba5d3f1f874c4bd720f33f02b20e82b9642195 100644 (file)
@@ -207,6 +207,8 @@ struct freq_tab
     struct hsh_table *data;    /* Undifferentiated data. */
     struct freq_mutable *valid; /* Valid freqs. */
     int n_valid;               /* Number of total freqs. */
+    const struct dictionary *dict; /* The dict from whence entries in the table
+                                     come */
 
     struct freq_mutable *missing; /* Missing freqs. */
     int n_missing;             /* Number of missing freqs. */
@@ -756,6 +758,7 @@ frq_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_freque
        }
       vf = var_attach_aux (v, xmalloc (sizeof *vf), var_dtor_free);
       vf->tab.valid = vf->tab.missing = NULL;
+      vf->tab.dict = dataset_dict (ds);
       vf->n_groups = 0;
       vf->groups = NULL;
       vf->width = var_get_width (v);
@@ -1110,7 +1113,7 @@ dump_full (const struct variable *v, const struct variable *wv)
            tab_text (t, 0, r, TAB_LEFT, label);
        }
 
-      tab_value (t, 0 + lab, r, TAB_NONE, &f->value, &vf->print);
+      tab_value (t, 0 + lab, r, TAB_NONE, &f->value, ft->dict, &vf->print);
       tab_double (t, 1 + lab, r, TAB_NONE, f->count, wfmt);
       tab_double (t, 2 + lab, r, TAB_NONE, percent, NULL);
       tab_double (t, 3 + lab, r, TAB_NONE, valid_percent, NULL);
@@ -1128,7 +1131,7 @@ dump_full (const struct variable *v, const struct variable *wv)
            tab_text (t, 0, r, TAB_LEFT, label);
        }
 
-      tab_value (t, 0 + lab, r, TAB_NONE, &f->value, &vf->print);
+      tab_value (t, 0 + lab, r, TAB_NONE, &f->value, ft->dict, &vf->print);
       tab_double (t, 1 + lab, r, TAB_NONE, f->count, wfmt);
       tab_double (t, 2 + lab, r, TAB_NONE,
                     f->count / ft->total_cases * 100.0, NULL);
@@ -1210,7 +1213,7 @@ dump_condensed (const struct variable *v, const struct variable *wv)
       percent = f->count / ft->total_cases * 100.0;
       cum_total += f->count / ft->valid_cases * 100.0;
 
-      tab_value (t, 0, r, TAB_NONE, &f->value, &vf->print);
+      tab_value (t, 0, r, TAB_NONE, &f->value, ft->dict, &vf->print);
       tab_double (t, 1, r, TAB_NONE, f->count, wfmt);
       tab_double (t, 2, r, TAB_NONE, percent, NULL);
       tab_double (t, 3, r, TAB_NONE, cum_total, NULL);
@@ -1218,7 +1221,7 @@ dump_condensed (const struct variable *v, const struct variable *wv)
     }
   for (; f < &ft->valid[n_categories]; f++)
     {
-      tab_value (t, 0, r, TAB_NONE, &f->value, &vf->print);
+      tab_value (t, 0, r, TAB_NONE, &f->value, ft->dict, &vf->print);
       tab_double (t, 1, r, TAB_NONE, f->count, wfmt);
       tab_double (t, 2, r, TAB_NONE,
                 f->count / ft->total_cases * 100.0, NULL);
index 84fd9e5787e17f1d57555bee40e30df475b6a0ab..34bdc6f0940724dd4420a1594b00514ad306de30 100644 (file)
@@ -947,7 +947,7 @@ run_regression (struct casereader *input, struct cmd_regression *cmd,
              lopts.get_indep_mean_std[i] = 1;
            }
          models[k] = pspp_linreg_cache_alloc (dep_var, (const struct variable **) indep_vars,
-                                              X->m->size1, X->m->size2);
+                                              X->m->size1, n_indep);
          models[k]->depvar = dep_var;
          /*
             For large data sets, use QR decomposition.
diff --git a/src/language/stats/roc.c b/src/language/stats/roc.c
new file mode 100644 (file)
index 0000000..1d21a4f
--- /dev/null
@@ -0,0 +1,1179 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <language/stats/roc.h>
+
+#include <data/procedure.h>
+#include <language/lexer/variable-parser.h>
+#include <language/lexer/value-parser.h>
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+
+#include <data/casegrouper.h>
+#include <data/casereader.h>
+#include <data/casewriter.h>
+#include <data/dictionary.h>
+#include <data/format.h>
+#include <math/sort.h>
+#include <data/subcase.h>
+
+
+#include <libpspp/misc.h>
+
+#include <gsl/gsl_cdf.h>
+#include <output/table.h>
+
+#include <output/chart.h>
+#include <output/charts/roc-chart.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+struct cmd_roc
+{
+  size_t n_vars;
+  const struct variable **vars;
+  const struct dictionary *dict;
+
+  const struct variable *state_var ;
+  union value state_value;
+
+  /* Plot the roc curve */
+  bool curve;
+  /* Plot the reference line */
+  bool reference;
+
+  double ci;
+
+  bool print_coords;
+  bool print_se;
+  bool bi_neg_exp; /* True iff the bi-negative exponential critieria
+                     should be used */
+  enum mv_class exclude;
+
+  bool invert ; /* True iff a smaller test result variable indicates
+                  a positive result */
+
+  double pos;
+  double neg;
+  double pos_weighted;
+  double neg_weighted;
+};
+
+static int run_roc (struct dataset *ds, struct cmd_roc *roc);
+
+int
+cmd_roc (struct lexer *lexer, struct dataset *ds)
+{
+  struct cmd_roc roc ;
+  const struct dictionary *dict = dataset_dict (ds);
+
+  roc.vars = NULL;
+  roc.n_vars = 0;
+  roc.print_se = false;
+  roc.print_coords = false;
+  roc.exclude = MV_ANY;
+  roc.curve = true;
+  roc.reference = false;
+  roc.ci = 95;
+  roc.bi_neg_exp = false;
+  roc.invert = false;
+  roc.pos = roc.pos_weighted = 0;
+  roc.neg = roc.neg_weighted = 0;
+  roc.dict = dataset_dict (ds);
+
+  if (!parse_variables_const (lexer, dict, &roc.vars, &roc.n_vars,
+                             PV_APPEND | PV_NO_DUPLICATE | PV_NUMERIC))
+    goto error;
+
+  if ( ! lex_force_match (lexer, T_BY))
+    {
+      goto error;
+    }
+
+  roc.state_var = parse_variable (lexer, dict);
+
+  if ( !lex_force_match (lexer, '('))
+    {
+      goto error;
+    }
+
+  parse_value (lexer, &roc.state_value, var_get_width (roc.state_var));
+
+
+  if ( !lex_force_match (lexer, ')'))
+    {
+      goto error;
+    }
+
+
+  while (lex_token (lexer) != '.')
+    {
+      lex_match (lexer, '/');
+      if (lex_match_id (lexer, "MISSING"))
+        {
+          lex_match (lexer, '=');
+          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+            {
+             if (lex_match_id (lexer, "INCLUDE"))
+               {
+                 roc.exclude = MV_SYSTEM;
+               }
+             else if (lex_match_id (lexer, "EXCLUDE"))
+               {
+                 roc.exclude = MV_ANY;
+               }
+             else
+               {
+                  lex_error (lexer, NULL);
+                 goto error;
+               }
+           }
+       }
+      else if (lex_match_id (lexer, "PLOT"))
+       {
+         lex_match (lexer, '=');
+         if (lex_match_id (lexer, "CURVE"))
+           {
+             roc.curve = true;
+             if (lex_match (lexer, '('))
+               {
+                 roc.reference = true;
+                 lex_force_match_id (lexer, "REFERENCE");
+                 lex_force_match (lexer, ')');
+               }
+           }
+         else if (lex_match_id (lexer, "NONE"))
+           {
+             roc.curve = false;
+           }
+         else
+           {
+             lex_error (lexer, NULL);
+             goto error;
+           }
+       }
+      else if (lex_match_id (lexer, "PRINT"))
+       {
+         lex_match (lexer, '=');
+          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+           {
+             if (lex_match_id (lexer, "SE"))
+               {
+                 roc.print_se = true;
+               }
+             else if (lex_match_id (lexer, "COORDINATES"))
+               {
+                 roc.print_coords = true;
+               }
+             else
+               {
+                 lex_error (lexer, NULL);
+                 goto error;
+               }
+           }
+       }
+      else if (lex_match_id (lexer, "CRITERIA"))
+       {
+         lex_match (lexer, '=');
+          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+           {
+             if (lex_match_id (lexer, "CUTOFF"))
+               {
+                 lex_force_match (lexer, '(');
+                 if (lex_match_id (lexer, "INCLUDE"))
+                   {
+                     roc.exclude = MV_SYSTEM;
+                   }
+                 else if (lex_match_id (lexer, "EXCLUDE"))
+                   {
+                     roc.exclude = MV_USER | MV_SYSTEM;
+                   }
+                 else
+                   {
+                     lex_error (lexer, NULL);
+                     goto error;
+                   }
+                 lex_force_match (lexer, ')');
+               }
+             else if (lex_match_id (lexer, "TESTPOS"))
+               {
+                 lex_force_match (lexer, '(');
+                 if (lex_match_id (lexer, "LARGE"))
+                   {
+                     roc.invert = false;
+                   }
+                 else if (lex_match_id (lexer, "SMALL"))
+                   {
+                     roc.invert = true;
+                   }
+                 else
+                   {
+                     lex_error (lexer, NULL);
+                     goto error;
+                   }
+                 lex_force_match (lexer, ')');
+               }
+             else if (lex_match_id (lexer, "CI"))
+               {
+                 lex_force_match (lexer, '(');
+                 lex_force_num (lexer);
+                 roc.ci = lex_number (lexer);
+                 lex_get (lexer);
+                 lex_force_match (lexer, ')');
+               }
+             else if (lex_match_id (lexer, "DISTRIBUTION"))
+               {
+                 lex_force_match (lexer, '(');
+                 if (lex_match_id (lexer, "FREE"))
+                   {
+                     roc.bi_neg_exp = false;
+                   }
+                 else if (lex_match_id (lexer, "NEGEXPO"))
+                   {
+                     roc.bi_neg_exp = true;
+                   }
+                 else
+                   {
+                     lex_error (lexer, NULL);
+                     goto error;
+                   }
+                 lex_force_match (lexer, ')');
+               }
+             else
+               {
+                 lex_error (lexer, NULL);
+                 goto error;
+               }
+           }
+       }
+      else
+       {
+         lex_error (lexer, NULL);
+         break;
+       }
+    }
+
+  if ( ! run_roc (ds, &roc)) 
+    goto error;
+
+  free (roc.vars);
+  return CMD_SUCCESS;
+
+ error:
+  free (roc.vars);
+  return CMD_FAILURE;
+}
+
+
+
+
+static void
+do_roc (struct cmd_roc *roc, struct casereader *group, struct dictionary *dict);
+
+
+static int
+run_roc (struct dataset *ds, struct cmd_roc *roc)
+{
+  struct dictionary *dict = dataset_dict (ds);
+  bool ok;
+  struct casereader *group;
+
+  struct casegrouper *grouper = casegrouper_create_splits (proc_open (ds), dict);
+  while (casegrouper_get_next_group (grouper, &group))
+    {
+      do_roc (roc, group, dataset_dict (ds));
+    }
+  ok = casegrouper_destroy (grouper);
+  ok = proc_commit (ds) && ok;
+
+  return ok;
+}
+
+#if 0
+static void
+dump_casereader (struct casereader *reader)
+{
+  struct ccase *c;
+  struct casereader *r = casereader_clone (reader);
+
+  for ( ; (c = casereader_read (r) ); case_unref (c))
+    {
+      int i;
+      for (i = 0 ; i < case_get_value_cnt (c); ++i)
+       {
+         printf ("%g ", case_data_idx (c, i)->f);
+       }
+      printf ("\n");
+    }
+
+  casereader_destroy (r);
+}
+#endif
+
+
+/* 
+   Return true iff the state variable indicates that C has positive actual state.
+
+   As a side effect, this function also accumulates the roc->{pos,neg} and 
+   roc->{pos,neg}_weighted counts.
+ */
+static bool
+match_positives (const struct ccase *c, void *aux)
+{
+  struct cmd_roc *roc = aux;
+  const struct variable *wv = dict_get_weight (roc->dict);
+  const double weight = wv ? case_data (c, wv)->f : 1.0;
+
+  const bool positive =
+  ( 0 == value_compare_3way (case_data (c, roc->state_var), &roc->state_value,
+    var_get_width (roc->state_var)));
+
+  if ( positive )
+    {
+      roc->pos++;
+      roc->pos_weighted += weight;
+    }
+  else
+    {
+      roc->neg++;
+      roc->neg_weighted += weight;
+    }
+
+  return positive;
+}
+
+
+#define VALUE  0
+#define N_EQ   1
+#define N_PRED 2
+
+/* Some intermediate state for calculating the cutpoints and the 
+   standard error values */
+struct roc_state
+{
+  double auc;  /* Area under the curve */
+
+  double n1;  /* total weight of positives */
+  double n2;  /* total weight of negatives */
+
+  /* intermediates for standard error */
+  double q1hat; 
+  double q2hat;
+
+  /* intermediates for cutpoints */
+  struct casewriter *cutpoint_wtr;
+  struct casereader *cutpoint_rdr;
+  double prev_result;
+  double min;
+  double max;
+};
+
+/* 
+   Return a new casereader based upon CUTPOINT_RDR.
+   The number of "positive" cases are placed into
+   the position TRUE_INDEX, and the number of "negative" cases
+   into FALSE_INDEX.
+   POS_COND and RESULT determine the semantics of what is 
+   "positive".
+   WEIGHT is the value of a single count.
+ */
+static struct casereader *
+accumulate_counts (struct casereader *cutpoint_rdr, 
+                  double result, double weight, 
+                  bool (*pos_cond) (double, double),
+                  int true_index, int false_index)
+{
+  const struct caseproto *proto = casereader_get_proto (cutpoint_rdr);
+  struct casewriter *w =
+    autopaging_writer_create (proto);
+  struct casereader *r = casereader_clone (cutpoint_rdr);
+  struct ccase *cpc;
+  double prev_cp = SYSMIS;
+
+  for ( ; (cpc = casereader_read (r) ); case_unref (cpc))
+    {
+      struct ccase *new_case;
+      const double cp = case_data_idx (cpc, ROC_CUTPOINT)->f;
+
+      assert (cp != SYSMIS);
+
+      /* We don't want duplicates here */
+      if ( cp == prev_cp )
+       continue;
+
+      new_case = case_clone (cpc);
+
+      if ( pos_cond (result, cp))
+       case_data_rw_idx (new_case, true_index)->f += weight;
+      else
+       case_data_rw_idx (new_case, false_index)->f += weight;
+
+      prev_cp = cp;
+
+      casewriter_write (w, new_case);
+    }
+  casereader_destroy (r);
+
+  return casewriter_make_reader (w);
+}
+
+
+
+static void output_roc (struct roc_state *rs, const struct cmd_roc *roc);
+
+/*
+  This function does 3 things:
+
+  1. Counts the number of cases which are equal to every other case in READER,
+  and those cases for which the relationship between it and every other case
+  satifies PRED (normally either > or <).  VAR is variable defining a case's value
+  for this purpose.
+
+  2. Counts the number of true and false cases in reader, and populates
+  CUTPOINT_RDR accordingly.  TRUE_INDEX and FALSE_INDEX are the indices
+  which receive these values.  POS_COND is the condition defining true
+  and false.
+  
+  3. CC is filled with the cumulative weight of all cases of READER.
+*/
+static struct casereader *
+process_group (const struct variable *var, struct casereader *reader,
+              bool (*pred) (double, double),
+              const struct dictionary *dict,
+              double *cc,
+              struct casereader **cutpoint_rdr, 
+              bool (*pos_cond) (double, double),
+              int true_index,
+              int false_index)
+{
+  const struct variable *w = dict_get_weight (dict);
+
+  struct casereader *r1 =
+    casereader_create_distinct (sort_execute_1var (reader, var), var, w);
+
+  const int weight_idx  = w ? var_get_case_index (w) :
+    caseproto_get_n_widths (casereader_get_proto (r1)) - 1;
+  
+  struct ccase *c1;
+
+  struct casereader *rclone = casereader_clone (r1);
+  struct casewriter *wtr;
+  struct caseproto *proto = caseproto_create ();
+
+  proto = caseproto_add_width (proto, 0);
+  proto = caseproto_add_width (proto, 0);
+  proto = caseproto_add_width (proto, 0);
+
+  wtr = autopaging_writer_create (proto);  
+
+  *cc = 0;
+
+  for ( ; (c1 = casereader_read (r1) ); case_unref (c1))
+    {
+      struct ccase *new_case = case_create (proto);
+      struct ccase *c2;
+      struct casereader *r2 = casereader_clone (rclone);
+
+      const double weight1 = case_data_idx (c1, weight_idx)->f;
+      const double d1 = case_data (c1, var)->f;
+      double n_eq = 0.0;
+      double n_pred = 0.0;
+
+      *cutpoint_rdr = accumulate_counts (*cutpoint_rdr, d1, weight1,
+                                        pos_cond,
+                                        true_index, false_index);
+
+      *cc += weight1;
+
+      for ( ; (c2 = casereader_read (r2) ); case_unref (c2))
+       {
+         const double d2 = case_data (c2, var)->f;
+         const double weight2 = case_data_idx (c2, weight_idx)->f;
+
+         if ( d1 == d2 )
+           {
+             n_eq += weight2;
+             continue;
+           }
+         else  if ( pred (d2, d1))
+           {
+             n_pred += weight2;
+           }
+       }
+
+      case_data_rw_idx (new_case, VALUE)->f = d1;
+      case_data_rw_idx (new_case, N_EQ)->f = n_eq;
+      case_data_rw_idx (new_case, N_PRED)->f = n_pred;
+
+      casewriter_write (wtr, new_case);
+
+      casereader_destroy (r2);
+    }
+
+  casereader_destroy (r1);
+  casereader_destroy (rclone);
+
+  return casewriter_make_reader (wtr);
+}
+
+/* Some more indeces into case data */
+#define N_POS_EQ 1  /* number of positive cases with values equal to n */
+#define N_POS_GT 2  /* number of postive cases with values greater than n */
+#define N_NEG_EQ 3  /* number of negative cases with values equal to n */
+#define N_NEG_LT 4  /* number of negative cases with values less than n */
+
+static bool
+gt (double d1, double d2)
+{
+  return d1 > d2;
+}
+
+
+static bool
+ge (double d1, double d2)
+{
+  return d1 > d2;
+}
+
+static bool
+lt (double d1, double d2)
+{
+  return d1 < d2;
+}
+
+
+/*
+  Return a casereader with width 3,
+  populated with cases based upon READER.
+  The cases will have the values:
+  (N, number of cases equal to N, number of cases greater than N)
+  As a side effect, update RS->n1 with the number of positive cases.
+*/
+static struct casereader *
+process_positive_group (const struct variable *var, struct casereader *reader,
+                       const struct dictionary *dict,
+                       struct roc_state *rs)
+{
+  return process_group (var, reader, gt, dict, &rs->n1,
+                       &rs->cutpoint_rdr,
+                       ge,
+                       ROC_TP, ROC_FN);
+}
+
+/*
+  Return a casereader with width 3,
+  populated with cases based upon READER.
+  The cases will have the values:
+  (N, number of cases equal to N, number of cases less than N)
+  As a side effect, update RS->n2 with the number of negative cases.
+*/
+static struct casereader *
+process_negative_group (const struct variable *var, struct casereader *reader,
+                       const struct dictionary *dict,
+                       struct roc_state *rs)
+{
+  return process_group (var, reader, lt, dict, &rs->n2,
+                       &rs->cutpoint_rdr,
+                       lt,
+                       ROC_TN, ROC_FP);
+}
+
+
+
+
+static void
+append_cutpoint (struct casewriter *writer, double cutpoint)
+{
+  struct ccase *cc = case_create (casewriter_get_proto (writer));
+
+  case_data_rw_idx (cc, ROC_CUTPOINT)->f = cutpoint;
+  case_data_rw_idx (cc, ROC_TP)->f = 0;
+  case_data_rw_idx (cc, ROC_FN)->f = 0;
+  case_data_rw_idx (cc, ROC_TN)->f = 0;
+  case_data_rw_idx (cc, ROC_FP)->f = 0;
+
+  casewriter_write (writer, cc);
+}
+
+
+/* 
+   Create and initialise the rs[x].cutpoint_rdr casereaders.  That is, the readers will
+   be created with width 5, ready to take the values (cutpoint, ROC_TP, ROC_FN, ROC_TN, ROC_FP), and the
+   reader will be populated with its final number of cases.
+   However on exit from this function, only ROC_CUTPOINT entries will be set to their final
+   value.  The other entries will be initialised to zero.
+*/
+static void
+prepare_cutpoints (struct cmd_roc *roc, struct roc_state *rs, struct casereader *input)
+{
+  int i;
+  struct casereader *r = casereader_clone (input);
+  struct ccase *c;
+  struct caseproto *proto = caseproto_create ();
+
+  struct subcase ordering;
+  subcase_init (&ordering, ROC_CUTPOINT, 0, SC_ASCEND);
+
+  proto = caseproto_add_width (proto, 0); /* cutpoint */
+  proto = caseproto_add_width (proto, 0); /* ROC_TP */
+  proto = caseproto_add_width (proto, 0); /* ROC_FN */
+  proto = caseproto_add_width (proto, 0); /* ROC_TN */
+  proto = caseproto_add_width (proto, 0); /* ROC_FP */
+
+  for (i = 0 ; i < roc->n_vars; ++i)
+    {
+      rs[i].cutpoint_wtr = sort_create_writer (&ordering, proto);
+      rs[i].prev_result = SYSMIS;
+      rs[i].max = -DBL_MAX;
+      rs[i].min = DBL_MAX;
+    }
+
+  for (; (c = casereader_read (r)) != NULL; case_unref (c))
+    {
+      for (i = 0 ; i < roc->n_vars; ++i)
+       {
+         const union value *v = case_data (c, roc->vars[i]); 
+         const double result = v->f;
+
+         if ( mv_is_value_missing (var_get_missing_values (roc->vars[i]), v, roc->exclude))
+           continue;
+
+         minimize (&rs[i].min, result);
+         maximize (&rs[i].max, result);
+
+         if ( rs[i].prev_result != SYSMIS && rs[i].prev_result != result )
+           {
+             const double mean = (result + rs[i].prev_result ) / 2.0;
+             append_cutpoint (rs[i].cutpoint_wtr, mean);
+           }
+
+         rs[i].prev_result = result;
+       }
+    }
+  casereader_destroy (r);
+
+
+  /* Append the min and max cutpoints */
+  for (i = 0 ; i < roc->n_vars; ++i)
+    {
+      append_cutpoint (rs[i].cutpoint_wtr, rs[i].min - 1);
+      append_cutpoint (rs[i].cutpoint_wtr, rs[i].max + 1);
+
+      rs[i].cutpoint_rdr = casewriter_make_reader (rs[i].cutpoint_wtr);
+    }
+}
+
+static void
+do_roc (struct cmd_roc *roc, struct casereader *reader, struct dictionary *dict)
+{
+  int i;
+
+  struct roc_state *rs = xcalloc (roc->n_vars, sizeof *rs);
+
+  struct casereader *negatives = NULL;
+  struct casereader *positives = NULL;
+
+  struct caseproto *n_proto = caseproto_create ();
+
+  struct subcase up_ordering;
+  struct subcase down_ordering;
+
+  struct casewriter *neg_wtr = NULL;
+
+  struct casereader *input = casereader_create_filter_missing (reader,
+                                                              roc->vars, roc->n_vars,
+                                                              roc->exclude,
+                                                              NULL,
+                                                              NULL);
+
+  input = casereader_create_filter_missing (input,
+                                           &roc->state_var, 1,
+                                           roc->exclude,
+                                           NULL,
+                                           NULL);
+
+  neg_wtr = autopaging_writer_create (casereader_get_proto (input));
+
+  prepare_cutpoints (roc, rs, input);
+
+
+  /* Separate the positive actual state cases from the negative ones */
+  positives = 
+    casereader_create_filter_func (input,
+                                  match_positives,
+                                  NULL,
+                                  roc,
+                                  neg_wtr);
+
+  n_proto = caseproto_create ();
+      
+  n_proto = caseproto_add_width (n_proto, 0);
+  n_proto = caseproto_add_width (n_proto, 0);
+  n_proto = caseproto_add_width (n_proto, 0);
+  n_proto = caseproto_add_width (n_proto, 0);
+  n_proto = caseproto_add_width (n_proto, 0);
+
+  subcase_init (&up_ordering, VALUE, 0, SC_ASCEND);
+  subcase_init (&down_ordering, VALUE, 0, SC_DESCEND);
+
+  for (i = 0 ; i < roc->n_vars; ++i)
+    {
+      struct casewriter *w = NULL;
+      struct casereader *r = NULL;
+
+      struct ccase *c;
+
+      struct ccase *cpos;
+      struct casereader *n_neg ;
+      const struct variable *var = roc->vars[i];
+
+      struct casereader *neg ;
+      struct casereader *pos = casereader_clone (positives);
+
+
+      struct casereader *n_pos =
+       process_positive_group (var, pos, dict, &rs[i]);
+
+      if ( negatives == NULL)
+       {
+         negatives = casewriter_make_reader (neg_wtr);
+       }
+
+      neg = casereader_clone (negatives);
+
+      n_neg = process_negative_group (var, neg, dict, &rs[i]);
+
+
+      /* Merge the n_pos and n_neg casereaders */
+      w = sort_create_writer (&up_ordering, n_proto);
+      for ( ; (cpos = casereader_read (n_pos) ); case_unref (cpos))
+       {
+         struct ccase *pos_case = case_create (n_proto);
+         struct ccase *cneg;
+         const double jpos = case_data_idx (cpos, VALUE)->f;
+
+         while ((cneg = casereader_read (n_neg)))
+           {
+             struct ccase *nc = case_create (n_proto);
+
+             const double jneg = case_data_idx (cneg, VALUE)->f;
+
+             case_data_rw_idx (nc, VALUE)->f = jneg;
+             case_data_rw_idx (nc, N_POS_EQ)->f = 0;
+
+             case_data_rw_idx (nc, N_POS_GT)->f = SYSMIS;
+
+             *case_data_rw_idx (nc, N_NEG_EQ) = *case_data_idx (cneg, N_EQ);
+             *case_data_rw_idx (nc, N_NEG_LT) = *case_data_idx (cneg, N_PRED);
+
+             casewriter_write (w, nc);
+
+             case_unref (cneg);
+             if ( jneg > jpos)
+               break;
+           }
+
+         case_data_rw_idx (pos_case, VALUE)->f = jpos;
+         *case_data_rw_idx (pos_case, N_POS_EQ) = *case_data_idx (cpos, N_EQ);
+         *case_data_rw_idx (pos_case, N_POS_GT) = *case_data_idx (cpos, N_PRED);
+         case_data_rw_idx (pos_case, N_NEG_EQ)->f = 0;
+         case_data_rw_idx (pos_case, N_NEG_LT)->f = SYSMIS;
+
+         casewriter_write (w, pos_case);
+       }
+
+/* These aren't used anymore */
+#undef N_EQ
+#undef N_PRED
+
+      r = casewriter_make_reader (w);
+
+      /* Propagate the N_POS_GT values from the positive cases
+        to the negative ones */
+      {
+       double prev_pos_gt = rs[i].n1;
+       w = sort_create_writer (&down_ordering, n_proto);
+
+       for ( ; (c = casereader_read (r) ); case_unref (c))
+         {
+           double n_pos_gt = case_data_idx (c, N_POS_GT)->f;
+           struct ccase *nc = case_clone (c);
+
+           if ( n_pos_gt == SYSMIS)
+             {
+               n_pos_gt = prev_pos_gt;
+               case_data_rw_idx (nc, N_POS_GT)->f = n_pos_gt;
+             }
+           
+           casewriter_write (w, nc);
+           prev_pos_gt = n_pos_gt;
+         }
+
+       r = casewriter_make_reader (w);
+      }
+
+      /* Propagate the N_NEG_LT values from the negative cases
+        to the positive ones */
+      {
+       double prev_neg_lt = rs[i].n2;
+       w = sort_create_writer (&up_ordering, n_proto);
+
+       for ( ; (c = casereader_read (r) ); case_unref (c))
+         {
+           double n_neg_lt = case_data_idx (c, N_NEG_LT)->f;
+           struct ccase *nc = case_clone (c);
+
+           if ( n_neg_lt == SYSMIS)
+             {
+               n_neg_lt = prev_neg_lt;
+               case_data_rw_idx (nc, N_NEG_LT)->f = n_neg_lt;
+             }
+           
+           casewriter_write (w, nc);
+           prev_neg_lt = n_neg_lt;
+         }
+
+       r = casewriter_make_reader (w);
+      }
+
+      {
+       struct ccase *prev_case = NULL;
+       for ( ; (c = casereader_read (r) ); case_unref (c))
+         {
+           const struct ccase *next_case = casereader_peek (r, 0);
+
+           const double j = case_data_idx (c, VALUE)->f;
+           double n_pos_eq = case_data_idx (c, N_POS_EQ)->f;
+           double n_pos_gt = case_data_idx (c, N_POS_GT)->f;
+           double n_neg_eq = case_data_idx (c, N_NEG_EQ)->f;
+           double n_neg_lt = case_data_idx (c, N_NEG_LT)->f;
+
+           if ( prev_case && j == case_data_idx (prev_case, VALUE)->f)
+             {
+               if ( 0 ==  case_data_idx (c, N_POS_EQ)->f)
+                 {
+                   n_pos_eq = case_data_idx (prev_case, N_POS_EQ)->f;
+                   n_pos_gt = case_data_idx (prev_case, N_POS_GT)->f;
+                 }
+
+               if ( 0 ==  case_data_idx (c, N_NEG_EQ)->f)
+                 {
+                   n_neg_eq = case_data_idx (prev_case, N_NEG_EQ)->f;
+                   n_neg_lt = case_data_idx (prev_case, N_NEG_LT)->f;
+                 }
+             }
+
+           if ( NULL == next_case || j != case_data_idx (next_case, VALUE)->f)
+             {
+               rs[i].auc += n_pos_gt * n_neg_eq + (n_pos_eq * n_neg_eq) / 2.0;
+
+               rs[i].q1hat +=
+                 n_neg_eq * ( pow2 (n_pos_gt) + n_pos_gt * n_pos_eq + pow2 (n_pos_eq) / 3.0);
+               rs[i].q2hat +=
+                 n_pos_eq * ( pow2 (n_neg_lt) + n_neg_lt * n_neg_eq + pow2 (n_neg_eq) / 3.0);
+
+             }
+
+           case_unref (prev_case);
+           prev_case = case_clone (c);
+         }
+
+       rs[i].auc /=  rs[i].n1 * rs[i].n2; 
+       if ( roc->invert ) 
+         rs[i].auc = 1 - rs[i].auc;
+
+       if ( roc->bi_neg_exp )
+         {
+           rs[i].q1hat = rs[i].auc / ( 2 - rs[i].auc);
+           rs[i].q2hat = 2 * pow2 (rs[i].auc) / ( 1 + rs[i].auc);
+         }
+       else
+         {
+           rs[i].q1hat /= rs[i].n2 * pow2 (rs[i].n1);
+           rs[i].q2hat /= rs[i].n1 * pow2 (rs[i].n2);
+         }
+      }
+    }
+
+  casereader_destroy (positives);
+  casereader_destroy (negatives);
+
+  output_roc (rs, roc);
+
+  free (rs);
+}
+
+static void
+show_auc  (struct roc_state *rs, const struct cmd_roc *roc)
+{
+  int i;
+  const int n_fields = roc->print_se ? 5 : 1;
+  const int n_cols = roc->n_vars > 1 ? n_fields + 1: n_fields;
+  const int n_rows = 2 + roc->n_vars;
+  struct tab_table *tbl = tab_create (n_cols, n_rows);
+
+  if ( roc->n_vars > 1)
+    tab_title (tbl, _("Area Under the Curve"));
+  else
+    tab_title (tbl, _("Area Under the Curve (%s)"), var_to_string (roc->vars[0]));
+
+  tab_headers (tbl, n_cols - n_fields, 0, 1, 0);
+
+  tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
+
+  tab_text (tbl, n_cols - n_fields, 1, TAT_TITLE, _("Area"));
+
+  tab_hline (tbl, TAL_2, 0, n_cols - 1, 2);
+
+  tab_box (tbl,
+          TAL_2, TAL_2,
+          -1, TAL_1,
+          0, 0,
+          n_cols - 1,
+          n_rows - 1);
+
+  if ( roc->print_se )
+    {
+      tab_text (tbl, n_cols - 4, 1, TAT_TITLE, _("Std. Error"));
+      tab_text (tbl, n_cols - 3, 1, TAT_TITLE, _("Asymptotic Sig."));
+
+      tab_text (tbl, n_cols - 2, 1, TAT_TITLE, _("Lower Bound"));
+      tab_text (tbl, n_cols - 1, 1, TAT_TITLE, _("Upper Bound"));
+
+      tab_joint_text_format (tbl, n_cols - 2, 0, 4, 0,
+                            TAT_TITLE | TAB_CENTER,
+                            _("Asymp. %g%% Confidence Interval"), roc->ci);
+      tab_vline (tbl, 0, n_cols - 1, 0, 0);
+      tab_hline (tbl, TAL_1, n_cols - 2, n_cols - 1, 1);
+    }
+
+  if ( roc->n_vars > 1)
+    tab_text (tbl, 0, 1, TAT_TITLE, _("Variable under test"));
+
+  if ( roc->n_vars > 1)
+    tab_vline (tbl, TAL_2, 1, 0, n_rows - 1);
+
+
+  for ( i = 0 ; i < roc->n_vars ; ++i )
+    {
+      tab_text (tbl, 0, 2 + i, TAT_TITLE, var_to_string (roc->vars[i]));
+
+      tab_double (tbl, n_cols - n_fields, 2 + i, 0, rs[i].auc, NULL);
+
+      if ( roc->print_se )
+       {
+         double se ;
+         const double sd_0_5 = sqrt ((rs[i].n1 + rs[i].n2 + 1) /
+                                     (12 * rs[i].n1 * rs[i].n2));
+         double ci ;
+         double yy ;
+
+         se = rs[i].auc * (1 - rs[i].auc) + (rs[i].n1 - 1) * (rs[i].q1hat - pow2 (rs[i].auc)) +
+           (rs[i].n2 - 1) * (rs[i].q2hat - pow2 (rs[i].auc));
+
+         se /= rs[i].n1 * rs[i].n2;
+
+         se = sqrt (se);
+
+         tab_double (tbl, n_cols - 4, 2 + i, 0,
+                     se,
+                     NULL);
+
+         ci = 1 - roc->ci / 100.0;
+         yy = gsl_cdf_gaussian_Qinv (ci, se) ;
+
+         tab_double (tbl, n_cols - 2, 2 + i, 0,
+                     rs[i].auc - yy,
+                     NULL);
+
+         tab_double (tbl, n_cols - 1, 2 + i, 0,
+                     rs[i].auc + yy,
+                     NULL);
+
+         tab_double (tbl, n_cols - 3, 2 + i, 0,
+                     2.0 * gsl_cdf_ugaussian_Q (fabs ((rs[i].auc - 0.5 ) / sd_0_5)),
+                     NULL);
+       }
+    }
+
+  tab_submit (tbl);
+}
+
+
+static void
+show_summary (const struct cmd_roc *roc)
+{
+  const int n_cols = 3;
+  const int n_rows = 4;
+  struct tab_table *tbl = tab_create (n_cols, n_rows);
+
+  tab_title (tbl, _("Case Summary"));
+
+  tab_headers (tbl, 1, 0, 2, 0);
+
+  tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
+
+  tab_box (tbl,
+          TAL_2, TAL_2,
+          -1, -1,
+          0, 0,
+          n_cols - 1,
+          n_rows - 1);
+
+  tab_hline (tbl, TAL_2, 0, n_cols - 1, 2);
+  tab_vline (tbl, TAL_2, 1, 0, n_rows - 1);
+
+
+  tab_hline (tbl, TAL_2, 1, n_cols - 1, 1);
+  tab_vline (tbl, TAL_1, 2, 1, n_rows - 1);
+
+
+  tab_text (tbl, 0, 1, TAT_TITLE | TAB_LEFT, var_to_string (roc->state_var));
+  tab_text (tbl, 1, 1, TAT_TITLE, _("Unweighted"));
+  tab_text (tbl, 2, 1, TAT_TITLE, _("Weighted"));
+
+  tab_joint_text (tbl, 1, 0, 2, 0,
+                 TAT_TITLE | TAB_CENTER,
+                 _("Valid N (listwise)"));
+
+
+  tab_text (tbl, 0, 2, TAB_LEFT, _("Positive"));
+  tab_text (tbl, 0, 3, TAB_LEFT, _("Negative"));
+
+
+  tab_double (tbl, 1, 2, 0, roc->pos, &F_8_0);
+  tab_double (tbl, 1, 3, 0, roc->neg, &F_8_0);
+
+  tab_double (tbl, 2, 2, 0, roc->pos_weighted, 0);
+  tab_double (tbl, 2, 3, 0, roc->neg_weighted, 0);
+
+  tab_submit (tbl);
+}
+
+
+static void
+show_coords (struct roc_state *rs, const struct cmd_roc *roc)
+{
+  int x = 1;
+  int i;
+  const int n_cols = roc->n_vars > 1 ? 4 : 3;
+  int n_rows = 1;
+  struct tab_table *tbl ;
+
+  for (i = 0; i < roc->n_vars; ++i)
+    n_rows += casereader_count_cases (rs[i].cutpoint_rdr);
+
+  tbl = tab_create (n_cols, n_rows);
+
+  if ( roc->n_vars > 1)
+    tab_title (tbl, _("Coordinates of the Curve"));
+  else
+    tab_title (tbl, _("Coordinates of the Curve (%s)"), var_to_string (roc->vars[0]));
+
+
+  tab_headers (tbl, 1, 0, 1, 0);
+
+  tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
+
+  tab_hline (tbl, TAL_2, 0, n_cols - 1, 1);
+
+  if ( roc->n_vars > 1)
+    tab_text (tbl, 0, 0, TAT_TITLE, _("Test variable"));
+
+  tab_text (tbl, n_cols - 3, 0, TAT_TITLE, _("Positive if greater than or equal to"));
+  tab_text (tbl, n_cols - 2, 0, TAT_TITLE, _("Sensitivity"));
+  tab_text (tbl, n_cols - 1, 0, TAT_TITLE, _("1 - Specificity"));
+
+  tab_box (tbl,
+          TAL_2, TAL_2,
+          -1, TAL_1,
+          0, 0,
+          n_cols - 1,
+          n_rows - 1);
+
+  if ( roc->n_vars > 1)
+    tab_vline (tbl, TAL_2, 1, 0, n_rows - 1);
+
+  for (i = 0; i < roc->n_vars; ++i)
+    {
+      struct ccase *cc;
+      struct casereader *r = casereader_clone (rs[i].cutpoint_rdr);
+
+      if ( roc->n_vars > 1)
+       tab_text (tbl, 0, x, TAT_TITLE, var_to_string (roc->vars[i]));
+
+      if ( i > 0)
+       tab_hline (tbl, TAL_1, 0, n_cols - 1, x);
+
+
+      for (; (cc = casereader_read (r)) != NULL;
+          case_unref (cc), x++)
+       {
+         const double se = case_data_idx (cc, ROC_TP)->f /
+           (
+            case_data_idx (cc, ROC_TP)->f
+            +
+            case_data_idx (cc, ROC_FN)->f
+            );
+
+         const double sp = case_data_idx (cc, ROC_TN)->f /
+           (
+            case_data_idx (cc, ROC_TN)->f
+            +
+            case_data_idx (cc, ROC_FP)->f
+            );
+
+         tab_double (tbl, n_cols - 3, x, 0, case_data_idx (cc, ROC_CUTPOINT)->f,
+                     var_get_print_format (roc->vars[i]));
+
+         tab_double (tbl, n_cols - 2, x, 0, se, NULL);
+         tab_double (tbl, n_cols - 1, x, 0, 1 - sp, NULL);
+       }
+
+      casereader_destroy (r);
+    }
+
+  tab_submit (tbl);
+}
+
+
+static void
+output_roc (struct roc_state *rs, const struct cmd_roc *roc)
+{
+  show_summary (roc);
+
+  if ( roc->curve )
+    {
+      struct roc_chart *rc;
+      size_t i;
+
+      rc = roc_chart_create (roc->reference);
+      for (i = 0; i < roc->n_vars; i++)
+        roc_chart_add_var (rc, var_get_name (roc->vars[i]),
+                           rs[i].cutpoint_rdr);
+      chart_submit (roc_chart_get_chart (rc));
+    }
+
+  show_auc (rs, roc);
+
+  if ( roc->print_coords )
+    show_coords (rs, roc);
+}
+
diff --git a/src/language/stats/roc.h b/src/language/stats/roc.h
new file mode 100644 (file)
index 0000000..5d63c96
--- /dev/null
@@ -0,0 +1,28 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LANGUAGE_STATS_ROC_H
+#define LANGUAGE_STATS_ROC_H 1
+
+/* These are case indexes into the cutpoint case readers for ROC
+   output, used by roc.c and roc-chart.c. */
+#define ROC_CUTPOINT 0
+#define ROC_TP 1
+#define ROC_FN 2
+#define ROC_TN 3
+#define ROC_FP 4
+
+#endif /* language/stats/roc.h */
index 3d47bb81f8d7b0bfcfbb648e9fe2f49fb873af38..8d2b2122d1bda6eca09682ba5c98a6df4c5f31b2 100644 (file)
@@ -974,8 +974,8 @@ trbox_paired_populate (struct trbox *trb,
       /* Degrees of freedom */
       tab_double (trb->t, 8, i + 3, TAB_RIGHT, df, &proc->weight_format);
 
-      p = gsl_cdf_tdist_P (t, df);
-      q = gsl_cdf_tdist_P (t, df);
+      p = gsl_cdf_tdist_P (t,df);
+      q = gsl_cdf_tdist_Q (t,df);
 
       tab_double (trb->t, 9, i + 3, TAB_RIGHT, 2.0 * (t > 0 ? q : p), NULL);
     }
index 26d14ab8f3b803559c01696e03bf2cdd632b89ca..c7e302779e63a8937c64a707eeb74126823e948c 100644 (file)
@@ -88,7 +88,7 @@ wilcoxon_execute (const struct dataset *ds,
 
   struct wilcoxon_state *ws = xcalloc (sizeof (*ws), t2s->n_pairs);
   const struct variable *weight = dict_get_weight (dict);
-  struct variable *weightx = var_create_internal (WEIGHT_IDX);
+  struct variable *weightx = var_create_internal (WEIGHT_IDX, 0);
   struct caseproto *proto;
 
   input =
@@ -108,8 +108,8 @@ wilcoxon_execute (const struct dataset *ds,
       struct subcase ordering;
       variable_pair *vp = &t2s->pairs[i];
 
-      ws[i].sign = var_create_internal (0);
-      ws[i].absdiff = var_create_internal (1);
+      ws[i].sign = var_create_internal (0, 0);
+      ws[i].absdiff = var_create_internal (1, 0);
 
       r = casereader_create_filter_missing (r, *vp, 2,
                                            exclude,
@@ -324,12 +324,12 @@ show_tests_box (const struct wilcoxon_state *ws,
 
 
   tab_text (table,  0, 1,  TAB_LEFT, _("Z"));
-  tab_text (table,  0, 2,  TAB_LEFT, _("Asymp. Sig (2-tailed)"));
+  tab_text (table,  0, 2,  TAB_LEFT, _("Asymp. Sig. (2-tailed)"));
 
   if ( exact )
     {
-      tab_text (table,  0, 3,  TAB_LEFT, _("Exact Sig (2-tailed)"));
-      tab_text (table,  0, 4,  TAB_LEFT, _("Exact Sig (1-tailed)"));
+      tab_text (table,  0, 3,  TAB_LEFT, _("Exact Sig. (2-tailed)"));
+      tab_text (table,  0, 4,  TAB_LEFT, _("Exact Sig. (1-tailed)"));
 
 #if 0
       tab_text (table,  0, 5,  TAB_LEFT, _("Point Probability"));
index 411022d43d40563ef11ade555e17ee004d74448a..9b5fd0430b56879fd92e1996c732cbe16e0c2068 100644 (file)
@@ -104,6 +104,7 @@ read_syntax_file (struct getl_interface *s,
   do
     {
       sfs->ln++;
+      ds_clear (line);
       if (!ds_read_line (line, sfs->syntax_file, SIZE_MAX))
         {
           if (ferror (sfs->syntax_file))
index d264a00ef95880dc4a16155eb1305f6836f77e64..fd4e1a93839e27b453abdc9298a559f3b1b8ce6d 100644 (file)
@@ -515,189 +515,183 @@ stc_custom_disk (struct lexer *lexer, struct dataset *ds, struct cmd_set *cmd UN
   return stc_custom_listing (lexer, ds, cmd, aux);
 }
 \f
-static void
+static char *
 show_blanks (const struct dataset *ds UNUSED)
 {
-  if (settings_get_blanks () == SYSMIS)
-    msg (SN, _("BLANKS is SYSMIS."));
-  else
-    msg (SN, _("BLANKS is %g."), settings_get_blanks ());
-
+  return (settings_get_blanks () == SYSMIS
+          ? xstrdup ("SYSMIS")
+          : xasprintf ("%g", settings_get_blanks ()));
 }
 
-static char *
-format_cc (struct substring in, char grouping, char *out)
+static void
+format_cc (struct string *out, struct substring in, char grouping)
 {
   while (!ss_is_empty (in))
     {
       char c = ss_get_char (&in);
       if (c == grouping || c == '\'')
-        *out++ = '\'';
+        ds_put_char (out, '\'');
       else if (c == '"')
-        *out++ = '"';
-      *out++ = c;
+        ds_put_char (out, '"');
+      ds_put_char (out, c);
     }
-  return out;
 }
 
-static void
+static char *
 show_cc (enum fmt_type type)
 {
   const struct fmt_number_style *cc = settings_get_style (type);
-  char cc_string[FMT_STYLE_AFFIX_MAX * 4 * 2 + 3 + 1];
-  char *out;
+  struct string out;
 
-  out = format_cc (cc->neg_prefix, cc->grouping, cc_string);
-  *out++ = cc->grouping;
-  out = format_cc (cc->prefix, cc->grouping, out);
-  *out++ = cc->grouping;
-  out = format_cc (cc->suffix, cc->grouping, out);
-  *out++ = cc->grouping;
-  out = format_cc (cc->neg_suffix, cc->grouping, out);
-  *out = '\0';
+  ds_init_empty (&out);
+  format_cc (&out, cc->neg_prefix, cc->grouping);
+  ds_put_char (&out, cc->grouping);
+  format_cc (&out, cc->prefix, cc->grouping);
+  ds_put_char (&out, cc->grouping);
+  format_cc (&out, cc->suffix, cc->grouping);
+  ds_put_char (&out, cc->grouping);
+  format_cc (&out, cc->neg_suffix, cc->grouping);
 
-  msg (SN, _("%s is \"%s\"."), fmt_name (type), cc_string);
+  return ds_cstr (&out);
 }
 
-static void
+static char *
 show_cca (const struct dataset *ds UNUSED)
 {
-  show_cc (FMT_CCA);
+  return show_cc (FMT_CCA);
 }
 
-static void
+static char *
 show_ccb (const struct dataset *ds UNUSED)
 {
-  show_cc (FMT_CCB);
+  return show_cc (FMT_CCB);
 }
 
-static void
+static char *
 show_ccc (const struct dataset *ds UNUSED)
 {
-  show_cc (FMT_CCC);
+  return show_cc (FMT_CCC);
 }
 
-static void
+static char *
 show_ccd (const struct dataset *ds UNUSED)
 {
-  show_cc (FMT_CCD);
+  return show_cc (FMT_CCD);
 }
 
-static void
+static char *
 show_cce (const struct dataset *ds UNUSED)
 {
-  show_cc (FMT_CCE);
+  return show_cc (FMT_CCE);
 }
 
-static void
+static char *
 show_decimals (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("DECIMAL is \"%c\"."), settings_get_decimal_char (FMT_F));
+  return xasprintf ("\"%c\"", settings_get_decimal_char (FMT_F));
 }
 
-static void
+static char *
 show_endcmd (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("ENDCMD is \"%c\"."), settings_get_endcmd ());
+  return xasprintf ("\"%c\"", settings_get_endcmd ());
 }
 
-static void
+static char *
 show_errors (const struct dataset *ds UNUSED)
 {
   bool terminal = settings_get_error_routing_to_terminal ();
   bool listing = settings_get_error_routing_to_listing ();
-  msg (SN, _("ERRORS is \"%s\"."),
-       terminal && listing ? "BOTH"
-       : terminal ? "TERMINAL"
-       : listing ? "LISTING"
-       : "NONE");
+  return xstrdup (terminal && listing ? "BOTH"
+                  : terminal ? "TERMINAL"
+                  : listing ? "LISTING"
+                  : "NONE");
 }
 
-static void
+static char *
 show_format (const struct dataset *ds UNUSED)
 {
   char str[FMT_STRING_LEN_MAX + 1];
-  msg (SN, _("FORMAT is %s."), fmt_to_string (settings_get_format (), str));
+  return xstrdup (fmt_to_string (settings_get_format (), str));
 }
 
-static void
+static char *
 show_length (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("LENGTH is %d."), settings_get_viewlength ());
+  return xasprintf ("%d", settings_get_viewlength ());
 }
 
-static void
+static char *
 show_locale (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("LOCALE is %s"), get_default_encoding ());
+  return xstrdup (get_default_encoding ());
 }
 
-static void
+static char *
 show_mxerrs (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("MXERRS is %d."), settings_get_mxerrs ());
+  return xasprintf ("%d", settings_get_mxerrs ());
 }
 
-static void
+static char *
 show_mxloops (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("MXLOOPS is %d."), settings_get_mxloops ());
+  return xasprintf ("%d", settings_get_mxloops ());
 }
 
-static void
+static char *
 show_mxwarns (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("MXWARNS is %d."), settings_get_mxwarns ());
+  return xasprintf ("%d", settings_get_mxwarns ());
 }
 
-/* Outputs that SETTING has the given INTEGER_FORMAT value. */
-static void
-show_integer_format (const char *setting, enum integer_format integer_format)
+/* Returns a name for the given INTEGER_FORMAT value. */
+static char *
+show_integer_format (enum integer_format integer_format)
 {
-  msg (SN, _("%s is %s (%s)."),
-       setting,
-       (integer_format == INTEGER_MSB_FIRST ? "MSBFIRST"
-        : integer_format == INTEGER_LSB_FIRST ? "LSBFIRST"
-        : "VAX"),
-       integer_format == INTEGER_NATIVE ? "NATIVE" : "nonnative");
+  return xasprintf ("%s (%s)",
+                    (integer_format == INTEGER_MSB_FIRST ? "MSBFIRST"
+                     : integer_format == INTEGER_LSB_FIRST ? "LSBFIRST"
+                     : "VAX"),
+                    integer_format == INTEGER_NATIVE ? "NATIVE" : "nonnative");
 }
 
-/* Outputs that SETTING has the given FLOAT_FORMAT value. */
-static void
-show_float_format (const char *setting, enum float_format float_format)
+/* Returns a name for the given FLOAT_FORMAT value. */
+static char *
+show_float_format (enum float_format float_format)
 {
   const char *format_name = "";
 
   switch (float_format)
     {
     case FLOAT_IEEE_SINGLE_LE:
-      format_name = "ISL (32-bit IEEE 754 single, little-endian)";
+      format_name = _("ISL (32-bit IEEE 754 single, little-endian)");
       break;
     case FLOAT_IEEE_SINGLE_BE:
-      format_name = "ISB (32-bit IEEE 754 single, big-endian)";
+      format_name = _("ISB (32-bit IEEE 754 single, big-endian)");
       break;
     case FLOAT_IEEE_DOUBLE_LE:
-      format_name = "IDL (64-bit IEEE 754 double, little-endian)";
+      format_name = _("IDL (64-bit IEEE 754 double, little-endian)");
       break;
     case FLOAT_IEEE_DOUBLE_BE:
-      format_name = "IDB (64-bit IEEE 754 double, big-endian)";
+      format_name = _("IDB (64-bit IEEE 754 double, big-endian)");
       break;
 
     case FLOAT_VAX_F:
-      format_name = "VF (32-bit VAX F, VAX-endian)";
+      format_name = _("VF (32-bit VAX F, VAX-endian)");
       break;
     case FLOAT_VAX_D:
-      format_name = "VD (64-bit VAX D, VAX-endian)";
+      format_name = _("VD (64-bit VAX D, VAX-endian)");
       break;
     case FLOAT_VAX_G:
-      format_name = "VG (64-bit VAX G, VAX-endian)";
+      format_name = _("VG (64-bit VAX G, VAX-endian)");
       break;
 
     case FLOAT_Z_SHORT:
-      format_name = "ZS (32-bit IBM Z hexadecimal short, big-endian)";
+      format_name = _("ZS (32-bit IBM Z hexadecimal short, big-endian)");
       break;
     case FLOAT_Z_LONG:
-      format_name = "ZL (64-bit IBM Z hexadecimal long, big-endian)";
+      format_name = _("ZL (64-bit IBM Z hexadecimal long, big-endian)");
       break;
 
     case FLOAT_FP:
@@ -705,73 +699,64 @@ show_float_format (const char *setting, enum float_format float_format)
       NOT_REACHED ();
     }
 
-  msg (SN, _("%s is %s (%s)."),
-       setting, format_name,
-       float_format == FLOAT_NATIVE_DOUBLE ? "NATIVE" : "nonnative");
+  return xasprintf ("%s (%s)", format_name,
+                    (float_format == FLOAT_NATIVE_DOUBLE
+                     ? "NATIVE" : "nonnative"));
 }
 
-static void
+static char *
 show_rib (const struct dataset *ds UNUSED)
 {
-  show_integer_format ("RIB", settings_get_input_integer_format ());
+  return show_integer_format (settings_get_input_integer_format ());
 }
 
-static void
+static char *
 show_rrb (const struct dataset *ds UNUSED)
 {
-  show_float_format ("RRB", settings_get_input_float_format ());
+  return show_float_format (settings_get_input_float_format ());
 }
 
-static void
+static char *
 show_scompression (const struct dataset *ds UNUSED)
 {
-  if (settings_get_scompression ())
-    msg (SN, _("SCOMPRESSION is ON."));
-  else
-    msg (SN, _("SCOMPRESSION is OFF."));
+  return xstrdup (settings_get_scompression () ? "ON" : "OFF");
 }
 
-static void
+static char *
 show_undefined (const struct dataset *ds UNUSED)
 {
-  if (settings_get_undefined ())
-    msg (SN, _("UNDEFINED is WARN."));
-  else
-    msg (SN, _("UNDEFINED is NOWARN."));
+  return xstrdup (settings_get_undefined () ? "WARN" : "NOWARN");
 }
 
-static void
+static char *
 show_weight (const struct dataset *ds)
 {
   const struct variable *var = dict_get_weight (dataset_dict (ds));
-  if (var == NULL)
-    msg (SN, _("WEIGHT is off."));
-  else
-    msg (SN, _("WEIGHT is variable %s."), var_get_name (var));
+  return xstrdup (var != NULL ? var_get_name (var) : "OFF");
 }
 
-static void
+static char *
 show_wib (const struct dataset *ds UNUSED)
 {
-  show_integer_format ("WIB", settings_get_output_integer_format ());
+  return show_integer_format (settings_get_output_integer_format ());
 }
 
-static void
+static char *
 show_wrb (const struct dataset *ds UNUSED)
 {
-  show_float_format ("WRB", settings_get_output_float_format ());
+  return show_float_format (settings_get_output_float_format ());
 }
 
-static void
+static char *
 show_width (const struct dataset *ds UNUSED)
 {
-  msg (SN, _("WIDTH is %d."), settings_get_viewwidth ());
+  return xasprintf ("%d", settings_get_viewwidth ());
 }
 
 struct show_sbc
   {
     const char *name;
-    void (*function) (const struct dataset *);
+    char *(*function) (const struct dataset *);
   };
 
 const struct show_sbc show_table[] =
@@ -801,22 +786,34 @@ const struct show_sbc show_table[] =
     {"WIDTH", show_width},
   };
 
+static void
+do_show (const struct dataset *ds, const struct show_sbc *sbc)
+{
+  char *value = sbc->function (ds);
+  msg (SN, _("%s is %s."), sbc->name, value);
+  free (value);
+}
+
 static void
 show_all (const struct dataset *ds)
 {
   size_t i;
 
   for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
-    show_table[i].function (ds);
+    do_show (ds, &show_table[i]);
 }
 
 static void
-show_all_cc (void)
+show_all_cc (const struct dataset *ds)
 {
   int i;
 
-  for (i = 0; i < 5; i++)
-    show_cc (i);
+  for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
+    {
+      const struct show_sbc *sbc = &show_table[i];
+      if (!strncmp (sbc->name, "CC", 2))
+        do_show (ds, sbc);
+    }
 }
 
 static void
@@ -845,7 +842,7 @@ cmd_show (struct lexer *lexer, struct dataset *ds)
       if (lex_match (lexer, T_ALL))
         show_all (ds);
       else if (lex_match_id (lexer, "CC"))
-        show_all_cc ();
+        show_all_cc (ds);
       else if (lex_match_id (lexer, "WARRANTY"))
         show_warranty (ds);
       else if (lex_match_id (lexer, "COPYING"))
@@ -855,10 +852,13 @@ cmd_show (struct lexer *lexer, struct dataset *ds)
           int i;
 
           for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
-            if (lex_match_id (lexer, show_table[i].name))
-              {
-                show_table[i].function (ds);
-                goto found;
+            {
+              const struct show_sbc *sbc = &show_table[i];
+              if (lex_match_id (lexer, sbc->name))
+                {
+                  do_show (ds, sbc);
+                  goto found;
+                }
               }
           lex_error (lexer, NULL);
           return CMD_FAILURE;
index 60c8f408291b4076bc8f25ab630c47e4bf90b92d..62b03ba073b9a5f6f6a1c5b282d9c26b0ce286b9 100644 (file)
@@ -83,6 +83,8 @@ struct recode_trns
   {
     struct pool *pool;
 
+
+
     /* Variable types, for convenience. */
     enum val_type src_type;     /* src_vars[*] type. */
     enum val_type dst_type;     /* dst_vars[*] type. */
@@ -90,6 +92,7 @@ struct recode_trns
     /* Variables. */
     const struct variable **src_vars;  /* Source variables. */
     const struct variable **dst_vars;  /* Destination variables. */
+    const struct dictionary *dst_dict;  /* Dictionary of dst_vars */
     char **dst_names;          /* Name of dest variables, if they're new. */
     size_t var_cnt;             /* Number of variables. */
 
@@ -540,6 +543,8 @@ create_dst_vars (struct recode_trns *trns, struct dictionary *dict)
 {
   size_t i;
 
+  trns->dst_dict = dict;
+
   for (i = 0; i < trns->var_cnt; i++)
     {
       const struct variable **var = &trns->dst_vars[i];
@@ -598,7 +603,7 @@ find_src_numeric (struct recode_trns *trns, double value, const struct variable
 /* Returns the output mapping in TRNS for an input of VALUE with
    the given WIDTH, or a null pointer if there is no mapping. */
 static const struct map_out *
-find_src_string (struct recode_trns *trns, const char *value,
+find_src_string (struct recode_trns *trns, const uint8_t *value,
                  const struct variable *src_var)
 {
   struct mapping *m;
@@ -625,7 +630,7 @@ find_src_string (struct recode_trns *trns, const char *value,
 
             msg_disable ();
             match = data_in (ss_buffer (value, width), LEGACY_NATIVE,
-                             FMT_F, 0, 0, 0, &uv, 0);
+                             FMT_F, 0, 0, 0, trns->dst_dict,  &uv, 0);
             msg_enable ();
             out->value.f = uv.f;
             break;
index 7fd7580e89d0d12fff978dbb35c6b95981758a00..e08ba2804bbf4d6b0dbe7c6cf81b820c7a239462 100644 (file)
@@ -28,6 +28,7 @@
 #include "assertion.h"
 #include "hmapx.h"
 #include "hash-functions.h"
+#include "pool.h"
 
 #include "i18n.h"
 
@@ -57,6 +58,7 @@ create_iconv (const char* tocode, const char* fromcode)
   size_t hash;
   struct hmapx_node *node;
   struct converter *converter;
+  assert (fromcode);
 
   hash = hash_string (tocode, hash_string (fromcode, 0));
   HMAPX_FOR_EACH_WITH_HASH (converter, node, hash, &map)
@@ -84,13 +86,22 @@ create_iconv (const char* tocode, const char* fromcode)
   return converter->conv;
 }
 
-/* Return a string based on TEXT converted according to HOW.
+char *
+recode_string (const char *to, const char *from,
+              const char *text, int length)
+{
+  return recode_string_pool (to, from, text, length, NULL);
+}
+
+
+/* Return a string based on TEXT which must be encoded using FROM.
+   The returned string will be encoded in TO.
    If length is not -1, then it must be the number of bytes in TEXT.
    The returned string must be freed when no longer required.
 */
 char *
-recode_string (const char *to, const char *from,
-              const char *text, int length)
+recode_string_pool (const char *to, const char *from,
+              const char *text, int length, struct pool *pool)
 {
   char *outbuf = 0;
   size_t outbufferlength;
@@ -109,7 +120,6 @@ recode_string (const char *to, const char *from,
   if ( length == -1 )
      length = strlen(text);
 
-
   if (to == NULL)
     to = default_encoding;
 
@@ -120,7 +130,7 @@ recode_string (const char *to, const char *from,
     if ( outbufferlength > length)
       break;
 
-  outbuf = xmalloc(outbufferlength);
+  outbuf = pool_malloc (pool, outbufferlength);
   op = outbuf;
 
   outbytes = outbufferlength;
@@ -157,7 +167,7 @@ recode_string (const char *to, const char *from,
          case E2BIG:
            free (outbuf);
            outbufferlength <<= 1;
-           outbuf = xmalloc (outbufferlength);
+           outbuf = pool_malloc (pool, outbufferlength);
            op = outbuf;
            outbytes = outbufferlength;
            inbytes = length;
@@ -175,7 +185,7 @@ recode_string (const char *to, const char *from,
   if (outbytes == 0 )
     {
       char *const oldaddr = outbuf;
-      outbuf = xrealloc (outbuf, outbufferlength + 1);
+      outbuf = pool_realloc (pool, outbuf, outbufferlength + 1);
 
       op += (outbuf - oldaddr) ;
     }
index 2c30a70012e18fd2c556c158f9355edb3a0a5d31..9c8f7c14014bdfca443b4d8d01012b1eb40539e9 100644 (file)
@@ -24,7 +24,12 @@ void  i18n_init (void);
 
 #define UTF8 "UTF-8"
 
-char * recode_string (const char *to, const char *from,
+struct pool;
+
+char *recode_string_pool (const char *to, const char *from,
+                         const char *text, int length, struct pool *pool);
+
+char *recode_string (const char *to, const char *from,
                      const char *text, int len);
 
 
index 45f0195f37f3fc18b035401fcd1313a85f76b259..18a621970c85da745917dcf2b179c9945862e13e 100644 (file)
 #include <config.h>
 
 #include <libpspp/legacy-encoding.h>
-
-#include "str.h"
-
-static const char ascii_to_ebcdic[256];
-static const char ebcdic_to_ascii[256];
-
-void
-legacy_recode (enum legacy_encoding from, const char *src,
-             enum legacy_encoding to, char *dst,
-             size_t size)
-{
-  if (from != to)
-    {
-      const char *table;
-      size_t i;
-
-      table = from == LEGACY_ASCII ? ascii_to_ebcdic : ebcdic_to_ascii;
-      for (i = 0; i < size; i++)
-        dst[i] = table[(unsigned char) src[i]];
-    }
-  else
-    {
-      if (src != dst)
-        memcpy (dst, src, size);
-    }
-}
+#include <libpspp/i18n.h>
+#include <stdlib.h>
 
 char
-legacy_to_native (enum legacy_encoding from, char c)
+legacy_to_native (const char *from, char c)
 {
-  legacy_recode (from, &c, LEGACY_NATIVE, &c, 1);
-  return c;
+  char x;
+  char *s = recode_string (LEGACY_NATIVE, from, &c, 1);
+  x = s[0];
+  free (s);
+  return x;
 }
 
 char
-legacy_from_native (enum legacy_encoding to, char c)
+legacy_from_native (const char *to, char c)
 {
-  legacy_recode (LEGACY_NATIVE, &c, to, &c, 1);
-  return c;
+  char x;
+  char *s = recode_string (to, LEGACY_NATIVE, &c, 1);
+  x = s[0];
+  free (s);
+  return x;
 }
-
-static const char ascii_to_ebcdic[256] =
-  {
-    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f,
-    0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26,
-    0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
-    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d,
-    0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
-    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
-    0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
-    0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
-    0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
-    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
-    0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x9a, 0x6d,
-    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
-    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
-    0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0x5f, 0x07,
-    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17,
-    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
-    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08,
-    0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
-    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
-    0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
-    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
-    0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
-    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d,
-    0x8e, 0x8f, 0x90, 0x6a, 0x9b, 0x9c, 0x9d, 0x9e,
-    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0x4a, 0xae, 0xaf,
-    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xa1, 0xbe, 0xbf,
-    0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
-    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed,
-    0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-  };
-
-static const char ebcdic_to_ascii[256] =
-  {
-    0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f,
-    0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-    0x10, 0x11, 0x12, 0x13, 0x9d, 0x85, 0x08, 0x87,
-    0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f,
-    0x80, 0x81, 0x82, 0x83, 0x84, 0x0a, 0x17, 0x1b,
-    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,
-    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
-    0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,
-    0x20, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
-    0xa7, 0xa8, 0xd5, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,
-    0x26, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
-    0xb0, 0xb1, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x7e,
-    0x2d, 0x2f, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-    0xb8, 0xb9, 0xcb, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
-    0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1,
-    0xc2, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,
-    0xc3, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
-    0x68, 0x69, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
-    0xca, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
-    0x71, 0x72, 0x5e, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
-    0xd1, 0xe5, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
-    0x79, 0x7a, 0xd2, 0xd3, 0xd4, 0x5b, 0xd6, 0xd7,
-    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
-    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0x5d, 0xe6, 0xe7,
-    0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
-    0x48, 0x49, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed,
-    0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
-    0x51, 0x52, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
-    0x5c, 0x9f, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
-    0x59, 0x5a, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
-    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-    0x38, 0x39, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-  };
-
index 12afe42b7f22d97a190659fad70579f7ee4e9043..c6ae0ab4aa2bb25faf9f074436aa3bd9637bb137 100644 (file)
 #ifndef LIBPSPP_LEGACY_ENCODING
 #define LIBPSPP_LEGACY_ENCODING 1
 
-#include <stddef.h>
 #include <libpspp/compiler.h>
 
-/* A legacy character encoding.
-   This exists only to handle the specific legacy EBCDIC-to-ASCII
-   recoding that MODE=360 file handles perform. */
-enum legacy_encoding
-  {
-    LEGACY_ASCII,         /* ASCII or similar character set. */
-    LEGACY_EBCDIC,        /* IBM EBCDIC character set. */
-
-    /* Native character set. */
 #if 'A' == 0x41
-    LEGACY_NATIVE = LEGACY_ASCII
+#define  LEGACY_NATIVE "ASCII"
 #elif 'A' == 0xc1
-    LEGACY_NATIVE = LEGACY_EBCDIC
+#define  LEGACY_NATIVE "EBCDIC-US"
 #else
 #error Cannot detect native character set.
 #endif
-  };
 
-void legacy_recode (enum legacy_encoding, const char *src,
-                    enum legacy_encoding, char *dst, size_t);
-char legacy_to_native (enum legacy_encoding from, char) PURE_FUNCTION;
-char legacy_from_native (enum legacy_encoding to, char) PURE_FUNCTION;
+char legacy_to_native (const char *from, char) PURE_FUNCTION;
+char legacy_from_native (const char *to, char) PURE_FUNCTION;
+
 
 #endif /* libpspp/legacy-encoding.h */
index c954a722c89987d371eee5084a9b52c452af0ee8..8243aa0690aad24a9b519db9bd1838724d32d729 100644 (file)
@@ -1442,3 +1442,25 @@ ds_relocate (struct string *st)
       free ((char *) rel);
     }
 }
+
+
+\f
+
+/* Operations on uint8_t "strings" */
+
+/* Copies buffer SRC, of SRC_SIZE bytes, to DST, of DST_SIZE bytes.
+   DST is truncated to DST_SIZE bytes or padded on the right with
+   copies of PAD as needed. */
+void
+u8_buf_copy_rpad (uint8_t *dst, size_t dst_size,
+                 const uint8_t *src, size_t src_size,
+                 char pad)
+{
+  if (src_size >= dst_size)
+    memmove (dst, src, dst_size);
+  else
+    {
+      memmove (dst, src, src_size);
+      memset (&dst[src_size], pad, dst_size - src_size);
+    }
+}
index b9be394c59c46a95f1f593e970ac83e4cdb8d7b8..a134079f90dd52f7c359d7ad4fba3049c5c85203 100644 (file)
@@ -20,6 +20,7 @@
 #include <assert.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -223,4 +224,10 @@ char *ds_put_uninit (struct string *st, size_t incr);
 /* calls relocate from gnulib on ST */
 void ds_relocate (struct string *st);
 
+
+void u8_buf_copy_rpad (uint8_t *dst, size_t dst_size,
+                      const uint8_t *src, size_t src_size,
+                      char pad);
+
+
 #endif /* str_h */
index 2a00a56d95d5c7a20a1a540bc714f539b7a9d58a..89660ba9c1e3f5fbc1f4168af2ef8af549a43c7d 100644 (file)
@@ -61,7 +61,9 @@ struct covariance_matrix
   struct moments1 **m1;
   struct moments **m;
   const struct variable **v_variables;
+  const struct interaction_variable **interactions;
   size_t n_variables;
+  size_t n_intr;
   int n_pass;
   int missing_handling;
   enum mv_class missing_value;
@@ -119,6 +121,7 @@ covariance_matrix_init (size_t n_variables,
   result->ca = covariance_hsh_create (&result->n_variables);
   result->m = NULL;
   result->m1 = NULL;
+  result->n_intr = 0;
   result->missing_handling = missing_handling;
   result->missing_value = missing_value;
   result->accumulate = (result->missing_handling == LISTWISE) ?
@@ -147,6 +150,14 @@ covariance_matrix_init (size_t n_variables,
 
   return result;
 }
+void
+covariance_interaction_set (struct covariance_matrix *cov, 
+                           const struct interaction_variable **intr, size_t n_intr)
+{
+  cov->interactions = intr;
+  cov->n_intr = n_intr;
+}
+
 static size_t 
 get_n_rows (size_t n_variables, const struct variable *v_variables[])
 {
@@ -177,6 +188,44 @@ covariance_matrix_create (size_t n_variables,
   return design_matrix_create (n_variables, v_variables, n_rows);
 }
 
+static size_t 
+get_n_rows_s (const struct variable *var)
+{
+  size_t result = 0;
+  if (var_is_numeric (var))
+    {
+      result++;
+    }
+  else
+    {
+      result += cat_get_n_categories (var) - 1;
+    }
+  return result;
+}
+static struct design_matrix *
+covariance_matrix_create_s (struct covariance_matrix *cov)
+{
+  struct variable **v_variables;
+  size_t n_variables;
+  size_t n_rows = 0;
+  size_t i;
+  size_t j;
+
+  n_variables = cov->n_variables + cov->n_intr;
+  v_variables = xnmalloc (n_variables, sizeof (*v_variables));
+  for (i = 0; i < cov->n_variables; i++)
+    {
+      v_variables[i] = cov->v_variables[i];
+      n_rows += get_n_rows_s (v_variables[i]);
+    }
+  for (j = 0; j < cov->n_intr; j++)
+    {
+      v_variables[i + j] = interaction_get_variable (cov->interactions[j]);
+      n_rows += get_n_rows_s (v_variables[i]);
+    }
+  return design_matrix_create (n_variables, v_variables, n_rows);
+}
+
 static void
 update_moments1 (struct covariance_matrix *cov, size_t i, double x)
 {
@@ -550,12 +599,12 @@ get_covariance_variables (const struct covariance_matrix *cov)
 }
 
 static void
-update_hash_entry (struct hsh_table *c,
-                  const struct variable *v1,
-                  const struct variable *v2,
-                  const union value *val1, const union value *val2, 
-                  const struct interaction_value *i_val1,
-                  const struct interaction_value *i_val2)
+update_hash_entry_intr (struct hsh_table *c,
+                       const struct variable *v1,
+                       const struct variable *v2,
+                       const union value *val1, const union value *val2, 
+                       const struct interaction_value *i_val1,
+                       const struct interaction_value *i_val2)
 {
   struct covariance_accumulator *ca;
   struct covariance_accumulator *new_entry;
@@ -588,6 +637,56 @@ update_hash_entry (struct hsh_table *c,
     }
 }
 
+static void
+update_hash_entry (struct hsh_table *c,
+                  const struct variable *v1,
+                  const struct variable *v2,
+                  const union value *val1, const union value *val2)
+{
+  struct covariance_accumulator *ca;
+  struct covariance_accumulator *new_entry;
+
+  ca = get_new_covariance_accumulator (v1, v2, val1, val2);
+  ca->dot_product = update_product (ca->v1, ca->v2, ca->val1, ca->val2);
+  ca->sum1 = update_sum (ca->v1, ca->val1, 1.0);
+  ca->sum2 = update_sum (ca->v2, ca->val2, 1.0);
+  ca->ssize = 1.0;
+  new_entry = hsh_insert (c, ca);
+
+  if (new_entry != NULL)
+    {
+      new_entry->dot_product += ca->dot_product;
+      new_entry->ssize += 1.0;
+      new_entry->sum1 += ca->sum1;
+      new_entry->sum2 += ca->sum2;
+      /*
+       If DOT_PRODUCT is null, CA was not already in the hash
+       hable, so we don't free it because it was just inserted.
+       If DOT_PRODUCT was not null, CA is already in the hash table.
+       Unnecessary now, it must be freed here.
+      */
+      free (ca);
+    }
+}
+
+static void
+inner_intr_loop (struct covariance_matrix *cov, const struct ccase  *ccase, const struct variable *var1,
+                const union value *val1, const struct interaction_variable **i_var, 
+                const struct interaction_value *i_val1, size_t j)
+{
+  struct variable *var2;
+  union value *val2;
+  struct interaction_value *i_val2;
+
+  var2 = interaction_get_variable (i_var[j]);
+  i_val2 = interaction_case_data (ccase, i_var[j]);
+  val2 = interaction_value_get (i_val2);
+  
+  if (!var_is_value_missing (var2, val2, cov->missing_value))
+    {
+      update_hash_entry_intr (cov->ca, var1, var2, val1, val2, i_val1, i_val2);
+    }
+}       
 /*
   Compute the covariance matrix in a single data-pass. Cases with
   missing values are dropped pairwise, in other words, only if one of
@@ -608,6 +707,8 @@ covariance_accumulate_pairwise (struct covariance_matrix *cov,
   const union value *val1;
   const union value *val2;
   const struct variable **v_variables;
+  const struct variable *var1;
+  const struct variable *var2;
   struct interaction_value *i_val1 = NULL;
   struct interaction_value *i_val2 = NULL;
 
@@ -619,39 +720,42 @@ covariance_accumulate_pairwise (struct covariance_matrix *cov,
 
   for (i = 0; i < cov->n_variables; ++i)
     {
-      if (is_interaction (v_variables[i], i_var, n_intr))
-       {
-         i_val1 = interaction_case_data (ccase, v_variables[i], i_var, n_intr);
-         val1 = interaction_value_get (i_val1);
-       }
-      else
-       {
-         val1 = case_data (ccase, v_variables[i]);
-       }
-      if (!var_is_value_missing (v_variables[i], val1, cov->missing_value))
+      var1 = v_variables[i];
+      val1 = case_data (ccase, var1);
+      if (!var_is_value_missing (var1, val1, cov->missing_value))
        {
-         cat_value_update (v_variables[i], val1);
-         if (var_is_numeric (v_variables[i]))
+         cat_value_update (var1, val1);
+         if (var_is_numeric (var1))
            cov->update_moments (cov, i, val1->f);
 
          for (j = i; j < cov->n_variables; j++)
            {
-             if (is_interaction (v_variables[j], i_var, n_intr))
-               {
-                 i_val2 = interaction_case_data (ccase, v_variables[j], i_var, n_intr);
-                 val2 = interaction_value_get (i_val2);
-               }
-             else
-               {
-                 val2 = case_data (ccase, v_variables[j]);
-               }
+             var2 = v_variables[j];
+             val2 = case_data (ccase, var2);
              if (!var_is_value_missing
-                 (v_variables[j], val2, cov->missing_value))
+                 (var2, val2, cov->missing_value))
                {
-                 update_hash_entry (cov->ca, v_variables[i], v_variables[j],
-                                    val1, val2, i_val1, i_val2);
+                 update_hash_entry (cov->ca, var1, var2, val1, val2);
                }
            }
+         for (j = 0; j < cov->n_intr; j++)
+           {
+             inner_intr_loop (cov, ccase, var1, val1, i_var, i_val1, j);
+           }
+       }
+    }
+  for (i = 0; i < cov->n_intr; i++)
+    {
+      var1 = interaction_get_variable (i_var[i]);
+      i_val1 = interaction_case_data (ccase, i_var[i]);
+      val1 = interaction_value_get (i_val1);
+      cat_value_update (var1, val1);
+      if (!var_is_value_missing (var1, val1, cov->missing_value))
+       {
+         for (j = i; j < cov->n_intr; j++)
+           {
+             inner_intr_loop (cov, ccase, var1, val1, i_var, i_val1, j);
+           }
        }
     }
 }
@@ -693,32 +797,15 @@ covariance_accumulate_listwise (struct covariance_matrix *cov,
 
   for (i = 0; i < cov->n_variables; ++i)
     {
-      if (is_interaction (v_variables[i], i_var, n_intr))
-       {
-         i_val1 = interaction_case_data (ccase, v_variables[i], i_var, n_intr);
-         val1 = interaction_value_get (i_val1);
-       }
-      else
-       {
-         val1 = case_data (ccase, v_variables[i]);
-       }
+      val1 = case_data (ccase, v_variables[i]);
       cat_value_update (v_variables[i], val1);
       if (var_is_numeric (v_variables[i]))
        cov->update_moments (cov, i, val1->f);
 
       for (j = i; j < cov->n_variables; j++)
        {
-         if (is_interaction (v_variables[j], i_var, n_intr))
-           {
-             i_val2 = interaction_case_data (ccase, v_variables[j], i_var, n_intr);
-             val2 = interaction_value_get (i_val2);
-           }
-         else
-           {
-             val2 = case_data (ccase, v_variables[j]);
-           }
          update_hash_entry (cov->ca, v_variables[i], v_variables[j],
-                            val1, val2, i_val1, i_val2);
+                            val1, val2);
        }
     }
 }
@@ -829,15 +916,18 @@ get_sum (const struct covariance_matrix *cov, size_t i)
       else
        {
          k = 0;
-         while (var_get_dict_index (cov->v_variables[k]) != var_get_dict_index (var))
+         while (cov->v_variables[k] != var && k  < cov->n_variables)
            {
              k++;
            }
-         moments1_calculate (cov->m1[k], &n, &mean, NULL, NULL, NULL);
-         return mean * n;
+         if (k < cov->n_variables)
+           {
+             moments1_calculate (cov->m1[k], &n, &mean, NULL, NULL, NULL);
+             return mean * n;
+           }
        }
     }
-
+      
   return 0.0;
 }
 static void
@@ -868,8 +958,8 @@ covariance_accumulator_to_matrix (struct covariance_matrix *cov)
   struct covariance_accumulator *entry;
   struct hsh_iterator iter;
 
-  cov->cov = covariance_matrix_create (cov->n_variables, cov->v_variables);
-  cov->ssize = covariance_matrix_create (cov->n_variables, cov->v_variables);
+  cov->cov = covariance_matrix_create_s (cov);
+  cov->ssize = covariance_matrix_create_s (cov);
   entry = hsh_first (cov->ca, &iter);
   while (entry != NULL)
     {
index 24ce791cf5f74da3bb27ae48b11c4a9591a9f2b8..c16e5cbc4dfde7d3056b05a32363769e43175251 100644 (file)
@@ -40,10 +40,9 @@ enum
 { LISTWISE,
   PAIRWISE
 };
-struct design_matrix *covariance_matrix_create (size_t,
-                                               const struct variable *[]);
+struct design_matrix *covariance_matrix_create (size_t, const struct variable *[]);
 
-void covariance_matrix_destroy (struct covariance_matrix *cov);
+void covariance_matrix_destroy (struct covariance_matrix *);
 void covariance_pass_two (struct design_matrix *, double,
                          double, double, const struct variable *,
                          const struct variable *, const union value *,
@@ -57,4 +56,6 @@ void covariance_matrix_accumulate (struct covariance_matrix *,
                                   const struct ccase *, void **, size_t);
 struct design_matrix *covariance_to_design (const struct covariance_matrix *);
 double covariance_matrix_get_element (const struct covariance_matrix *, size_t, size_t);
+void covariance_interaction_set (struct covariance_matrix *, 
+                                const struct interaction_variable **, size_t);
 #endif
index c8795ed58a00495e72995a2561b9f7ba60fd179f..7fc9f0f63d2c5efee0098f06fe921d50758425e6 100644 (file)
@@ -15,7 +15,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 /*
-  An interaction is a gsl_vector containing a "product" of other
+  An interaction is a structure containing a "product" of other
   variables. The variables can be either categorical or numeric.
   If the variables are all numeric, the interaction is just the
   scalar product. If any of the variables are categorical, their
 
 #include <config.h>
 #include <assert.h>
-#include <gsl/gsl_math.h>
-#include <gsl/gsl_vector.h>
 #include <data/value.h>
 #include <data/variable.h>
+#include <gl/unistr.h>
 #include <math/interaction.h>
 #include <string.h>
 #include <xalloc.h>
@@ -70,6 +69,8 @@ interaction_variable_create (const struct variable **vars, int n_vars)
 
   if (n_vars > 0)
     {
+      int width = 0;
+
       result = xmalloc (sizeof (*result));
       result->n_alpha = 0;
       result->members = xnmalloc (n_vars, sizeof (*result->members));
@@ -80,10 +81,11 @@ interaction_variable_create (const struct variable **vars, int n_vars)
          if (var_is_alpha (vars[i]))
            {
              result->n_alpha++;
+             width += var_get_width (vars[i]);
            }
        }
+      result->intr = var_create_internal (0, width);
     }
-  result->intr = var_create_internal (0);
 
   return result;
 }
@@ -98,7 +100,7 @@ void interaction_variable_destroy (struct interaction_variable *iv)
   Get one of the member variables.
  */
 const struct variable *
-interaction_variable_get_member (const struct interaction_variable *iv, size_t i)
+interaction_get_member (const struct interaction_variable *iv, size_t i)
 {
   return iv->members[i];
 }
@@ -122,10 +124,10 @@ interaction_get_n_numeric (const struct interaction_variable *iv)
 }
 
 /*
-  Get the interaction varibale itself.
+  Get the interaction variable itself.
  */
 const struct variable *
-interaction_variable_get_var (const struct interaction_variable *iv)
+interaction_get_variable (const struct interaction_variable *iv)
 {
   return iv->intr;
 }
@@ -140,30 +142,27 @@ struct interaction_value *
 interaction_value_create (const struct interaction_variable *var, const union value **vals)
 {
   struct interaction_value *result = NULL;
-  const struct variable *member;
-  size_t i;
-  size_t n_vars;
   
   if (var != NULL)
     {
-      int val_width;
-      char *val;
+      size_t i;
+      int val_width = var_get_width (interaction_get_variable (var));
+      int offset = 0;
+      size_t n_vars = interaction_get_n_vars (var);
 
       result = xmalloc (sizeof (*result));
       result->intr = var;
-      n_vars = interaction_get_n_vars (var);
-      val_width = n_vars * MAX_SHORT_STRING + 1;
+
       value_init (&result->val, val_width);
-      val = value_str_rw (&result->val, val_width);
-      val[0] = '\0';
+
       result->f = 1.0;
       for (i = 0; i < n_vars; i++)
        {
-         member = interaction_variable_get_member (var, i);
+          const struct variable *member = interaction_get_member (var, i);
 
          if (var_is_value_missing (member, vals[i], MV_ANY))
            {
-             value_set_missing (&result->val, MAX_SHORT_STRING);
+             value_set_missing (&result->val, val_width);
              result->f = SYSMIS;
              break;
            }
@@ -171,8 +170,10 @@ interaction_value_create (const struct interaction_variable *var, const union va
            {
              if (var_is_alpha (var->members[i]))
                {
+                 uint8_t *val = value_str_rw (&result->val, val_width);
                   int w = var_get_width (var->members[i]);
-                 strncat (val, value_str (vals[i], w), MAX_SHORT_STRING);
+                  u8_cpy (val + offset, value_str (vals[i], w), w);
+                  offset += w;
                }
              else if (var_is_numeric (var->members[i]))
                {
@@ -211,7 +212,7 @@ interaction_value_get (const struct interaction_value *val)
 /*
   Returns the numeric value of the non-zero entry for the vector
   corresponding to this interaction.  Do not use this function to get
-  the numeric value of a purley numeric interaction. Instead, use the
+  the numeric value of a purely numeric interaction. Instead, use the
   union value * returned by interaction_value_get.
  */
 double 
@@ -227,8 +228,7 @@ interaction_value_destroy (struct interaction_value *val)
 {
   if (val != NULL)
     {
-      size_t n_vars = interaction_get_n_vars (val->intr);
-      int val_width = n_vars * MAX_SHORT_STRING + 1;
+      int val_width = var_get_width (interaction_get_variable (val->intr));
 
       value_destroy (&val->val, val_width);
       free (val);
@@ -239,32 +239,22 @@ interaction_value_destroy (struct interaction_value *val)
   Return a value from a variable that is an interaction. 
  */
 struct interaction_value *
-interaction_case_data (const struct ccase *ccase, const struct variable *var, 
-                      const struct interaction_variable **intr_vars, size_t n_intr)
+interaction_case_data (const struct ccase *ccase, const struct interaction_variable *iv)
 {
   size_t i;
   size_t n_vars;
-  const struct interaction_variable *iv = NULL;
-  const struct variable *intr;
   const struct variable *member;
   const union value **vals = NULL;
 
-  for (i = 0; i < n_intr; i++)
-    {
-      iv = intr_vars[i];
-      intr = interaction_variable_get_var (iv);
-      if (var_get_dict_index (intr) == var_get_dict_index (var))
-       {
-         break;
-       }
-    }
   n_vars = interaction_get_n_vars (iv);
   vals = xnmalloc (n_vars, sizeof (*vals));
+
   for (i = 0; i < n_vars; i++)
-    {
-      member = interaction_variable_get_member (iv, i);
-      vals[i] = case_data (ccase, member);
-    }
+       {
+         member = interaction_get_member (iv, i);
+         vals[i] = case_data (ccase, member);
+       }
+
   return interaction_value_create (iv, vals);
 }
 
@@ -276,7 +266,7 @@ is_interaction (const struct variable *var, const struct interaction_variable **
   
   for (i = 0; i < n_intr; i++)
     {
-      intr = interaction_variable_get_var (iv[i]);
+      intr = interaction_get_variable (iv[i]);
       if (var_get_dict_index (intr) == var_get_dict_index (var))
        {
          return true;
index 66025b6628f428d012ff879268f00367e3a26a1f..995d0684517d78a8207e040121126b1ae63f473c 100644 (file)
@@ -28,14 +28,13 @@ void interaction_value_destroy (struct interaction_value *);
 size_t interaction_variable_get_n_vars (const struct interaction_variable *);
 double interaction_value_get_nonzero_entry (const struct interaction_value *);
 const union value *interaction_value_get (const struct interaction_value *);
-const struct variable * interaction_variable_get_var (const struct interaction_variable *);
+const struct variable * interaction_get_variable (const struct interaction_variable *);
 size_t interaction_get_n_numeric (const struct interaction_variable *);
 size_t interaction_get_n_alpha (const struct interaction_variable *);
 size_t interaction_get_n_vars (const struct interaction_variable *);
-const struct variable * interaction_variable_get_member (const struct interaction_variable *, size_t);
+const struct variable * interaction_get_member (const struct interaction_variable *, size_t);
 bool is_interaction (const struct variable *, const struct interaction_variable **, size_t);
 struct interaction_value *
-interaction_case_data (const struct ccase *, const struct variable *, 
-                      const struct interaction_variable **, size_t);
+interaction_case_data (const struct ccase *, const struct interaction_variable *);
 double interaction_value_get_nonzero_entry (const struct interaction_value *);
 #endif
index 8028697c6b7f3410b12927a0fe7ae1d82c5a6b4b..c03af4672955f4dd20514291faf8cf06bebb49e5 100644 (file)
@@ -383,8 +383,8 @@ pspp_linreg (const gsl_vector * Y, const struct design_matrix *dm,
              gsl_matrix_set (design, j, i, tmp);
            }
        }
-      sw = gsl_matrix_calloc (cache->n_indeps + 1, cache->n_indeps + 1);
-      xtx = gsl_matrix_submatrix (sw, 0, 0, cache->n_indeps, cache->n_indeps);
+      sw = gsl_matrix_calloc (cache->n_coeffs + 1, cache->n_coeffs + 1);
+      xtx = gsl_matrix_submatrix (sw, 0, 0, cache->n_coeffs, cache->n_coeffs);
 
       for (i = 0; i < xtx.matrix.size1; i++)
        {
@@ -399,8 +399,8 @@ pspp_linreg (const gsl_vector * Y, const struct design_matrix *dm,
            }
        }
 
-      gsl_matrix_set (sw, cache->n_indeps, cache->n_indeps, cache->sst);
-      xty = gsl_matrix_column (sw, cache->n_indeps);
+      gsl_matrix_set (sw, cache->n_coeffs, cache->n_coeffs, cache->sst);
+      xty = gsl_matrix_column (sw, cache->n_coeffs);
       /*
          This loop starts at 1, with i=0 outside the loop, so we can get
          the model sum of squares due to the first independent variable.
@@ -410,7 +410,7 @@ pspp_linreg (const gsl_vector * Y, const struct design_matrix *dm,
       gsl_vector_set (&(xty.vector), 0, tmp);
       tmp *= tmp / gsl_vector_get (cache->ssx, 0);
       gsl_vector_set (cache->ss_indeps, 0, tmp);
-      for (i = 1; i < cache->n_indeps; i++)
+      for (i = 1; i < cache->n_coeffs; i++)
        {
          xi = gsl_matrix_column (design, i);
          gsl_blas_ddot (&(xi.vector), Y, &tmp);
@@ -641,7 +641,7 @@ double pspp_linreg_get_indep_variable_mean (pspp_linreg_cache *c, const struct v
       coef = pspp_linreg_get_coeff (c, v, NULL);
       return pspp_coeff_get_mean (coef);
     }
-  return GSL_NAN;
+  return 0.0;
 }
 
 void pspp_linreg_set_indep_variable_mean (pspp_linreg_cache *c, const struct variable *v, 
index 34aac525b8f47288317f56c666f91670dd4f37a8..eb9f7b78e78ddcd9194020fe18049ca2676cf6bc 100644 (file)
@@ -22,6 +22,8 @@ src_output_liboutput_la_SOURCES = \
        src/output/charts/plot-chart.h \
        src/output/charts/plot-hist.c \
        src/output/charts/plot-hist.h \
+       src/output/charts/roc-chart.c \
+       src/output/charts/roc-chart.h \
        src/output/html.c \
        src/output/htmlP.h \
        src/output/journal.c \
index a2d5fef9d1ddfd36914ef6f3fa22e55fdcb48424..b0b4f7d3e1fe0dd0be16577171e21faccc3f4c2c 100644 (file)
@@ -518,7 +518,7 @@ xr_output_chart (struct outp_driver *this, const struct chart *chart)
   chart_geometry_init (x->cairo, &geom,
                        xr_to_pt (this->width), xr_to_pt (this->length));
   chart_draw (chart, x->cairo, &geom);
-  chart_geometry_free (x->cairo);
+  chart_geometry_free (x->cairo, &geom);
   cairo_restore (x->cairo);
 
   outp_close_page (this);
index 6065036d0f26b4416048e334d2b5c1b02a98dd81..9becb6f5ed2e200e69474e6059dc8d5bb259ff55 100644 (file)
@@ -43,8 +43,11 @@ struct chart_geometry
 
     int title_bottom ;
 
+    /* Legend. */
     int legend_left ;
     int legend_right ;
+    const char **dataset;
+    int n_datasets;
 
     /* Default font size for the plot. */
     double font_size;
@@ -58,6 +61,7 @@ struct chart_geometry
     double x_max;
     double y_min;
     double y_max;
+    bool in_path;
   };
 
 struct chart_class
@@ -76,7 +80,7 @@ void chart_init (struct chart *, const struct chart_class *);
 
 void chart_geometry_init (cairo_t *, struct chart_geometry *,
                           double width, double length);
-void chart_geometry_free (cairo_t *);
+void chart_geometry_free (cairo_t *, struct chart_geometry *);
 
 void chart_draw (const struct chart *, cairo_t *, struct chart_geometry *);
 char *chart_draw_png (const struct chart *, const char *file_name_template,
index 1f85d8e485d2303f1cbce08523247d854583a1e9..e31422bc6bb35799243d68337d41914ae059c430 100644 (file)
@@ -63,6 +63,9 @@ chart_geometry_init (cairo_t *cr, struct chart_geometry *geom,
   geom->legend_left = 0.810 * width;
   geom->legend_right = width;
   geom->font_size = 15.0;
+  geom->in_path = false;
+  geom->dataset = NULL;
+  geom->n_datasets = 0;
 
   geom->fill_colour.red = 255;
   geom->fill_colour.green = 0;
@@ -77,8 +80,13 @@ chart_geometry_init (cairo_t *cr, struct chart_geometry *geom,
 }
 
 void
-chart_geometry_free (cairo_t *cr UNUSED)
+chart_geometry_free (cairo_t *cr UNUSED, struct chart_geometry *geom)
 {
+  int i;
+
+  for (i = 0 ; i < geom->n_datasets; ++i)
+    free (geom->dataset[i]);
+  free (geom->dataset);
 }
 
 void
@@ -125,7 +133,7 @@ chart_draw_png (const struct chart *chart, const char *file_name_template,
 
   chart_geometry_init (cr, &geom, width, length);
   chart_draw (chart, cr, &geom);
-  chart_geometry_free (cr);
+  chart_geometry_free (cr, &geom);
 
   status = cairo_surface_write_to_png (surface, file_name);
   if (status != CAIRO_STATUS_SUCCESS)
index 74840c30c5254e949d610a839d54047a0b46a093..eabcf516e8e1cdc7b84a148646c3aef38de956bc 100644 (file)
 #include <output/charts/plot-chart.h>
 #include <libpspp/compiler.h>
 
-struct dataset
+#include "xalloc.h"
+
+/* Start a new vector called NAME */
+void
+chart_vector_start (cairo_t *cr, struct chart_geometry *geom, const char *name)
 {
-  int n_data;
-  const char *label;
-};
+  const struct chart_colour *colour;
 
+  cairo_save (cr);
 
-#define DATASETS 2
+  colour = &data_colour[geom->n_datasets % N_CHART_COLOURS];
+  cairo_set_source_rgb (cr,
+                        colour->red / 255.0,
+                        colour->green / 255.0,
+                        colour->blue / 255.0);
 
-static const struct dataset dataset[DATASETS] =
-  {
-    { 13, "male"},
-    { 11, "female"},
-  };
+  geom->n_datasets++;
+  geom->dataset = xrealloc (geom->dataset,
+                            geom->n_datasets * sizeof (*geom->dataset));
 
+  geom->dataset[geom->n_datasets - 1] = strdup (name);
+}
 
 /* Plot a data point */
 void
@@ -55,6 +62,35 @@ chart_datum (cairo_t *cr, const struct chart_geometry *geom,
   chart_draw_marker (cr, x_pos, y_pos, MARKER_SQUARE, 15);
 }
 
+void
+chart_vector_end (cairo_t *cr, struct chart_geometry *geom)
+{
+  cairo_stroke (cr);
+  cairo_restore (cr);
+  geom->in_path = false;
+}
+
+/* Plot a data point */
+void
+chart_vector (cairo_t *cr, struct chart_geometry *geom, double x, double y)
+{
+  const double x_pos =
+    (x - geom->x_min) * geom->abscissa_scale + geom->data_left ;
+
+  const double y_pos =
+    (y - geom->y_min) * geom->ordinate_scale + geom->data_bottom ;
+
+  if (geom->in_path)
+    cairo_line_to (cr, x_pos, y_pos);
+  else
+    {
+      cairo_move_to (cr, x_pos, y_pos);
+      geom->in_path = true;
+    }
+}
+
+
+
 /* Draw a line with slope SLOPE and intercept INTERCEPT.
    between the points limit1 and limit2.
    If lim_dim is CHART_DIM_Y then the limit{1,2} are on the
index feda1b6fb724d79201c1ee154d47827aa6e8c652..3c21db6efc444c87cca867bbe184867dd1e707fe 100644 (file)
@@ -31,6 +31,11 @@ enum CHART_DIM
 
 struct chart_geometry;
 
+void  chart_vector_start (cairo_t *, struct chart_geometry *,
+                          const char *name);
+void chart_vector_end (cairo_t *, struct chart_geometry *);
+void chart_vector (cairo_t *, struct chart_geometry *, double x, double y);
+
 /* Plot a data point */
 void chart_datum(cairo_t *, const struct chart_geometry *,
                  int dataset UNUSED, double x, double y);
index 98e4c866e8a7afeae0b0d2653c2dcdc6103904d2..46884e19dfd3a1d662797be507199dbaa170a2c7 100644 (file)
@@ -288,3 +288,49 @@ chart_write_ylabel (cairo_t *cr, const struct chart_geometry *geom,
   chart_label (cr, 'l', 'x', geom->font_size, label);
   cairo_restore (cr);
 }
+
+
+void
+chart_write_legend (cairo_t *cr, const struct chart_geometry *geom)
+{
+  int i;
+  const int vstep = geom->font_size * 2;
+  const int xpad = 10;
+  const int ypad = 10;
+  const int swatch = 20;
+  const int legend_top = geom->data_top;
+  const int legend_bottom = legend_top -
+    (vstep * geom->n_datasets + 2 * ypad );
+
+  cairo_save (cr);
+
+  cairo_rectangle (cr, geom->legend_left, legend_top,
+                   geom->legend_right - xpad - geom->legend_left,
+                   legend_bottom - legend_top);
+  cairo_stroke (cr);
+
+  for (i = 0 ; i < geom->n_datasets ; ++i )
+    {
+      const int ypos = legend_top - vstep * (i + 1);
+      const int xpos = geom->legend_left + xpad;
+      const struct chart_colour *colour;
+
+      cairo_move_to (cr, xpos, ypos);
+
+      cairo_save (cr);
+      colour = &data_colour [ i % N_CHART_COLOURS];
+      cairo_set_source_rgb (cr,
+                            colour->red / 255.0,
+                            colour->green / 255.0,
+                            colour->blue / 255.0);
+      cairo_rectangle (cr, xpos, ypos, swatch, swatch);
+      cairo_fill_preserve (cr);
+      cairo_stroke (cr);
+      cairo_restore (cr);
+
+      cairo_move_to (cr, xpos + swatch * 1.5, ypos);
+      chart_label (cr, 'l', 'x', geom->font_size, geom->dataset[i]);
+    }
+
+  cairo_restore (cr);
+}
index 03788f007507a0e2e0ad55e8c650460991e78a2a..896b630b137e7245f679c15c5437e7b8a47168fe 100644 (file)
@@ -93,4 +93,6 @@ void chart_write_xlabel(cairo_t *, const struct chart_geometry *,
 void  chart_write_ylabel(cairo_t *, const struct chart_geometry *,
                          const char *label);
 
+void chart_write_legend (cairo_t *, const struct chart_geometry *);
+
 #endif
diff --git a/src/output/charts/roc-chart.c b/src/output/charts/roc-chart.c
new file mode 100644 (file)
index 0000000..2094ede
--- /dev/null
@@ -0,0 +1,148 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <output/charts/roc-chart.h>
+
+#include <output/chart-provider.h>
+#include <output/charts/cartesian.h>
+#include <output/charts/plot-chart.h>
+#include <data/casereader.h>
+#include <language/stats/roc.h>
+
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct roc_var
+  {
+    char *name;
+    struct casereader *cutpoint_reader;
+  };
+
+struct roc_chart
+  {
+    struct chart chart;
+    bool reference;
+    struct roc_var *vars;
+    size_t n_vars;
+    size_t allocated_vars;
+  };
+
+static const struct chart_class roc_chart_class;
+
+struct roc_chart *
+roc_chart_create (bool reference)
+{
+  struct roc_chart *rc = xmalloc (sizeof *rc);
+  chart_init (&rc->chart, &roc_chart_class);
+  rc->reference = reference;
+  rc->vars = NULL;
+  rc->n_vars = 0;
+  rc->allocated_vars = 0;
+  return rc;
+}
+
+void
+roc_chart_add_var (struct roc_chart *rc, const char *var_name,
+                   const struct casereader *cutpoint_reader)
+{
+  struct roc_var *rv;
+
+  if (rc->n_vars >= rc->allocated_vars)
+    rc->vars = x2nrealloc (rc->vars, &rc->allocated_vars, sizeof *rc->vars);
+
+  rv = &rc->vars[rc->n_vars++];
+  rv->name = xstrdup (var_name);
+  rv->cutpoint_reader = casereader_clone (cutpoint_reader);
+}
+
+struct chart *
+roc_chart_get_chart (struct roc_chart *rc)
+{
+  return &rc->chart;
+}
+
+static void
+roc_chart_draw (const struct chart *chart, cairo_t *cr,
+                struct chart_geometry *geom)
+{
+  const struct roc_chart *rc = UP_CAST (chart, struct roc_chart, chart);
+  size_t i;
+
+  chart_write_title (cr, geom, _("ROC Curve"));
+  chart_write_xlabel (cr, geom, _("1 - Specificity"));
+  chart_write_ylabel (cr, geom, _("Sensitivity"));
+
+  chart_write_xscale (cr, geom, 0, 1, 5);
+  chart_write_yscale (cr, geom, 0, 1, 5);
+
+  if ( rc->reference )
+    {
+      chart_line (cr, geom, 1.0, 0,
+                 0.0, 1.0,
+                 CHART_DIM_X);
+    }
+
+  for (i = 0; i < rc->n_vars; ++i)
+    {
+      const struct roc_var *rv = &rc->vars[i];
+      struct casereader *r = casereader_clone (rv->cutpoint_reader);
+      struct ccase *cc;
+
+      chart_vector_start (cr, geom, rv->name);
+      for (; (cc = casereader_read (r)) != NULL; case_unref (cc))
+       {
+         double se = case_data_idx (cc, ROC_TP)->f;
+         double sp = case_data_idx (cc, ROC_TN)->f;
+
+         se /= case_data_idx (cc, ROC_FN)->f + case_data_idx (cc, ROC_TP)->f ;
+         sp /= case_data_idx (cc, ROC_TN)->f + case_data_idx (cc, ROC_FP)->f ;
+
+         chart_vector (cr, geom, 1 - sp, se);
+       }
+      chart_vector_end (cr, geom);
+      casereader_destroy (r);
+    }
+
+  chart_write_legend (cr, geom);
+}
+
+static void
+roc_chart_destroy (struct chart *chart)
+{
+  struct roc_chart *rc = UP_CAST (chart, struct roc_chart, chart);
+  size_t i;
+
+  for (i = 0; i < rc->n_vars; i++)
+    {
+      struct roc_var *rv = &rc->vars[i];
+      free (rv->name);
+      casereader_destroy (rv->cutpoint_reader);
+    }
+  free (rc->vars);
+  free (rc);
+}
+
+static const struct chart_class roc_chart_class =
+  {
+    roc_chart_draw,
+    roc_chart_destroy
+  };
+
+
diff --git a/src/output/charts/roc-chart.h b/src/output/charts/roc-chart.h
new file mode 100644 (file)
index 0000000..dca8420
--- /dev/null
@@ -0,0 +1,29 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_CHARTS_ROC_CHART_H
+#define OUTPUT_CHARTS_ROC_CHART_H 1
+
+#include <stdbool.h>
+
+struct casereader;
+
+struct roc_chart *roc_chart_create (bool reference);
+void roc_chart_add_var (struct roc_chart *, const char *var_name,
+                        const struct casereader *cutpoint_reader);
+struct chart *roc_chart_get_chart (struct roc_chart *);
+
+#endif /* output/charts/roc-chart.h */
index c94532e81e6f31f4a71d9facf0b6b1c5322343e8..f8736e629c0148279ae8ed18b120c519d7de5271 100644 (file)
@@ -29,6 +29,7 @@
 #include <data/data-out.h>
 #include <data/format.h>
 #include <data/value.h>
+#include <data/dictionary.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
 #include <libpspp/misc.h>
@@ -515,7 +516,8 @@ tab_natural_dimensions (struct tab_rendering *r, void *aux UNUSED)
    from V, displayed with format spec F. */
 void
 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
-          const union value *v, const struct fmt_spec *f)
+          const union value *v, const struct dictionary *dict, 
+          const struct fmt_spec *f)
 {
   char *contents;
 
@@ -534,11 +536,10 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt,
     }
 #endif
 
-  contents = pool_alloc (table->container, f->w);
-  table->cc[c + r * table->cf] = ss_buffer (contents, f->w);
-  table->ct[c + r * table->cf] = opt;
+  contents = data_out_pool (v, dict_get_encoding (dict), f, table->container);
 
-  data_out (v, f, contents);
+  table->cc[c + r * table->cf] = ss_cstr (contents);
+  table->ct[c + r * table->cf] = opt;
 }
 
 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
@@ -547,8 +548,7 @@ void
 tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
           double val, int w, int d)
 {
-  char *contents;
-  char buf[40], *cp;
+  char *s, *cp;
 
   struct fmt_spec f;
   union value double_value;
@@ -577,17 +577,15 @@ tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
 #endif
 
   double_value.f = val;
-  data_out (&double_value, &f, buf);
+  s = data_out_pool (&double_value, LEGACY_NATIVE, &f, table->container);
 
-  cp = buf;
-  while (isspace ((unsigned char) *cp) && cp < &buf[w])
+  cp = s;
+  while (isspace ((unsigned char) *cp) && cp < &s[w])
     cp++;
-  f.w = w - (cp - buf);
+  f.w = w - (cp - s);
 
-  contents = pool_alloc (table->container, f.w);
-  table->cc[c + r * table->cf] = ss_buffer (contents, f.w);
+  table->cc[c + r * table->cf] = ss_buffer (cp, f.w);
   table->ct[c + r * table->cf] = opt;
-  memcpy (contents, cp, f.w);
 }
 
 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL as
@@ -598,11 +596,8 @@ void
 tab_double (struct tab_table *table, int c, int r, unsigned char opt,
           double val, const struct fmt_spec *fmt)
 {
-  int w;
-  char *contents;
-  char buf[40], *cp;
-
-  union value double_value;
+  struct substring ss;
+  union value double_value ;
 
   assert (table != NULL);
 
@@ -631,17 +626,12 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt,
 #endif
 
   double_value.f = val;
-  data_out (&double_value, fmt, buf);
+  ss = ss_cstr (data_out_pool (&double_value, LEGACY_NATIVE, fmt, table->container));
 
-  cp = buf;
-  while (isspace ((unsigned char) *cp) && cp < &buf[fmt->w])
-    cp++;
-  w = fmt->w - (cp - buf);
+  ss_ltrim (&ss, ss_cstr (" "));
 
-  contents = pool_alloc (table->container, w);
-  table->cc[c + r * table->cf] = ss_buffer (contents, w);
+  table->cc[c + r * table->cf] = ss;
   table->ct[c + r * table->cf] = opt;
-  memcpy (contents, cp, w);
 }
 
 
index 84c709644a73195f8b9400c041fcf971176c008b..f4fbc786f0440ea39da04ebfa0c54070ccec7cd1 100644 (file)
@@ -161,9 +161,11 @@ enum
 
 /* Cells. */
 struct fmt_spec;
+struct dictionary;
 union value;
 void tab_value (struct tab_table *, int c, int r, unsigned char opt,
-               const union value *, const struct fmt_spec *);
+               const union value *, const struct dictionary *dict,
+               const struct fmt_spec *);
 
 void tab_fixed (struct tab_table *, int c, int r, unsigned char opt,
                double v, int w, int d);
index c217833cbea5bf140f99c36cc2aa75106a8401b5..f520762fc1f090647b2af3d446aeae3808a6e575 100644 (file)
 #include "about.h"
 #include "helper.h"
 
+#include <gettext.h>
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
 
 static const gchar *artists[] = { "Patrick Brunier", "Dondi Bogusky", NULL};
 
 void
 about_new (GtkMenuItem *m, GtkWindow *parent)
 {
-  GtkBuilder *xml = builder_new ("psppire.ui");
-
-  GtkWidget *about =  get_widget_assert (xml, "aboutdialog1");
+  GtkWidget *about =  gtk_about_dialog_new ();
 
   GdkPixbuf *pb =
     gdk_pixbuf_new_from_file_at_size (relocate (PKGDATADIR "/pspplogo.png"),
@@ -58,6 +60,19 @@ about_new (GtkMenuItem *m, GtkWindow *parent)
   gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (about),
                                copyleft);
 
+  gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (about),
+                                _("A program for the analysis of sampled data"));
+
+  gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (about),
+                                 "Free Software Foundation");
+
+  gtk_about_dialog_set_translator_credits 
+    (
+     GTK_ABOUT_DIALOG (about),
+     /* TRANSLATORS: Use this string to list the people who have helped with
+       translation to your language. */
+     _("translator-credits")
+     );
 
   gtk_window_set_transient_for (GTK_WINDOW (about), parent);
 
index 923953a1514bd34e0d223144ed4d4aaec27107ed..02d6d96c763d3064840fe72ebcd6d590aaa4acf7 100644 (file)
@@ -145,7 +145,7 @@ comments_dialog (GObject *o, gpointer data)
   }
 
   cd.xml = xml;
-  cd.dict = vs->dict;
+  g_object_get (vs, "dictionary", &cd.dict, NULL);
 
   g_signal_connect (buffer, "mark-set",
                    G_CALLBACK (set_column_number), label);
index 183aa31b4da8a3e04e961a2da7e2e5fa82de034d..c09c7571936fa4e4ca493bd0647b2586629caa6d 100644 (file)
@@ -389,7 +389,7 @@ compute_dialog (GObject *o, gpointer data)
 
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
-  scd.dict = vs->dict;
+  g_object_get (vs, "dictionary", &scd.dict, NULL);
   scd.use_type = FALSE;
 
   g_signal_connect (expression, "toggled",
@@ -397,8 +397,8 @@ compute_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (dict_view,
-               "dictionary", vs->dict,
+  
+  g_object_set (dict_view, "dictionary", scd.dict,
                "selection-mode", GTK_SELECTION_SINGLE,
                NULL);
 
@@ -604,7 +604,6 @@ insert_source_row_into_text_view (GtkTreeIter iter,
   gint *idx;
   struct variable *var;
   GtkTreeIter dict_iter;
-  gchar *name;
   GtkTextBuffer *buffer;
 
   g_return_if_fail (GTK_IS_TEXT_VIEW (dest));
@@ -632,15 +631,10 @@ insert_source_row_into_text_view (GtkTreeIter iter,
 
   gtk_tree_path_free (path);
 
-  name = recode_string (UTF8, psppire_dict_encoding (dict),
-                       var_get_name (var),
-                       -1);
-
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dest));
 
   erase_selection (buffer);
 
-  gtk_text_buffer_insert_at_cursor (buffer, name, -1);
+  gtk_text_buffer_insert_at_cursor (buffer, var_get_name (var), -1);
 
-  g_free (name);
 }
index f5593586778cd3b3bf17bcdb6376564f44d08085..019d8c361dffe49c35b58b2f2799f701abd392b8 100644 (file)
@@ -389,6 +389,7 @@ crosstabs_dialog (GObject *o, gpointer data)
 
   GtkBuilder *xml = builder_new ("crosstabs.ui");
   PsppireVarStore *vs = NULL;
+  PsppireDict *dict = NULL;
 
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
 
@@ -422,10 +423,11 @@ crosstabs_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (source, "dictionary", vs->dict, NULL);
+  g_object_get (vs, "dictionary", &dict, NULL);
+  g_object_set (source, "dictionary", dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (dest_rows), vs->dict);
-  set_dest_model (GTK_TREE_VIEW (dest_cols), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (dest_rows), dict);
+  set_dest_model (GTK_TREE_VIEW (dest_cols), dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (row_selector),
                                 source,
@@ -443,7 +445,7 @@ crosstabs_dialog (GObject *o, gpointer data)
 
   cd.row_vars = GTK_TREE_VIEW (dest_rows);
   cd.col_vars = GTK_TREE_VIEW (dest_cols);
-  cd.dict = vs->dict;
+  g_object_get (vs, "dictionary", &cd.dict, NULL);
   cd.format_dialog = get_widget_assert (xml, "format-dialog");
   cd.table_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "print-tables"));
   cd.pivot_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "pivot"));
index a867fe016d05131f0ff759e3536118c5ae60c855..a1e65ea7d7971a9fbb4643dac59ccfabad308628 100644 (file)
@@ -218,16 +218,18 @@ descriptives_dialog (GObject *o, gpointer data)
   GtkWidget *stats_treeview = get_widget_assert    (xml, "statistics");
 
   PsppireVarStore *vs = NULL;
+  PsppireDict *dict;
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
+  g_object_get (vs, "dictionary", &dict, NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (source, "dictionary", vs->dict,
-       "predicate", var_is_numeric, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (dest), vs->dict);
+  g_object_set (source, "dictionary", dict,
+       "predicate", var_is_numeric, NULL);
 
+  set_dest_model (GTK_TREE_VIEW (dest), dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
                                 source,
@@ -242,7 +244,9 @@ descriptives_dialog (GObject *o, gpointer data)
 
   scd.stat_vars = GTK_TREE_VIEW (dest);
   scd.stats = gtk_tree_view_get_model (GTK_TREE_VIEW (stats_treeview));
-  scd.dict = vs->dict;
+  
+  g_object_get (vs, "dictionary", &scd.dict, NULL);
+  
   scd.include_user_missing =
     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "include_user_missing"));
   scd.exclude_missing_listwise =
index 8d03bed16186e5664207b9fc2b8e989c63f10eae..5d52204ce566ad89cdb1807adda7be338bf846e5 100644 (file)
@@ -114,15 +114,9 @@ cell_var_name (GtkTreeViewColumn *tree_column,
               gpointer data)
 {
   PsppireDict *dict = data;
-  struct variable *var;
-  gchar *name;
-
-  var = get_selected_variable (tree_model, iter, dict);
+  const struct variable *var = get_selected_variable (tree_model, iter, dict);
 
-  name = recode_string (UTF8, psppire_dict_encoding (dict),
-                       var_get_name (var), -1);
-  g_object_set (cell, "text", name, NULL);
-  g_free (name);
+  g_object_set (cell, "text", var_get_name (var), NULL);
 }
 
 
index d6b1bcd58c3b60bc5bb17705da7c18c4121d4105..1665d7ff3f7a3c0a4bc8e1b4ebeb12b99cc8cfb9 100644 (file)
@@ -67,7 +67,6 @@ insert_source_row_into_entry (GtkTreeIter iter,
   gint *idx;
   struct variable *var;
   GtkTreeIter dict_iter;
-  gchar *name;
 
   g_return_if_fail (GTK_IS_ENTRY(dest));
 
@@ -81,10 +80,7 @@ insert_source_row_into_entry (GtkTreeIter iter,
 
   gtk_tree_path_free (path);
 
-  name = recode_string (UTF8, psppire_dict_encoding (PSPPIRE_DICT (dict)),
-                       var_get_name (var), -1);
-  gtk_entry_set_text (GTK_ENTRY (dest),  name);
-  g_free (name);
+  gtk_entry_set_text (GTK_ENTRY (dest),  var_get_name (var));
 }
 
 
@@ -123,14 +119,13 @@ is_currently_in_entry (GtkTreeModel *model, GtkTreeIter *iter,
                       PsppireSelector *selector)
 {
   gboolean result;
-  gchar *name;
   GtkTreeIter dict_iter;
   GtkTreeModel *dict;
   struct variable *var;
   gint dict_index;
   gint *indeces;
   GtkTreePath *path;
-  const gchar *text =   gtk_entry_get_text (GTK_ENTRY (selector->dest));
+  const gchar *text =  gtk_entry_get_text (GTK_ENTRY (selector->dest));
 
   get_base_model (model, iter, &dict, &dict_iter);
 
@@ -144,10 +139,7 @@ is_currently_in_entry (GtkTreeModel *model, GtkTreeIter *iter,
 
   gtk_tree_path_free (path);
 
-  name = recode_string (UTF8, psppire_dict_encoding (PSPPIRE_DICT (dict)),
-                       var_get_name (var), -1);
-  result = ( 0 == strcmp (text, name));
-  g_free (name);
+  result = ( 0 == strcmp (text, var_get_name (var) ));
 
   return result;
 }
index 13ef847a36f436b49c8cd062eda617d7f0563624..470c4dbbe37797ac23e23d3430741c56da0aa94b 100644 (file)
@@ -279,10 +279,10 @@ examine_dialog (GObject *o, gpointer data)
   gtk_window_set_transient_for (GTK_WINDOW (ex_d.stats_dialog), GTK_WINDOW (de));
   gtk_window_set_transient_for (GTK_WINDOW (ex_d.opts_dialog), GTK_WINDOW (de));
 
-  g_object_set (source, "dictionary", vs->dict, NULL);
+  g_object_get (vs, "dictionary", &ex_d.dict, NULL);
+  g_object_set (source, "dictionary", ex_d.dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (ex_d.dep_list), vs->dict);
-  ex_d.dict = vs->dict;
+  set_dest_model (GTK_TREE_VIEW (ex_d.dep_list), ex_d.dict);
 
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (dep_selector),
@@ -294,7 +294,7 @@ examine_dialog (GObject *o, gpointer data)
   psppire_selector_set_allow (PSPPIRE_SELECTOR (dep_selector),
                              numeric_only);
 
-  set_dest_model (GTK_TREE_VIEW (ex_d.fct_list), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (ex_d.fct_list), ex_d.dict);
 
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (fct_selector),
index 3d3aed8813c9628b672bd6d853d9385af7caec41..0c16bfa8140c0a78f4036c2c2ef2e3eeadb5023a 100644 (file)
@@ -220,7 +220,8 @@ find_dialog (GObject *o, gpointer data)
                "data-store", &ds,
                NULL);
 
-  fd.dict = vs->dict;
+  g_object_get (vs, "dictionary", &fd.dict, NULL);
+
   fd.data = ds->datasheet;
 
   fd.variable_entry        = get_widget_assert (fd.xml, "find-variable-entry");
@@ -428,6 +429,7 @@ struct comparator
 {
   const struct variable *var;
   enum string_cmp_flags flags;
+  const PsppireDict *dict;
 
   bool (*compare) (const struct comparator *,
                   const union value *);
@@ -493,20 +495,24 @@ static bool
 string_value_compare (const struct comparator *cmptr,
                      const union value *val)
 {
+  bool found;
+  char *text;
   const struct string_comparator *ssc =
     (const struct string_comparator *) cmptr;
 
   int width = var_get_width (cmptr->var);
-  const char *text = value_str (val, width);
-
+  g_return_val_if_fail (width > 0, false);
   assert ( ! (cmptr->flags & STR_CMP_LABELS));
 
-  g_return_val_if_fail (width > 0, false);
+  text = value_to_text (*val, cmptr->dict, *var_get_write_format (cmptr->var));
 
   if ( cmptr->flags & STR_CMP_SUBSTR)
-    return (NULL != g_strstr_len (text, width, ssc->pattern));
+    found =  (NULL != g_strstr_len (text, width, ssc->pattern));
   else
-    return (0 == strncmp (text, ssc->pattern, width));
+    found = (0 == strncmp (text, ssc->pattern, width));
+
+  free (text);
+  return found;
 }
 
 
@@ -527,9 +533,9 @@ regexp_value_compare (const struct comparator *cmptr,
 
   g_return_val_if_fail (width > 0, false);
 
+  text = value_to_text (*val, cmptr->dict, *var_get_write_format (cmptr->var));
   /* We must remove trailing whitespace, otherwise $ will not match where
      one would expect */
-  text = g_strndup (value_str (val, width), width);
   g_strchomp (text);
 
   retval = (0 == regexec (&rec->re, text, 0, 0, 0));
@@ -581,10 +587,8 @@ cmptr_value_destroy (struct comparator *cmptr)
 
 
 static struct comparator *
-value_comparator_create (const struct variable *var, const char *target)
+value_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target)
 {
-  const struct fmt_spec *fmt;
-  int width ;
   struct value_comparator *vc = xzalloc (sizeof (*vc));
   struct comparator *cmptr = &vc->parent;
 
@@ -592,28 +596,16 @@ value_comparator_create (const struct variable *var, const char *target)
   cmptr->var = var;
   cmptr->compare  = value_compare ;
   cmptr->destroy = cmptr_value_destroy;
+  cmptr->dict = dict;
 
-  width = var_get_width (var);
-  fmt = var_get_write_format (var);
-
-  value_init (&vc->pattern, width);
-
-  if ( ! data_in (ss_cstr (target),
-                  LEGACY_NATIVE,
-                 fmt->type,
-                 0, 0, 0,
-                 &vc->pattern, width) )
-    {
-      value_destroy (&vc->pattern, width);
-      free (vc);
-      return NULL;
-    }
+  text_to_value (target, dict, var, &vc->pattern);
 
   return cmptr;
 }
 
 static struct comparator *
-string_comparator_create (const struct variable *var, const char *target,
+string_comparator_create (const struct variable *var, const PsppireDict *dict, 
+                         const char *target,
                          enum string_cmp_flags flags)
 {
   struct string_comparator *ssc = xzalloc (sizeof (*ssc));
@@ -621,6 +613,7 @@ string_comparator_create (const struct variable *var, const char *target,
 
   cmptr->flags = flags;
   cmptr->var = var;
+  cmptr->dict = dict;
 
   if ( flags & STR_CMP_LABELS)
     cmptr->compare = string_label_compare;
@@ -634,7 +627,7 @@ string_comparator_create (const struct variable *var, const char *target,
 
 
 static struct comparator *
-regexp_comparator_create (const struct variable *var, const char *target,
+regexp_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target,
                          enum string_cmp_flags flags)
 {
   int code;
@@ -643,6 +636,7 @@ regexp_comparator_create (const struct variable *var, const char *target,
 
   cmptr->flags = flags;
   cmptr->var = var;
+  cmptr->dict = dict;
   cmptr->compare  = (flags & STR_CMP_LABELS)
     ? regexp_label_compare : regexp_value_compare ;
 
@@ -692,16 +686,16 @@ comparator_destroy (struct comparator *cmptr)
 
 
 static struct comparator *
-comparator_factory (const struct variable *var, const char *str,
+comparator_factory (const struct variable *var, const PsppireDict *dict, const char *str,
                    enum string_cmp_flags flags)
 {
   if ( flags & STR_CMP_REGEXP )
-    return regexp_comparator_create (var, str, flags);
+    return regexp_comparator_create (var, dict, str, flags);
 
   if ( flags & (STR_CMP_SUBSTR | STR_CMP_LABELS) )
-    return string_comparator_create (var, str, flags);
+    return string_comparator_create (var, dict, str, flags);
 
-  return value_comparator_create (var, str);
+  return value_comparator_create (var, dict, str);
 }
 
 
@@ -747,7 +741,7 @@ find_value (const struct find_dialog *fd, casenumber current_row,
     casenumber i;
     const struct casenum_iterator *ip = get_iteration_params (fd);
     struct comparator *cmptr =
-      comparator_factory (var, target_string, flags);
+      comparator_factory (var, fd->dict, target_string, flags);
 
     value_init (&val, width);
     if ( ! cmptr)
index 9d9814f1a64045ba96fe967c85588e796869d803..8706f3a4e63ac105e0caee6a46e597cee048fc40 100644 (file)
@@ -333,9 +333,11 @@ frequencies_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (source, "dictionary", vs->dict, NULL);
+  g_object_get (vs, "dictionary", &fd.dict, NULL);
+  g_object_set (source, "dictionary", fd.dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (dest), vs->dict);
+
+  set_dest_model (GTK_TREE_VIEW (dest), fd.dict);
 
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
@@ -347,7 +349,6 @@ frequencies_dialog (GObject *o, gpointer data)
 
 
   fd.stat_vars = GTK_TREE_VIEW (dest);
-  fd.dict = vs->dict;
   fd.table_button = get_widget_assert (xml, "checkbutton1");
   fd.format_dialog = get_widget_assert (xml, "format-dialog");
   fd.maximum_cats = get_widget_assert (xml, "hbox5");
index a4c07ca46d78ae74efd5317f3a7b87216578b1ee..b09a2f58c3f1cc7bff73e36aecbb4775a81c1049 100644 (file)
 /* Formats a value according to FORMAT
    The returned string must be freed when no longer required */
 gchar *
-value_to_text (union value v, struct fmt_spec format)
+value_to_text (union value v, const PsppireDict *dict, struct fmt_spec format)
 {
   gchar *s = 0;
 
-  s = g_new (gchar, format.w + 1);
-  data_out (&v, &format, s);
-  s[format.w]='\0';
+  s = data_out (&v, dict_get_encoding (dict->dict),  &format);
   g_strchug (s);
 
   return s;
 }
 
 
+/* Converts TEXT to a value.
 
-gboolean
-text_to_value (const gchar *text, union value *v,
-             struct fmt_spec format)
+   VAL will be initialised and filled by this function.
+   It is the caller's responsibility to destroy VAL when no longer needed.
+   VAR and DICT must be the variable and dictionary with which VAL
+   is associated.
+
+   On success, VAL is returned, NULL otherwise.
+*/
+union value *
+text_to_value (const gchar *text,
+              const PsppireDict *dict,
+              const struct variable *var,
+              union value *val)
 {
-  bool ok;
+  const struct fmt_spec *format = var_get_print_format (var);
+  int width = var_get_width (var);
 
-  if ( format.type != FMT_A)
+  if ( format->type != FMT_A)
     {
-      if ( ! text ) return FALSE;
+      if ( ! text ) return NULL;
 
       {
        const gchar *s = text;
@@ -82,16 +91,18 @@ text_to_value (const gchar *text, union value *v,
            s++;
          }
 
-       if ( !*s) return FALSE;
+       if ( !*s) return NULL;
       }
     }
 
+  value_init (val, width);
   msg_disable ();
-  ok = data_in (ss_cstr (text), LEGACY_NATIVE, format.type, 0, 0, 0,
-                v, fmt_var_width (&format));
+  data_in (ss_cstr (text), UTF8, format->type, 0, 0, 0,
+               dict->dict,
+                val, width);
   msg_enable ();
 
-  return ok;
+  return val;
 }
 
 
index a6287ddaf1db3260ae0baed48f2fc65bd9365d83..dfdd89323a7bd5c7a9982f1f03b4aef133b601d8 100644 (file)
 
 #include <gtk/gtk.h>
 
-
+#include "psppire-dict.h"
 
 void paste_syntax_in_new_window (const gchar *syntax);
 
 struct fmt_spec;
 
+
 /* Formats a value according to FORMAT
    The returned string must be freed when no longer required */
-gchar * value_to_text (union value v, struct fmt_spec format);
+gchar * value_to_text (union value v, const PsppireDict *dict, struct fmt_spec format);
 
 
-gboolean text_to_value (const gchar *text, union value *v,
-                      struct fmt_spec format);
+union value *
+text_to_value (const gchar *text,
+              const PsppireDict *dict,
+              const struct variable *var,
+              union value *);
 
 GObject *get_object_assert (GtkBuilder *builder, const gchar *name, GType type);
 GtkAction * get_action_assert (GtkBuilder *builder, const gchar *name);
index 8efbaf975d90acad6154da39b2aab9d53af24164..7e04b8548e02fb6cd02602645e2b8fbd99287b59 100644 (file)
@@ -80,8 +80,6 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
 {
   struct missing_val_dialog *dialog = data;
 
-  const struct fmt_spec *write_spec = var_get_write_format (dialog->pv);
-
   if ( gtk_toggle_button_get_active (dialog->button_discrete))
     {
       gint nvals = 0;
@@ -100,7 +98,7 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
              continue;
            }
 
-         if ( text_to_value (text, &v, *write_spec))
+         if ( text_to_value (text, dialog->dict, dialog->pv, &v))
            {
              nvals++;
              mv_add_value (&dialog->mvl, &v);
@@ -108,6 +106,7 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
          else
              badvals++;
          g_free (text);
+         value_destroy (&v, var_get_width (dialog->pv));
        }
       if ( nvals == 0 || badvals > 0 )
        {
@@ -126,14 +125,16 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
       const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
       const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
 
-      if ( text_to_value (low_text, &low_val, *write_spec)
+      if ( text_to_value (low_text, dialog->dict, dialog->pv, &low_val)
           &&
-          text_to_value (high_text, &high_val, *write_spec) )
+          text_to_value (high_text, dialog->dict, dialog->pv, &high_val))
        {
          if ( low_val.f > high_val.f )
            {
              err_dialog (_("Incorrect range specification"),
                          GTK_WINDOW (dialog->window));
+             value_destroy (&low_val, var_get_width (dialog->pv));
+             value_destroy (&high_val, var_get_width (dialog->pv));
              return ;
            }
        }
@@ -141,6 +142,8 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
        {
          err_dialog (_("Incorrect range specification"),
                      GTK_WINDOW (dialog->window));
+         value_destroy (&low_val, var_get_width (dialog->pv));
+         value_destroy (&high_val, var_get_width (dialog->pv));
          return;
        }
 
@@ -150,18 +153,25 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
       mv_clear (&dialog->mvl);
       mv_add_range (&dialog->mvl, low_val.f, high_val.f);
 
+      value_destroy (&low_val, var_get_width (dialog->pv));
+      value_destroy (&high_val, var_get_width (dialog->pv));
+
       if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
        {
          union value discrete_val;
-         if ( !text_to_value (discrete_text, &discrete_val,
-                             *write_spec))
+         if ( !text_to_value (discrete_text, 
+                              dialog->dict,
+                              dialog->pv,
+                              &discrete_val))
            {
              err_dialog (_("Incorrect value for variable type"),
                         GTK_WINDOW (dialog->window) );
              g_free (discrete_text);
+             value_destroy (&discrete_val, var_get_width (dialog->pv));
              return;
            }
          mv_add_value (&dialog->mvl, &discrete_val);
+         value_destroy (&discrete_val, var_get_width (dialog->pv));
        }
       g_free (discrete_text);
     }
@@ -309,8 +319,9 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
       gchar *high_text;
       mv_get_range (&dialog->mvl, &low.f, &high.f);
 
-      low_text = value_to_text (low, *write_spec);
-      high_text = value_to_text (high, *write_spec);
+
+      low_text = value_to_text (low, dialog->dict, *write_spec);
+      high_text = value_to_text (high, dialog->dict,  *write_spec);
 
       gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
       gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
@@ -320,7 +331,7 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
       if ( mv_has_value (&dialog->mvl))
        {
          gchar *text;
-         text = value_to_text (*mv_get_value (&dialog->mvl, 0), *write_spec);
+         text = value_to_text (*mv_get_value (&dialog->mvl, 0), dialog->dict, *write_spec);
          gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
          g_free (text);
        }
@@ -341,7 +352,7 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
            {
              gchar *text ;
 
-             text = value_to_text (*mv_get_value (&dialog->mvl, i),
+             text = value_to_text (*mv_get_value (&dialog->mvl, i), dialog->dict,
                                     *write_spec);
              gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
              g_free (text);
index 7dc079d731d342244ef256759acc9cc6cc23e1c4..82acf9757f0738eea85ec186a9a51047c18ebad3 100644 (file)
@@ -32,6 +32,9 @@ struct missing_val_dialog
   /* The variable whose missing values are to be updated */
   struct variable *pv;
 
+  /* The dictionary to which that value belongs */
+  PsppireDict *dict;
+
   /* local copy */
   struct missing_values mvl;
 
index a17a93977e612db7fa99b9eb58226fd9b91f72c8..1814dd6737562a1d922722141d9e6c6f3c2b0a63 100644 (file)
@@ -164,16 +164,16 @@ oneway_anova_dialog (GObject *o, gpointer data)
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
-  ow.dict = vs->dict;
+  g_object_get (vs, "dictionary", &ow.dict, NULL);
 
   ow.dialog =
     GTK_WINDOW (get_widget_assert (builder, "oneway-anova-dialog"));
 
   gtk_window_set_transient_for (ow.dialog, GTK_WINDOW (de));
 
-  g_object_set (dict_view, "dictionary", vs->dict, NULL);
+  g_object_set (dict_view, "dictionary", ow.dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (ow.vars_treeview), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (ow.vars_treeview), ow.dict);
 
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector1),
index 7c3fca685eaa5e7d295455c4773584b649861ffd..58aa0b8f91f740ba2630763ac7703cad8a243148 100644 (file)
@@ -744,15 +744,10 @@ update_data_ref_entry (const PsppireSheet *sheet,
          gchar *text = g_strdup_printf ("%d: %s", row + FIRST_CASE_NUMBER,
                                         var_get_name (var));
 
-         gchar *s = recode_string (UTF8,
-                                   psppire_dict_encoding (data_store->dict),
-                                   text, -1);
 
-         g_free (text);
-
-         gtk_entry_set_text (GTK_ENTRY (de->cell_ref_entry), s);
+         gtk_entry_set_text (GTK_ENTRY (de->cell_ref_entry), text);
 
-         g_free (s);
+         g_free (text);
        }
       else
        goto blank_entry;
@@ -1208,9 +1203,13 @@ popup_variable_row_menu (PsppireSheet *sheet, gint row,
 
   PsppireVarStore *var_store =
     PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
+  
+  PsppireDict *dict;
+  const struct variable *v ;
 
-  const struct variable *v =
-    psppire_dict_get_variable (var_store->dict, row);
+  g_object_get (var_store, "dictionary", &dict, NULL);
+
+  v = psppire_dict_get_variable (dict, row);
 
   if ( v && event->button == 3)
     {
@@ -1331,10 +1330,14 @@ psppire_data_editor_insert_case (PsppireDataEditor *de)
 {
   glong posn = -1;
 
-  if ( de->data_sheet[0]->state == PSPPIRE_SHEET_ROW_SELECTED )
-    posn = PSPPIRE_SHEET (de->data_sheet[0])->range.row0;
+  if ( PSPPIRE_SHEET (de->data_sheet[0])->select_status == PSPPIRE_SHEET_ROW_SELECTED )
+    {
+      posn = PSPPIRE_SHEET (de->data_sheet[0])->range.row0;
+    }
   else
-    posn = PSPPIRE_SHEET (de->data_sheet[0])->active_cell.row;
+    {
+      posn = PSPPIRE_SHEET (de->data_sheet[0])->active_cell.row;
+    }
 
   if ( posn == -1 ) posn = 0;
 
@@ -1358,6 +1361,7 @@ psppire_data_editor_delete_cases    (PsppireDataEditor *de)
 void
 psppire_data_editor_delete_variables (PsppireDataEditor *de)
 {
+  PsppireDict *dict = NULL;
   gint first, n;
 
   switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
@@ -1375,7 +1379,9 @@ psppire_data_editor_delete_variables (PsppireDataEditor *de)
       break;
     }
 
-  psppire_dict_delete_variables (de->var_store->dict, first, n);
+  g_object_get (de->var_store, "dictionary", &dict, NULL);
+
+  psppire_dict_delete_variables (dict, first, n);
 
   psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
   psppire_sheet_unselect_range (PSPPIRE_SHEET (de->var_sheet));
@@ -1562,43 +1568,45 @@ data_sheet_set_clip (PsppireSheet *sheet)
   struct case_map *map = NULL;
   casenumber max_rows;
   size_t max_columns;
+  gint row0, rowi;
+  gint col0, coli;
 
   ds = PSPPIRE_DATA_STORE (psppire_sheet_get_model (sheet));
 
   psppire_sheet_get_selected_range (sheet, &range);
 
+  col0 = MIN (range.col0, range.coli);
+  coli = MAX (range.col0, range.coli);
+  row0 = MIN (range.row0, range.rowi);
+  rowi = MAX (range.row0, range.rowi);
+
    /* If nothing selected, then use active cell */
-  if ( range.row0 < 0 || range.col0 < 0 )
+  if ( row0 < 0 || col0 < 0 )
     {
       gint row, col;
       psppire_sheet_get_active_cell (sheet, &row, &col);
 
-      range.row0 = range.rowi = row;
-      range.col0 = range.coli = col;
+      row0 = rowi = row;
+      col0 = coli = col;
     }
 
   /* The sheet range can include cells that do not include data.
      Exclude them from the range. */
   max_rows = psppire_data_store_get_case_count (ds);
-  if (range.rowi >= max_rows)
+  if (rowi >= max_rows)
     {
       if (max_rows == 0)
         return;
-      range.rowi = max_rows - 1;
+      rowi = max_rows - 1;
     }
   max_columns = dict_get_var_cnt (ds->dict->dict);
-  if (range.coli >= max_columns)
+  if (coli >= max_columns)
     {
       if (max_columns == 0)
         return;
-      range.coli = max_columns - 1;
+      coli = max_columns - 1;
     }
 
-  g_return_if_fail (range.rowi >= range.row0);
-  g_return_if_fail (range.row0 >= 0);
-  g_return_if_fail (range.coli >= range.col0);
-  g_return_if_fail (range.col0 >= 0);
-
   /* Destroy any existing clip */
   if ( clip_datasheet )
     {
@@ -1614,7 +1622,8 @@ data_sheet_set_clip (PsppireSheet *sheet)
 
   /* Construct clip dictionary. */
   clip_dict = dict_create ();
-  for (i = range.col0; i <= range.coli; i++)
+  dict_set_encoding (clip_dict, dict_get_encoding (ds->dict->dict));
+  for (i = col0; i <= coli; i++)
     {
       const struct variable *old = dict_get_var (ds->dict->dict, i);
       dict_clone_var_assert (clip_dict, old, var_get_name (old));
@@ -1623,7 +1632,7 @@ data_sheet_set_clip (PsppireSheet *sheet)
   /* Construct clip data. */
   map = case_map_by_name (ds->dict->dict, clip_dict);
   writer = autopaging_writer_create (dict_get_proto (clip_dict));
-  for (i = range.row0; i <= range.rowi ; ++i )
+  for (i = row0; i <= rowi ; ++i )
     {
       struct ccase *old = psppire_data_store_get_case (ds, i);
       if (old != NULL)
@@ -1647,20 +1656,18 @@ enum {
 
 /* Perform data_out for case CC, variable V, appending to STRING */
 static void
-data_out_g_string (GString *string, const struct variable *v,
+data_out_g_string (GString *string, const struct dictionary *dict, 
+                  const struct variable *v,
                   const struct ccase *cc)
 {
-  char *buf ;
-
   const struct fmt_spec *fs = var_get_print_format (v);
   const union value *val = case_data (cc, v);
-  buf = xzalloc (fs->w);
 
-  data_out (val, fs, buf);
+  char *s = data_out (val, dict_get_encoding (dict), fs);
 
-  g_string_append_len (string, buf, fs->w);
+  g_string_append (string, s);
 
-  g_free (buf);
+  g_free (s);
 }
 
 static GString *
@@ -1690,7 +1697,7 @@ clip_to_text (void)
       for (c = 0 ; c < var_cnt ; ++c)
        {
          const struct variable *v = dict_get_var (clip_dict, c);
-         data_out_g_string (string, v, cc);
+         data_out_g_string (string, clip_dict, v, cc);
          if ( c < val_cnt - 1 )
            g_string_append (string, "\t");
        }
@@ -1715,9 +1722,11 @@ clip_to_html (void)
   const casenumber case_cnt = casereader_get_case_cnt (clip_datasheet);
   const size_t var_cnt = dict_get_var_cnt (clip_dict);
 
-
   /* Guestimate the size needed */
-  string = g_string_sized_new (20 * val_cnt * case_cnt);
+  string = g_string_sized_new (80 + 20 * val_cnt * case_cnt);
+
+  g_string_append (string,
+                  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
 
   g_string_append (string, "<table>\n");
   for (r = 0 ; r < case_cnt ; ++r )
@@ -1735,7 +1744,7 @@ clip_to_html (void)
        {
          const struct variable *v = dict_get_var (clip_dict, c);
          g_string_append (string, "<td>");
-         data_out_g_string (string, v, cc);
+         data_out_g_string (string, clip_dict, v, cc);
          g_string_append (string, "</td>\n");
        }
 
index b67e27c139024308fecd33da12e0db50beb09d38..9833fb496f8a0be6dd3145fc7bbb334fe46b341f 100644 (file)
@@ -583,13 +583,15 @@ psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
   char *text;
   const struct fmt_spec *fp ;
   const struct variable *pv ;
+  const struct dictionary *dict;
   union value v;
   int width;
-  GString *s;
 
   g_return_val_if_fail (store->dict, NULL);
   g_return_val_if_fail (store->datasheet, NULL);
 
+  dict = store->dict->dict;
+
   if (column >= psppire_dict_get_var_cnt (store->dict))
     return NULL;
 
@@ -615,28 +617,13 @@ psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
       if (label)
         {
           value_destroy (&v, width);
-         return recode_string (UTF8, psppire_dict_encoding (store->dict),
-                               label, -1);
+         return g_strdup (label);
         }
     }
 
   fp = var_get_write_format (pv);
 
-  s = g_string_sized_new (fp->w + 1);
-  g_string_set_size (s, fp->w);
-
-  memset (s->str, 0, fp->w);
-
-  g_assert (fp->w == s->len);
-
-  /* Converts binary value V into printable form in the exactly
-     FP->W character in buffer S according to format specification
-     FP.  No null terminator is appended to the buffer.  */
-  data_out (&v, fp, s->str);
-
-  text = recode_string (UTF8, psppire_dict_encoding (store->dict),
-                       s->str, fp->w);
-  g_string_free (s, TRUE);
+  text = data_out (&v, dict_get_encoding (dict), fp);
 
   g_strchomp (text);
 
@@ -677,7 +664,6 @@ gboolean
 psppire_data_store_set_string (PsppireDataStore *store,
                               const gchar *text, glong row, glong col)
 {
-  gchar *s;
   glong n_cases;
   const struct variable *pv = psppire_dict_get_variable (store->dict, col);
   if ( NULL == pv)
@@ -691,12 +677,9 @@ psppire_data_store_set_string (PsppireDataStore *store,
   if (row == n_cases)
     psppire_data_store_insert_new_case (store, row);
 
-  s = recode_string (psppire_dict_encoding (store->dict), UTF8, text, -1);
-
   psppire_data_store_data_in (store, row,
-                             var_get_case_index (pv), ss_cstr (s),
+                             var_get_case_index (pv), ss_cstr (text),
                              var_get_write_format (pv));
-  free (s);
 
   psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (store), row, col, row, col);
 
@@ -767,15 +750,9 @@ static const gchar null_var_name[]=N_("var");
 static gchar *
 get_row_button_label (const PsppireSheetModel *model, gint unit)
 {
-  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
-  gchar *s = g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
-
-  gchar *text =  recode_string (UTF8, psppire_dict_encoding (ds->dict),
-                               s, -1);
+  // PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
 
-  g_free (s);
-
-  return text;
+  return g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
 }
 
 
@@ -795,7 +772,6 @@ get_row_sensitivity (const PsppireSheetModel *model, gint unit)
 static gchar *
 get_column_subtitle (const PsppireSheetModel *model, gint col)
 {
-  gchar *text;
   const struct variable *v ;
   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
 
@@ -807,16 +783,12 @@ get_column_subtitle (const PsppireSheetModel *model, gint col)
   if ( ! var_has_label (v))
     return NULL;
 
-  text =  recode_string (UTF8, psppire_dict_encoding (ds->dict),
-                        var_get_label (v), -1);
-
-  return text;
+  return xstrdup (var_get_label (v));
 }
 
 static gchar *
 get_column_button_label (const PsppireSheetModel *model, gint col)
 {
-  gchar *text;
   struct variable *pv ;
   PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
 
@@ -825,10 +797,10 @@ get_column_button_label (const PsppireSheetModel *model, gint col)
 
   pv = psppire_dict_get_variable (ds->dict, col);
 
-  text = recode_string (UTF8, psppire_dict_encoding (ds->dict),
-                       var_get_name (pv), -1);
+  if (NULL == pv)
+    return NULL;
 
-  return text;
+  return xstrdup (var_get_name (pv));
 }
 
 static gboolean
@@ -972,18 +944,23 @@ psppire_data_store_data_in (PsppireDataStore *ds, casenumber casenum, gint idx,
   int width;
   bool ok;
 
+  PsppireDict *dict;
+
   g_return_val_if_fail (ds, FALSE);
   g_return_val_if_fail (ds->datasheet, FALSE);
 
   g_return_val_if_fail (idx < datasheet_get_n_columns (ds->datasheet), FALSE);
 
+  dict = ds->dict;
+
   width = fmt_var_width (fmt);
   g_return_val_if_fail (caseproto_get_width (
                           datasheet_get_proto (ds->datasheet), idx) == width,
                         FALSE);
   value_init (&value, width);
   ok = (datasheet_get_value (ds->datasheet, casenum, idx, &value)
-        && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, &value, width)
+        && data_in (input, UTF8, fmt->type, 0, 0, 0,
+                   dict->dict, &value, width)
         && datasheet_put_value (ds->datasheet, casenum, idx, &value));
   value_destroy (&value, width);
 
index 1df084c1418c79339d458151ce25bb4ac4c07d82..ffa9482eb0f4b766c391e32ac7c3ecac9dca3087 100644 (file)
@@ -231,12 +231,14 @@ on_filter_change (GObject *o, gint filter_index, gpointer data)
   else
     {
       PsppireVarStore *vs = NULL;
+      PsppireDict *dict = NULL;
       struct variable *var ;
       gchar *text ;
 
       g_object_get (de->data_editor, "var-store", &vs, NULL);
+      g_object_get (vs, "dictionary", &dict, NULL);
 
-      var = psppire_dict_get_variable (vs->dict, filter_index);
+      var = psppire_dict_get_variable (dict, filter_index);
 
       text = g_strdup_printf (_("Filter by %s"), var_get_name (var));
 
@@ -302,11 +304,13 @@ on_weight_change (GObject *o, gint weight_index, gpointer data)
     {
       struct variable *var ;
       PsppireVarStore *vs = NULL;
+      PsppireDict *dict = NULL;
       gchar *text;
 
       g_object_get (de->data_editor, "var-store", &vs, NULL);
-
-      var = psppire_dict_get_variable (vs->dict, weight_index);
+      g_object_get (vs, "dictionary", &dict, NULL);
+      
+      var = psppire_dict_get_variable (dict, weight_index);
 
       text = g_strdup_printf (_("Weight by %s"), var_get_name (var));
 
@@ -521,7 +525,6 @@ static void
 insert_case (GtkAction *action, gpointer data)
 {
   PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (data);
-
   psppire_data_editor_insert_case (dw->data_editor);
 }
 
@@ -1091,6 +1094,7 @@ static void
 psppire_data_window_init (PsppireDataWindow *de)
 {
   PsppireVarStore *vs;
+  PsppireDict *dict = NULL;
 
   GtkWidget *menubar;
   GtkWidget *hb ;
@@ -1146,15 +1150,17 @@ psppire_data_window_init (PsppireDataWindow *de)
 
   g_assert(vs); /* Traps a possible bug in w32 build */
 
-  g_signal_connect (vs->dict, "weight-changed",
+  g_object_get (vs, "dictionary", &dict, NULL);
+
+  g_signal_connect (dict, "weight-changed",
                    G_CALLBACK (on_weight_change),
                    de);
 
-  g_signal_connect (vs->dict, "filter-changed",
+  g_signal_connect (dict, "filter-changed",
                    G_CALLBACK (on_filter_change),
                    de);
 
-  g_signal_connect (vs->dict, "split-changed",
+  g_signal_connect (dict, "split-changed",
                    G_CALLBACK (on_split_change),
                    de);
 
index 8ff92a48fc57c01f7d255ab27001dd4cdc5c5f15..c82395f2ebdc047e1f8678b9e9d6873df2452207 100644 (file)
@@ -760,11 +760,8 @@ tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
     {
     case DICT_TVM_COL_NAME:
       {
-       gchar *name = recode_string (UTF8, psppire_dict_encoding (dict),
-                                    var_get_name (var), -1);
        g_value_init (value, G_TYPE_STRING);
-       g_value_set_string (value, name);
-       g_free (name);
+       g_value_set_string (value, var_get_name (var));
       }
       break;
     case DICT_TVM_COL_VAR:
@@ -859,11 +856,10 @@ psppire_dict_dump (const PsppireDict *dict)
     {
       const struct variable *v = psppire_dict_get_variable (dict, i);
       int di = var_get_dict_index (v);
-      g_print ("\"%s\" idx=%d, fv=%d, size=%d\n",
+      g_print ("\"%s\" idx=%d, fv=%d\n",
               var_get_name(v),
               di,
-              var_get_case_index(v),
-              value_cnt_from_width(var_get_width(v)));
+              var_get_case_index(v));
 
     }
 }
index f63ea0ba6fe578367d492fc2ff724487695d9034..243d907826f909a933f1fe8a73478b888da83c5c 100644 (file)
@@ -340,19 +340,12 @@ var_description_cell_data_func (GtkTreeViewColumn *col,
                                     "<span stretch=\"condensed\">%s</span>",
                                     var_get_label (var));
 
-      char *utf8 = recode_string (UTF8, psppire_dict_encoding (dict),
-                                 text, -1);
-
+      g_object_set (cell, "markup", text, NULL);
       g_free (text);
-      g_object_set (cell, "markup", utf8, NULL);
-      g_free (utf8);
     }
   else
     {
-      char *name = recode_string (UTF8, psppire_dict_encoding (dict),
-                                 var_get_name (var), -1);
-      g_object_set (cell, "text", name, NULL);
-      g_free (name);
+      g_object_set (cell, "text", var_get_name (var), NULL);
     }
 }
 
@@ -439,7 +432,7 @@ set_tooltip_for_variable (GtkTreeView  *treeview,
     return FALSE;
 
   {
-    gchar *tip ;
+    const gchar *tip ;
     GtkTreeModel *m;
     PsppireDict *dict;
 
@@ -447,15 +440,11 @@ set_tooltip_for_variable (GtkTreeView  *treeview,
     dict = PSPPIRE_DICT (m);
 
     if ( PSPPIRE_DICT_VIEW (treeview)->prefer_labels )
-      tip = recode_string (UTF8, psppire_dict_encoding (dict),
-                          var_get_name (var), -1);
+      tip = var_get_name (var);
     else
-      tip = recode_string (UTF8, psppire_dict_encoding (dict),
-                          var_get_label (var), -1);
+      tip = var_get_label (var);
 
     gtk_tooltip_set_text (tooltip, tip);
-
-    g_free (tip);
   }
 
   return TRUE;
index ed06da91a91af9fa2dc927d21c491f42431a65b6..606a950475fc6ecc1d4833fb7eea46e9faf8ccdf 100644 (file)
@@ -24,6 +24,7 @@
 #include <gtk/gtkaction.h>
 #include <gtk/gtktextbuffer.h>
 #include "psppire-window.h"
+#include "psppire.h"
 #include <gtk/gtk.h>
 
 extern int viewer_length;
index 3ebea2ea182a23b2e0dab2324127f434b42555d7..70e1044fcb25ed9d46dbc2fcc8d2232c3687fda6 100644 (file)
@@ -251,6 +251,9 @@ traverse_cell_callback (PsppireSheet *sheet,
 
   gint n_vars = psppire_var_store_get_var_cnt (var_store);
 
+  if (new_cell->col >=  PSPPIRE_VAR_STORE_n_COLS)
+    return TRUE;
+
   if (new_cell->row >= n_vars && !var_sheet->may_create_vars)
     return TRUE;
 
@@ -260,10 +263,10 @@ traverse_cell_callback (PsppireSheet *sheet,
 
       const gchar *name = gtk_entry_get_text (entry);
 
-      if (! psppire_dict_check_name (var_store->dict, name, TRUE))
+      if (! psppire_dict_check_name (var_store->dictionary, name, TRUE))
        return TRUE;
 
-      psppire_dict_insert_variable (var_store->dict, existing_cell->row, name);
+      psppire_dict_insert_variable (var_store->dictionary, existing_cell->row, name);
 
       return FALSE;
     }
@@ -278,7 +281,7 @@ traverse_cell_callback (PsppireSheet *sheet,
     {
       gint i;
       for ( i = n_vars ; i <= new_cell->row; ++i )
-       psppire_dict_insert_variable (var_store->dict, i, NULL);
+       psppire_dict_insert_variable (var_store->dictionary, i, NULL);
     }
 
   return FALSE;
@@ -384,6 +387,8 @@ var_sheet_change_active_cell (PsppireVarSheet *vs,
        vs->missing_val_dialog->pv =
          psppire_var_store_get_var (var_store, row);
 
+       vs->missing_val_dialog->dict = var_store->dictionary;
+
        g_signal_connect_swapped (customEntry,
                                  "clicked",
                                  G_CALLBACK (missing_val_dialog_show),
@@ -479,7 +484,8 @@ psppire_var_sheet_realize (GtkWidget *w)
   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (vs));
 
   vs->val_labs_dialog = val_labs_dialog_create (GTK_WINDOW (toplevel),
-                                               PSPPIRE_SHEET (vs));
+                                               PSPPIRE_VAR_STORE (psppire_sheet_get_model (PSPPIRE_SHEET (vs))));
+
   vs->missing_val_dialog = missing_val_dialog_create (GTK_WINDOW (toplevel));
   vs->var_type_dialog = var_type_dialog_create (GTK_WINDOW (toplevel));
 
index aadc585548582fc79629dca6b580e271ad6c7cde..ece728127c142733b6986844146d22e06129b9fb 100644 (file)
 
 #include "var-display.h"
 
+static void
+var_change_callback (GtkWidget *w, gint n, gpointer data)
+{
+  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
+
+  psppire_sheet_model_range_changed (model,
+                                n, 0, n, PSPPIRE_VAR_STORE_n_COLS);
+}
+
+
+static void
+var_delete_callback (GtkWidget *w, gint dict_idx, gint case_idx, gint val_cnt, gpointer data)
+{
+  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
+
+  psppire_sheet_model_rows_deleted (model, dict_idx, 1);
+}
+
+
+
+static void
+var_insert_callback (GtkWidget *w, glong row, gpointer data)
+{
+  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
+
+  psppire_sheet_model_rows_inserted (model, row, 1);
+}
+
+static void
+refresh (PsppireDict  *d, gpointer data)
+{
+  PsppireVarStore *vs = data;
+
+  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (vs), -1, -1, -1, -1);
+}
+
 enum
   {
     PROP_0,
-    PSPPIRE_VAR_STORE_FORMAT_TYPE
+    PSPPIRE_VAR_STORE_FORMAT_TYPE,
+    PSPPIRE_VAR_STORE_DICT
   };
 
 static void         psppire_var_store_init            (PsppireVarStore      *var_store);
 static void         psppire_var_store_class_init      (PsppireVarStoreClass *class);
 static void         psppire_var_store_sheet_model_init (PsppireSheetModelIface *iface);
 static void         psppire_var_store_finalize        (GObject           *object);
+static void         psppire_var_store_dispose        (GObject           *object);
 
 
 static gchar *psppire_var_store_get_string (const PsppireSheetModel *sheet_model, glong row, glong column);
@@ -145,6 +183,27 @@ psppire_var_store_set_property (GObject      *object,
       self->format_type = g_value_get_enum (value);
       break;
 
+    case PSPPIRE_VAR_STORE_DICT:
+      if ( self->dictionary)
+       g_object_unref (self->dictionary);
+      self->dictionary = g_value_dup_object (value);
+      g_signal_connect (self->dictionary, "variable-changed", G_CALLBACK (var_change_callback),
+                       self);
+
+      g_signal_connect (self->dictionary, "variable-deleted", G_CALLBACK (var_delete_callback),
+                       self);
+
+      g_signal_connect (self->dictionary, "variable-inserted",
+                       G_CALLBACK (var_insert_callback), self);
+
+      g_signal_connect (self->dictionary, "backend-changed", G_CALLBACK (refresh),
+                       self);
+
+      /* The entire model has changed */
+      psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (self), -1, -1, -1, -1);
+
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
       break;
@@ -165,8 +224,12 @@ psppire_var_store_get_property (GObject      *object,
       g_value_set_enum (value, self->format_type);
       break;
 
+    case PSPPIRE_VAR_STORE_DICT:
+      g_value_take_object (value, self->dictionary);
+      break;
+
     default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
     }
 }
@@ -176,16 +239,18 @@ static void
 psppire_var_store_class_init (PsppireVarStoreClass *class)
 {
   GObjectClass *object_class;
-  GParamSpec *pspec;
+  GParamSpec *format_pspec;
+  GParamSpec *dict_pspec;
 
   parent_class = g_type_class_peek_parent (class);
   object_class = (GObjectClass*) class;
 
   object_class->finalize = psppire_var_store_finalize;
+  object_class->dispose = psppire_var_store_dispose;
   object_class->set_property = psppire_var_store_set_property;
   object_class->get_property = psppire_var_store_get_property;
 
-  pspec = g_param_spec_enum ("format-type",
+  format_pspec = g_param_spec_enum ("format-type",
                              "Variable format type",
                              ("Whether variables have input or output "
                               "formats"),
@@ -195,7 +260,17 @@ psppire_var_store_class_init (PsppireVarStoreClass *class)
 
   g_object_class_install_property (object_class,
                                    PSPPIRE_VAR_STORE_FORMAT_TYPE,
-                                   pspec);
+                                   format_pspec);
+
+  dict_pspec = g_param_spec_object ("dictionary",
+                                   "Dictionary",
+                                   "The PsppireDict represented by this var store",
+                                   PSPPIRE_TYPE_DICT,
+                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+                                   
+  g_object_class_install_property (object_class,
+                                   PSPPIRE_VAR_STORE_DICT,
+                                   dict_pspec);
 }
 
 #define DISABLED_COLOR "gray"
@@ -206,7 +281,7 @@ psppire_var_store_init (PsppireVarStore *var_store)
   if ( ! gdk_color_parse (DISABLED_COLOR, &var_store->disabled))
        g_critical ("Could not parse color \"%s\"", DISABLED_COLOR);
 
-  var_store->dict = 0;
+  var_store->dictionary = NULL;
   var_store->format_type = PSPPIRE_VAR_STORE_OUTPUT_FORMATS;
 }
 
@@ -254,7 +329,7 @@ psppire_var_store_item_editable (PsppireVarStore *var_store, glong row, glong co
 struct variable *
 psppire_var_store_get_var (PsppireVarStore *store, glong row)
 {
-  return psppire_dict_get_variable (store->dict, row);
+  return psppire_dict_get_variable (store->dictionary, row);
 }
 
 static gboolean
@@ -315,49 +390,14 @@ psppire_var_store_new (PsppireDict *dict)
 {
   PsppireVarStore *retval;
 
-  retval = g_object_new (GTK_TYPE_VAR_STORE, NULL);
+  retval = g_object_new (GTK_TYPE_VAR_STORE, "dictionary", dict, NULL);
 
-  psppire_var_store_set_dictionary (retval, dict);
+  //  psppire_var_store_set_dictionary (retval, dict);
 
   return retval;
 }
 
-static void
-var_change_callback (GtkWidget *w, gint n, gpointer data)
-{
-  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
-
-  psppire_sheet_model_range_changed (model,
-                                n, 0, n, PSPPIRE_VAR_STORE_n_COLS);
-}
-
-
-static void
-var_delete_callback (GtkWidget *w, gint dict_idx, gint case_idx, gint val_cnt, gpointer data)
-{
-  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
-
-  psppire_sheet_model_rows_deleted (model, dict_idx, 1);
-}
-
-
-
-static void
-var_insert_callback (GtkWidget *w, glong row, gpointer data)
-{
-  PsppireSheetModel *model = PSPPIRE_SHEET_MODEL (data);
-
-  psppire_sheet_model_rows_inserted (model, row, 1);
-}
-
-static void
-refresh (PsppireDict  *d, gpointer data)
-{
-  PsppireVarStore *vs = data;
-
-  psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (vs), -1, -1, -1, -1);
-}
-
+#if 0
 /**
  * psppire_var_store_replace_set_dictionary:
  * @var_store: The variable store
@@ -388,6 +428,7 @@ psppire_var_store_set_dictionary (PsppireVarStore *var_store, PsppireDict *dict)
   /* The entire model has changed */
   psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (var_store), -1, -1, -1, -1);
 }
+#endif
 
 static void
 psppire_var_store_finalize (GObject *object)
@@ -396,6 +437,19 @@ psppire_var_store_finalize (GObject *object)
   (* parent_class->finalize) (object);
 }
 
+static void
+psppire_var_store_dispose (GObject *object)
+{
+  PsppireVarStore *self = PSPPIRE_VAR_STORE (object);
+
+  if (self->dictionary)
+    g_object_unref (self->dictionary);
+
+  /* must chain up */
+  (* parent_class->finalize) (object);
+}
+
+
 static gchar *
 psppire_var_store_get_string (const PsppireSheetModel *model,
                              glong row, glong column)
@@ -404,10 +458,10 @@ psppire_var_store_get_string (const PsppireSheetModel *model,
 
   struct variable *pv;
 
-  if ( row >= psppire_dict_get_var_cnt (store->dict))
+  if ( row >= psppire_dict_get_var_cnt (store->dictionary))
     return 0;
 
-  pv = psppire_dict_get_variable (store->dict, row);
+  pv = psppire_dict_get_variable (store->dictionary, row);
 
   return text_for_column (store, pv, column, 0);
 }
@@ -424,7 +478,7 @@ psppire_var_store_clear (PsppireSheetModel *model,  glong row, glong col)
 
   PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
 
-  if ( row >= psppire_dict_get_var_cnt (var_store->dict))
+  if ( row >= psppire_dict_get_var_cnt (var_store->dictionary))
       return FALSE;
 
   pv = psppire_var_store_get_var (var_store, row);
@@ -435,7 +489,7 @@ psppire_var_store_clear (PsppireSheetModel *model,  glong row, glong col)
   switch (col)
     {
     case PSPPIRE_VAR_STORE_COL_LABEL:
-      var_set_label (pv, 0);
+      var_set_label (pv, NULL);
       return TRUE;
       break;
     }
@@ -455,7 +509,7 @@ psppire_var_store_set_string (PsppireSheetModel *model,
 
   PsppireVarStore *var_store = PSPPIRE_VAR_STORE (model);
 
-  if ( row >= psppire_dict_get_var_cnt (var_store->dict))
+  if ( row >= psppire_dict_get_var_cnt (var_store->dictionary))
       return FALSE;
 
   pv = psppire_var_store_get_var (var_store, row);
@@ -468,13 +522,7 @@ psppire_var_store_set_string (PsppireSheetModel *model,
     case PSPPIRE_VAR_STORE_COL_NAME:
       {
        gboolean ok;
-       char *s = recode_string (psppire_dict_encoding (var_store->dict),
-                                UTF8,
-                                text, -1);
-
-       ok =  psppire_dict_rename_var (var_store->dict, pv, s);
-
-       free (s);
+       ok =  psppire_dict_rename_var (var_store->dictionary, pv, text);
        return ok;
       }
     case PSPPIRE_VAR_STORE_COL_COLUMNS:
@@ -540,11 +588,7 @@ psppire_var_store_set_string (PsppireSheetModel *model,
       break;
     case PSPPIRE_VAR_STORE_COL_LABEL:
       {
-       gchar *s = recode_string (psppire_dict_encoding (var_store->dict),
-                                 UTF8,
-                                 text, -1);
-       var_set_label (pv, s);
-       free (s);
+       var_set_label (pv, text);
        return TRUE;
       }
       break;
@@ -571,7 +615,7 @@ static  gchar *
 text_for_column (PsppireVarStore *vs,
                 const struct variable *pv, gint c, GError **err)
 {
-  PsppireDict *dict = vs->dict;
+  PsppireDict *dict = vs->dictionary;
   static const gchar *const type_label[] =
     {
       N_("Numeric"),
@@ -583,6 +627,7 @@ text_for_column (PsppireVarStore *vs,
       N_("Custom"),
       N_("String")
     };
+
   enum {VT_NUMERIC, VT_COMMA, VT_DOT, VT_SCIENTIFIC, VT_DATE, VT_DOLLAR,
        VT_CUSTOM, VT_STRING};
 
@@ -591,8 +636,7 @@ text_for_column (PsppireVarStore *vs,
   switch (c)
     {
     case PSPPIRE_VAR_STORE_COL_NAME:
-      return recode_string (UTF8, psppire_dict_encoding (dict),
-                           var_get_name (pv), -1);
+      return xstrdup (var_get_name (pv));
       break;
     case PSPPIRE_VAR_STORE_COL_TYPE:
       {
@@ -679,8 +723,12 @@ text_for_column (PsppireVarStore *vs,
       }
       break;
     case PSPPIRE_VAR_STORE_COL_LABEL:
-      return recode_string (UTF8, psppire_dict_encoding (dict),
-                           var_get_label (pv), -1);
+      {
+       const char *label = var_get_label (pv);
+       if (label)
+         return xstrdup (label);
+       return NULL;
+      }
       break;
 
     case PSPPIRE_VAR_STORE_COL_MISSING:
@@ -694,8 +742,6 @@ text_for_column (PsppireVarStore *vs,
          return g_locale_to_utf8 (gettext (none), -1, 0, 0, err);
        else
          {
-           gchar *ss;
-           GString *gstr = g_string_sized_new (10);
            const struct val_labs *vls = var_get_value_labels (pv);
             const struct val_lab **labels = val_labs_sorted (vls);
            const struct val_lab *vl = labels[0];
@@ -704,17 +750,10 @@ text_for_column (PsppireVarStore *vs,
            g_assert (vl);
 
            {
-             gchar *const vstr = value_to_text (vl->value, *write_spec);
+             gchar *const vstr = value_to_text (vl->value, dict, *write_spec);
 
-             g_string_printf (gstr, "{%s,\"%s\"}_",
-                               vstr, val_lab_get_label (vl));
-             g_free (vstr);
+             return g_strdup_printf ( "{%s,\"%s\"}_", vstr, val_lab_get_label (vl));
            }
-
-           ss = recode_string (UTF8, psppire_dict_encoding (dict),
-                               gstr->str, gstr->len);
-           g_string_free (gstr, TRUE);
-           return ss;
          }
       }
       break;
@@ -741,7 +780,7 @@ text_for_column (PsppireVarStore *vs,
 gint
 psppire_var_store_get_var_cnt (PsppireVarStore  *store)
 {
-  return psppire_dict_get_var_cnt (store->dict);
+  return psppire_dict_get_var_cnt (store->dictionary);
 }
 
 
@@ -751,8 +790,8 @@ psppire_var_store_get_row_count (const PsppireSheetModel * model)
   gint rows = 0;
   PsppireVarStore *vs = PSPPIRE_VAR_STORE (model);
 
-  if (vs->dict)
-    rows =  psppire_dict_get_var_cnt (vs->dict);
+  if (vs->dictionary)
+    rows =  psppire_dict_get_var_cnt (vs->dictionary);
 
   return rows ;
 }
@@ -773,10 +812,10 @@ get_row_sensitivity (const PsppireSheetModel *model, gint row)
 {
   PsppireVarStore *vs = PSPPIRE_VAR_STORE (model);
 
-  if ( ! vs->dict)
+  if ( ! vs->dictionary)
     return FALSE;
 
-  return  row < psppire_dict_get_var_cnt (vs->dict);
+  return  row < psppire_dict_get_var_cnt (vs->dictionary);
 }
 
 
index 4cda0159bf0e776f4601f1e1b126b3ed211d11f2..e4c2ecd827c47fd9bc6747fddcb1d710357e157b 100644 (file)
@@ -63,7 +63,7 @@ struct _PsppireVarStore
   GObject parent;
 
   /*< private >*/
-  PsppireDict *dict;
+  PsppireDict *dictionary;
   GdkColor disabled;
   PsppireVarStoreFormatType format_type;
 };
@@ -84,9 +84,6 @@ GType         psppire_var_store_get_type         (void) G_GNUC_CONST;
 PsppireVarStore *psppire_var_store_new              (PsppireDict *dict);
 struct variable * psppire_var_store_get_var (PsppireVarStore *store, glong row);
 
-void psppire_var_store_set_dictionary (PsppireVarStore *var_store, PsppireDict *dict);
-
-
 /* Return the number of variables */
 gint psppire_var_store_get_var_cnt (PsppireVarStore      *var_store);
 
index a6f4bb223f35612ce9a399c647444556c85c5bda..a096752897ccecf703757980637c43c786230e9c 100644 (file)
@@ -3,31 +3,6 @@
 <!--*- mode: xml -*-->
 <glade-interface>
   <requires lib="psppire"/>
-  <widget class="GtkAboutDialog" id="aboutdialog1">
-    <property name="modal">True</property>
-    <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
-    <property name="copyright">Free Software Foundation</property>
-    <property name="comments" translatable="yes">This is beta status software.  Please report bugs to bug-gnu-pspp@gnu.org</property>
-    <property name="authors"></property>
-    <property name="logo">pspplogo.png</property>
-    <child internal-child="vbox">
-      <widget class="GtkVBox" id="dialog-vbox1">
-        <property name="visible">True</property>
-        <child>
-          <placeholder/>
-        </child>
-        <child internal-child="action_area">
-          <widget class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">GTK_PACK_END</property>
-          </packing>
-        </child>
-      </widget>
-    </child>
-  </widget>
   <widget class="PsppireDialog" id="weight-cases-dialog">
     <property name="title">Weight Cases</property>
     <property name="modal">True</property>
index db5cd4fbb4bf1972065e0230e9ad34cc919a43ef..b2894095b76c69335e6b3f73d3276305967b5787 100644 (file)
@@ -238,7 +238,7 @@ rank_dialog (GObject *o, gpointer data)
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
-  rd.dict = vs->dict;
+  g_object_get (vs, "dictionary", &rd.dict, NULL);
   rd.rank_vars =   get_widget_assert (builder, "variables-treeview");
   rd.group_vars =  get_widget_assert (builder, "group-vars-treeview");
   rd.dialog = get_widget_assert   (builder, "rank-dialog");
@@ -306,9 +306,9 @@ rank_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (rd.dialog), GTK_WINDOW (de));
 
-  g_object_set (vars, "dictionary", vs->dict, NULL);
+  g_object_set (vars, "dictionary", rd.dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (rd.rank_vars), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (rd.rank_vars), rd.dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector1),
                                 vars,
@@ -317,7 +317,7 @@ rank_dialog (GObject *o, gpointer data)
                                 NULL,
                                 NULL);
 
-  set_dest_model (GTK_TREE_VIEW (rd.group_vars), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (rd.group_vars), rd.dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector2),
                                 vars,
index 495aefb82914b8026f7f507e75aa72b13759a019..0bb82eb335a9a6d3c75a13f6c1cf34e47863c8a3 100644 (file)
@@ -867,7 +867,7 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
   rd.new_name_entry = get_widget_assert (builder, "dest-name-entry");
   rd.new_label_entry = get_widget_assert (builder, "dest-label-entry");
 
-  rd.dict = vs->dict;
+  g_object_get (vs, "dictionary", &rd.dict, NULL);
 
   rd.value_map = gtk_list_store_new (2,
                                     old_value_get_type (),
@@ -888,11 +888,11 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
   gtk_window_set_transient_for (GTK_WINDOW (rd.dialog), GTK_WINDOW (de));
 
 
-  g_object_set (rd.dict_treeview, "dictionary", vs->dict, NULL);
+  g_object_set (rd.dict_treeview, "dictionary", rd.dict, NULL);
 
   if ( ! rd.different )
     {
-      set_dest_model (GTK_TREE_VIEW (rd.variable_treeview), vs->dict);
+      set_dest_model (GTK_TREE_VIEW (rd.variable_treeview), rd.dict);
     }
   else
     {
@@ -916,7 +916,7 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
 
       gtk_tree_view_column_set_cell_data_func (col, renderer,
                                               cell_var_name,
-                                              vs->dict, 0);
+                                              rd.dict, 0);
 
 
       gtk_tree_view_append_column (GTK_TREE_VIEW (rd.variable_treeview), col);
index a702ffb78df0c8d7681c2ec52ce8b6612efc65f8..eaca17e074e49aef32c5cbbb7447ef3c012b94b8 100644 (file)
@@ -253,10 +253,11 @@ regression_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (source, "dictionary", vs->dict, NULL);
+  g_object_get (vs, "dictionary", &rd.dict, NULL);
+  g_object_set (source, "dictionary", rd.dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (dest_dep), vs->dict);
-  set_dest_model (GTK_TREE_VIEW (dest_indep), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (dest_dep), rd.dict);
+  set_dest_model (GTK_TREE_VIEW (dest_indep), rd.dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (dep_selector),
                                 source,
@@ -274,7 +275,8 @@ regression_dialog (GObject *o, gpointer data)
 
   rd.dep_vars = GTK_TREE_VIEW (dest_dep);
   rd.indep_vars = GTK_TREE_VIEW (dest_indep);
-  rd.dict = vs->dict;
+
+
   rd.save_dialog = get_widget_assert (xml, "save-dialog");
   rd.pred_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "pred-button"));
   rd.resid_button = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "resid-button"));
index 4db99d978e34d8bffc9a5b7c808eeea4b94d2174..66c8bf5ce4b3eed41425643db8bd3eb5ec043790 100644 (file)
@@ -137,11 +137,10 @@ reliability_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (source, "dictionary", vs->dict, NULL);
+  g_object_get (vs, "dictionary", &rd.dict, NULL);
+  g_object_set (source, "dictionary", rd.dict, NULL);
 
-  rd.dict = vs->dict;
-
-  set_dest_model (GTK_TREE_VIEW (rd.variables), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (rd.variables), rd.dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
                                 source,
index a11356109daad8f9c4ac3a202dd382bd9a3305af..4e7ac61f5ca94ddd2670ccd8baadfeb65c0529e7 100644 (file)
@@ -111,9 +111,10 @@ sort_cases_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (source, "dictionary", vs->dict, NULL);
+  g_object_get (vs, "dictionary", &scd.dict, NULL);
+  g_object_set (source, "dictionary", scd.dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (dest), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (dest), scd.dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
                                 source,
@@ -125,7 +126,6 @@ sort_cases_dialog (GObject *o, gpointer data)
   g_signal_connect (dialog, "refresh", G_CALLBACK (refresh),  dest);
 
   scd.tv = GTK_TREE_VIEW (dest);
-  scd.dict = vs->dict;
   scd.ascending =
     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "sort-cases-radiobutton0"));
 
index 458a3c53532a1eafdddbd9552f14cc4b11286ffc..613f8e91fe601cf544f32bb62933c00211c3869a 100644 (file)
@@ -186,19 +186,16 @@ split_file_dialog (GObject *o, gpointer data)
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
-  sfd.dict = vs->dict;
+  g_object_get (vs, "dictionary", &sfd.dict, NULL);
   sfd.tv = GTK_TREE_VIEW (dest);
   sfd.selector  = PSPPIRE_SELECTOR (
                                    get_widget_assert   (sfd.xml, "split-file-selector"));
 
-  g_object_set (source, "dictionary",
-                                vs->dict, NULL);
-
+  g_object_set (source, "dictionary", sfd.dict, NULL);
 
   g_signal_connect (on_off, "toggled", G_CALLBACK(on_off_toggled),  sfd.xml);
 
-
-  set_dest_model (GTK_TREE_VIEW (dest), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (dest), sfd.dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
                                 source,
index f5df9f36e3004533789b74a78ae16670f57baab5..5d77ce43031ea7e46b37c3f0de57e9f9a22e67eb 100644 (file)
@@ -416,7 +416,7 @@ t_test_independent_samples_dialog (GObject *o, gpointer data)
 
   tt_d.dialog = get_widget_assert (xml, "t-test-independent-samples-dialog");
   tt_d.xml = xml;
-  tt_d.dict = vs->dict;
+  g_object_get (vs, "dictionary", &tt_d.dict, NULL);
 
   tt_d.define_groups_button = get_widget_assert (xml, "define-groups-button");
   tt_d.groups_entry = get_widget_assert (xml, "indep-samples-t-test-entry");
@@ -426,11 +426,9 @@ t_test_independent_samples_dialog (GObject *o, gpointer data)
 
   gtk_window_set_transient_for (GTK_WINDOW (tt_d.dialog), GTK_WINDOW (de));
 
-  g_object_set (dict_view, "dictionary", 
-                                vs->dict,
-                                NULL);
+  g_object_set (dict_view, "dictionary", tt_d.dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (test_variables_treeview), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (test_variables_treeview), tt_d.dict);
 
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector1),
index 18bdbb5dd3003f506a73a3b265a449a679541d77..8b2d8af795e055552e3cec44981e1e6b5f2ed4f9 100644 (file)
@@ -141,7 +141,7 @@ t_test_one_sample_dialog (GObject *o, gpointer data)
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
-  tt_d.dict = vs->dict;
+  g_object_get (vs, "dictionary", &tt_d.dict, NULL);
   tt_d.vars_treeview = get_widget_assert (xml, "one-sample-t-test-treeview1");
   tt_d.test_value_entry = get_widget_assert (xml, "test-value-entry");
   tt_d.opt = tt_options_dialog_create (xml, GTK_WINDOW (de));
@@ -149,11 +149,11 @@ t_test_one_sample_dialog (GObject *o, gpointer data)
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
   g_object_set (dict_view, "dictionary",
-                                vs->dict,
-       "predicate",
-                                var_is_numeric, NULL);
+               tt_d.dict,
+               "predicate",
+               var_is_numeric, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (tt_d.vars_treeview), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (tt_d.vars_treeview), tt_d.dict);
 
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
index dcc24fadd85c8ddc75354efdf94100190dd17c28..15b99ad21914c6e3b119b5ab810dc54e6941dc48 100644 (file)
@@ -199,7 +199,7 @@ t_test_paired_samples_dialog (GObject *o, gpointer data)
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
-  tt_d.dict = vs->dict;
+  g_object_get (vs, "dictionary", &tt_d.dict, NULL);
   tt_d.pairs_treeview =
    get_widget_assert (xml, "paired-samples-t-test-treeview2");
   tt_d.opt = tt_options_dialog_create (xml, GTK_WINDOW (de));
@@ -207,10 +207,9 @@ t_test_paired_samples_dialog (GObject *o, gpointer data)
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
 
-  g_object_set (dict_view, "dictionary",
-                                vs->dict,
-                                "predicate",
-                                var_is_numeric, NULL);
+  g_object_set (dict_view, "dictionary", tt_d.dict,
+               "predicate",
+               var_is_numeric, NULL);
 
   {
     tt_d.list_store =
index dac8b4c1e0a5c0ad8cb22ef0887b85375eefe94b..6f33ff6d8bb8b6547a76a91bc06d35260a3a1881 100644 (file)
@@ -1543,6 +1543,7 @@ init_formats_page (struct import_assistant *ia)
   p->data_tree_view = GTK_TREE_VIEW (get_widget_assert (builder, "data"));
   p->modified_vars = NULL;
   p->modified_var_cnt = 0;
+  p->dict = NULL;
 }
 
 /* Frees IA's formats substructure. */
@@ -1748,7 +1749,9 @@ parse_field (struct import_assistant *ia,
   if (field.string != NULL)
     {
       msg_disable ();
+
       if (!data_in (field, LEGACY_NATIVE, in->type, 0, 0, 0,
+                   ia->formats.dict,
                     &val, var_get_width (var)))
         {
           char fmt_string[FMT_STRING_LEN_MAX + 1];
@@ -1768,10 +1771,7 @@ parse_field (struct import_assistant *ia,
     }
   if (outputp != NULL)
     {
-      char *output = xmalloc (out.w + 1);
-      data_out (&val, &out, output);
-      output[out.w] = '\0';
-      *outputp = output;
+      *outputp = data_out (&val, dict_get_encoding (ia->formats.dict),  &out);
     }
   value_destroy (&val, var_get_width (var));
 
index beed72d731590eb4089d442a41e684545e2be6da..36640f6f752a71829b391c1310a243d97de8eb17 100644 (file)
@@ -80,6 +80,7 @@ transpose_dialog (GObject *o, gpointer data)
 {
   gint response ;
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
+  PsppireDict *dict = NULL;
 
   GtkBuilder *xml = builder_new ("psppire.ui");
 
@@ -94,9 +95,10 @@ transpose_dialog (GObject *o, gpointer data)
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
-  g_object_set (source, "dictionary", vs->dict, NULL);
+  g_object_get (vs, "dictionary", &dict, NULL);
+  g_object_set (source, "dictionary", dict, NULL);
 
-  set_dest_model (GTK_TREE_VIEW (dest), vs->dict);
+  set_dest_model (GTK_TREE_VIEW (dest), dict);
 
   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector1),
                                 source, dest,
@@ -125,7 +127,7 @@ transpose_dialog (GObject *o, gpointer data)
     {
     case GTK_RESPONSE_OK:
       {
-       gchar *syntax = generate_syntax (vs->dict, xml);
+       gchar *syntax = generate_syntax (dict, xml);
 
        struct getl_interface *sss = create_syntax_string_source (syntax);
        execute_syntax (sss);
@@ -135,7 +137,7 @@ transpose_dialog (GObject *o, gpointer data)
       break;
     case PSPPIRE_RESPONSE_PASTE:
       {
-       gchar *syntax = generate_syntax (vs->dict, xml);
+       gchar *syntax = generate_syntax (dict, xml);
         paste_syntax_in_new_window (syntax);
 
        g_free (syntax);
index 0af805912da167444ece82f14bd079c03f054da9..14eacabfadddb5842e81f444855233b0e903ec03 100644 (file)
@@ -34,7 +34,8 @@ struct val_labs_dialog
 {
   GtkWidget *window;
 
-  PsppireSheet *vs;
+  PsppireVarStore *var_store;
+  PsppireDict *dict;
 
   /* The variable to be updated */
   struct variable *pv;
@@ -71,9 +72,10 @@ on_label_entry_change (GtkEntry *entry, gpointer data)
 
   text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
 
-  text_to_value (text, &v,
-               *var_get_write_format (dialog->pv));
-
+  text_to_value (text,
+                dialog->dict,
+                dialog->pv,
+                &v);
 
   if (val_labs_find (dialog->labs, &v))
     {
@@ -85,6 +87,8 @@ on_label_entry_change (GtkEntry *entry, gpointer data)
       gtk_widget_set_sensitive (dialog->change_button, FALSE);
       gtk_widget_set_sensitive (dialog->add_button, TRUE);
     }
+
+  value_destroy (&v, var_get_width (dialog->pv));
 }
 
 
@@ -141,8 +145,10 @@ on_value_entry_change (GtkEntry *entry, gpointer data)
   const gchar *text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
 
   union value v;
-  text_to_value (text, &v,
-               *var_get_write_format (dialog->pv));
+  text_to_value (text,
+                dialog->dict,
+                dialog->pv,
+                &v);
 
 
   g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
@@ -166,6 +172,8 @@ on_value_entry_change (GtkEntry *entry, gpointer data)
 
   g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
                         dialog->change_handler_id);
+
+  value_destroy (&v, var_get_width (dialog->pv));
 }
 
 
@@ -202,14 +210,12 @@ val_labs_cancel (struct val_labs_dialog *dialog)
 
 /* Callback for when the Value Labels dialog is closed using
    the Cancel button.*/
-static gint
+static void
 on_cancel (GtkWidget *w, gpointer data)
 {
   struct val_labs_dialog *dialog = data;
 
   val_labs_cancel (dialog);
-
-  return FALSE;
 }
 
 
@@ -258,7 +264,7 @@ get_selected_tuple (struct val_labs_dialog *dialog,
 static void repopulate_dialog (struct val_labs_dialog *dialog);
 
 /* Callback which occurs when the "Change" button is clicked */
-static gint
+static void
 on_change (GtkWidget *w, gpointer data)
 {
   struct val_labs_dialog *dialog = data;
@@ -267,8 +273,10 @@ on_change (GtkWidget *w, gpointer data)
 
   union value v;
 
-  text_to_value (val_text, &v,
-               *var_get_write_format (dialog->pv));
+  text_to_value (val_text,
+                dialog->dict,
+                dialog->pv,
+                &v);
 
   val_labs_replace (dialog->labs, &v,
                    gtk_entry_get_text (GTK_ENTRY (dialog->label_entry)));
@@ -278,11 +286,11 @@ on_change (GtkWidget *w, gpointer data)
   repopulate_dialog (dialog);
   gtk_widget_grab_focus (dialog->value_entry);
 
-  return FALSE;
+  value_destroy (&v, var_get_width (dialog->pv));
 }
 
 /* Callback which occurs when the "Add" button is clicked */
-static gint
+static void
 on_add (GtkWidget *w, gpointer data)
 {
   struct val_labs_dialog *dialog = data;
@@ -291,25 +299,26 @@ on_add (GtkWidget *w, gpointer data)
 
   const gchar *text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
 
-  text_to_value (text, &v,
-               *var_get_write_format (dialog->pv));
+  text_to_value (text,
+                dialog->dict,
+                dialog->pv,
+                &v);
 
+  if (val_labs_add (dialog->labs, &v,
+                   gtk_entry_get_text
+                   ( GTK_ENTRY (dialog->label_entry)) ) )
+    {
+      gtk_widget_set_sensitive (dialog->add_button, FALSE);
 
-  if ( ! val_labs_add (dialog->labs, &v,
-                      gtk_entry_get_text
-                      ( GTK_ENTRY (dialog->label_entry)) ) )
-    return FALSE;
-
-  gtk_widget_set_sensitive (dialog->add_button, FALSE);
-
-  repopulate_dialog (dialog);
-  gtk_widget_grab_focus (dialog->value_entry);
+      repopulate_dialog (dialog);
+      gtk_widget_grab_focus (dialog->value_entry);
+    }
 
-  return FALSE;
+  value_destroy (&v, var_get_width (dialog->pv));
 }
 
 /* Callback which occurs when the "Remove" button is clicked */
-static gint
+static void
 on_remove (GtkWidget *w, gpointer data)
 {
   struct val_labs_dialog *dialog = data;
@@ -326,8 +335,6 @@ on_remove (GtkWidget *w, gpointer data)
   gtk_widget_grab_focus (dialog->value_entry);
 
   gtk_widget_set_sensitive (dialog->remove_button, FALSE);
-
-  return FALSE;
 }
 
 
@@ -337,19 +344,15 @@ on_remove (GtkWidget *w, gpointer data)
 static void
 on_select_row (GtkTreeView *treeview, gpointer data)
 {
-  gchar *labeltext;
   struct val_labs_dialog *dialog = data;
 
   union value value;
-  const char *label;
+  const char *label = NULL;
 
   gchar *text;
 
-  PsppireVarStore *var_store =
-    PSPPIRE_VAR_STORE (psppire_sheet_get_model (dialog->vs));
-
   get_selected_tuple (dialog, &value, &label);
-  text = value_to_text (value, *var_get_write_format (dialog->pv));
+  text = value_to_text (value, dialog->dict, *var_get_write_format (dialog->pv));
 
   g_signal_handler_block (GTK_ENTRY (dialog->value_entry),
                         dialog->value_handler_id);
@@ -364,12 +367,8 @@ on_select_row (GtkTreeView *treeview, gpointer data)
                         dialog->change_handler_id);
 
 
-  labeltext = recode_string (UTF8, psppire_dict_encoding (var_store->dict),
-                            label, -1);
-
   gtk_entry_set_text (GTK_ENTRY (dialog->label_entry),
-                    labeltext);
-  g_free (labeltext);
+                     label);
 
   g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
                         dialog->change_handler_id);
@@ -382,7 +381,7 @@ on_select_row (GtkTreeView *treeview, gpointer data)
 /* Create a new dialog box
    (there should  normally be only one)*/
 struct val_labs_dialog *
-val_labs_dialog_create (GtkWindow *toplevel, PsppireSheet *sheet)
+val_labs_dialog_create (GtkWindow *toplevel, PsppireVarStore *var_store)
 {
   GtkTreeViewColumn *column;
 
@@ -392,10 +391,11 @@ val_labs_dialog_create (GtkWindow *toplevel, PsppireSheet *sheet)
 
   struct val_labs_dialog *dialog = g_malloc (sizeof (*dialog));
 
+  dialog->var_store = var_store;
+  g_object_get (var_store, "dictionary", &dialog->dict, NULL);
   dialog->window = get_widget_assert (xml,"val_labs_dialog");
   dialog->value_entry = get_widget_assert (xml,"value_entry");
   dialog->label_entry = get_widget_assert (xml,"label_entry");
-  dialog->vs = sheet;
 
   gtk_window_set_transient_for
     (GTK_WINDOW (dialog->window), toplevel);
@@ -420,38 +420,38 @@ val_labs_dialog_create (GtkWindow *toplevel, PsppireSheet *sheet)
 
   g_signal_connect (get_widget_assert (xml, "val_labs_cancel"),
                   "clicked",
-                  GTK_SIGNAL_FUNC (on_cancel), dialog);
+                  G_CALLBACK (on_cancel), dialog);
 
   g_signal_connect (dialog->window, "delete-event",
-                   GTK_SIGNAL_FUNC (on_delete), dialog);
+                   G_CALLBACK (on_delete), dialog);
 
   g_signal_connect (get_widget_assert (xml, "val_labs_ok"),
                   "clicked",
-                  GTK_SIGNAL_FUNC (val_labs_ok), dialog);
+                  G_CALLBACK (val_labs_ok), dialog);
 
   dialog->change_handler_id =
     g_signal_connect (dialog->label_entry,
                     "changed",
-                    GTK_SIGNAL_FUNC (on_label_entry_change), dialog);
+                    G_CALLBACK (on_label_entry_change), dialog);
 
   dialog->value_handler_id  =
     g_signal_connect (dialog->value_entry,
                     "changed",
-                    GTK_SIGNAL_FUNC (on_value_entry_change), dialog);
+                    G_CALLBACK (on_value_entry_change), dialog);
 
   g_signal_connect (dialog->change_button,
                   "clicked",
-                  GTK_SIGNAL_FUNC (on_change), dialog);
+                  G_CALLBACK (on_change), dialog);
 
 
   g_signal_connect (dialog->treeview, "cursor-changed",
-                  GTK_SIGNAL_FUNC (on_select_row), dialog);
+                  G_CALLBACK (on_select_row), dialog);
 
   g_signal_connect (dialog->remove_button, "clicked",
-                  GTK_SIGNAL_FUNC (on_remove), dialog);
+                  G_CALLBACK (on_remove), dialog);
 
   g_signal_connect (dialog->add_button, "clicked",
-                  GTK_SIGNAL_FUNC (on_add), dialog);
+                  G_CALLBACK (on_add), dialog);
 
   dialog->labs = 0;
 
@@ -481,9 +481,6 @@ repopulate_dialog (struct val_labs_dialog *dialog)
 
   GtkTreeIter iter;
 
-  PsppireVarStore *var_store =
-    PSPPIRE_VAR_STORE (psppire_sheet_get_model (dialog->vs));
-
   GtkListStore *list_store = gtk_list_store_new (2,
                                                 G_TYPE_STRING,
                                                 G_TYPE_DOUBLE);
@@ -508,16 +505,11 @@ repopulate_dialog (struct val_labs_dialog *dialog)
       const struct val_lab *vl = labels[i];
 
       gchar *const vstr  =
-       value_to_text (vl->value,
+       value_to_text (vl->value, dialog->dict,
                      *var_get_write_format (dialog->pv));
 
-      gchar *labeltext =
-       recode_string (UTF8,
-                      psppire_dict_encoding (var_store->dict),
-                      val_lab_get_label (vl), -1);
-
       gchar *const text = g_strdup_printf ("%s = \"%s\"",
-                                          vstr, labeltext);
+                                          vstr, val_lab_get_label (vl));
 
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
@@ -525,7 +517,6 @@ repopulate_dialog (struct val_labs_dialog *dialog)
                          1, vl->value.f,
                          -1);
 
-      g_free (labeltext);
       g_free (text);
       g_free (vstr);
     }
index 3a09f1ca410e0f2f6b775741d9e62dde48e4aae7..745e0a0ae5f795b2786a078d9e435ca633ad242c 100644 (file)
 
 #include <gtk/gtk.h>
 #include <data/variable.h>
-#include <gtk-contrib/psppire-sheet.h>
-
+//#include <gtk-contrib/psppire-sheet.h>
+#include "psppire-var-store.h"
 
 struct val_labs;
 
 
-struct val_labs_dialog * val_labs_dialog_create (GtkWindow *, PsppireSheet *);
+struct val_labs_dialog * val_labs_dialog_create (GtkWindow *, PsppireVarStore *);
 
 void val_labs_dialog_show (struct val_labs_dialog *);
 
index b615fe522b3f76286143daef43bca1b9b42cd49a..7081e9e2c0bde74fc4c9424f729733ba8a74c1c2 100644 (file)
@@ -45,15 +45,14 @@ missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GE
          gint i;
          for (i = 0 ; i < n; ++i )
            {
-             mv[i] = value_to_text (*mv_get_value (miss, i), *fmt);
+             mv[i] = value_to_text (*mv_get_value (miss, i), dict, *fmt);
              if ( i > 0 )
                g_string_append (gstr, ", ");
              g_string_append (gstr, mv[i]);
              g_free (mv[i]);
            }
-         s = recode_string (UTF8, psppire_dict_encoding (dict),
-                            gstr->str, gstr->len);
-         g_string_free (gstr, TRUE);
+         s = gstr->str;
+         g_string_free (gstr, FALSE);
        }
       else
        {
@@ -62,8 +61,8 @@ missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GE
          union value low, high;
          mv_get_range (miss, &low.f, &high.f);
 
-         l = value_to_text (low, *fmt);
-         h = value_to_text (high, *fmt);
+         l = value_to_text (low, dict, *fmt);
+         h = value_to_text (high, dict,*fmt);
 
          g_string_printf (gstr, "%s - %s", l, h);
          g_free (l);
@@ -73,15 +72,14 @@ missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GE
            {
              gchar *ss = 0;
 
-             ss = value_to_text (*mv_get_value (miss, 0), *fmt);
+             ss = value_to_text (*mv_get_value (miss, 0), dict, *fmt);
 
              g_string_append (gstr, ", ");
              g_string_append (gstr, ss);
              free (ss);
            }
-         s = recode_string (UTF8, psppire_dict_encoding (dict),
-                            gstr->str, gstr->len);
-         g_string_free (gstr, TRUE);
+         s = gstr->str;
+         g_string_free (gstr, FALSE);
        }
 
       return s;
index c433bf3b2535e080e926093b2be5193c1760a252..05ba5d3c9e748c61662bc8ee48914a521938490f 100644 (file)
@@ -262,12 +262,12 @@ preview_custom (GtkWidget *w, gpointer data)
       union value v;
       v.f = 1234.56;
 
-      sample_text = value_to_text (v, dialog->fmt_l);
+      sample_text = value_to_text (v, NULL, dialog->fmt_l);
       gtk_label_set_text (GTK_LABEL (dialog->label_psample), sample_text);
       g_free (sample_text);
 
       v.f = -v.f;
-      sample_text = value_to_text (v, dialog->fmt_l);
+      sample_text = value_to_text (v, NULL, dialog->fmt_l);
       gtk_label_set_text (GTK_LABEL (dialog->label_nsample), sample_text);
       g_free (sample_text);
     }
index fa9d51011e8d2fec88b14cd2439d606a65836fd3..2fdf2df87440ce8beec883aa65aab02dce988123 100644 (file)
 static const gchar none[] = N_("None");
 
 
-static gchar *
-name_to_string (const struct variable *var, PsppireDict *dict)
-{
-  const char *name = var_get_name (var);
-  g_assert (name);
-
-  return recode_string (UTF8, psppire_dict_encoding (dict),
-                       name, -1);
-}
-
-
-static gchar *
-label_to_string (const struct variable *var, PsppireDict *dict)
+static const gchar *
+label_to_string (const struct variable *var)
 {
   const char *label = var_get_label (var);
 
-  if (! label) return g_strdup (none);
+  if (NULL == label) return g_strdup (none);
 
-  return recode_string (UTF8, psppire_dict_encoding (dict),
-                       label, -1);
+  return label;
 }
 
 
@@ -77,21 +65,15 @@ populate_text (PsppireDictView *treeview, gpointer data)
   if ( var == NULL)
     return;
 
-  g_object_get (treeview,
-               "dictionary", &dict,
+  g_object_get (treeview, "dictionary", &dict,
                NULL);
 
   gstring = g_string_sized_new (200);
-  text = name_to_string (var, dict);
-  g_string_assign (gstring, text);
-  g_free (text);
+  g_string_assign (gstring, var_get_name (var));
   g_string_append (gstring, "\n");
 
 
-  text = label_to_string (var, dict);
-  g_string_append_printf (gstring, _("Label: %s\n"), text);
-  g_free (text);
-
+  g_string_append_printf (gstring, _("Label: %s\n"), label_to_string (var));
   {
     const struct fmt_spec *fmt = var_get_print_format (var);
     char buffer[FMT_STRING_LEN_MAX + 1];
@@ -130,14 +112,10 @@ populate_text (PsppireDictView *treeview, gpointer data)
         {
           const struct val_lab *vl = labels[i];
          gchar *const vstr  =
-           value_to_text (vl->value,  *var_get_print_format (var));
-
-         text = recode_string (UTF8, psppire_dict_encoding (dict),
-                               val_lab_get_label (vl), -1);
+           value_to_text (vl->value,  dict, *var_get_print_format (var));
 
-         g_string_append_printf (gstring, _("%s %s\n"), vstr, text);
+         g_string_append_printf (gstring, _("%s %s\n"), vstr, val_lab_get_label (vl));
 
-         g_free (text);
          g_free (vstr);
        }
       free (labels);
@@ -180,13 +158,14 @@ variable_info_dialog (GObject *o, gpointer data)
   GtkWidget *textview = get_widget_assert (xml, "textview1");
 
   PsppireVarStore *vs = NULL;
+  PsppireDict *dict = NULL;
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
-  g_object_set (treeview,
-               "dictionary", vs->dict,
+  g_object_get (vs, "dictionary", &dict, NULL);
+  g_object_set (treeview, "dictionary", dict,
                "selection-mode", GTK_SELECTION_SINGLE,
                NULL);
 
index 11b528ba76d1ebf2f3f06cea96cabad8d8eac7f9..b3087159f941adf7d16b7d2dc1d66f7165ee38d5 100644 (file)
@@ -120,6 +120,7 @@ weight_cases_dialog (GObject *o, gpointer data)
   PsppireVarStore *vs = NULL;
 
   g_object_get (de->data_editor, "var-store", &vs,  NULL);
+  g_object_get (vs, "dictionary", &wcd.dict, NULL);
 
   gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
 
@@ -130,7 +131,8 @@ weight_cases_dialog (GObject *o, gpointer data)
   g_signal_connect (selector, "de-selected", G_CALLBACK (on_deselect),
                    radiobutton1);
 
-  g_object_set (source, "dictionary", vs->dict,
+  
+  g_object_set (source, "dictionary", wcd.dict,
                                 "selection-mode", GTK_SELECTION_SINGLE,
                                 "predicate", var_is_numeric,
                                 NULL);
@@ -144,7 +146,7 @@ weight_cases_dialog (GObject *o, gpointer data)
                                 );
 
 
-  wcd.dict = vs->dict;
+
   wcd.entry = GTK_ENTRY (entry);
   wcd.status = GTK_LABEL (status);
   wcd.off = GTK_TOGGLE_BUTTON (radiobutton1);
index bf1ee12f244caadbfc4197c0b7be466c7660a51e..22e717ac965903acdb5a8b12f95e5e3dd6492832 100644 (file)
@@ -146,20 +146,23 @@ syntax_gen_number (struct string *output,
           & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
     {
       union value v_in, v_out;
-      char buffer[FMT_MAX_NUMERIC_WIDTH];
+      char *s;
       bool ok;
 
       v_in.f = number;
-      data_out (&v_in, format, buffer);
+      s = data_out (&v_in, "FIXME",  format);
       msg_disable ();
-      ok = data_in (ss_buffer (buffer, format->w), LEGACY_NATIVE,
-                    format->type, false, 0, 0, &v_out, 0);
+      /* FIXME: UTF8 encoded strings will fail here */
+      ok = data_in (ss_cstr (s), LEGACY_NATIVE,
+                    format->type, false, 0, 0, NULL, &v_out, 0);
       msg_enable ();
       if (ok && v_out.f == number)
         {
-          syntax_gen_string (output, ss_buffer (buffer, format->w));
+          syntax_gen_string (output, ss_cstr (s));
+         free (s);
           return;
         }
+      free (s);
     }
 
   if (number == SYSMIS)
index 0fa61752bfe5c9ca68de6651c0c2c88622176bbb..15e297a0150209c1586636de126a7a92a5d8defe 100644 (file)
@@ -56,6 +56,8 @@ dist_TESTS = \
        tests/command/regression.sh \
        tests/command/regression-qr.sh \
        tests/command/reliability.sh \
+       tests/command/roc.sh \
+       tests/command/roc2.sh \
        tests/command/sample.sh \
        tests/command/sort.sh \
        tests/command/sysfiles.sh \
@@ -134,12 +136,14 @@ dist_TESTS = \
        tests/bugs/overwrite-special-file.sh \
        tests/bugs/piechart.sh \
        tests/bugs/random.sh \
+       tests/bugs/shbang.sh \
        tests/bugs/signals.sh \
        tests/bugs/t-test-with-temp.sh \
        tests/bugs/t-test.sh \
        tests/bugs/t-test-alpha.sh \
        tests/bugs/t-test-alpha2.sh \
        tests/bugs/t-test-alpha3.sh \
+       tests/bugs/t-test-paired.sh \
        tests/bugs/temporary.sh \
        tests/bugs/unwritable-dir.sh \
        tests/bugs/val-labs.sh \
diff --git a/tests/bugs/shbang.sh b/tests/bugs/shbang.sh
new file mode 100755 (executable)
index 0000000..826d5dc
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/sh
+
+# This program tests that PSPP ignores the first line of a PSPP syntax
+# file that begins with #!, without issuing an error (bug #26518).
+
+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
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+
+cleanup()
+{
+     if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then 
+       echo "NOT cleaning $TEMPDIR"
+       return ; 
+     fi
+     cd /
+     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
+#! $PSPP
+DATA LIST LIST NOTABLE /a.
+BEGIN DATA.
+1
+2
+END DATA.
+LIST.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="run program"
+$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+activity="compare output"
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
+diff -b  -w $TEMPDIR/pspp.list - << EOF
+       a
+--------
+    1.00
+    2.00
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+pass;
diff --git a/tests/bugs/t-test-paired.sh b/tests/bugs/t-test-paired.sh
new file mode 100755 (executable)
index 0000000..f722f61
--- /dev/null
@@ -0,0 +1,117 @@
+#!/bin/sh
+
+# This program tests for a bug in the paired samples T test.
+# Thanks to Mike Griffiths for reporting this problem.
+
+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
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+LANG=C
+export LANG
+
+
+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
+set format f8.3.
+data list list /A * B *.
+begin data.
+11 2
+1  1
+1  1
+end data.
+
+t-test pairs = a with b (paired).
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="run program"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="compare output"
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
+diff  -b  $TEMPDIR/pspp.list - << EOF
+1.1 DATA LIST.  Reading free-form data from INLINE.
++--------+------+
+|Variable|Format|
+#========#======#
+|A       |F8.0  |
+|B       |F8.0  |
++--------+------+
+2.1 T-TEST.  Paired Sample Statistics
+#========#=====#=#==============#========#
+#        # Mean|N|Std. Deviation|SE. Mean#
+#========#=====#=#==============#========#
+#Pair 0 A#4.333|3|         5.774|   3.333#
+#       B#1.333|3|          .577|    .333#
+#========#=====#=#==============#========#
+2.2 T-TEST.  Paired Samples Correlations
+#======#=====#=#===========#====#
+#      |     #N|Correlation|Sig.#
+#======#=====#=#===========#====#
+#Pair 0|A & B#3|      1.000|.000#
+#======#=====#=#===========#====#
+2.3 T-TEST.  Paired Samples Test
+#===========#==================================================#=====#==#===============#
+#           #                Paired Differences                |     |  |               #
+#           #-----+--------------+---------------+-------------+     |  |               #
+#           #     |              |               |     95%     |     |  |               #
+#           #     |              |               +------+------+     |  |               #
+#           # Mean|Std. Deviation|Std. Error Mean| Lower| Upper|  t  |df|Sig. (2-tailed)#
+#===========#=====#==============#===============#======#======#=====#==#===============#
+#Pair 0A - B#3.000|         5.196|          3.000|-9.908|15.908|1.000| 2|           .423#
+#===========#=====#==============#===============#======#======#=====#==#===============#
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+pass;
index 7d3890c3430bf5fe34c22467cfcc9338bf4ff6f7..3f821199ff3e2d10f22627e6ce35c93ec7b1f157 100755 (executable)
@@ -76,7 +76,7 @@ begin data.
 6
 7,
 8 9
-0,1,,,
+0,1 ,,,
 ,,,,
 2
 
index 746f1a670911e629e2121bf8187cb06e00f7bef4..c28c8dd478c9f6dc4dd04ea8ddd5dbb2ac27a069 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# This program tests that pspp can read gnumeric files
+# This program tests that pspp can read Gnumeric files
 
 TEMPDIR=/tmp/pspp-tst-$$
 TESTFILE=$TEMPDIR/`basename $0`.sps
index ae0d39fcba50afedfa9c7f66db21af4310387d96..4242b55b6581dcd82e551392856857c7fc3919e0 100755 (executable)
@@ -107,14 +107,14 @@ cat > $TEMPDIR/results.txt <<EOF
 #============================#==#=========#============#
 
 1.2 NPAR TESTS.  Test Statistics
-#=====================#==============#
-#                     #second - first#
-#=====================#==============#
-#Z                    #          -.18#
-#Asymp. Sig (2-tailed)#           .86#
-#Exact Sig (2-tailed) #           .89#
-#Exact Sig (1-tailed) #           .45#
-#=====================#==============#
+#======================#==============#
+#                      #second - first#
+#======================#==============#
+#Z                     #          -.18#
+#Asymp. Sig. (2-tailed)#           .86#
+#Exact Sig. (2-tailed) #           .89#
+#Exact Sig. (1-tailed) #           .45#
+#======================#==============#
 
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
diff --git a/tests/command/roc.sh b/tests/command/roc.sh
new file mode 100755 (executable)
index 0000000..0c24f0c
--- /dev/null
@@ -0,0 +1,173 @@
+#!/bin/sh
+
+# This program tests  the ROC command.
+
+TEMPDIR=/tmp/pspp-tst-$$
+TESTFILE=$TEMPDIR/`basename $0`.sps
+
+# ensure that top_builddir  are absolute
+if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
+if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
+top_builddir=`cd $top_builddir; pwd`
+PSPP=$top_builddir/src/ui/terminal/pspp
+
+# ensure that top_srcdir is absolute
+top_srcdir=`cd $top_srcdir; pwd`
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+LANG=C
+export LANG
+
+cleanup()
+{
+     if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then 
+       echo "NOT cleaning $TEMPDIR" 
+       return ; 
+     fi
+     cd /
+     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
+
+activity="create program"
+cat > $TESTFILE <<EOF
+set format F10.3.
+data list notable list /x * y * w * a *.
+begin data.
+1 1 2  1
+1 2 28 0
+2 3 4  1
+2 4 14 0
+3 5 10 1
+. . 1  0
+3 1 5  0
+4 2 14 1
+4 3 2  0
+5 4 20 1
+5 4 20 .
+5 5 1  0
+end data.
+
+weight by w.
+
+roc x by a (1)
+       /plot = none
+       /print = se coordinates
+       /criteria = testpos(large) distribution(free) ci(99)
+       /missing = exclude .
+
+roc x y by a (1)
+       /plot = curve(reference)
+        /print = se coordinates
+       /criteria = testpos(large) distribution(negexpo) ci(95)
+       /missing = exclude .
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program"
+$SUPERVISOR $PSPP --testing-mode $TESTFILE
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="compare results"
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
+diff -b  $TEMPDIR/pspp.list - << EOF
+1.1 ROC.  Case Summary
+#========#===================#
+#        # Valid N (listwise)#
+#        #==========#========#
+#a       #Unweighted|Weighted#
+#========#==========#========#
+#Positive#         5|  50.000#
+#Negative#         5|  50.000#
+#========#==========#========#
+1.2 ROC.  Area Under the Curve (x)
+#====#==========#===============#=======================#
+#    |          |               | Asymp. 99% Confidence #
+#    |          |               +-----------+-----------#
+#Area|Std. Error|Asymptotic Sig.|Lower Bound|Upper Bound#
+#====#==========#===============#===========#===========#
+#.910|      .030|           .000|       .839|       .981#
+#====#==========#===============#===========#===========#
+1.3 ROC.  Coordinates of the Curve (x)
+#====================================#===========#===============#
+#Positive if greater than or equal to|Sensitivity|1 - Specificity#
+#====================================#===========#===============#
+#                                .000|      1.000|          1.000#
+#                               1.500|       .960|           .440#
+#                               2.500|       .880|           .160#
+#                               3.500|       .680|           .060#
+#                               4.500|       .400|           .020#
+#                               6.000|       .000|           .000#
+#====================================#===========#===============#
+2.1 ROC.  Case Summary
+#========#===================#
+#        # Valid N (listwise)#
+#        #==========#========#
+#a       #Unweighted|Weighted#
+#========#==========#========#
+#Positive#         5|  50.000#
+#Negative#         5|  50.000#
+#========#==========#========#
+See pspp-1.png for a chart.
+2.2 ROC.  Area Under the Curve
+#===================#====#==========#===============#=======================#
+#                   #    |          |               | Asymp. 95%            #
+#                   #    |          |               +-----------+-----------#
+#Variable under test#Area|Std. Error|Asymptotic Sig.|Lower Bound|Upper Bound#
+#===================#====#==========#===============#===========#===========#
+#                  x#.910|      .030|           .000|       .860|       .960#
+#                  y#.697|      .052|           .001|       .611|       .783#
+#===================#====#==========#===============#===========#===========#
+2.3 ROC.  Coordinates of the Curve
+#=============#====================================#===========#===============#
+#Test variable#Positive if greater than or equal to|Sensitivity|1 - Specificity#
+#=============#====================================#===========#===============#
+#            x#                                .000|      1.000|          1.000#
+#             #                               1.500|       .960|           .440#
+#             #                               2.500|       .880|           .160#
+#             #                               3.500|       .680|           .060#
+#             #                               4.500|       .400|           .020#
+#             #                               6.000|       .000|           .000#
+#-------------#------------------------------------+-----------+---------------#
+#            y#                                .000|      1.000|          1.000#
+#             #                               1.500|       .960|           .900#
+#             #                               2.500|       .680|           .340#
+#             #                               3.000|       .600|           .340#
+#             #                               3.500|       .600|           .300#
+#             #                               4.500|       .200|           .020#
+#             #                               6.000|       .000|           .000#
+#=============#====================================#===========#===============#
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+pass
diff --git a/tests/command/roc2.sh b/tests/command/roc2.sh
new file mode 100755 (executable)
index 0000000..a8020b0
--- /dev/null
@@ -0,0 +1,131 @@
+#!/bin/sh
+
+# This program tests  the ROC command.
+
+TEMPDIR=/tmp/pspp-tst-$$
+TESTFILE=$TEMPDIR/`basename $0`.sps
+
+# ensure that top_builddir  are absolute
+if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
+if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
+top_builddir=`cd $top_builddir; pwd`
+PSPP=$top_builddir/src/ui/terminal/pspp
+
+# ensure that top_srcdir is absolute
+top_srcdir=`cd $top_srcdir; pwd`
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+LANG=C
+export LANG
+
+cleanup()
+{
+     if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then 
+       echo "NOT cleaning $TEMPDIR" 
+       return ; 
+     fi
+     cd /
+     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
+
+activity="create program"
+cat > $TESTFILE <<EOF
+set format F10.3.
+data list notable list /x * a * comment (a20).
+begin data.
+0  1 ""
+0  0 ""
+1  1 ""
+1  0 ""
+2  1 ""
+2  0 ""
+5  1 ""
+5  0 ""
+10 1 ""
+10 0 ""
+15 1 ""
+15 0 ""
+20 1 ""
+20 1 ""
+22 0 "here and"
+22 0 "here is the anomoly"
+25 1 ""
+25 0 ""
+30 1 ""
+30 0 ""
+35 1 ""
+35 0 ""
+38 1 ""
+38 0 ""
+39 1 ""
+39 0 ""
+40 1 ""
+40 0 ""
+end data.
+
+roc x by a (1)
+       /plot = none
+       print = se 
+       .
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program"
+$SUPERVISOR $PSPP --testing-mode $TESTFILE
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="compare results"
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
+diff -b  $TEMPDIR/pspp.list - << EOF
+1.1 ROC.  Case Summary
+#========#===================#
+#        # Valid N (listwise)#
+#        #==========#========#
+#a       #Unweighted|Weighted#
+#========#==========#========#
+#Positive#        14|  14.000#
+#Negative#        14|  14.000#
+#========#==========#========#
+1.2 ROC.  Area Under the Curve (x)
+#====#==========#===============#=======================#
+#    |          |               | Asymp. 95% Confidence #
+#    |          |               +-----------+-----------#
+#Area|Std. Error|Asymptotic Sig.|Lower Bound|Upper Bound#
+#====#==========#===============#===========#===========#
+#.490|      .111|           .927|       .307|       .673#
+#====#==========#===============#===========#===========#
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+pass
index a9f4bf2fb27f43b525fb764c07fb14c706d111d6..c46c268376c77031baff7e6c06fa14a44808bd65 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <ctype.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 
 #include <data/casereader-provider.h>
@@ -404,7 +405,7 @@ value_from_param (union value *value, int width, unsigned int idx)
   else
     {
       unsigned int hash = hash_int (idx, 0);
-      char *string = value_str_rw (value, width);
+      uint8_t *string = value_str_rw (value, width);
       int offset;
 
       assert (width < 32);
index 897d48ffb59bf26d832c1d069f4173ed1c0ee9b5..85f3644211d3171423239c59b14ab7136f28b36a 100644 (file)
@@ -583,13 +583,18 @@ read_machine_float_info (struct sfm_reader *r, size_t size, size_t count)
 
   printf ("\tsysmis: %g\n", sysmis);
   if (sysmis != SYSMIS)
-    sys_warn (r, _("File specifies unexpected value %g as SYSMIS."), sysmis);
+    sys_warn (r, _("File specifies unexpected value %g as %s."),
+              sysmis, "SYSMIS");
+
   printf ("\thighest: %g\n", highest);
   if (highest != HIGHEST)
-    sys_warn (r, _("File specifies unexpected value %g as HIGHEST."), highest);
+    sys_warn (r, _("File specifies unexpected value %g as %s."),
+              highest, "HIGHEST");
+
   printf ("\tlowest: %g\n", lowest);
   if (lowest != LOWEST)
-    sys_warn (r, _("File specifies unexpected value %g as LOWEST."), lowest);
+    sys_warn (r, _("File specifies unexpected value %g as %s."),
+              lowest, "LOWEST");
 }
 
 /* Read record type 7, subtype 11. */